Properly build 'buildxl.dscript' VSCode extension with Npm (#966)

* build vscode extension automatically with BuildXL
* copy package-lock.json to cg/npm
This commit is contained in:
Rijul Luman 2019-10-03 11:24:02 -07:00 коммит произвёл GitHub
Родитель 621edb7bd8
Коммит b4785aa5f4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 325 добавлений и 143 удалений

Просмотреть файл

@ -71,7 +71,7 @@ namespace Node {
pkgContents,
],
prepareTempDirectory: true,
dependsOnWindowsDirectories: true,
dependsOnCurrentHostOSDirectories: true,
dependsOnAppDataDirectory: true,
};
}
@ -103,4 +103,25 @@ namespace Node {
return pkgContents.getFile(executable);
}
@@public
export function tscCompile(workingDirectory: Directory, dependencies: StaticDirectory[]) : OpaqueDirectory {
const outPath = d`${workingDirectory}/out`;
const arguments: Argument[] = [
Cmd.argument(Artifact.none(f`${workingDirectory}/node_modules/typescript/lib/tsc.js`)),
Cmd.argument("-p"),
Cmd.argument("."),
];
const result = Node.run({
arguments: arguments,
workingDirectory: workingDirectory,
dependencies: dependencies,
outputs: [
{ directory: outPath, kind: "shared" }
]
});
return result.getOutputDirectory(outPath);
}
}

Просмотреть файл

@ -41,6 +41,36 @@ namespace Npm {
};
}
@@public
export function npmInstall(rootDir: StaticDirectory): OpaqueDirectory {
const wd = rootDir.root;
const nodeModulesPath = d`${wd}/node_modules`;
const npmCachePath = Context.getNewOutputDirectory('npm-install-cache');
const arguments: Argument[] = [
Cmd.argument(Artifact.input(Node.npmCli)),
Cmd.argument("install"),
Cmd.option("--cache ", Artifact.none(npmCachePath)), // Forces the npm cache to use this output folder for this object so that it doesn't write to user folder
];
const result = Node.run({
arguments: arguments,
workingDirectory: wd,
dependencies: [ rootDir ],
outputs: [
{ directory: wd, kind: "shared" },
npmCachePath, // Place the cache path as an output directory so it is cleaned each time.
],
environmentVariables: [
{ name: "NPM_CONFIG_USERCONFIG", value: f`${wd}/.npmrc` }, // Prevents user configuration to change behavior
{ name: "NPM_CONFIG_GLOBALCONFIG", value: f`${wd}/global.npmrc` }, // Prevent machine installed configuration file to change behavior.
{ name: "NO_UPDATE_NOTIFIER", value: "1" }, // Prevent npm from checking for the latest version online and write to the user folder with the check information
],
});
return result.getOutputDirectory(wd);
}
@@public
export interface Arguments {
name: string,
@ -48,7 +78,6 @@ namespace Npm {
}
export interface Result {
nodeModules: OpaqueDirectory,
nodeModules: OpaqueDirectory
}
}
}

Просмотреть файл

@ -53,12 +53,12 @@ export interface DeployedFileWithProvenance {
@@public
export interface FlattenedResult {
flattenedFiles: Map<RelativePath, DeployedFileWithProvenance>,
flattenedOpaques: Map<RelativePath, OpaqueDirectory>,
flattenedOpaques: Map<RelativePath, OpaqueSubDirectory>, // Tuple of (1) an opaque directory, and (2) a path relative to that opaque directory designating a subdirectory to be added to the deployment
visitedItems: Set<Object>,
}
/**
* Helper type alias for handeling duplicate file deployments. It can decide to return one or the other, but commonly it should just fail.
* Helper type alias for handling duplicate file deployments. It can decide to return one or the other, but commonly it should just fail.
* The canaonical implementation is Diagnostics.reportDuplicateError
*/
@@public
@ -84,7 +84,7 @@ export interface Deployable {
/**
* Callback for when deployments will be processed. By processing we mean flattening the recursive structure into a flat list which is encoded by the FlattenedResult type.
* @param item - The item that is deployable. Think of this as the 'this' pointer which is not accessable from interface implementations.
* @param item - The item that is deployable. Think of this as the 'this' pointer which is not accessible from interface implementations.
* @param targetFolder - The folder to place this deployable item into
* @param onDuplicate - The error handler for duplicate files
* @param currentResult - The current flattened result to add the extra flattened files to

Просмотреть файл

@ -16,6 +16,31 @@ export interface OnDiskDeployment {
/** Optional primary file, i.e. an executable or test dll */
primaryFile?: File;
/** Optional opaque directories robocopied/rsynced into this deployment */
targetOpaques?: OpaqueDirectory[];
}
@@public
export interface OpaqueSubDirectory {
/** Parent opaque directory */
opaque: OpaqueDirectory,
/** An optional path relative to that opaque directory designating a subdirectory to be added to the deployment.
* If not specified, the whole opaque directory will be added to the deployment
*/
subDirectory?: RelativePath,
}
/**
* Used to represent deployment of a subdirectory of an opaque directory.
*
* Call the 'createDeployableOpaqueSubDirectory' function below to create an instance of this type.
*/
@@public
export interface DeployableOpaqueSubDirectory extends Deployable, OpaqueSubDirectory {
/** This property is set automatically by the 'createDeployableOpaqueSubDirectory' function below */
deploy: FlattenForDeploymentFunction
}
/**
@ -39,6 +64,153 @@ export interface DeployToDiskArguments {
deploymentOptions?: DeploymentOptions;
}
@@public
export function createDeployableOpaqueSubDirectory(opaque: OpaqueDirectory, sub?: RelativePath): Deployable {
return <DeployableOpaqueSubDirectory> {
opaque: opaque,
subDirectory: sub,
deploy: (
item: Object,
targetFolder: RelativePath,
handleDuplicateFile: HandleDuplicateFileDeployment,
result: FlattenedResult,
deploymentOptions?: Object,
provenance?: Diagnostics.Provenance) =>
{
const existingOpaque = result.flattenedOpaques.get(targetFolder);
if (existingOpaque !== undefined) {
if (!(existingOpaque.opaque === opaque && existingOpaque.subDirectory === sub)) {
let subDir = sub || r`.`;
Contract.fail(`Duplicate opaque directory. Can't deploy both '${existingOpaque.opaque.root}/${subDir}' and '${opaque.root}/${subDir}' to '${targetFolder}'`);
}
return result;
}
else {
return {
flattenedFiles: result.flattenedFiles,
flattenedOpaques: result.flattenedOpaques.add(targetFolder, {opaque: <OpaqueDirectory>opaque, subDirectory: sub}),
visitedItems: result.visitedItems.add(d`{opaque.root}/${sub}`),
};
}
}
};
}
/**
* Schedules a platform-specific process to copy file from 'source' to 'target'. This process takes a dependency
* on 'sourceOpaqueDir`, which should be the parent opaque directory containing the file 'source'.
*/
@@public
export function copyFileFromOpaqueDirectory(source: Path, target: Path, sourceOpaqueDir: OpaqueDirectory): DerivedFile {
const args: Transformer.ExecuteArguments = Context.getCurrentHost().os === "win"
? <Transformer.ExecuteArguments>{
tool: {
exe: f`${Context.getMount("Windows").path}/System32/cmd.exe`,
dependsOnWindowsDirectories: true,
description: "Copy File",
},
workingDirectory: d`${source.parent}`,
arguments: [
Cmd.argument("/D"),
Cmd.argument("/C"),
Cmd.argument("copy"),
Cmd.argument("/Y"),
Cmd.argument("/V"),
Cmd.argument(Artifact.none(source)),
Cmd.argument(Artifact.output(target))
],
dependencies: [
sourceOpaqueDir
]
}
: <Transformer.ExecuteArguments>{
tool: {
exe: f`/bin/cp`,
description: "Copy File",
dependsOnCurrentHostOSDirectories: true,
prepareTempDirectory: true
},
workingDirectory: d`${source.parent}`,
arguments: [
Cmd.argument("-f"),
Cmd.argument(Artifact.none(source)),
Cmd.argument(Artifact.output(target))
],
dependencies: [
sourceOpaqueDir
]
};
const result = Transformer.execute(args);
return result.getOutputFile(target);
}
/**
* Based on the current platform schedules either a robocopy.exe or rsync pip to copy 'sourceDir' to 'targetDir'.
* That pip takes a dependency on `sourceDirDep`. If 'sourceDir' is not within `sourceDirDep.root`, disallowed
* file accesses are almost certain to happen.
*/
@@public
export function copyDirectory(sourceDir: Directory, targetDir: Directory, sourceDirDep: StaticDirectory): OpaqueDirectory {
const args: Transformer.ExecuteArguments = Context.getCurrentHost().os === "win"
? <Transformer.ExecuteArguments>{
tool: {
exe: f`${Context.getMount("Windows").path}/System32/Robocopy.exe`,
dependsOnWindowsDirectories: true,
description: "Copy Directory",
},
workingDirectory: targetDir,
successExitCodes: [
0,
1,
2,
4,
],
arguments: [
Cmd.argument(Artifact.none(sourceDir)),
Cmd.argument(Artifact.none(targetDir)),
Cmd.argument("*.*"),
Cmd.argument("/MIR"), // Mirror the directory
Cmd.argument("/NJH"), // No Job Header
Cmd.argument("/NFL"), // No File list reducing stdout processing
Cmd.argument("/NP"), // Don't show per-file progress counter
Cmd.argument("/MT"), // Multi threaded
],
dependencies: [
sourceDirDep
],
outputs: [
{ directory: targetDir, kind: "shared" }
]
}
: <Transformer.ExecuteArguments>{
tool: {
exe: f`/usr/bin/rsync`,
description: "Copy Directory",
dependsOnCurrentHostOSDirectories: true,
prepareTempDirectory: true
},
workingDirectory: targetDir,
arguments: [
Cmd.argument("-arvh"),
Cmd.argument(Cmd.join("", [ Artifact.none(sourceDir), '/' ])),
Cmd.argument(Artifact.none(targetDir)),
Cmd.argument("--delete"),
],
dependencies: [
sourceDirDep
],
outputs: [
{ directory: targetDir, kind: "shared" }
]
};
const result = Transformer.execute(args);
return result.getOutputDirectory(targetDir);
}
/**
* Deploys a given deployment to disk
*/
@ -57,66 +229,26 @@ export function deployToDisk(args: DeployToDiskArguments): OnDiskDeployment {
return Transformer.copyFile(data.file, targetPath, args.tags);
});
if (flattened.flattenedOpaques.count() > 0) {
const targetOpaques = flattened.flattenedOpaques.forEach(tuple => {
const relativeTarget = tuple[0];
const opaque = tuple[1];
const targetOpaques = flattened.flattenedOpaques.toArray().map(tuple => {
const relativeTarget = tuple[0];
const opaque = tuple[1].opaque;
const opaqueSub = tuple[1].subDirectory || r`.`;
const targetDir = d`${rootDir}/${relativeTarget}`;
const targetDir = d`${rootDir}/${relativeTarget}`;
return copyDirectory(d`${opaque}/${opaqueSub}`, targetDir, opaque);
});
const result = Context.getCurrentHost().os === "win"
? Transformer.execute({
tool: {
exe: f`${Context.getMount("Windows").path}/System32/Robocopy.exe`,
dependsOnWindowsDirectories: true,
description: "Copy Directory",
},
workingDirectory: targetDir,
successExitCodes: [
0,
1,
2,
4,
],
arguments: [
Cmd.argument(Artifact.input(opaque)),
Cmd.argument(Artifact.output(targetDir)),
Cmd.argument("*.*"),
Cmd.argument("/MIR"), // Mirror the directory
Cmd.argument("/NJH"), // No Job Header
Cmd.argument("/NFL"), // No File list reducing stdout processing
Cmd.argument("/NP"), // Don't show per-file progress counter
Cmd.argument("/MT"), // Multi threaded
]
})
: Transformer.execute({
tool: {
exe: f`/usr/bin/rsync`,
description: "Copy Directory",
},
workingDirectory: targetDir,
arguments: [
Cmd.argument("-arvh"),
Cmd.argument(Cmd.join("", [ Artifact.input(opaque), '/' ])),
Cmd.argument(Artifact.output(targetDir)),
Cmd.argument("--delete"),
]
});
return result.getOutputDirectory(targetDir);
});;
}
// TODO: We lack the ability to combine files and OpagueDuirecties into a new OpaqueDirectory (unless we write a single process that would do all the copies)
// Therefore for now we'll just copy the opaques but don't make it part of the output StaticDirectory field contents
// There is a hole here for consumers but today we only use this in selfhost in the final deployment.
// TODO: We lack the ability to combine files and OpaqueDirectories into a new OpaqueDirectory (unless we write a single process that would do all the copies)
// Therefore for now we'll just copy the opaques but don't make it part of the output StaticDirectory field contents;
// we do, however, pass those additional opaque directories along (via the 'targetOpaques' property)
// so the caller can appropriately take dependencies on them.
const contents = Transformer.sealPartialDirectory(rootDir, targetFiles, args.tags);
return {
deployedDefinition: args.definition,
contents: contents,
primaryFile : args.primaryFile ? contents.getFile(args.primaryFile) : undefined,
targetOpaques: targetOpaques
};
}
@ -192,4 +324,4 @@ export interface CreateFromDiskOptions {
/** Whether to recurse into directories or not */
recursive?: boolean
}
}

Просмотреть файл

@ -4,7 +4,7 @@
@@public
export const emptyFlattenedResult : FlattenedResult = {
flattenedFiles: Map.empty<RelativePath, { file: File, disambiguationData: any }>(),
flattenedOpaques: Map.empty<RelativePath, OpaqueDirectory>(),
flattenedOpaques: Map.empty<RelativePath, OpaqueSubDirectory>(),
visitedItems: Set.empty<Object>(),
};
@ -230,7 +230,7 @@ function flattenStaticDirectory(staticDirectory: StaticDirectory, targetFolder:
// TODO: Improve error logging and disambiguation
if (existingOpaque !== undefined) {
if (existingOpaque !== staticDirectory) {
if (existingOpaque[0] !== staticDirectory) {
Contract.fail(`Duplicate opaque directory. Can't deploy both '{existingOpaque.root}' and '{staticDirectory.root}' to '{targetFolder}'`);
}
@ -240,7 +240,7 @@ function flattenStaticDirectory(staticDirectory: StaticDirectory, targetFolder:
// TODO: Validate if there is a flattenedFile already under this OpaqueDirectory. To implement this we'll need IsWithin on RelativePath
return {
flattenedFiles: result.flattenedFiles,
flattenedOpaques: result.flattenedOpaques.add(targetFolder, <OpaqueDirectory>staticDirectory),
flattenedOpaques: result.flattenedOpaques.add(targetFolder, {opaque: <OpaqueDirectory>staticDirectory}),
visitedItems: result.visitedItems.add(staticDirectory),
};
}

Просмотреть файл

@ -204,10 +204,10 @@ function createNuSpecFile(
// Process the flattened opaque directories
for (let opaque of flattened.flattenedOpaques.toArray())
{
dependencies = dependencies.push(opaque[1]);
dependencies = dependencies.push(opaque[1].opaque);
fileElements = fileElements.push(
Xml.elem("file",
Xml.attr("src", [opaque[1].path, "\\**"]),
Xml.attr("src", [opaque[1].opaque.path, "\\**"]),
Xml.attr("target", opaque[0])
)
);

Просмотреть файл

@ -86,7 +86,7 @@ namespace DeploymentHelpers {
const filesResult = runner.addFilesToDrop(createResult, args, filesToAdd);
// Add all Opaque directories via a batch call.
const directoriesToAdd = flattenedResult.flattenedOpaques.forEach(kvp => <DirectoryInfo>{dropPath: kvp[0], directory: kvp[1]});
const directoriesToAdd = flattenedResult.flattenedOpaques.forEach(kvp => <DirectoryInfo>{dropPath: kvp[0], directory: kvp[1].opaque});
const directoryResults = runner.addDirectoriesToDrop(createResult, args, directoriesToAdd);
};
}

Просмотреть файл

@ -1,22 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
import {Transformer} from "Sdk.Transformers";
import {Artifact, Transformer} from "Sdk.Transformers";
import * as ManagedSdk from "Sdk.Managed";
import * as Deployment from "Sdk.Deployment";
import * as Transformers from "Sdk.Transformers";
import * as DetoursServices from "BuildXL.Sandbox.Windows";
import * as Branding from "BuildXL.Branding";
import * as VSIntegration from "BuildXL.Ide.VsIntegration";
import {Node, Npm} from "Sdk.NodeJs";
namespace VsCode.Client {
// A new namespace with empty qualifier space to ensure the values inside are evaluated only once
export declare const qualifier: {};
const clientSealDir = Transformer.sealDirectory(d`client`, globR(d`client`));
const clientCopy: OpaqueDirectory = Deployment.copyDirectory(clientSealDir.root, Context.getNewOutputDirectory("client-copy"), clientSealDir);
@public
export const installRootDir: OpaqueDirectory = Npm.npmInstall(clientCopy);
@@public
export const compileOutDir: OpaqueDirectory = Node.tscCompile(clientCopy.root, [clientCopy, installRootDir]);
@@public
export const deployedNpmPackageLockFile = Deployment.copyFileFromOpaqueDirectory(
// Here we want to copy a file from inside an opaque output directory.
// If done using Transformer.copyFile we would have no way of specifying a dependency
// of that copy pip to the pip producing this opaque directory, so we wouldn't be able to
// ensure that the copy operation runs after the opaque directory is produced.
p`${installRootDir}/package-lock.json`,
p`${Context.getMount("CgNpmRoot").path}/package-lock.json`,
installRootDir);
}
namespace LanguageService.Server {
/**
* Builds a VSIX for given version that packages the server assembly (with closure of its references)
* as well as client resources
*/
export function buildVsix(serverAssembly: ManagedSdk.Assembly) : DerivedFile {
const vsixDeploymentDefinition = buildVsixDeploymentDefinition(serverAssembly);
// Special "scrubbable" mount should be use for deploying vsix package content.
@ -34,7 +58,8 @@ namespace LanguageService.Server {
outputFileName: `BuildXL.vscode.${qualifier.targetRuntime}.vsix`,
inputDirectory: vsixDeployment.contents,
useUriEncoding: true,
fixUnixPermissions: qualifier.targetRuntime === "osx-x64"
fixUnixPermissions: qualifier.targetRuntime === "osx-x64",
additionalDependencies: vsixDeployment.targetOpaques
});
return vsix;
@ -48,7 +73,6 @@ namespace LanguageService.Server {
* means that any change to client/src/extension.ts needs to be recompiled and the checked-in file updated.
*/
export function buildVsixDeploymentDefinition(serverAssembly: ManagedSdk.Assembly) : Deployment.Definition {
// We have to publish the vsix to the Visual Studio MarketPlace which doesn't handle prerelease tags.
let version = Branding.versionNumberForToolsThatDontSupportPreReleaseTag;
let manifest = IDE.VersionUtilities.updateVersion(version, f`pluginTemplate/extension.vsixmanifest`);
@ -89,23 +113,24 @@ namespace LanguageService.Server {
subfolder: a`projectManagement`,
contents: globR(d`client/projectManagement`)
},
{
subfolder: a`node_modules`,
contents: [ Deployment.createDeployableOpaqueSubDirectory(VsCode.Client.installRootDir, r`node_modules`) ]
},
{
subfolder: a`out`,
contents: [ VsCode.Client.compileOutDir ]
},
f`client/License.txt`,
f`client/package.nls.json`,
readme,
f`client/ThirdPartyNotices.txt`,
Branding.pngFile,
json,
// This contains the actual extension source as well as the
// node_modules that it depends on.
Transformer.sealDirectory({
root: d`pluginTemplate/extension`,
files: globR(d`pluginTemplate/extension`)
}),
]
},
f`pluginTemplate/[Content_Types].xml`,
manifest
manifest,
]
};

Просмотреть файл

@ -1,15 +1,5 @@
# BuildXL DScript IDE
## Making a change
In order to avoid doing TS compilations in-build (that would have to deal with installing packages, etc.) the 'pluginTemplate' folder contains a checked-in compiled version extension.ts.
- This means that any changes to files under
<b>client/src</b> needs to be recompiled and the checked-in file updated.
The recompilation can be triggered by manually running <b>buildVsix.bat</b>, and then replacing <b>pluginTemplate/extension/out/src/extension.ts</b> with the result of the compilation, located under client/out/src.
- The same goes for node_modules, some of which are checked in. If you update <b>client/package.json</b> with a new version of a node module, please make sure to check in the updated modules to <b>pluginTemplates/extension</b>
## Debugging with VSCode
Step by step:
> Install NPM (https://www.npmjs.com/get-npm)

Просмотреть файл

@ -303,8 +303,6 @@
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"update-vscode": "node ./node_modules/vscode/bin/install",
"postinstall": "node ./node_modules/vscode/bin/install",
"package": "vsce package"
},
"devDependencies": {

3
Public/Src/IDE/VsCode/package-lock.json сгенерированный
Просмотреть файл

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

Просмотреть файл

@ -1,23 +0,0 @@
@echo off
SET myPath=%~dp0
set templatePath=%myPath%\pluginTemplate
set clientPath=%myPath%\client
echo Recompiling the plugin
cmd /c %clientPath%\node_modules\.bin\tsc -p %clientPath%
if exist %templatePath%\extension (
echo Cleaning template directory
rd /s /q %templatePath%\extension
)
echo Updating the template
xcopy /q /y /s /e %clientPath%\out\src\*.* %templatePath%\extension\out\src\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode\*.* %templatePath%\extension\node_modules\vscode\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-debugadapter\*.* %templatePath%\extension\node_modules\vscode-debugadapter\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-debugprotocol\*.* %templatePath%\extension\node_modules\vscode-debugprotocol\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-jsonrpc\*.* %templatePath%\extension\node_modules\vscode-jsonrpc\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-languageclient\*.* %templatePath%\extension\node_modules\vscode-languageclient\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-languageserver-protocol\*.* %templatePath%\extension\node_modules\vscode-languageserver-protocol\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-languageserver-types\*.* %templatePath%\extension\node_modules\vscode-languageserver-types\ > NUL
xcopy /q /y /s /e %clientPath%\node_modules\vscode-nls\*.* %templatePath%\extension\node_modules\vscode-nls\ > NUL

Просмотреть файл

@ -36,6 +36,7 @@ namespace Tool.CreateZipPackage {
outputFileName: string;
useUriEncoding?: boolean;
fixUnixPermissions?: boolean;
additionalDependencies?: Transformer.InputArtifact[];
}
@@public
@ -52,7 +53,12 @@ namespace Tool.CreateZipPackage {
const tool = CreateZipPackage.withQualifier(BuildXLSdk.TargetFrameworks.currentMachineQualifier).deployed;
const result = Transformer.execute({tool: tool, workingDirectory: wd, arguments: cmdLineArguments});
const result = Transformer.execute({
tool: tool,
workingDirectory: wd,
arguments: cmdLineArguments,
dependencies: args.additionalDependencies
});
return result.getOutputFile(outFile);
}

Просмотреть файл

@ -552,7 +552,7 @@ if (!$skipFilter){
if ($Minimal) {
# filtering by core deployment.
$AdditionalBuildXLArguments += "/f:(output='$($useDeployment.buildDir)\*'or(output='out\bin\$DeployConfig\Sdk\*')or($CacheOutputFilter))and~($CacheLongRunningFilter)ortag='protobufgenerator'"
$AdditionalBuildXLArguments += "/f:(output='$($useDeployment.buildDir)\*'or(output='out\bin\$DeployConfig\Sdk\*')or($CacheOutputFilter))and~($CacheLongRunningFilter)ortag='protobufgenerator'oroutput='cg\*'"
}
if ($Cache) {

Просмотреть файл

@ -5,15 +5,15 @@
"requires": true,
"dependencies": {
"@types/mocha": {
"version": "2.2.44",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz",
"integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==",
"version": "2.2.48",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
"integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==",
"dev": true
},
"@types/node": {
"version": "6.0.92",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.92.tgz",
"integrity": "sha512-awEYSSTn7dauwVCYSx2CJaPTu0Z1Ht2oR1b2AD3CYao6ZRb+opb6EL43fzmD7eMFgMHzTBWSUzlWSD+S8xN0Nw==",
"version": "6.14.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.7.tgz",
"integrity": "sha512-YbPXbaynBTe0pVExPhL76TsWnxSPeFAvImIsmylpBWn/yfw+lHy+Q68aawvZHsgskT44ZAoeE67GM5f+Brekew==",
"dev": true
},
"agent-base": {
@ -508,9 +508,9 @@
"dev": true
},
"psl": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz",
"integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
"integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==",
"dev": true
},
"punycode": {
@ -659,9 +659,9 @@
"dev": true
},
"typescript": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
"integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=",
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
"dev": true
},
"uri-js": {
@ -684,9 +684,9 @@
}
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
"dev": true
},
"verror": {
@ -721,20 +721,20 @@
"integrity": "sha1-hyOdnhZrLXNSJFuKgTWXgEwdY6o="
},
"vscode-languageclient": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.0.tgz",
"integrity": "sha1-NtAswYaoNlpEZ3GaKQ+yAKmuSQo=",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-3.5.1.tgz",
"integrity": "sha512-GTQ+hSq/o4c/y6GYmyP9XNrVoIu0NFZ67KltSkqN+tO0eUNDIlrVNX+3DJzzyLhSsrctuGzuYWm3t87mNAcBmQ==",
"requires": {
"vscode-languageserver-protocol": "^3.5.0"
"vscode-languageserver-protocol": "3.5.1"
}
},
"vscode-languageserver-protocol": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz",
"integrity": "sha1-Bnxcvidwl5U5jRGWksl+u6FFIgk=",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.1.tgz",
"integrity": "sha512-1fPDIwsAv1difCV+8daOrJEGunClNJWqnUHq/ncWrjhitKWXgGmRCjlwZ3gDUTt54yRcvXz1PXJDaRNvNH6pYA==",
"requires": {
"vscode-jsonrpc": "^3.5.0",
"vscode-languageserver-types": "^3.5.0"
"vscode-jsonrpc": "3.5.0",
"vscode-languageserver-types": "3.5.0"
}
},
"vscode-languageserver-types": {

Просмотреть файл

@ -645,6 +645,13 @@ config({
isWritable: true,
isReadable: true,
},
{
name: a`CgNpmRoot`,
path: p`cg/npm`,
trackSourceFileChanges: true,
isWritable: true,
isReadable: true
},
{
// Special scrubbable mount with the content that can be cleaned up by running bxl.exe /scrub
name: a`ScrubbableDeployment`,