mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 22:37:41 +00:00
Merge remote-tracking branch 'origin/master' into rebornix/notebook
This commit is contained in:
commit
c78a8696fc
|
@ -614,6 +614,17 @@
|
|||
"*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "**/test/integration/**",
|
||||
"restrictions": [
|
||||
"**/test/integration/**",
|
||||
"*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "{**/api/**.test.ts,}",
|
||||
"restrictions": "{**/vs/**,assert,sinon,crypto,vscode}"
|
||||
},
|
||||
{
|
||||
"target": "{**/**.test.ts,**/test/**}",
|
||||
"restrictions": "{**/vs/**,assert,sinon,crypto}"
|
||||
|
|
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
|
@ -79,6 +79,24 @@
|
|||
"order": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"name": "VS Code Git Tests",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"/tmp/my4g9l",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}/extensions/git",
|
||||
"--extensionTestsPath=${workspaceFolder}/extensions/git/out/test"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/extensions/git/out/**/*.js"
|
||||
],
|
||||
"presentation": {
|
||||
"group": "5_tests",
|
||||
"order": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
|
@ -167,7 +185,9 @@
|
|||
"webRoot": "${workspaceFolder}",
|
||||
// Settings for js-debug:
|
||||
"pauseForSourceMap": false,
|
||||
"outFiles": ["${workspaceFolder}/out/**/*.js"],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
|
@ -282,7 +302,7 @@
|
|||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Run Unit Tests",
|
||||
"program": "${workspaceFolder}/test/electron/index.js",
|
||||
"program": "${workspaceFolder}/test/unit/electron/index.js",
|
||||
"runtimeExecutable": "${workspaceFolder}/.build/electron/Code - OSS.app/Contents/MacOS/Electron",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/.build/electron/Code - OSS.exe"
|
||||
|
|
2
.yarnrc
2
.yarnrc
|
@ -1,3 +1,3 @@
|
|||
disturl "https://atom.io/download/electron"
|
||||
target "6.1.6"
|
||||
target "7.1.11"
|
||||
runtime "electron"
|
||||
|
|
|
@ -44,15 +44,16 @@ async function doesAssetExist(blobService: azure.BlobService, quality: string, b
|
|||
return existsResult.exists;
|
||||
}
|
||||
|
||||
async function uploadBlob(blobService: azure.BlobService, quality: string, blobName: string, file: string): Promise<void> {
|
||||
async function uploadBlob(blobService: azure.BlobService, quality: string, blobName: string, filePath: string, fileName: string): Promise<void> {
|
||||
const blobOptions: azure.BlobService.CreateBlockBlobRequestOptions = {
|
||||
contentSettings: {
|
||||
contentType: mime.lookup(file),
|
||||
contentType: mime.lookup(filePath),
|
||||
contentDisposition: `attachment; filename="${fileName}"`,
|
||||
cacheControl: 'max-age=31536000, public'
|
||||
}
|
||||
};
|
||||
|
||||
await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, file, blobOptions, err => err ? e(err) : c()));
|
||||
await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, filePath, blobOptions, err => err ? e(err) : c()));
|
||||
}
|
||||
|
||||
function getEnv(name: string): string {
|
||||
|
@ -66,24 +67,24 @@ function getEnv(name: string): string {
|
|||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const [, , platform, type, name, file] = process.argv;
|
||||
const [, , platform, type, fileName, filePath] = process.argv;
|
||||
const quality = getEnv('VSCODE_QUALITY');
|
||||
const commit = getEnv('BUILD_SOURCEVERSION');
|
||||
|
||||
console.log('Creating asset...');
|
||||
|
||||
const stat = await new Promise<fs.Stats>((c, e) => fs.stat(file, (err, stat) => err ? e(err) : c(stat)));
|
||||
const stat = await new Promise<fs.Stats>((c, e) => fs.stat(filePath, (err, stat) => err ? e(err) : c(stat)));
|
||||
const size = stat.size;
|
||||
|
||||
console.log('Size:', size);
|
||||
|
||||
const stream = fs.createReadStream(file);
|
||||
const stream = fs.createReadStream(filePath);
|
||||
const [sha1hash, sha256hash] = await Promise.all([hashStream('sha1', stream), hashStream('sha256', stream)]);
|
||||
|
||||
console.log('SHA1:', sha1hash);
|
||||
console.log('SHA256:', sha256hash);
|
||||
|
||||
const blobName = commit + '/' + name;
|
||||
const blobName = commit + '/' + fileName;
|
||||
const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']!;
|
||||
|
||||
const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!)
|
||||
|
@ -98,7 +99,7 @@ async function main(): Promise<void> {
|
|||
|
||||
console.log('Uploading blobs to Azure storage...');
|
||||
|
||||
await uploadBlob(blobService, quality, blobName, file);
|
||||
await uploadBlob(blobService, quality, blobName, filePath, fileName);
|
||||
|
||||
console.log('Blobs successfully uploaded.');
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ steps:
|
|||
- script: |
|
||||
./scripts/test.sh --tfs "Unit Tests"
|
||||
displayName: Run Unit Tests
|
||||
- script: |
|
||||
yarn test-browser --browser chromium --browser webkit
|
||||
displayName: Run Unit Tests (Browsers)
|
||||
- script: |
|
||||
./scripts/test-integration.sh --tfs "Integration Tests"
|
||||
displayName: Run Integration Tests
|
||||
|
|
12
build/azure-pipelines/darwin/entitlements.plist
Normal file
12
build/azure-pipelines/darwin/entitlements.plist
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -44,6 +44,13 @@ steps:
|
|||
|
||||
git config user.email "vscode@microsoft.com"
|
||||
git config user.name "VSCode"
|
||||
|
||||
security create-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
security default-keychain -s $(agent.tempdirectory)/buildagent.keychain
|
||||
security unlock-keychain -p pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
echo "$(macos-developer-certificate)" | base64 -D > $(agent.tempdirectory)/cert.p12
|
||||
security import $(agent.tempdirectory)/cert.p12 -k $(agent.tempdirectory)/buildagent.keychain -P "$(macos-developer-certificate-key)" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k pwd $(agent.tempdirectory)/buildagent.keychain
|
||||
displayName: Prepare tooling
|
||||
|
||||
- script: |
|
||||
|
@ -127,7 +134,12 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd
|
||||
codesign -s 99FM488X57 --deep --force --options runtime --entitlements build/azure-pipelines/darwin/entitlements.plist $(agent.builddirectory)/VSCode-darwin/*.app
|
||||
displayName: Set Hardened Entitlements
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
pushd $(agent.builddirectory)/VSCode-darwin && zip -r -X -y $(agent.builddirectory)/VSCode-darwin.zip * && popd
|
||||
displayName: Archive build
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
|
@ -141,13 +153,53 @@ steps:
|
|||
{
|
||||
"keyCode": "CP-401337-Apple",
|
||||
"operationSetCode": "MacAppDeveloperSign",
|
||||
"parameters": [ ],
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "Hardening",
|
||||
"parameterValue": "--options=runtime"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 60
|
||||
displayName: Codesign
|
||||
|
||||
- script: |
|
||||
zip -d $(agent.builddirectory)/VSCode-darwin.zip "*.pkg"
|
||||
displayName: Clean Archive
|
||||
|
||||
- script: |
|
||||
APP_ROOT=$(agent.builddirectory)/VSCode-darwin
|
||||
APP_NAME="`ls $APP_ROOT | head -n 1`"
|
||||
BUNDLE_IDENTIFIER=$(node -p "require(\"$APP_ROOT/$APP_NAME/Contents/Resources/app/product.json\").darwinBundleIdentifier")
|
||||
echo "##vso[task.setvariable variable=BundleIdentifier]$BUNDLE_IDENTIFIER"
|
||||
displayName: Export bundle identifier
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)'
|
||||
Pattern: 'VSCode-darwin.zip'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
[
|
||||
{
|
||||
"keyCode": "CP-401337-Apple",
|
||||
"operationSetCode": "MacAppNotarize",
|
||||
"parameters": [
|
||||
{
|
||||
"parameterName": "BundleId",
|
||||
"parameterValue": "$(BundleIdentifier)"
|
||||
}
|
||||
],
|
||||
"toolName": "sign",
|
||||
"toolVersion": "1.0"
|
||||
}
|
||||
]
|
||||
SessionTimeout: 120
|
||||
displayName: Codesign
|
||||
displayName: Notarization
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# remove pkg from archive
|
||||
zip -d ../VSCode-darwin.zip "*.pkg"
|
||||
|
||||
# publish the build
|
||||
node build/azure-pipelines/common/createAsset.js \
|
||||
darwin \
|
||||
|
|
|
@ -49,6 +49,9 @@ steps:
|
|||
- script: |
|
||||
DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests"
|
||||
displayName: Run Unit Tests
|
||||
- script: |
|
||||
DISPLAY=:10 yarn test-browser --browser chromium
|
||||
displayName: Run Unit Tests (Browser)
|
||||
- script: |
|
||||
DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests"
|
||||
displayName: Run Integration Tests
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="EsrpClient" version="1.0.27" />
|
||||
<package id="Microsoft.ESRPClient" version="1.2.25" />
|
||||
</packages>
|
||||
|
|
|
@ -46,6 +46,9 @@ steps:
|
|||
- powershell: |
|
||||
.\scripts\test.bat --tfs "Unit Tests"
|
||||
displayName: Run Unit Tests
|
||||
- powershell: |
|
||||
yarn test-browser --browser chromium --browser webkit
|
||||
displayName: Run Unit Tests (Browser)
|
||||
- powershell: |
|
||||
.\scripts\test-integration.bat --tfs "Integration Tests"
|
||||
displayName: Run Integration Tests
|
||||
|
|
|
@ -67,4 +67,4 @@ $Input = Create-TmpJson @{
|
|||
|
||||
$Output = [System.IO.Path]::GetTempFileName()
|
||||
$ScriptPath = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
||||
& "$ScriptPath\ESRPClient\packages\EsrpClient.1.0.27\tools\ESRPClient.exe" Sign -a $Auth -p $Policy -i $Input -o $Output
|
||||
& "$ScriptPath\ESRPClient\packages\Microsoft.ESRPClient.1.2.25\tools\ESRPClient.exe" Sign -a $Auth -p $Policy -i $Input -o $Output
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
},
|
||||
{
|
||||
"name": "ms-vscode.js-debug-nightly",
|
||||
"version": "2020.1.43263",
|
||||
"version": "2020.2.517",
|
||||
"forQualities": [
|
||||
"insider"
|
||||
],
|
||||
|
|
|
@ -227,8 +227,13 @@ function toExternalDTS(contents) {
|
|||
if (line.indexOf('declare namespace monaco.') === 0) {
|
||||
lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
|
||||
}
|
||||
|
||||
if (line.indexOf('declare let MonacoEnvironment') === 0) {
|
||||
lines[i] = `declare global {\n let MonacoEnvironment: Environment | undefined;\n}`;
|
||||
// lines[i] = line.replace('declare namespace monaco.', 'export namespace ');
|
||||
}
|
||||
}
|
||||
return lines.join('\n');
|
||||
return lines.join('\n').replace(/\n\n\n+/g, '\n\n');
|
||||
}
|
||||
|
||||
function filterStream(testFunc) {
|
||||
|
|
|
@ -33,6 +33,7 @@ const all = [
|
|||
'scripts/**/*',
|
||||
'src/**/*',
|
||||
'test/**/*',
|
||||
'!test/**/out/**',
|
||||
'!**/node_modules/**'
|
||||
];
|
||||
|
||||
|
@ -53,7 +54,7 @@ const indentationFilter = [
|
|||
'!src/vs/base/common/marked/marked.js',
|
||||
'!src/vs/base/node/terminateProcess.sh',
|
||||
'!src/vs/base/node/cpuUsage.sh',
|
||||
'!test/assert.js',
|
||||
'!test/unit/assert.js',
|
||||
|
||||
// except specific folders
|
||||
'!test/automation/out/**',
|
||||
|
@ -82,7 +83,7 @@ const indentationFilter = [
|
|||
'!src/vs/*/**/*.d.ts',
|
||||
'!src/typings/**/*.d.ts',
|
||||
'!extensions/**/*.d.ts',
|
||||
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe,ico,icns}',
|
||||
'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe,ico,icns,plist}',
|
||||
'!build/{lib,download}/**/*.js',
|
||||
'!build/**/*.sh',
|
||||
'!build/azure-pipelines/**/*.js',
|
||||
|
|
|
@ -146,6 +146,10 @@
|
|||
"name": "vs/workbench/contrib/search",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/searchEditor",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/snippets",
|
||||
"project": "vscode-workbench"
|
||||
|
|
|
@ -38,6 +38,7 @@ const CORE_TYPES = [
|
|||
'group',
|
||||
'groupEnd',
|
||||
'table',
|
||||
'assert',
|
||||
'Error',
|
||||
'String',
|
||||
'throws',
|
||||
|
@ -102,6 +103,14 @@ const RULES = [
|
|||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// Browser (editor contrib)
|
||||
{
|
||||
target: '**/src/vs/editor/contrib/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
// node.js
|
||||
{
|
||||
target: '**/vs/**/node/**',
|
||||
|
|
|
@ -39,6 +39,7 @@ const CORE_TYPES = [
|
|||
'group',
|
||||
'groupEnd',
|
||||
'table',
|
||||
'assert',
|
||||
'Error',
|
||||
'String',
|
||||
'throws',
|
||||
|
@ -112,6 +113,15 @@ const RULES = [
|
|||
]
|
||||
},
|
||||
|
||||
// Browser (editor contrib)
|
||||
{
|
||||
target: '**/src/vs/editor/contrib/**',
|
||||
allowedTypes: CORE_TYPES,
|
||||
disallowedDefinitions: [
|
||||
'@types/node' // no node.js
|
||||
]
|
||||
},
|
||||
|
||||
// node.js
|
||||
{
|
||||
target: '**/vs/**/node/**',
|
||||
|
|
|
@ -3,12 +3,18 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare let MonacoEnvironment: monaco.Environment | undefined;
|
||||
|
||||
declare namespace monaco {
|
||||
|
||||
// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.
|
||||
|
||||
export type Thenable<T> = PromiseLike<T>;
|
||||
|
||||
export interface Environment {
|
||||
baseUrl?: string;
|
||||
getWorker?(workerId: string, label: string): Worker;
|
||||
getWorkerUrl?(workerId: string, label: string): string;
|
||||
}
|
||||
|
||||
export interface IDisposable {
|
||||
dispose(): void;
|
||||
}
|
||||
|
|
|
@ -72,4 +72,5 @@ runtime "${runtime}"`;
|
|||
yarnInstall(`build`); // node modules required for build
|
||||
yarnInstall('test/automation'); // node modules required for smoketest
|
||||
yarnInstall('test/smoke'); // node modules required for smoketest
|
||||
yarnInstall('test/integration/browser'); // node modules required for integration
|
||||
yarnInstallBuildDependencies(); // node modules for watching, specific to host node version, not electron
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"git": {
|
||||
"name": "chromium",
|
||||
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
|
||||
"commitHash": "91f08db83c2ce8c722ddf0911ead8f7c473bedfa"
|
||||
"commitHash": "e4745133a1d3745f066e068b8033c6a269b59caf"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
|
@ -40,7 +40,7 @@
|
|||
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
],
|
||||
"isOnlyProductionDependency": true,
|
||||
"version": "76.0.3809.146"
|
||||
"version": "78.0.3904.130"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
@ -48,11 +48,11 @@
|
|||
"git": {
|
||||
"name": "nodejs",
|
||||
"repositoryUrl": "https://github.com/nodejs/node",
|
||||
"commitHash": "64219741218aa87e259cf8257596073b8e747f0a"
|
||||
"commitHash": "787378879acfb212ed4ff824bf9f767a24a5cb43a"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"version": "12.4.0"
|
||||
"version": "12.8.1"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
@ -60,12 +60,12 @@
|
|||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "19c705ab80cd6fdccca3d65803ec2c4addb9540a"
|
||||
"commitHash": "d17dfabfcba7bd0bc994b8dac5f5d2000bef572c"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "6.1.6"
|
||||
"version": "7.1.11"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
|
|
@ -29,7 +29,9 @@
|
|||
"type": "array",
|
||||
"description": "Ports that are forwarded from the container to the local machine.",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
"type": "integer",
|
||||
"maximum": 65535,
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"remoteEnv": {
|
||||
|
|
|
@ -1780,6 +1780,9 @@
|
|||
"@types/mocha": "2.2.43",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/which": "^1.0.28",
|
||||
"mocha": "^3.2.0"
|
||||
"mocha": "^3.2.0",
|
||||
"mocha-junit-reporter": "^1.23.3",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"vscode": "^1.1.36"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Model } from '../model';
|
||||
import { Repository as BaseRepository, Resource } from '../repository';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions } from './git';
|
||||
import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode';
|
||||
import { mapEvent } from '../util';
|
||||
import { toGitUri } from '../uri';
|
||||
|
@ -202,6 +202,10 @@ export class ApiRepository implements Repository {
|
|||
log(options?: LogOptions): Promise<Commit[]> {
|
||||
return this._repository.log(options);
|
||||
}
|
||||
|
||||
commit(message: string, opts?: CommitOptions): Promise<void> {
|
||||
return this._repository.commit(message, opts);
|
||||
}
|
||||
}
|
||||
|
||||
export class ApiGit implements Git {
|
||||
|
|
10
extensions/git/src/api/git.d.ts
vendored
10
extensions/git/src/api/git.d.ts
vendored
|
@ -121,6 +121,14 @@ export interface LogOptions {
|
|||
readonly maxEntries?: number;
|
||||
}
|
||||
|
||||
export interface CommitOptions {
|
||||
all?: boolean | 'tracked';
|
||||
amend?: boolean;
|
||||
signoff?: boolean;
|
||||
signCommit?: boolean;
|
||||
empty?: boolean;
|
||||
}
|
||||
|
||||
export interface Repository {
|
||||
|
||||
readonly rootUri: Uri;
|
||||
|
@ -176,6 +184,8 @@ export interface Repository {
|
|||
|
||||
blame(path: string): Promise<string>;
|
||||
log(options?: LogOptions): Promise<Commit[]>;
|
||||
|
||||
commit(message: string, opts?: CommitOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export type APIState = 'uninitialized' | 'initialized';
|
||||
|
|
|
@ -9,8 +9,8 @@ import * as path from 'path';
|
|||
import { commands, Disposable, LineChange, MessageOptions, OutputChannel, Position, ProgressLocation, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder } from 'vscode';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, GitErrorCodes, Ref, RefType, Status } from './api/git';
|
||||
import { CommitOptions, ForcePushMode, Git, Stash } from './git';
|
||||
import { Branch, GitErrorCodes, Ref, RefType, Status, CommitOptions } from './api/git';
|
||||
import { ForcePushMode, Git, Stash } from './git';
|
||||
import { Model } from './model';
|
||||
import { Repository, Resource, ResourceGroupType } from './repository';
|
||||
import { applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineChange, toLineRanges } from './staging';
|
||||
|
@ -1620,7 +1620,7 @@ export class CommandCenter {
|
|||
|
||||
const rawBranchName = defaultName || await window.showInputBox({
|
||||
placeHolder: localize('branch name', "Branch name"),
|
||||
prompt: localize('provide branch name', "Please provide a branch name"),
|
||||
prompt: localize('provide branch name', "Please provide a new branch name"),
|
||||
value: initialValue,
|
||||
ignoreFocusOut: true,
|
||||
validateInput: (name: string) => {
|
||||
|
@ -2332,14 +2332,20 @@ export class CommandCenter {
|
|||
}
|
||||
|
||||
@command('git.openDiff', { repository: false })
|
||||
async openDiff(uri: Uri, hash: string) {
|
||||
async openDiff(uri: Uri, lhs: string, rhs: string) {
|
||||
const basename = path.basename(uri.fsPath);
|
||||
|
||||
if (hash === '~') {
|
||||
return commands.executeCommand('vscode.diff', toGitUri(uri, hash), toGitUri(uri, `HEAD`), `${basename} (Index)`);
|
||||
let title;
|
||||
if ((lhs === 'HEAD' || lhs === '~') && rhs === '') {
|
||||
title = `${basename} (Working Tree)`;
|
||||
}
|
||||
else if (lhs === 'HEAD' && rhs === '~') {
|
||||
title = `${basename} (Index)`;
|
||||
} else {
|
||||
title = `${basename} (${lhs.endsWith('^') ? `${lhs.substr(0, 8)}^` : lhs.substr(0, 8)}) \u27f7 ${basename} (${rhs.endsWith('^') ? `${rhs.substr(0, 8)}^` : rhs.substr(0, 8)})`;
|
||||
}
|
||||
|
||||
return commands.executeCommand('vscode.diff', toGitUri(uri, `${hash}^`), toGitUri(uri, hash), `${basename} (${hash.substr(0, 8)}^) \u27f7 ${basename} (${hash.substr(0, 8)})`);
|
||||
return commands.executeCommand('vscode.diff', toGitUri(uri, lhs), rhs === '' ? uri : toGitUri(uri, rhs), title);
|
||||
}
|
||||
|
||||
private createCommand(id: string, key: string, method: Function, options: CommandOptions): (...args: any[]) => any {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { fromGitUri, toGitUri } from './uri';
|
|||
import { Model, ModelChangeEvent, OriginalResourceChangeEvent } from './model';
|
||||
import { filterEvent, eventToPromise, isDescendant, pathEquals, EmptyDisposable } from './util';
|
||||
import { Repository } from './repository';
|
||||
import { TextEncoder } from 'util';
|
||||
|
||||
interface CacheRow {
|
||||
uri: Uri;
|
||||
|
|
|
@ -15,7 +15,7 @@ import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes,
|
|||
import { CancellationToken, Progress, Uri } from 'vscode';
|
||||
import { URI } from 'vscode-uri';
|
||||
import { detectEncoding } from './encoding';
|
||||
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git';
|
||||
import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, CommitOptions } from './api/git';
|
||||
import * as byline from 'byline';
|
||||
import { StringDecoder } from 'string_decoder';
|
||||
|
||||
|
@ -725,14 +725,6 @@ export function parseLsFiles(raw: string): LsFilesElement[] {
|
|||
.map(([, mode, object, stage, file]) => ({ mode, object, stage, file }));
|
||||
}
|
||||
|
||||
export interface CommitOptions {
|
||||
all?: boolean | 'tracked';
|
||||
amend?: boolean;
|
||||
signoff?: boolean;
|
||||
signCommit?: boolean;
|
||||
empty?: boolean;
|
||||
}
|
||||
|
||||
export interface PullOptions {
|
||||
unshallow?: boolean;
|
||||
tags?: boolean;
|
||||
|
|
|
@ -7,10 +7,10 @@ import * as fs from 'fs';
|
|||
import * as path from 'path';
|
||||
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, OutputChannel, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, Decoration } from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status } from './api/git';
|
||||
import { Branch, Change, GitErrorCodes, LogOptions, Ref, RefType, Remote, Status, CommitOptions } from './api/git';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
import { debounce, memoize, throttle } from './decorators';
|
||||
import { Commit, CommitOptions, ForcePushMode, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions } from './git';
|
||||
import { Commit, ForcePushMode, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions } from './git';
|
||||
import { StatusBarCommands } from './statusbar';
|
||||
import { toGitUri } from './uri';
|
||||
import { anyEvent, combinedDisposable, debounceEvent, dispose, EmptyDisposable, eventToPromise, filterEvent, find, IDisposable, isDescendant, onceEvent } from './util';
|
||||
|
@ -309,11 +309,17 @@ export const enum Operation {
|
|||
|
||||
function isReadOnly(operation: Operation): boolean {
|
||||
switch (operation) {
|
||||
case Operation.Show:
|
||||
case Operation.GetCommitTemplate:
|
||||
case Operation.Blame:
|
||||
case Operation.CheckIgnore:
|
||||
case Operation.Diff:
|
||||
case Operation.FindTrackingBranches:
|
||||
case Operation.GetBranch:
|
||||
case Operation.GetCommitTemplate:
|
||||
case Operation.GetObjectDetails:
|
||||
case Operation.Log:
|
||||
case Operation.LogFile:
|
||||
case Operation.MergeBase:
|
||||
case Operation.Show:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -189,7 +189,9 @@ suite('git', () => {
|
|||
suite('parseGitCommit', () => {
|
||||
test('single parent commit', function () {
|
||||
const GIT_OUTPUT_SINGLE_PARENT = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
John Doe
|
||||
john.doe@mail.com
|
||||
1580811030
|
||||
8e5a374372b8393906c7e380dbb09349c5385554
|
||||
This is a commit message.\x00`;
|
||||
|
||||
|
@ -197,13 +199,17 @@ This is a commit message.\x00`;
|
|||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: ['8e5a374372b8393906c7e380dbb09349c5385554'],
|
||||
authorDate: new Date(1580811030000),
|
||||
authorName: 'John Doe',
|
||||
authorEmail: 'john.doe@mail.com',
|
||||
}]);
|
||||
});
|
||||
|
||||
test('multiple parent commits', function () {
|
||||
const GIT_OUTPUT_MULTIPLE_PARENTS = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
John Doe
|
||||
john.doe@mail.com
|
||||
1580811030
|
||||
8e5a374372b8393906c7e380dbb09349c5385554 df27d8c75b129ab9b178b386077da2822101b217
|
||||
This is a commit message.\x00`;
|
||||
|
||||
|
@ -211,13 +217,17 @@ This is a commit message.\x00`;
|
|||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: ['8e5a374372b8393906c7e380dbb09349c5385554', 'df27d8c75b129ab9b178b386077da2822101b217'],
|
||||
authorDate: new Date(1580811030000),
|
||||
authorName: 'John Doe',
|
||||
authorEmail: 'john.doe@mail.com',
|
||||
}]);
|
||||
});
|
||||
|
||||
test('no parent commits', function () {
|
||||
const GIT_OUTPUT_NO_PARENTS = `52c293a05038d865604c2284aa8698bd087915a1
|
||||
John Doe
|
||||
john.doe@mail.com
|
||||
1580811030
|
||||
|
||||
This is a commit message.\x00`;
|
||||
|
||||
|
@ -225,6 +235,8 @@ This is a commit message.\x00`;
|
|||
hash: '52c293a05038d865604c2284aa8698bd087915a1',
|
||||
message: 'This is a commit message.',
|
||||
parents: [],
|
||||
authorDate: new Date(1580811030000),
|
||||
authorName: 'John Doe',
|
||||
authorEmail: 'john.doe@mail.com',
|
||||
}]);
|
||||
});
|
||||
|
|
30
extensions/git/src/test/index.ts
Normal file
30
extensions/git/src/test/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
const testRunner = require('vscode/lib/testrunner');
|
||||
|
||||
const suite = 'Integration Git Tests';
|
||||
|
||||
const options: any = {
|
||||
ui: 'tdd',
|
||||
useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'),
|
||||
timeout: 60000
|
||||
};
|
||||
|
||||
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
|
||||
options.reporter = 'mocha-multi-reporters';
|
||||
options.reporterOptions = {
|
||||
reporterEnabled: 'spec, mocha-junit-reporter',
|
||||
mochaJunitReporterReporterOptions: {
|
||||
testsuitesTitle: `${suite} ${process.platform}`,
|
||||
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testRunner.configure(options);
|
||||
|
||||
export = testRunner;
|
127
extensions/git/src/test/smoke.test.ts
Normal file
127
extensions/git/src/test/smoke.test.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'mocha';
|
||||
import * as assert from 'assert';
|
||||
import { workspace, commands, window, Uri, WorkspaceEdit, Range, TextDocument, extensions } from 'vscode';
|
||||
import * as cp from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { GitExtension, API, Repository, Status } from '../api/git';
|
||||
import { eventToPromise } from '../util';
|
||||
|
||||
suite('git smoke test', function () {
|
||||
const cwd = fs.realpathSync(workspace.workspaceFolders![0].uri.fsPath);
|
||||
|
||||
function file(relativePath: string) {
|
||||
return path.join(cwd, relativePath);
|
||||
}
|
||||
|
||||
function uri(relativePath: string) {
|
||||
return Uri.file(file(relativePath));
|
||||
}
|
||||
|
||||
async function open(relativePath: string) {
|
||||
const doc = await workspace.openTextDocument(uri(relativePath));
|
||||
await window.showTextDocument(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
async function type(doc: TextDocument, text: string) {
|
||||
const edit = new WorkspaceEdit();
|
||||
const end = doc.lineAt(doc.lineCount - 1).range.end;
|
||||
edit.replace(doc.uri, new Range(end, end), text);
|
||||
await workspace.applyEdit(edit);
|
||||
}
|
||||
|
||||
let git: API;
|
||||
let repository: Repository;
|
||||
|
||||
suiteSetup(async function () {
|
||||
fs.writeFileSync(file('app.js'), 'hello', 'utf8');
|
||||
fs.writeFileSync(file('index.pug'), 'hello', 'utf8');
|
||||
cp.execSync('git init', { cwd });
|
||||
cp.execSync('git config user.name testuser', { cwd });
|
||||
cp.execSync('git config user.email monacotools@microsoft.com', { cwd });
|
||||
cp.execSync('git add .', { cwd });
|
||||
cp.execSync('git commit -m "initial commit"', { cwd });
|
||||
|
||||
// make sure git is activated
|
||||
const ext = extensions.getExtension<GitExtension>('vscode.git');
|
||||
await ext?.activate();
|
||||
git = ext!.exports.getAPI(1);
|
||||
|
||||
if (git.repositories.length === 0) {
|
||||
await eventToPromise(git.onDidOpenRepository);
|
||||
}
|
||||
|
||||
assert.equal(git.repositories.length, 1);
|
||||
assert.equal(fs.realpathSync(git.repositories[0].rootUri.fsPath), cwd);
|
||||
|
||||
repository = git.repositories[0];
|
||||
});
|
||||
|
||||
test('reflects working tree changes', async function () {
|
||||
await commands.executeCommand('workbench.view.scm');
|
||||
|
||||
const appjs = await open('app.js');
|
||||
await type(appjs, ' world');
|
||||
await appjs.save();
|
||||
await repository.status();
|
||||
assert.equal(repository.state.workingTreeChanges.length, 1);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED);
|
||||
|
||||
fs.writeFileSync(file('newfile.txt'), '');
|
||||
const newfile = await open('newfile.txt');
|
||||
await type(newfile, 'hey there');
|
||||
await newfile.save();
|
||||
await repository.status();
|
||||
assert.equal(repository.state.workingTreeChanges.length, 2);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === newfile.uri.path && r.status === Status.UNTRACKED);
|
||||
});
|
||||
|
||||
test('opens diff editor', async function () {
|
||||
const appjs = uri('app.js');
|
||||
await commands.executeCommand('git.openChange', appjs);
|
||||
|
||||
assert(window.activeTextEditor);
|
||||
assert.equal(window.activeTextEditor!.document.uri.path, appjs.path);
|
||||
|
||||
// TODO: how do we really know this is a diff editor?
|
||||
});
|
||||
|
||||
test('stages correctly', async function () {
|
||||
const appjs = uri('app.js');
|
||||
const newfile = uri('newfile.txt');
|
||||
|
||||
await commands.executeCommand('git.stage', appjs);
|
||||
assert.equal(repository.state.workingTreeChanges.length, 1);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED);
|
||||
assert.equal(repository.state.indexChanges.length, 1);
|
||||
repository.state.indexChanges.some(r => r.uri.path === appjs.path && r.status === Status.INDEX_MODIFIED);
|
||||
|
||||
await commands.executeCommand('git.unstage', appjs);
|
||||
assert.equal(repository.state.workingTreeChanges.length, 2);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === appjs.path && r.status === Status.MODIFIED);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED);
|
||||
});
|
||||
|
||||
test('stages, commits changes and verifies outgoing change', async function () {
|
||||
const appjs = uri('app.js');
|
||||
const newfile = uri('newfile.txt');
|
||||
|
||||
await commands.executeCommand('git.stage', appjs);
|
||||
await repository.commit('second commit');
|
||||
assert.equal(repository.state.workingTreeChanges.length, 1);
|
||||
repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED);
|
||||
assert.equal(repository.state.indexChanges.length, 0);
|
||||
|
||||
await commands.executeCommand('git.stageAll', appjs);
|
||||
await repository.commit('third commit');
|
||||
assert.equal(repository.state.workingTreeChanges.length, 0);
|
||||
assert.equal(repository.state.indexChanges.length, 0);
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@
|
|||
import * as dayjs from 'dayjs';
|
||||
import * as advancedFormat from 'dayjs/plugin/advancedFormat';
|
||||
import * as relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, TimelineItem, TimelineProvider, Uri, workspace } from 'vscode';
|
||||
import { CancellationToken, Disposable, Event, EventEmitter, ThemeIcon, TimelineItem, TimelineProvider, Uri, workspace, TimelineChangeEvent } from 'vscode';
|
||||
import { Model } from './model';
|
||||
import { Repository } from './repository';
|
||||
import { debounce } from './decorators';
|
||||
|
@ -19,13 +19,13 @@ dayjs.extend(relativeTime);
|
|||
// TODO[ECA]: Localize or use a setting for date format
|
||||
|
||||
export class GitTimelineProvider implements TimelineProvider {
|
||||
private _onDidChange = new EventEmitter<Uri | undefined>();
|
||||
get onDidChange(): Event<Uri | undefined> {
|
||||
private _onDidChange = new EventEmitter<TimelineChangeEvent>();
|
||||
get onDidChange(): Event<TimelineChangeEvent> {
|
||||
return this._onDidChange.event;
|
||||
}
|
||||
|
||||
readonly source = 'git-history';
|
||||
readonly sourceDescription = 'Git History';
|
||||
readonly id = 'git-history';
|
||||
readonly label = 'Git History';
|
||||
|
||||
private _disposable: Disposable;
|
||||
|
||||
|
@ -62,8 +62,8 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
this._repo = repo;
|
||||
this._repoStatusDate = new Date();
|
||||
this._repoDisposable = Disposable.from(
|
||||
repo.onDidChangeRepository(this.onRepositoryChanged, this),
|
||||
repo.onDidRunGitStatus(this.onRepositoryStatusChanged, this)
|
||||
repo.onDidChangeRepository(uri => this.onRepositoryChanged(repo, uri)),
|
||||
repo.onDidRunGitStatus(() => this.onRepositoryStatusChanged(repo))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -82,19 +82,18 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
|
||||
dateFormatter = dayjs(c.authorDate);
|
||||
|
||||
return {
|
||||
id: c.hash,
|
||||
timestamp: c.authorDate?.getTime() ?? 0,
|
||||
iconPath: new ThemeIcon('git-commit'),
|
||||
label: message,
|
||||
description: `${dateFormatter.fromNow()} \u2022 ${c.authorName}`,
|
||||
detail: `${c.authorName} (${c.authorEmail}) \u2014 ${c.hash.substr(0, 8)}\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n\n${c.message}`,
|
||||
command: {
|
||||
title: 'Open Diff',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, c.hash]
|
||||
}
|
||||
const item = new TimelineItem(message, c.authorDate?.getTime() ?? 0);
|
||||
item.id = c.hash;
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 ${c.authorName}`;
|
||||
item.detail = `${c.authorName} (${c.authorEmail}) \u2014 ${c.hash.substr(0, 8)}\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n\n${c.message}`;
|
||||
item.command = {
|
||||
title: 'Open Diff',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, `${c.hash}^`, c.hash]
|
||||
};
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
const index = repo.indexGroup.resourceStates.find(r => r.resourceUri.fsPath === uri.fsPath);
|
||||
|
@ -124,43 +123,91 @@ export class GitTimelineProvider implements TimelineProvider {
|
|||
break;
|
||||
}
|
||||
|
||||
const item = new TimelineItem('Staged Changes', date.getTime());
|
||||
item.id = 'index';
|
||||
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 You`;
|
||||
item.detail = `You \u2014 Index\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, 'HEAD', '~']
|
||||
};
|
||||
|
||||
items.push({
|
||||
id: '~',
|
||||
timestamp: date.getTime(),
|
||||
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
|
||||
iconPath: new ThemeIcon('git-commit'),
|
||||
label: 'Staged Changes',
|
||||
description: `${dateFormatter.fromNow()} \u2022 You`,
|
||||
detail: `You \u2014 Index\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`,
|
||||
command: {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, '~']
|
||||
}
|
||||
});
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
|
||||
const working = repo.workingTreeGroup.resourceStates.find(r => r.resourceUri.fsPath === uri.fsPath);
|
||||
if (working) {
|
||||
const date = new Date();
|
||||
dateFormatter = dayjs(date);
|
||||
|
||||
let status;
|
||||
switch (working.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
status = 'Modified';
|
||||
break;
|
||||
case Status.INDEX_ADDED:
|
||||
status = 'Added';
|
||||
break;
|
||||
case Status.INDEX_DELETED:
|
||||
status = 'Deleted';
|
||||
break;
|
||||
case Status.INDEX_RENAMED:
|
||||
status = 'Renamed';
|
||||
break;
|
||||
case Status.INDEX_COPIED:
|
||||
status = 'Copied';
|
||||
break;
|
||||
default:
|
||||
status = '';
|
||||
break;
|
||||
}
|
||||
|
||||
const item = new TimelineItem('Uncommited Changes', date.getTime());
|
||||
item.id = 'working';
|
||||
// TODO[ECA]: Replace with a better icon -- reflecting its status maybe?
|
||||
item.iconPath = new (ThemeIcon as any)('git-commit');
|
||||
item.description = `${dateFormatter.fromNow()} \u2022 You`;
|
||||
item.detail = `You \u2014 Working Tree\n${dateFormatter.fromNow()} (${dateFormatter.format('MMMM Do, YYYY h:mma')})\n${status}`;
|
||||
item.command = {
|
||||
title: 'Open Comparison',
|
||||
command: 'git.openDiff',
|
||||
arguments: [uri, index ? '~' : 'HEAD', '']
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
private onRepositoriesChanged(_repo: Repository) {
|
||||
// console.log(`GitTimelineProvider.onRepositoriesChanged`);
|
||||
|
||||
// TODO[ECA]: Being naive for now and just always refreshing each time there is a new repository
|
||||
this._onDidChange.fire();
|
||||
this.fireChanged();
|
||||
}
|
||||
|
||||
private onRepositoryChanged(_repo: Repository, _uri: Uri) {
|
||||
// console.log(`GitTimelineProvider.onRepositoryChanged: uri=${uri.toString(true)}`);
|
||||
|
||||
this.fireChanged();
|
||||
}
|
||||
|
||||
private onRepositoryStatusChanged(_repo: Repository) {
|
||||
// console.log(`GitTimelineProvider.onRepositoryStatusChanged`);
|
||||
|
||||
// This is crappy, but for now just save the last time a status was run and use that as the timestamp for staged items
|
||||
this._repoStatusDate = new Date();
|
||||
|
||||
this.fireChanged();
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
private onRepositoryChanged() {
|
||||
// console.log(`GitTimelineProvider.onRepositoryChanged`);
|
||||
|
||||
private fireChanged() {
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
|
||||
private onRepositoryStatusChanged() {
|
||||
// This is crappy, but for now just save the last time a status was run and use that as the timestamp for staged items
|
||||
this._repoStatusDate = new Date();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vscode';
|
||||
import { Event, Disposable } from 'vscode';
|
||||
import { dirname, sep } from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import { promises as fs, createReadStream } from 'fs';
|
||||
|
@ -33,15 +33,15 @@ export function combinedDisposable(disposables: IDisposable[]): IDisposable {
|
|||
export const EmptyDisposable = toDisposable(() => null);
|
||||
|
||||
export function fireEvent<T>(event: Event<T>): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(_ => (listener as any).call(thisArgs), null, disposables);
|
||||
return (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => event(_ => (listener as any).call(thisArgs), null, disposables);
|
||||
}
|
||||
|
||||
export function mapEvent<I, O>(event: Event<I>, map: (i: I) => O): Event<O> {
|
||||
return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables);
|
||||
return (listener: (e: O) => any, thisArgs?: any, disposables?: Disposable[]) => event(i => listener.call(thisArgs, map(i)), null, disposables);
|
||||
}
|
||||
|
||||
export function filterEvent<T>(event: Event<T>, filter: (e: T) => boolean): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
return (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables);
|
||||
}
|
||||
|
||||
export function latchEvent<T>(event: Event<T>): Event<T> {
|
||||
|
@ -57,7 +57,7 @@ export function latchEvent<T>(event: Event<T>): Event<T> {
|
|||
}
|
||||
|
||||
export function anyEvent<T>(...events: Event<T>[]): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
return (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => {
|
||||
const result = combinedDisposable(events.map(event => event(i => listener.call(thisArgs, i))));
|
||||
|
||||
if (disposables) {
|
||||
|
@ -73,7 +73,7 @@ export function done<T>(promise: Promise<T>): Promise<void> {
|
|||
}
|
||||
|
||||
export function onceEvent<T>(event: Event<T>): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
return (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => {
|
||||
const result = event(e => {
|
||||
result.dispose();
|
||||
return listener.call(thisArgs, e);
|
||||
|
@ -84,7 +84,7 @@ export function onceEvent<T>(event: Event<T>): Event<T> {
|
|||
}
|
||||
|
||||
export function debounceEvent<T>(event: Event<T>, delay: number): Event<T> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
return (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => {
|
||||
let timer: NodeJS.Timer;
|
||||
return event(e => {
|
||||
clearTimeout(timer);
|
||||
|
|
|
@ -36,6 +36,28 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6"
|
||||
integrity sha1-AW44dim4gXvtZT/jLqtdESecjfY=
|
||||
|
||||
agent-base@4, agent-base@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
|
||||
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
ajv@^6.5.5:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
|
||||
integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
applicationinsights@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5"
|
||||
|
@ -45,11 +67,45 @@ applicationinsights@1.0.8:
|
|||
diagnostic-channel-publishers "0.2.1"
|
||||
zone.js "0.7.6"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
|
||||
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
|
||||
|
@ -63,11 +119,43 @@ browser-stdout@1.3.0:
|
|||
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f"
|
||||
integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8=
|
||||
|
||||
browser-stdout@1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
|
||||
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||
|
||||
byline@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
|
||||
integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||
|
||||
charenc@~0.0.1:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@2.15.1:
|
||||
version "2.15.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
|
||||
integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==
|
||||
|
||||
commander@2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
|
||||
|
@ -80,6 +168,23 @@ concat-map@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
crypt@~0.0.1:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
dayjs@1.8.19:
|
||||
version "1.8.19"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.19.tgz#5117dc390d8f8e586d53891dbff3fa308f51abfe"
|
||||
|
@ -92,6 +197,32 @@ debug@2.6.8:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^2.2.0:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
diagnostic-channel-publishers@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3"
|
||||
|
@ -109,21 +240,92 @@ diff@3.2.0:
|
|||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
|
||||
integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k=
|
||||
|
||||
diff@3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.8"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
escape-string-regexp@1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
file-type@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-7.2.0.tgz#113cfed52e1d6959ab80248906e2f25a8cdccb74"
|
||||
integrity sha1-ETz+1S4daVmrgCSJBuLyWozcy3Q=
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob@7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
||||
|
@ -136,26 +338,98 @@ glob@7.1.1:
|
|||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.1.2:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
"graceful-readlink@>= 1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||
integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
|
||||
|
||||
growl@1.10.5:
|
||||
version "1.10.5"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
|
||||
integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==
|
||||
|
||||
growl@1.9.2:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
|
||||
integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.0:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
|
||||
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
|
||||
dependencies:
|
||||
ajv "^6.5.5"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
has-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
|
||||
he@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
|
||||
|
||||
http-proxy-agent@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||
integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
|
||||
dependencies:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
https-proxy-agent@^2.2.1:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
||||
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
|
||||
dependencies:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
|
@ -176,21 +450,66 @@ inherits@2:
|
|||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
is-buffer@~1.1.1:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jschardet@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
|
||||
integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q==
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
json3@3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
|
||||
integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
lodash._baseassign@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
|
||||
|
@ -247,7 +566,33 @@ lodash.keys@^3.0.0:
|
|||
lodash.isarguments "^3.0.0"
|
||||
lodash.isarray "^3.0.0"
|
||||
|
||||
minimatch@^3.0.2:
|
||||
lodash@^4.16.4:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
|
||||
md5@^2.1.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
|
||||
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
|
||||
dependencies:
|
||||
charenc "~0.0.1"
|
||||
crypt "~0.0.1"
|
||||
is-buffer "~1.1.1"
|
||||
|
||||
mime-db@1.43.0:
|
||||
version "1.43.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||
integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.19:
|
||||
version "2.1.26"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
|
||||
integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
|
||||
dependencies:
|
||||
mime-db "1.43.0"
|
||||
|
||||
minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
|
@ -259,13 +604,32 @@ minimist@0.0.8:
|
|||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
mkdirp@0.5.1:
|
||||
mkdirp@0.5.1, mkdirp@~0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mocha-junit-reporter@^1.23.3:
|
||||
version "1.23.3"
|
||||
resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.3.tgz#941e219dd759ed732f8641e165918aa8b167c981"
|
||||
integrity sha512-ed8LqbRj1RxZfjt/oC9t12sfrWsjZ3gNnbhV1nuj9R/Jb5/P3Xb4duv2eCfCDMYH+fEu0mqca7m4wsiVjsxsvA==
|
||||
dependencies:
|
||||
debug "^2.2.0"
|
||||
md5 "^2.1.0"
|
||||
mkdirp "~0.5.1"
|
||||
strip-ansi "^4.0.0"
|
||||
xml "^1.0.0"
|
||||
|
||||
mocha-multi-reporters@^1.1.7:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82"
|
||||
integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI=
|
||||
dependencies:
|
||||
debug "^3.1.0"
|
||||
lodash "^4.16.4"
|
||||
|
||||
mocha@^3.2.0:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d"
|
||||
|
@ -284,11 +648,38 @@ mocha@^3.2.0:
|
|||
mkdirp "0.5.1"
|
||||
supports-color "3.1.2"
|
||||
|
||||
mocha@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6"
|
||||
integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==
|
||||
dependencies:
|
||||
browser-stdout "1.3.1"
|
||||
commander "2.15.1"
|
||||
debug "3.1.0"
|
||||
diff "3.5.0"
|
||||
escape-string-regexp "1.0.5"
|
||||
glob "7.1.2"
|
||||
growl "1.10.5"
|
||||
he "1.1.1"
|
||||
minimatch "3.0.4"
|
||||
mkdirp "0.5.1"
|
||||
supports-color "5.4.0"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
|
@ -301,7 +692,73 @@ path-is-absolute@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
psl@^1.1.24:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
|
||||
integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
querystringify@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
|
||||
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
|
||||
|
||||
request@^2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.0"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.4.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
requires-port@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
@ -311,6 +768,46 @@ semver@^5.3.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
|
||||
|
||||
semver@^5.4.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
source-map-support@^0.5.0:
|
||||
version "0.5.16"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
|
||||
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
source-map@^0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
getpass "^0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
supports-color@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
|
||||
|
@ -318,6 +815,62 @@ supports-color@3.1.2:
|
|||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
supports-color@5.4.0:
|
||||
version "5.4.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
|
||||
integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
|
||||
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
url-parse@^1.4.4:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
|
||||
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
|
||||
dependencies:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vscode-extension-telemetry@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.1.1.tgz#91387e06b33400c57abd48979b0e790415ae110b"
|
||||
|
@ -330,11 +883,32 @@ vscode-nls@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
|
||||
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==
|
||||
|
||||
vscode-test@^0.4.1:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-test/-/vscode-test-0.4.3.tgz#461ebf25fc4bc93d77d982aed556658a2e2b90b8"
|
||||
integrity sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==
|
||||
dependencies:
|
||||
http-proxy-agent "^2.1.0"
|
||||
https-proxy-agent "^2.2.1"
|
||||
|
||||
vscode-uri@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542"
|
||||
integrity sha512-lWXWofDSYD8r/TIyu64MdwB4FaSirQ608PP/TzUyslyOeHGwQ0eTHUZeJrK1ILOmwUHaJtV693m2JoUYroUDpw==
|
||||
|
||||
vscode@^1.1.36:
|
||||
version "1.1.36"
|
||||
resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.36.tgz#5e1a0d1bf4977d0c7bc5159a9a13d5b104d4b1b6"
|
||||
integrity sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==
|
||||
dependencies:
|
||||
glob "^7.1.2"
|
||||
mocha "^5.2.0"
|
||||
request "^2.88.0"
|
||||
semver "^5.4.1"
|
||||
source-map-support "^0.5.0"
|
||||
url-parse "^1.4.4"
|
||||
vscode-test "^0.4.1"
|
||||
|
||||
which@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
|
||||
|
@ -347,6 +921,11 @@ wrappy@1:
|
|||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xml@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
|
||||
integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=
|
||||
|
||||
zone.js@0.7.6:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009"
|
||||
|
|
|
@ -329,7 +329,7 @@ documents.onDidClose(event => {
|
|||
});
|
||||
|
||||
const pendingValidationRequests: { [uri: string]: NodeJS.Timer; } = {};
|
||||
const validationDelayMs = 500;
|
||||
const validationDelayMs = 300;
|
||||
|
||||
function cleanPendingValidation(textDocument: TextDocument): void {
|
||||
const request = pendingValidationRequests[textDocument.uri];
|
||||
|
@ -363,12 +363,12 @@ function validateTextDocument(textDocument: TextDocument, callback?: (diagnostic
|
|||
|
||||
const documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'warning' } : { comments: 'error', trailingCommas: 'error' };
|
||||
languageService.doValidation(textDocument, jsonDocument, documentSettings).then(diagnostics => {
|
||||
setTimeout(() => {
|
||||
setImmediate(() => {
|
||||
const currDocument = documents.get(textDocument.uri);
|
||||
if (currDocument && currDocument.version === version) {
|
||||
respond(diagnostics); // Send the computed diagnostics to VSCode.
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}, error => {
|
||||
connection.console.error(formatError(`Error while validating ${textDocument.uri}`, error));
|
||||
});
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
"extends": "../../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"jsx": "react"
|
||||
"jsx": "react",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ mappings.forEach(([ext, scope, regexp]) =>
|
|||
{
|
||||
name: [scopes.resultBlock.result.meta, scopes.resultBlock.result.metaMultiLine].join(' '),
|
||||
begin: "^ ((\\d+) )",
|
||||
while: "^ ((\\d+)(:))|((\\d+) )",
|
||||
while: "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
beginCaptures: {
|
||||
"0": { name: scopes.resultBlock.result.prefix.meta },
|
||||
"1": { name: scopes.resultBlock.result.prefix.metaContext },
|
||||
|
@ -215,7 +215,7 @@ const plainText = [
|
|||
}
|
||||
},
|
||||
{
|
||||
match: "^ ((\\d+)(:))|((\\d+)( ))(.*)",
|
||||
match: "^ (?:((\\d+)(:))|((\\d+)( ))(.*))",
|
||||
name: [scopes.resultBlock.meta, scopes.resultBlock.result.meta].join(' '),
|
||||
captures: {
|
||||
"1": { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaMatch].join(' ') },
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"match": "^ ((\\d+)(:))|((\\d+)( ))(.*)",
|
||||
"match": "^ (?:((\\d+)(:))|((\\d+)( ))(.*))",
|
||||
"name": "meta.resultBlock.search meta.resultLine.search",
|
||||
"captures": {
|
||||
"1": {
|
||||
|
@ -297,7 +297,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -383,7 +383,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -469,7 +469,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -555,7 +555,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -641,7 +641,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -727,7 +727,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -813,7 +813,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -899,7 +899,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -985,7 +985,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1071,7 +1071,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1157,7 +1157,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1243,7 +1243,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1329,7 +1329,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1415,7 +1415,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1501,7 +1501,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1587,7 +1587,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1673,7 +1673,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1759,7 +1759,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1845,7 +1845,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -1931,7 +1931,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2017,7 +2017,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2103,7 +2103,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2189,7 +2189,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2275,7 +2275,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2361,7 +2361,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2447,7 +2447,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2533,7 +2533,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2619,7 +2619,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2705,7 +2705,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2791,7 +2791,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2877,7 +2877,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -2963,7 +2963,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3049,7 +3049,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3135,7 +3135,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3221,7 +3221,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3307,7 +3307,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3393,7 +3393,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3479,7 +3479,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3565,7 +3565,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3651,7 +3651,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3737,7 +3737,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3823,7 +3823,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3909,7 +3909,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -3995,7 +3995,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4081,7 +4081,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4167,7 +4167,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4253,7 +4253,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4339,7 +4339,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4425,7 +4425,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4511,7 +4511,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4597,7 +4597,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4683,7 +4683,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
@ -4769,7 +4769,7 @@
|
|||
{
|
||||
"name": "meta.resultLine.search meta.resultLine.multiLine.search",
|
||||
"begin": "^ ((\\d+) )",
|
||||
"while": "^ ((\\d+)(:))|((\\d+) )",
|
||||
"while": "^ (?:((\\d+)(:))|((\\d+) ))",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "constant.numeric.integer meta.resultLinePrefix.search"
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2018",
|
||||
"lib": [
|
||||
"es2018"
|
||||
],
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
|
@ -9,4 +12,4 @@
|
|||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -730,6 +730,12 @@
|
|||
"default": 3072,
|
||||
"description": "%configuration.tsserver.maxTsServerMemory%",
|
||||
"scope": "window"
|
||||
},
|
||||
"typescript.tsserver.experimental.enableProjectDiagnostics": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.tsserver.experimental.enableProjectDiagnostics%",
|
||||
"scope": "window"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -882,10 +888,10 @@
|
|||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "^\\s*(?:message TS6032:|\\[?\\D*\\d{1,2}:\\d{1,2}:\\d{1,2}\\D*(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\."
|
||||
"regexp": "^\\s*(?:message TS6032:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(?:\\]| -)) File change detected\\. Starting incremental compilation\\.\\.\\."
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "^\\s*(?:message TS6042:|\\[?\\D*\\d{1,2}:\\d{1,2}:\\d{1,2}\\D*(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\."
|
||||
"regexp": "^\\s*(?:message TS6042:|\\[?\\D*\\d{1,2}[:.]\\d{1,2}[:.]\\d{1,2}\\D*(?:\\]| -)) (?:Compilation complete\\.|Found \\d+ errors?\\.) Watching for file changes\\."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
"configuration.suggest.paths": "Enable/disable suggestions for paths in import statements and require calls.",
|
||||
"configuration.tsserver.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Requires using TypeScript 3.4.0 or newer in the workspace.",
|
||||
"configuration.tsserver.maxTsServerMemory": "Set the maximum amount of memory (in MB) to allocate to the TypeScript server process",
|
||||
"configuration.tsserver.experimental.enableProjectDiagnostics": "(Experimental) Enables project wide error reporting.",
|
||||
"typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.",
|
||||
"javascript.implicitProjectConfig.experimentalDecorators": "Enable/disable `experimentalDecorators` for JavaScript files that are not part of a project. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.",
|
||||
"configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.",
|
||||
|
|
|
@ -19,7 +19,6 @@ import LogDirectoryProvider from './utils/logDirectoryProvider';
|
|||
import ManagedFileContextManager from './utils/managedFileContext';
|
||||
import { PluginManager } from './utils/plugins';
|
||||
import * as ProjectStatus from './utils/projectStatus';
|
||||
import { Surveyor } from './utils/surveyor';
|
||||
import TscTaskProvider from './features/task';
|
||||
|
||||
export function activate(
|
||||
|
@ -70,8 +69,6 @@ function createLazyClientHost(
|
|||
|
||||
context.subscriptions.push(clientHost);
|
||||
|
||||
context.subscriptions.push(new Surveyor(context.globalState, clientHost.serviceClient));
|
||||
|
||||
clientHost.serviceClient.onReady(() => {
|
||||
context.subscriptions.push(
|
||||
ProjectStatus.create(
|
||||
|
|
|
@ -289,19 +289,25 @@ class GetErrRequest {
|
|||
public readonly files: ResourceMap<void>,
|
||||
onDone: () => void
|
||||
) {
|
||||
const args: Proto.GeterrRequestArgs = {
|
||||
delay: 0,
|
||||
files: coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource)))
|
||||
};
|
||||
const allFiles = coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource)));
|
||||
if (!allFiles.length) {
|
||||
this._done = true;
|
||||
onDone();
|
||||
} else {
|
||||
const request = client.configuration.enableProjectDiagnostics
|
||||
// Note that geterrForProject is almost certainly not the api we want here as it ends up computing far
|
||||
// too many diagnostics
|
||||
? client.executeAsync('geterrForProject', { delay: 0, file: allFiles[0] }, this._token.token)
|
||||
: client.executeAsync('geterr', { delay: 0, files: allFiles }, this._token.token);
|
||||
|
||||
client.executeAsync('geterr', args, this._token.token)
|
||||
.finally(() => {
|
||||
request.finally(() => {
|
||||
if (this._done) {
|
||||
return;
|
||||
}
|
||||
this._done = true;
|
||||
onDone();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public cancel(): any {
|
||||
|
@ -329,7 +335,7 @@ export default class BufferSyncSupport extends Disposable {
|
|||
|
||||
constructor(
|
||||
client: ITypeScriptServiceClient,
|
||||
modeIds: string[]
|
||||
modeIds: readonly string[]
|
||||
) {
|
||||
super();
|
||||
this.client = client;
|
||||
|
@ -454,7 +460,9 @@ export default class BufferSyncSupport extends Disposable {
|
|||
}
|
||||
|
||||
public interuptGetErr<R>(f: () => R): R {
|
||||
if (!this.pendingGetErr) {
|
||||
if (!this.pendingGetErr
|
||||
|| this.client.configuration.enableProjectDiagnostics // `geterr` happens on seperate server so no need to cancel it.
|
||||
) {
|
||||
return f();
|
||||
}
|
||||
|
||||
|
|
|
@ -66,17 +66,19 @@ class MyCompletionItem extends vscode.CompletionItem {
|
|||
this.useCodeSnippet = useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method);
|
||||
|
||||
if (tsEntry.replacementSpan) {
|
||||
this.range = typeConverters.Range.fromTextSpan(tsEntry.replacementSpan);
|
||||
let replaceRange = typeConverters.Range.fromTextSpan(tsEntry.replacementSpan);
|
||||
// Make sure we only replace a single line at most
|
||||
if (!this.range.isSingleLine) {
|
||||
this.range = new vscode.Range(this.range.start.line, this.range.start.character, this.range.start.line, line.length);
|
||||
if (!replaceRange.isSingleLine) {
|
||||
replaceRange = new vscode.Range(replaceRange.start.line, replaceRange.start.character, replaceRange.start.line, line.length);
|
||||
}
|
||||
this.range = {
|
||||
inserting: new vscode.Range(replaceRange.start, position),
|
||||
replacing: replaceRange,
|
||||
};
|
||||
}
|
||||
|
||||
this.insertText = tsEntry.insertText;
|
||||
// Set filterText for intelliCode and bracket accessors , but not for `this.` completions since it results in
|
||||
// them being overly prioritized. #74164
|
||||
this.filterText = tsEntry.insertText && !/^this\./.test(tsEntry.insertText) ? tsEntry.insertText : undefined;
|
||||
this.filterText = this.getFilterText(line, tsEntry.insertText);
|
||||
|
||||
if (completionContext.isMemberCompletion && completionContext.dotAccessorContext) {
|
||||
this.filterText = completionContext.dotAccessorContext.text + (this.insertText || this.label);
|
||||
|
@ -119,29 +121,68 @@ class MyCompletionItem extends vscode.CompletionItem {
|
|||
this.resolveRange(line);
|
||||
}
|
||||
|
||||
private getFilterText(line: string, insertText: string | undefined): string | undefined {
|
||||
// Handle private field completions
|
||||
if (this.tsEntry.name.startsWith('#')) {
|
||||
const wordRange = this.document.getWordRangeAtPosition(this.position);
|
||||
const wordStart = wordRange ? line.charAt(wordRange.start.character) : undefined;
|
||||
if (insertText) {
|
||||
if (insertText.startsWith('this.#')) {
|
||||
return wordStart === '#' ? insertText : insertText.replace(/^this\.#/, '');
|
||||
} else {
|
||||
return insertText;
|
||||
}
|
||||
} else {
|
||||
return wordStart === '#' ? undefined : this.tsEntry.name.replace(/^#/, '');
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// For `this.` completions, generally don't set the filter text since we don't want them to be overly prioritized. #74164
|
||||
if (insertText?.startsWith('this.')) {
|
||||
return undefined;
|
||||
}
|
||||
// Handle the case:
|
||||
// ```
|
||||
// const xyz = { 'ab c': 1 };
|
||||
// xyz.ab|
|
||||
// ```
|
||||
// In which case we want to insert a bracket accessor but should use `.abc` as the filter text instead of
|
||||
// the bracketed insert text.
|
||||
else if (insertText?.startsWith('[')) {
|
||||
return insertText.replace(/^\[['"](.+)[['"]\]$/, '.$1');
|
||||
}
|
||||
|
||||
// In all other cases, fallback to using the insertText
|
||||
return insertText;
|
||||
}
|
||||
|
||||
private resolveRange(line: string): void {
|
||||
if (this.range) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const wordRange = this.document.getWordRangeAtPosition(this.position);
|
||||
if (wordRange) {
|
||||
// TODO: Reverted next line due to https://github.com/Microsoft/vscode/issues/66187
|
||||
// this.range = wordRange;
|
||||
}
|
||||
let replaceRange = wordRange;
|
||||
|
||||
// Try getting longer, prefix based range for completions that span words
|
||||
const text = line.slice(Math.max(0, this.position.character - this.label.length), this.position.character).toLowerCase();
|
||||
const entryName = this.label.toLowerCase();
|
||||
for (let i = entryName.length; i >= 0; --i) {
|
||||
if (text.endsWith(entryName.substr(0, i)) && (!wordRange || wordRange.start.character > this.position.character - i)) {
|
||||
this.range = new vscode.Range(
|
||||
replaceRange = new vscode.Range(
|
||||
new vscode.Position(this.position.line, Math.max(0, this.position.character - i)),
|
||||
this.position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceRange) {
|
||||
this.range = {
|
||||
inserting: new vscode.Range(replaceRange.start, this.position),
|
||||
replacing: replaceRange
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static convertKind(kind: string): vscode.CompletionItemKind {
|
||||
|
@ -464,7 +505,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider
|
|||
return this.client.apiVersion.gte(API.v310) && this.client.apiVersion.lt(API.v320) ? undefined : '@';
|
||||
|
||||
case '#': // Workaround for https://github.com/microsoft/TypeScript/issues/36367
|
||||
return this.client.apiVersion.lt(API.v381) ? undefined : '#' as Proto.CompletionsTriggerCharacter;
|
||||
return this.client.apiVersion.lt(API.v381) ? undefined : '#';
|
||||
|
||||
case '.':
|
||||
case '"':
|
||||
|
|
|
@ -28,7 +28,7 @@ class JsDocCompletionItem extends vscode.CompletionItem {
|
|||
const suffix = line.slice(position.character).match(/^\s*\**\//);
|
||||
const start = position.translate(0, prefix ? -prefix[0].length : 0);
|
||||
const range = new vscode.Range(start, position.translate(0, suffix ? suffix[0].length : 0));
|
||||
this.range = <any>{ inserting: range, replacing: range };
|
||||
this.range = { inserting: range, replacing: range };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const jsTsLanguageConfiguration: vscode.LanguageConfiguration = {
|
|||
decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]].*$/,
|
||||
increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/
|
||||
},
|
||||
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
|
||||
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
|
||||
onEnterRules: [
|
||||
{
|
||||
// e.g. /** | */
|
||||
|
|
|
@ -3,38 +3,23 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { disposeAll } from '../utils/dispose';
|
||||
import { createTestEditor, joinLines, wait } from './testUtils';
|
||||
import { acceptFirstSuggestion, typeCommitCharacter } from './suggestTestHelpers';
|
||||
import { assertEditorContents, Config, createTestEditor, joinLines, updateConfig, VsCodeConfiguration, wait, enumerateConfig } from './testUtils';
|
||||
|
||||
const testDocumentUri = vscode.Uri.parse('untitled:test.ts');
|
||||
|
||||
type VsCodeConfiguration = { [key: string]: any };
|
||||
|
||||
async function updateConfig(newConfig: VsCodeConfiguration): Promise<VsCodeConfiguration> {
|
||||
const oldConfig: VsCodeConfiguration = {};
|
||||
const config = vscode.workspace.getConfiguration(undefined, testDocumentUri);
|
||||
for (const configKey of Object.keys(newConfig)) {
|
||||
oldConfig[configKey] = config.get(configKey);
|
||||
await new Promise((resolve, reject) =>
|
||||
config.update(configKey, newConfig[configKey], vscode.ConfigurationTarget.Global)
|
||||
.then(() => resolve(), reject));
|
||||
}
|
||||
return oldConfig;
|
||||
}
|
||||
|
||||
namespace Config {
|
||||
export const suggestSelection = 'editor.suggestSelection';
|
||||
export const completeFunctionCalls = 'typescript.suggest.completeFunctionCalls';
|
||||
}
|
||||
const insertModes = Object.freeze(['insert', 'replace']);
|
||||
|
||||
suite('TypeScript Completions', () => {
|
||||
const configDefaults: VsCodeConfiguration = Object.freeze({
|
||||
[Config.suggestSelection]: 'first',
|
||||
[Config.autoClosingBrackets]: 'always',
|
||||
[Config.completeFunctionCalls]: false,
|
||||
[Config.insertMode]: 'insert',
|
||||
[Config.snippetSuggestions]: 'none',
|
||||
[Config.suggestSelection]: 'first',
|
||||
});
|
||||
|
||||
const _disposables: vscode.Disposable[] = [];
|
||||
|
@ -44,76 +29,87 @@ suite('TypeScript Completions', () => {
|
|||
await wait(100);
|
||||
|
||||
// Save off config and apply defaults
|
||||
oldConfig = await updateConfig(configDefaults);
|
||||
oldConfig = await updateConfig(testDocumentUri, configDefaults);
|
||||
});
|
||||
|
||||
teardown(async () => {
|
||||
disposeAll(_disposables);
|
||||
|
||||
// Restore config
|
||||
await updateConfig(oldConfig);
|
||||
await updateConfig(testDocumentUri, oldConfig);
|
||||
|
||||
return vscode.commands.executeCommand('workbench.action.closeAllEditors');
|
||||
});
|
||||
|
||||
test('Basic var completion', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`const abcdef = 123;`,
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abcdef = 123;`,
|
||||
`abcdef;`
|
||||
));
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abcdef = 123;`,
|
||||
`abcdef;`
|
||||
),
|
||||
`config: ${config}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('Should treat period as commit character for var completions', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`const abcdef = 123;`,
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
const document = await typeCommitCharacter(testDocumentUri, '.', _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abcdef = 123;`,
|
||||
`abcdef.;`
|
||||
));
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
await typeCommitCharacter(testDocumentUri, '.', _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abcdef = 123;`,
|
||||
`abcdef.;`
|
||||
),
|
||||
`config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Should treat paren as commit character for function completions', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`function abcdef() {};`,
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
const document = await typeCommitCharacter(testDocumentUri, '(', _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`function abcdef() {};`,
|
||||
`abcdef();`
|
||||
));
|
||||
`ab$0;`
|
||||
);
|
||||
|
||||
await typeCommitCharacter(testDocumentUri, '(', _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`function abcdef() {};`,
|
||||
`abcdef();`
|
||||
), `config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Should insert backets when completing dot properties with spaces in name', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
'const x = { "hello world": 1 };',
|
||||
'x.$0'
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
'const x = { "hello world": 1 };',
|
||||
'x["hello world"]'
|
||||
));
|
||||
'x.$0'
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
'const x = { "hello world": 1 };',
|
||||
'x["hello world"]'
|
||||
), `config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Should allow commit characters for backet completions', async () => {
|
||||
|
@ -121,14 +117,14 @@ suite('TypeScript Completions', () => {
|
|||
{ char: '.', insert: '.' },
|
||||
{ char: '(', insert: '()' },
|
||||
]) {
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
'const x = { "hello world2": 1 };',
|
||||
'x.$0'
|
||||
);
|
||||
|
||||
const document = await typeCommitCharacter(testDocumentUri, char, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await typeCommitCharacter(testDocumentUri, char, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
'const x = { "hello world2": 1 };',
|
||||
`x["hello world2"]${insert}`
|
||||
|
@ -140,23 +136,26 @@ suite('TypeScript Completions', () => {
|
|||
});
|
||||
|
||||
test('Should not prioritize bracket accessor completions. #63100', async () => {
|
||||
// 'a' should be first entry in completion list
|
||||
await createTestEditor(testDocumentUri,
|
||||
'const x = { "z-z": 1, a: 1 };',
|
||||
'x.$0'
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
// 'a' should be first entry in completion list
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
'const x = { "z-z": 1, a: 1 };',
|
||||
'x.a'
|
||||
));
|
||||
'x.$0'
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
'const x = { "z-z": 1, a: 1 };',
|
||||
'x.a'
|
||||
),
|
||||
`config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Accepting a string completion should replace the entire string. #53962', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
'interface TFunction {',
|
||||
` (_: 'abc.abc2', __ ?: {}): string;`,
|
||||
` (_: 'abc.abc', __?: {}): string;`,
|
||||
|
@ -165,9 +164,9 @@ suite('TypeScript Completions', () => {
|
|||
`f('abc.abc$0')`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables, { useLineRange: true });
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
'interface TFunction {',
|
||||
` (_: 'abc.abc2', __ ?: {}): string;`,
|
||||
|
@ -178,35 +177,18 @@ suite('TypeScript Completions', () => {
|
|||
));
|
||||
});
|
||||
|
||||
test.skip('Accepting a member completion should result in valid code. #58597', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`const abc = 123;`,
|
||||
`ab$0c`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
`const abc = 123;`,
|
||||
`abc`
|
||||
));
|
||||
});
|
||||
|
||||
test('completeFunctionCalls should complete function parameters when at end of word', async () => {
|
||||
await updateConfig({
|
||||
[Config.completeFunctionCalls]: true,
|
||||
});
|
||||
await updateConfig(testDocumentUri, { [Config.completeFunctionCalls]: true });
|
||||
|
||||
// Complete with-in word
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef$0`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef(x, y, z)`
|
||||
|
@ -214,18 +196,16 @@ suite('TypeScript Completions', () => {
|
|||
});
|
||||
|
||||
test.skip('completeFunctionCalls should complete function parameters when within word', async () => {
|
||||
await updateConfig({
|
||||
[Config.completeFunctionCalls]: true,
|
||||
});
|
||||
await updateConfig(testDocumentUri, { [Config.completeFunctionCalls]: true });
|
||||
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcd$0ef`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef(x, y, z)`
|
||||
|
@ -233,18 +213,16 @@ suite('TypeScript Completions', () => {
|
|||
});
|
||||
|
||||
test('completeFunctionCalls should not complete function parameters at end of word if we are already in something that looks like a function call, #18131', async () => {
|
||||
await updateConfig({
|
||||
[Config.completeFunctionCalls]: true,
|
||||
});
|
||||
await updateConfig(testDocumentUri, { [Config.completeFunctionCalls]: true });
|
||||
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef$0(1, 2, 3)`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef(1, 2, 3)`
|
||||
|
@ -252,45 +230,396 @@ suite('TypeScript Completions', () => {
|
|||
});
|
||||
|
||||
test.skip('completeFunctionCalls should not complete function parameters within word if we are already in something that looks like a function call, #18131', async () => {
|
||||
await updateConfig({
|
||||
[Config.completeFunctionCalls]: true,
|
||||
});
|
||||
await updateConfig(testDocumentUri, { [Config.completeFunctionCalls]: true });
|
||||
|
||||
await createTestEditor(testDocumentUri,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcd$0ef(1, 2, 3)`
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`function abcdef(x, y, z) { }`,
|
||||
`abcdef(1, 2, 3)`
|
||||
));
|
||||
});
|
||||
|
||||
test('should not de-prioritized this.member suggestion, #74164', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` private detail = '';`,
|
||||
test('should not de-prioritize `this.member` suggestion, #74164', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` private detail = '';`,
|
||||
` foo() {`,
|
||||
` det$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` private detail = '';`,
|
||||
` foo() {`,
|
||||
` this.detail`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Member completions for string property name should insert `this.` and use brackets', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` ['xyz 123'] = 1`,
|
||||
` foo() {`,
|
||||
` xyz$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` ['xyz 123'] = 1`,
|
||||
` foo() {`,
|
||||
` this["xyz 123"]`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Member completions for string property name already using `this.` should add brackets', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` ['xyz 123'] = 1`,
|
||||
` foo() {`,
|
||||
` this.xyz$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` ['xyz 123'] = 1`,
|
||||
` foo() {`,
|
||||
` this["xyz 123"]`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Accepting a completion in word using `insert` mode should insert', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'insert' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abc = 123;`,
|
||||
`ab$0c`
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abc = 123;`,
|
||||
`abcc`
|
||||
));
|
||||
});
|
||||
|
||||
test('Accepting a completion in word using `replace` mode should replace', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'replace' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abc = 123;`,
|
||||
`ab$0c`
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abc = 123;`,
|
||||
`abc`
|
||||
));
|
||||
});
|
||||
|
||||
test('Accepting a member completion in word using `insert` mode add `this.` and insert', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'insert' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class Foo {`,
|
||||
` abc = 1;`,
|
||||
` foo() {`,
|
||||
` det$0`,
|
||||
` ab$0c`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` private detail = '';`,
|
||||
`class Foo {`,
|
||||
` abc = 1;`,
|
||||
` foo() {`,
|
||||
` this.detail`,
|
||||
` this.abcc`,
|
||||
` }`,
|
||||
`}`,
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
test('Accepting a member completion in word using `replace` mode should add `this.` and replace', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'replace' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class Foo {`,
|
||||
` abc = 1;`,
|
||||
` foo() {`,
|
||||
` ab$0c`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class Foo {`,
|
||||
` abc = 1;`,
|
||||
` foo() {`,
|
||||
` this.abc`,
|
||||
` }`,
|
||||
`}`,
|
||||
));
|
||||
});
|
||||
|
||||
test('Accepting string completion inside string using `insert` mode should insert', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'insert' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abc = { 'xy z': 123 }`,
|
||||
`abc["x$0y w"]`
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abc = { 'xy z': 123 }`,
|
||||
`abc["xy zy w"]`
|
||||
));
|
||||
});
|
||||
|
||||
// Waiting on https://github.com/microsoft/TypeScript/issues/35602
|
||||
test.skip('Accepting string completion inside string using insert mode should insert', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'replace' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`const abc = { 'xy z': 123 }`,
|
||||
`abc["x$0y w"]`
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`const abc = { 'xy z': 123 }`,
|
||||
`abc["xy w"]`
|
||||
));
|
||||
});
|
||||
|
||||
test('Private field completions on `this.#` should work', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.#$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.#xyz`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Private field completions on `#` should insert `this.`', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` #$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.#xyz`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Private field completions should not require strict prefix match (#89556)', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.xyz$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.#xyz`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Private field completions without `this.` should not require strict prefix match (#89556)', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` xyz$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` #xyz = 1;`,
|
||||
` foo() {`,
|
||||
` this.#xyz`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('Accepting a completion for async property in `insert` mode should insert and add await', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'insert' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'abc': 1 });`,
|
||||
` async foo() {`,
|
||||
` this.xyz.ab$0c`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'abc': 1 });`,
|
||||
` async foo() {`,
|
||||
` (await this.xyz).abcc`,
|
||||
` }`,
|
||||
`}`,
|
||||
));
|
||||
});
|
||||
|
||||
test('Accepting a completion for async property in `replace` mode should replace and add await', async () => {
|
||||
await updateConfig(testDocumentUri, { [Config.insertMode]: 'replace' });
|
||||
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'abc': 1 });`,
|
||||
` async foo() {`,
|
||||
` this.xyz.ab$0c`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'abc': 1 });`,
|
||||
` async foo() {`,
|
||||
` (await this.xyz).abc`,
|
||||
` }`,
|
||||
`}`,
|
||||
));
|
||||
});
|
||||
|
||||
test.skip('Accepting a completion for async string property should add await plus brackets', async () => {
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModes, async config => {
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'ab c': 1 });`,
|
||||
` async foo() {`,
|
||||
` this.xyz.ab$0`,
|
||||
` }`,
|
||||
`}`,
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`class A {`,
|
||||
` xyz = Promise.resolve({ 'abc': 1 });`,
|
||||
` async foo() {`,
|
||||
` (await this.xyz)["ab c"]`,
|
||||
` }`,
|
||||
`}`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,42 +3,59 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { disposeAll } from '../utils/dispose';
|
||||
import { createTestEditor, joinLines, wait } from './testUtils';
|
||||
import { acceptFirstSuggestion } from './suggestTestHelpers';
|
||||
import { assertEditorContents, Config, createTestEditor, CURSOR, enumerateConfig, insertModesValues, joinLines, updateConfig, VsCodeConfiguration, wait } from './testUtils';
|
||||
|
||||
const testDocumentUri = vscode.Uri.parse('untitled:test.ts');
|
||||
|
||||
suite('JSDoc Completions', () => {
|
||||
const _disposables: vscode.Disposable[] = [];
|
||||
|
||||
const configDefaults: VsCodeConfiguration = Object.freeze({
|
||||
[Config.snippetSuggestions]: 'inline',
|
||||
});
|
||||
|
||||
let oldConfig: { [key: string]: any } = {};
|
||||
|
||||
setup(async () => {
|
||||
await wait(100);
|
||||
|
||||
// Save off config and apply defaults
|
||||
oldConfig = await updateConfig(testDocumentUri, configDefaults);
|
||||
});
|
||||
|
||||
teardown(async () => {
|
||||
disposeAll(_disposables);
|
||||
|
||||
// Restore config
|
||||
await updateConfig(testDocumentUri, oldConfig);
|
||||
|
||||
return vscode.commands.executeCommand('workbench.action.closeAllEditors');
|
||||
});
|
||||
|
||||
test('Should complete jsdoc inside single line comment', async () => {
|
||||
await createTestEditor(testDocumentUri,
|
||||
`/**$0 */`,
|
||||
`function abcdef(x, y) { }`,
|
||||
);
|
||||
await enumerateConfig(testDocumentUri, Config.insertMode, insertModesValues, async config => {
|
||||
|
||||
const document = await acceptFirstSuggestion(testDocumentUri, _disposables, { useLineRange: true});
|
||||
assert.strictEqual(
|
||||
document.getText(),
|
||||
joinLines(
|
||||
`/**`,
|
||||
` *`,
|
||||
` * @param {*} x `,
|
||||
` * @param {*} y `,
|
||||
` */`,
|
||||
const editor = await createTestEditor(testDocumentUri,
|
||||
`/**$0 */`,
|
||||
`function abcdef(x, y) { }`,
|
||||
));
|
||||
);
|
||||
|
||||
await acceptFirstSuggestion(testDocumentUri, _disposables);
|
||||
|
||||
assertEditorContents(editor,
|
||||
joinLines(
|
||||
`/**`,
|
||||
` * `,
|
||||
` * @param x ${CURSOR}`,
|
||||
` * @param y `,
|
||||
` */`,
|
||||
`function abcdef(x, y) { }`,
|
||||
),
|
||||
`Config: ${config}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,5 +54,15 @@ suite('typescript.previewer', () => {
|
|||
'x {@link http://www.example.com/foo y [bar](http://www.example.com/bar) z');
|
||||
});
|
||||
|
||||
test('Should support non-ascii characters in parameter name (#90108)', async () => {
|
||||
assert.strictEqual(
|
||||
tagsMarkdownPreview([
|
||||
{
|
||||
name: 'param',
|
||||
text: 'parámetroConDiacríticos this will not'
|
||||
}
|
||||
]),
|
||||
'*@param* `parámetroConDiacríticos` — this will not');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -7,23 +7,18 @@ import 'mocha';
|
|||
import * as vscode from 'vscode';
|
||||
import { wait } from './testUtils';
|
||||
|
||||
export async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[], options?: { useLineRange?: boolean }) {
|
||||
export async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[]) {
|
||||
const didChangeDocument = onChangedDocument(uri, _disposables);
|
||||
const didSuggest = onDidSuggest(_disposables, options);
|
||||
await vscode.commands.executeCommand('editor.action.triggerSuggest');
|
||||
await didSuggest;
|
||||
// TODO: depends on reverting fix for https://github.com/Microsoft/vscode/issues/64257
|
||||
// Make sure we have time to resolve the suggestion because `acceptSelectedSuggestion` doesn't
|
||||
await wait(40);
|
||||
await wait(1000); // Give time for suggestions to show
|
||||
await vscode.commands.executeCommand('acceptSelectedSuggestion');
|
||||
return await didChangeDocument;
|
||||
return didChangeDocument;
|
||||
}
|
||||
|
||||
export async function typeCommitCharacter(uri: vscode.Uri, character: string, _disposables: vscode.Disposable[]) {
|
||||
const didChangeDocument = onChangedDocument(uri, _disposables);
|
||||
const didSuggest = onDidSuggest(_disposables);
|
||||
await vscode.commands.executeCommand('editor.action.triggerSuggest');
|
||||
await didSuggest;
|
||||
await wait(1000); // Give time for suggestions to show
|
||||
await vscode.commands.executeCommand('type', { text: character });
|
||||
return await didChangeDocument;
|
||||
}
|
||||
|
@ -35,29 +30,3 @@ export function onChangedDocument(documentUri: vscode.Uri, disposables: vscode.D
|
|||
}
|
||||
}, undefined, disposables));
|
||||
}
|
||||
|
||||
|
||||
function onDidSuggest(disposables: vscode.Disposable[], options?: { useLineRange?: boolean }) {
|
||||
return new Promise(resolve =>
|
||||
disposables.push(vscode.languages.registerCompletionItemProvider('typescript', new class implements vscode.CompletionItemProvider {
|
||||
provideCompletionItems(doc: vscode.TextDocument, position: vscode.Position): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
// Return a fake item that will come first
|
||||
const range = options && options.useLineRange
|
||||
? new vscode.Range(new vscode.Position(position.line, 0), position)
|
||||
: doc.getWordRangeAtPosition(position.translate({ characterDelta: -1 }));
|
||||
return [{
|
||||
label: '🦄',
|
||||
insertText: doc.getText(range),
|
||||
filterText: doc.getText(range),
|
||||
preselect: true,
|
||||
sortText: 'a',
|
||||
range: range
|
||||
}];
|
||||
}
|
||||
async resolveCompletionItem(item: vscode.CompletionItem) {
|
||||
await vscode.commands.executeCommand('selectNextSuggestion');
|
||||
resolve();
|
||||
return item;
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as assert from 'assert';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import { join } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
function rndName() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10);
|
||||
|
@ -73,11 +74,62 @@ export const joinLines = (...args: string[]) => args.join('\n');
|
|||
|
||||
export async function createTestEditor(uri: vscode.Uri, ...lines: string[]) {
|
||||
const document = await vscode.workspace.openTextDocument(uri);
|
||||
await vscode.window.showTextDocument(document);
|
||||
const activeEditor = vscode.window.activeTextEditor;
|
||||
if (!activeEditor) {
|
||||
throw new Error('no active editor');
|
||||
}
|
||||
|
||||
await activeEditor.insertSnippet(new vscode.SnippetString(joinLines(...lines)), new vscode.Range(0, 0, 1000, 0));
|
||||
const editor = await vscode.window.showTextDocument(document);
|
||||
await editor.insertSnippet(new vscode.SnippetString(joinLines(...lines)), new vscode.Range(0, 0, 1000, 0));
|
||||
return editor;
|
||||
}
|
||||
|
||||
export function assertEditorContents(editor: vscode.TextEditor, expectedDocContent: string, message?: string): void {
|
||||
const cursorIndex = expectedDocContent.indexOf(CURSOR);
|
||||
|
||||
assert.strictEqual(
|
||||
editor.document.getText(),
|
||||
expectedDocContent.replace(CURSOR, ''),
|
||||
message);
|
||||
|
||||
if (cursorIndex >= 0) {
|
||||
const expectedCursorPos = editor.document.positionAt(cursorIndex);
|
||||
assert.deepEqual(
|
||||
{ line: editor.selection.active.line, character: editor.selection.active.line },
|
||||
{ line: expectedCursorPos.line, character: expectedCursorPos.line },
|
||||
'Cursor position'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export type VsCodeConfiguration = { [key: string]: any };
|
||||
|
||||
export async function updateConfig(documentUri: vscode.Uri, newConfig: VsCodeConfiguration): Promise<VsCodeConfiguration> {
|
||||
const oldConfig: VsCodeConfiguration = {};
|
||||
const config = vscode.workspace.getConfiguration(undefined, documentUri);
|
||||
for (const configKey of Object.keys(newConfig)) {
|
||||
oldConfig[configKey] = config.get(configKey);
|
||||
await new Promise((resolve, reject) =>
|
||||
config.update(configKey, newConfig[configKey], vscode.ConfigurationTarget.Global)
|
||||
.then(() => resolve(), reject));
|
||||
}
|
||||
return oldConfig;
|
||||
}
|
||||
|
||||
export const Config = Object.freeze({
|
||||
autoClosingBrackets: 'editor.autoClosingBrackets',
|
||||
completeFunctionCalls: 'typescript.suggest.completeFunctionCalls',
|
||||
insertMode: 'editor.suggest.insertMode',
|
||||
snippetSuggestions: 'editor.snippetSuggestions',
|
||||
suggestSelection: 'editor.suggestSelection',
|
||||
} as const);
|
||||
|
||||
export const insertModesValues = Object.freeze(['insert', 'replace']);
|
||||
|
||||
export async function enumerateConfig(
|
||||
documentUri: vscode.Uri,
|
||||
configKey: string,
|
||||
values: readonly string[],
|
||||
f: (message: string) => Promise<void>
|
||||
): Promise<void> {
|
||||
for (const value of values) {
|
||||
const newConfig = { [configKey]: value };
|
||||
await updateConfig(documentUri, newConfig);
|
||||
await f(JSON.stringify(newConfig));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,22 +297,128 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe
|
|||
}
|
||||
|
||||
|
||||
class RequestRouter {
|
||||
|
||||
private static readonly sharedCommands = new Set<keyof TypeScriptRequests>([
|
||||
'change',
|
||||
'close',
|
||||
'open',
|
||||
'updateOpen',
|
||||
'configure',
|
||||
'configurePlugin',
|
||||
]);
|
||||
|
||||
constructor(
|
||||
private readonly servers: ReadonlyArray<{ readonly server: ITypeScriptServer, readonly preferredCommands?: ReadonlySet<keyof TypeScriptRequests> }>,
|
||||
private readonly delegate: TsServerDelegate,
|
||||
) { }
|
||||
|
||||
public execute(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>> | undefined {
|
||||
if (RequestRouter.sharedCommands.has(command)) {
|
||||
// Dispatch shared commands to all server but only return from first one one
|
||||
|
||||
const requestStates: RequestState.State[] = this.servers.map(() => RequestState.Unresolved);
|
||||
|
||||
// Also make sure we never cancel requests to just one server
|
||||
let token: vscode.CancellationToken | undefined = undefined;
|
||||
if (executeInfo.token) {
|
||||
const source = new vscode.CancellationTokenSource();
|
||||
executeInfo.token.onCancellationRequested(() => {
|
||||
if (requestStates.some(state => state === RequestState.Resolved)) {
|
||||
// Don't cancel.
|
||||
// One of the servers completed this request so we don't want to leave the other
|
||||
// in a different state.
|
||||
return;
|
||||
}
|
||||
source.cancel();
|
||||
});
|
||||
token = source.token;
|
||||
}
|
||||
|
||||
let firstRequest: Promise<ServerResponse.Response<Proto.Response>> | undefined;
|
||||
|
||||
for (let serverIndex = 0; serverIndex < this.servers.length; ++serverIndex) {
|
||||
const server = this.servers[serverIndex].server;
|
||||
|
||||
const request = server.executeImpl(command, args, { ...executeInfo, token });
|
||||
if (serverIndex === 0) {
|
||||
firstRequest = request;
|
||||
}
|
||||
if (request) {
|
||||
request
|
||||
.then(result => {
|
||||
requestStates[serverIndex] = RequestState.Resolved;
|
||||
const erroredRequest = requestStates.find(state => state.type === RequestState.Type.Errored) as RequestState.Errored | undefined;
|
||||
if (erroredRequest) {
|
||||
// We've gone out of sync
|
||||
this.delegate.onFatalError(command, erroredRequest.err);
|
||||
}
|
||||
return result;
|
||||
}, err => {
|
||||
requestStates[serverIndex] = new RequestState.Errored(err);
|
||||
if (requestStates.some(state => state === RequestState.Resolved)) {
|
||||
// We've gone out of sync
|
||||
this.delegate.onFatalError(command, err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return firstRequest;
|
||||
}
|
||||
|
||||
for (const { preferredCommands, server } of this.servers) {
|
||||
if (!preferredCommands || preferredCommands.has(command)) {
|
||||
return server.executeImpl(command, args, executeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not find server for command: '${command}'`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServer {
|
||||
|
||||
private static readonly syntaxCommands = new Set<keyof TypeScriptRequests>([
|
||||
'navtree',
|
||||
'getOutliningSpans',
|
||||
'jsxClosingTag',
|
||||
'selectionRange',
|
||||
'format',
|
||||
'formatonkey',
|
||||
'docCommentTemplate',
|
||||
]);
|
||||
|
||||
private readonly syntaxServer: ITypeScriptServer;
|
||||
private readonly semanticServer: ITypeScriptServer;
|
||||
private readonly router: RequestRouter;
|
||||
|
||||
public constructor(
|
||||
private readonly syntaxServer: ITypeScriptServer,
|
||||
private readonly semanticServer: ITypeScriptServer,
|
||||
private readonly _delegate: TsServerDelegate,
|
||||
servers: { syntax: ITypeScriptServer, semantic: ITypeScriptServer },
|
||||
delegate: TsServerDelegate,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(syntaxServer.onEvent(e => this._onEvent.fire(e)));
|
||||
this._register(semanticServer.onEvent(e => this._onEvent.fire(e)));
|
||||
this.syntaxServer = servers.syntax;
|
||||
this.semanticServer = servers.semantic;
|
||||
|
||||
this._register(semanticServer.onExit(e => {
|
||||
this.router = new RequestRouter(
|
||||
[
|
||||
{ server: this.syntaxServer, preferredCommands: SyntaxRoutingTsServer.syntaxCommands },
|
||||
{ server: this.semanticServer, preferredCommands: undefined /* gets all other commands */ }
|
||||
],
|
||||
delegate);
|
||||
|
||||
this._register(this.syntaxServer.onEvent(e => this._onEvent.fire(e)));
|
||||
this._register(this.semanticServer.onEvent(e => this._onEvent.fire(e)));
|
||||
|
||||
this._register(this.semanticServer.onExit(e => {
|
||||
this._onExit.fire(e);
|
||||
this.syntaxServer.kill();
|
||||
}));
|
||||
this._register(semanticServer.onError(e => this._onError.fire(e)));
|
||||
this._register(this.semanticServer.onError(e => this._onError.fire(e)));
|
||||
}
|
||||
|
||||
private readonly _onEvent = this._register(new vscode.EventEmitter<Proto.Event>());
|
||||
|
@ -333,98 +439,91 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ
|
|||
this.semanticServer.kill();
|
||||
}
|
||||
|
||||
private static readonly syntaxCommands = new Set<keyof TypeScriptRequests>([
|
||||
'navtree',
|
||||
'getOutliningSpans',
|
||||
'jsxClosingTag',
|
||||
'selectionRange',
|
||||
'format',
|
||||
'formatonkey',
|
||||
'docCommentTemplate',
|
||||
]);
|
||||
private static readonly sharedCommands = new Set<keyof TypeScriptRequests>([
|
||||
'change',
|
||||
'close',
|
||||
'open',
|
||||
'updateOpen',
|
||||
'configure',
|
||||
'configurePlugin',
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined;
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>>;
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>> | undefined {
|
||||
return this.router.execute(command, args, executeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class GetErrRoutingTsServer extends Disposable implements ITypeScriptServer {
|
||||
|
||||
private static readonly diagnosticEvents = new Set([
|
||||
'configFileDiag',
|
||||
'syntaxDiag',
|
||||
'semanticDiag',
|
||||
'suggestionDiag'
|
||||
]);
|
||||
|
||||
private readonly getErrServer: ITypeScriptServer;
|
||||
private readonly mainServer: ITypeScriptServer;
|
||||
private readonly router: RequestRouter;
|
||||
|
||||
public constructor(
|
||||
servers: { getErr: ITypeScriptServer, primary: ITypeScriptServer },
|
||||
delegate: TsServerDelegate,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.getErrServer = servers.getErr;
|
||||
this.mainServer = servers.primary;
|
||||
|
||||
this.router = new RequestRouter(
|
||||
[
|
||||
{ server: this.getErrServer, preferredCommands: new Set<keyof TypeScriptRequests>(['geterr', 'geterrForProject']) },
|
||||
{ server: this.mainServer, preferredCommands: undefined /* gets all other commands */ }
|
||||
],
|
||||
delegate);
|
||||
|
||||
this._register(this.getErrServer.onEvent(e => {
|
||||
if (GetErrRoutingTsServer.diagnosticEvents.has(e.event)) {
|
||||
this._onEvent.fire(e);
|
||||
}
|
||||
// Ignore all other events
|
||||
}));
|
||||
this._register(this.mainServer.onEvent(e => {
|
||||
if (!GetErrRoutingTsServer.diagnosticEvents.has(e.event)) {
|
||||
this._onEvent.fire(e);
|
||||
}
|
||||
// Ignore all other events
|
||||
}));
|
||||
|
||||
this._register(this.getErrServer.onError(e => this._onError.fire(e)));
|
||||
this._register(this.mainServer.onError(e => this._onError.fire(e)));
|
||||
|
||||
this._register(this.mainServer.onExit(e => {
|
||||
this._onExit.fire(e);
|
||||
this.getErrServer.kill();
|
||||
}));
|
||||
}
|
||||
|
||||
private readonly _onEvent = this._register(new vscode.EventEmitter<Proto.Event>());
|
||||
public readonly onEvent = this._onEvent.event;
|
||||
|
||||
private readonly _onExit = this._register(new vscode.EventEmitter<any>());
|
||||
public readonly onExit = this._onExit.event;
|
||||
|
||||
private readonly _onError = this._register(new vscode.EventEmitter<any>());
|
||||
public readonly onError = this._onError.event;
|
||||
|
||||
public get onReaderError() { return this.mainServer.onReaderError; }
|
||||
|
||||
public get tsServerLogFile() { return this.mainServer.tsServerLogFile; }
|
||||
|
||||
public kill(): void {
|
||||
this.getErrServer.kill();
|
||||
this.mainServer.kill();
|
||||
}
|
||||
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined;
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>>;
|
||||
public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>> | undefined {
|
||||
if (SyntaxRoutingTsServer.syntaxCommands.has(command)) {
|
||||
return this.syntaxServer.executeImpl(command, args, executeInfo);
|
||||
} else if (SyntaxRoutingTsServer.sharedCommands.has(command)) {
|
||||
// Dispatch to both server but only return from syntax one
|
||||
|
||||
let syntaxRequestState: RequestState.State = RequestState.Unresolved;
|
||||
let semanticRequestState: RequestState.State = RequestState.Unresolved;
|
||||
|
||||
// Also make sure we never cancel requests to just one server
|
||||
let token: vscode.CancellationToken | undefined = undefined;
|
||||
if (executeInfo.token) {
|
||||
const source = new vscode.CancellationTokenSource();
|
||||
executeInfo.token.onCancellationRequested(() => {
|
||||
if (syntaxRequestState !== RequestState.Unresolved && semanticRequestState === RequestState.Unresolved
|
||||
|| syntaxRequestState === RequestState.Unresolved && semanticRequestState !== RequestState.Unresolved
|
||||
) {
|
||||
// Don't cancel.
|
||||
// One of the servers completed this request so we don't want to leave the other
|
||||
// in a different state
|
||||
return;
|
||||
}
|
||||
source.cancel();
|
||||
});
|
||||
token = source.token;
|
||||
}
|
||||
|
||||
const semanticRequest = this.semanticServer.executeImpl(command, args, { ...executeInfo, token });
|
||||
if (semanticRequest) {
|
||||
semanticRequest
|
||||
.then(result => {
|
||||
semanticRequestState = RequestState.Resolved;
|
||||
if (syntaxRequestState.type === RequestState.Type.Errored) {
|
||||
// We've gone out of sync
|
||||
this._delegate.onFatalError(command, syntaxRequestState.err);
|
||||
}
|
||||
return result;
|
||||
}, err => {
|
||||
semanticRequestState = new RequestState.Errored(err);
|
||||
if (syntaxRequestState === RequestState.Resolved) {
|
||||
// We've gone out of sync
|
||||
this._delegate.onFatalError(command, err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
const syntaxRequest = this.syntaxServer.executeImpl(command, args, { ...executeInfo, token });
|
||||
if (syntaxRequest) {
|
||||
syntaxRequest
|
||||
.then(result => {
|
||||
syntaxRequestState = RequestState.Resolved;
|
||||
if (semanticRequestState.type === RequestState.Type.Errored) {
|
||||
// We've gone out of sync
|
||||
this._delegate.onFatalError(command, semanticRequestState.err);
|
||||
}
|
||||
return result;
|
||||
}, err => {
|
||||
syntaxRequestState = new RequestState.Errored(err);
|
||||
if (semanticRequestState === RequestState.Resolved) {
|
||||
// We've gone out of sync
|
||||
this._delegate.onFatalError(command, err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return syntaxRequest;
|
||||
} else {
|
||||
return this.semanticServer.executeImpl(command, args, executeInfo);
|
||||
}
|
||||
return this.router.execute(command, args, executeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace RequestState {
|
||||
export const enum Type { Unresolved, Resolved, Errored }
|
||||
|
||||
|
|
|
@ -18,9 +18,14 @@ import { PluginManager } from '../utils/plugins';
|
|||
import { TelemetryReporter } from '../utils/telemetry';
|
||||
import Tracer from '../utils/tracer';
|
||||
import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider';
|
||||
import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess, TsServerDelegate } from './server';
|
||||
import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess, TsServerDelegate, GetErrRoutingTsServer } from './server';
|
||||
|
||||
type ServerKind = 'main' | 'syntax' | 'semantic';
|
||||
const enum ServerKind {
|
||||
Main = 'main',
|
||||
Syntax = 'syntax',
|
||||
Semantic = 'semantic',
|
||||
Diagnostics = 'diagnostics'
|
||||
}
|
||||
|
||||
export class TypeScriptServerSpawner {
|
||||
public constructor(
|
||||
|
@ -38,13 +43,24 @@ export class TypeScriptServerSpawner {
|
|||
pluginManager: PluginManager,
|
||||
delegate: TsServerDelegate,
|
||||
): ITypeScriptServer {
|
||||
let primaryServer: ITypeScriptServer;
|
||||
if (this.shouldUseSeparateSyntaxServer(version, configuration)) {
|
||||
const syntaxServer = this.spawnTsServer('syntax', version, configuration, pluginManager);
|
||||
const semanticServer = this.spawnTsServer('semantic', version, configuration, pluginManager);
|
||||
return new SyntaxRoutingTsServer(syntaxServer, semanticServer, delegate);
|
||||
primaryServer = new SyntaxRoutingTsServer({
|
||||
syntax: this.spawnTsServer(ServerKind.Syntax, version, configuration, pluginManager),
|
||||
semantic: this.spawnTsServer(ServerKind.Semantic, version, configuration, pluginManager)
|
||||
}, delegate);
|
||||
} else {
|
||||
primaryServer = this.spawnTsServer(ServerKind.Main, version, configuration, pluginManager);
|
||||
}
|
||||
|
||||
return this.spawnTsServer('main', version, configuration, pluginManager);
|
||||
if (this.shouldUseSeparateDiagnosticsServer(configuration)) {
|
||||
return new GetErrRoutingTsServer({
|
||||
getErr: this.spawnTsServer(ServerKind.Diagnostics, version, configuration, pluginManager),
|
||||
primary: primaryServer,
|
||||
}, delegate);
|
||||
}
|
||||
|
||||
return primaryServer;
|
||||
}
|
||||
|
||||
private shouldUseSeparateSyntaxServer(
|
||||
|
@ -54,6 +70,12 @@ export class TypeScriptServerSpawner {
|
|||
return configuration.useSeparateSyntaxServer && !!version.apiVersion && version.apiVersion.gte(API.v340);
|
||||
}
|
||||
|
||||
private shouldUseSeparateDiagnosticsServer(
|
||||
configuration: TypeScriptServiceConfiguration,
|
||||
): boolean {
|
||||
return configuration.enableProjectDiagnostics;
|
||||
}
|
||||
|
||||
private spawnTsServer(
|
||||
kind: ServerKind,
|
||||
version: TypeScriptVersion,
|
||||
|
@ -107,7 +129,7 @@ export class TypeScriptServerSpawner {
|
|||
const args: string[] = [];
|
||||
let tsServerLogFile: string | undefined;
|
||||
|
||||
if (kind === 'syntax') {
|
||||
if (kind === ServerKind.Syntax) {
|
||||
args.push('--syntaxOnly');
|
||||
}
|
||||
|
||||
|
@ -117,11 +139,11 @@ export class TypeScriptServerSpawner {
|
|||
args.push('--useSingleInferredProject');
|
||||
}
|
||||
|
||||
if (configuration.disableAutomaticTypeAcquisition || kind === 'syntax') {
|
||||
if (configuration.disableAutomaticTypeAcquisition || kind === ServerKind.Syntax || kind === ServerKind.Diagnostics) {
|
||||
args.push('--disableAutomaticTypingAcquisition');
|
||||
}
|
||||
|
||||
if (kind !== 'syntax') {
|
||||
if (kind === ServerKind.Semantic || kind === ServerKind.Main) {
|
||||
args.push('--enableTelemetry');
|
||||
}
|
||||
|
||||
|
|
|
@ -55,18 +55,6 @@ export default class TypeScriptServiceClientHost extends Disposable {
|
|||
onCompletionAccepted: (item: vscode.CompletionItem) => void,
|
||||
) {
|
||||
super();
|
||||
const handleProjectCreateOrDelete = () => {
|
||||
this.triggerAllDiagnostics();
|
||||
};
|
||||
const handleProjectChange = () => {
|
||||
setTimeout(() => {
|
||||
this.triggerAllDiagnostics();
|
||||
}, 1500);
|
||||
};
|
||||
const configFileWatcher = this._register(vscode.workspace.createFileSystemWatcher('**/[tj]sconfig.json'));
|
||||
configFileWatcher.onDidCreate(handleProjectCreateOrDelete, this, this._disposables);
|
||||
configFileWatcher.onDidDelete(handleProjectCreateOrDelete, this, this._disposables);
|
||||
configFileWatcher.onDidChange(handleProjectChange, this, this._disposables);
|
||||
|
||||
const allModeIds = this.getAllModeIds(descriptions, pluginManager);
|
||||
this.client = this._register(new TypeScriptServiceClient(
|
||||
|
|
|
@ -74,6 +74,7 @@ interface NoResponseTsServerRequests {
|
|||
|
||||
interface AsyncTsServerRequests {
|
||||
'geterr': [Proto.GeterrRequestArgs, Proto.Response];
|
||||
'geterrForProject': [Proto.GeterrForProjectRequestArgs, Proto.Response];
|
||||
}
|
||||
|
||||
export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRequests & AsyncTsServerRequests;
|
||||
|
@ -137,7 +138,11 @@ export interface ITypeScriptServiceClient {
|
|||
args: NoResponseTsServerRequests[K][0]
|
||||
): void;
|
||||
|
||||
executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise<ServerResponse.Response<Proto.Response>>;
|
||||
executeAsync<K extends keyof AsyncTsServerRequests>(
|
||||
command: K,
|
||||
args: AsyncTsServerRequests[K][0],
|
||||
token: vscode.CancellationToken
|
||||
): Promise<ServerResponse.Response<Proto.Response>>;
|
||||
|
||||
/**
|
||||
* Cancel on going geterr requests and re-queue them after `f` has been evaluated.
|
||||
|
|
|
@ -121,7 +121,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
|
|||
private readonly onDidChangeTypeScriptVersion: (version: TypeScriptVersion) => void,
|
||||
public readonly pluginManager: PluginManager,
|
||||
private readonly logDirectoryProvider: LogDirectoryProvider,
|
||||
allModeIds: string[]
|
||||
allModeIds: readonly string[]
|
||||
) {
|
||||
super();
|
||||
this.pathSeparator = path.sep;
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
||||
|
|
|
@ -55,6 +55,7 @@ export class TypeScriptServiceConfiguration {
|
|||
public readonly experimentalDecorators: boolean;
|
||||
public readonly disableAutomaticTypeAcquisition: boolean;
|
||||
public readonly useSeparateSyntaxServer: boolean;
|
||||
public readonly enableProjectDiagnostics: boolean;
|
||||
public readonly maxTsServerMemory: number;
|
||||
|
||||
public static loadFromWorkspace(): TypeScriptServiceConfiguration {
|
||||
|
@ -74,6 +75,7 @@ export class TypeScriptServiceConfiguration {
|
|||
this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration);
|
||||
this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration);
|
||||
this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration);
|
||||
this.enableProjectDiagnostics = TypeScriptServiceConfiguration.readEnableProjectDiagnostics(configuration);
|
||||
this.maxTsServerMemory = TypeScriptServiceConfiguration.readMaxTsServerMemory(configuration);
|
||||
}
|
||||
|
||||
|
@ -88,6 +90,7 @@ export class TypeScriptServiceConfiguration {
|
|||
&& this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition
|
||||
&& arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths)
|
||||
&& this.useSeparateSyntaxServer === other.useSeparateSyntaxServer
|
||||
&& this.enableProjectDiagnostics === other.enableProjectDiagnostics
|
||||
&& this.maxTsServerMemory === other.maxTsServerMemory;
|
||||
}
|
||||
|
||||
|
@ -150,6 +153,10 @@ export class TypeScriptServiceConfiguration {
|
|||
return configuration.get<boolean>('typescript.tsserver.useSeparateSyntaxServer', true);
|
||||
}
|
||||
|
||||
private static readEnableProjectDiagnostics(configuration: vscode.WorkspaceConfiguration): boolean {
|
||||
return configuration.get<boolean>('typescript.tsserver.experimental.enableProjectDiagnostics', false);
|
||||
}
|
||||
|
||||
private static readMaxTsServerMemory(configuration: vscode.WorkspaceConfiguration): number {
|
||||
const defaultMaxMemory = 3072;
|
||||
const minimumMaxMemory = 128;
|
||||
|
|
|
@ -68,8 +68,8 @@ function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined {
|
|||
case 'extends':
|
||||
case 'param':
|
||||
case 'template':
|
||||
const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/);
|
||||
if (body && body.length === 3) {
|
||||
const body = (tag.text || '').split(/^(\S+)\s*-?\s*/);
|
||||
if (body?.length === 3) {
|
||||
const param = body[1];
|
||||
const doc = body[2];
|
||||
const label = `*@${tag.name}* \`${param}\``;
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import TypeScriptServiceClient from '../typescriptServiceClient';
|
||||
import { Disposable } from './dispose';
|
||||
import { memoize } from './memoize';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
interface SurveyData {
|
||||
/**
|
||||
* Internal id of the survey. Comes from TypeScript.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* Text displayed to the user when survey is triggered.
|
||||
*/
|
||||
readonly prompt: string;
|
||||
|
||||
/**
|
||||
* Number of times to trigger with `surveyReady` before showing the survey.
|
||||
*
|
||||
* This is cumulative and shared across workspaces.
|
||||
*/
|
||||
readonly globalTriggerThreshold: number;
|
||||
|
||||
/**
|
||||
* Survey link.
|
||||
*/
|
||||
readonly url: vscode.Uri;
|
||||
|
||||
/**
|
||||
* Milliseconds to wait after 'Remind later' is chosen before trying to prompt again.
|
||||
*/
|
||||
readonly remindLaterDelayInMilliseconds: number;
|
||||
}
|
||||
|
||||
const allSurveys: ReadonlyArray<SurveyData> = [
|
||||
{
|
||||
id: 'checkJs',
|
||||
prompt: localize('survey.checkJs.prompt', "Help improve VS Code's support for [checkJs](https://code.visualstudio.com/Docs/languages/javascript#_type-checking) in JavaScript! Since you have been using this feature, would you consider taking a short survey about your experience?"),
|
||||
globalTriggerThreshold: 10,
|
||||
url: vscode.Uri.parse('https://www.surveymonkey.com/r/FH8PZQ3'),
|
||||
remindLaterDelayInMilliseconds: 3 * 24 * 60 * 60 * 1000 // 3 days
|
||||
}
|
||||
];
|
||||
|
||||
class Survey {
|
||||
|
||||
private _hasShownInThisSession = false;
|
||||
|
||||
public constructor(
|
||||
private readonly data: SurveyData,
|
||||
private readonly memento: vscode.Memento
|
||||
) { }
|
||||
|
||||
public get id(): string { return this.data.id; }
|
||||
|
||||
public get prompt(): string { return this.data.prompt; }
|
||||
|
||||
public get isActive(): boolean {
|
||||
return !this._hasShownInThisSession && !this.memento.get<boolean>(this.isCompletedMementoKey);
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.markComplete();
|
||||
vscode.commands.executeCommand<void>('vscode.open', this.data.url);
|
||||
}
|
||||
|
||||
public remindLater(): void {
|
||||
// Make sure we don't show again in this session (but don't persist as completed)
|
||||
this._hasShownInThisSession = true;
|
||||
|
||||
// And save off prompt time.
|
||||
this.memento.update(this.lastPromptTimeMementoKey, Date.now());
|
||||
}
|
||||
|
||||
public trigger(): boolean {
|
||||
const triggerCount = this.triggerCount + 1;
|
||||
this.memento.update(this.triggerCountMementoKey, triggerCount);
|
||||
if (triggerCount >= this.data.globalTriggerThreshold) {
|
||||
const lastPromptTime = this.memento.get<number>(this.lastPromptTimeMementoKey);
|
||||
if (!lastPromptTime || isNaN(+lastPromptTime)) {
|
||||
return true;
|
||||
}
|
||||
return (lastPromptTime + this.data.remindLaterDelayInMilliseconds < Date.now());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public willShow() {
|
||||
this._hasShownInThisSession = true;
|
||||
}
|
||||
|
||||
public markComplete() {
|
||||
this._hasShownInThisSession = true;
|
||||
this.memento.update(this.isCompletedMementoKey, true);
|
||||
}
|
||||
|
||||
private get triggerCount(): number {
|
||||
const count = this.memento.get<number>(this.triggerCountMementoKey);
|
||||
return !count || isNaN(+count) ? 0 : +count;
|
||||
}
|
||||
|
||||
private getMementoKey(part: string): string {
|
||||
return `survey.v0.${this.id}.${part}`;
|
||||
}
|
||||
|
||||
private get isCompletedMementoKey(): string {
|
||||
return this.getMementoKey('isComplete');
|
||||
}
|
||||
|
||||
private get lastPromptTimeMementoKey(): string {
|
||||
return this.getMementoKey('lastPromptTime');
|
||||
}
|
||||
|
||||
private get triggerCountMementoKey(): string {
|
||||
return this.getMementoKey('globalTriggerCount');
|
||||
}
|
||||
}
|
||||
|
||||
export class Surveyor extends Disposable {
|
||||
|
||||
public constructor(
|
||||
private readonly memento: vscode.Memento,
|
||||
serviceClient: TypeScriptServiceClient,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(serviceClient.onSurveyReady(e => this.surveyReady(e.surveyId)));
|
||||
}
|
||||
|
||||
@memoize
|
||||
private get surveys(): Map<string, Survey> {
|
||||
return new Map<string, Survey>(
|
||||
allSurveys.map(data => [data.id, new Survey(data, this.memento)] as [string, Survey]));
|
||||
}
|
||||
|
||||
private surveyReady(surveyId: string): void {
|
||||
const survey = this.tryGetActiveSurvey(surveyId);
|
||||
if (survey && survey.trigger()) {
|
||||
survey.willShow();
|
||||
this.showSurveyToUser(survey);
|
||||
}
|
||||
}
|
||||
|
||||
private async showSurveyToUser(survey: Survey): Promise<void> {
|
||||
enum Choice {
|
||||
GoToSurvey = 1,
|
||||
RemindLater = 2,
|
||||
NeverAgain = 3,
|
||||
}
|
||||
|
||||
interface MessageItem extends vscode.MessageItem {
|
||||
readonly choice: Choice;
|
||||
}
|
||||
|
||||
const response = await vscode.window.showInformationMessage<MessageItem>(survey.prompt,
|
||||
{
|
||||
title: localize('takeShortSurvey', "Take Short Survey"),
|
||||
choice: Choice.GoToSurvey
|
||||
}, {
|
||||
title: localize('remindLater', "Remind Me Later"),
|
||||
choice: Choice.RemindLater
|
||||
}, {
|
||||
title: localize('neverAgain', "Disable JS/TS Surveys"),
|
||||
choice: Choice.NeverAgain
|
||||
});
|
||||
|
||||
switch (response && response.choice) {
|
||||
case Choice.GoToSurvey:
|
||||
survey.open();
|
||||
break;
|
||||
|
||||
case Choice.NeverAgain:
|
||||
survey.markComplete();
|
||||
this.disableSurveys();
|
||||
break;
|
||||
|
||||
case Choice.RemindLater:
|
||||
default: // If user just closes the notification, treat this as a remind later.
|
||||
survey.remindLater();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private tryGetActiveSurvey(surveyId: string): Survey | undefined {
|
||||
const survey = this.surveys.get(surveyId);
|
||||
if (!survey) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.areSurveysEnabled() && survey.isActive) {
|
||||
return survey;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private areSurveysEnabled() {
|
||||
const config = vscode.workspace.getConfiguration('typescript');
|
||||
return config.get<boolean>('surveys.enabled', true);
|
||||
}
|
||||
|
||||
private disableSurveys() {
|
||||
const config = vscode.workspace.getConfiguration('typescript');
|
||||
config.update('surveys.enabled', false);
|
||||
}
|
||||
}
|
|
@ -2,9 +2,16 @@
|
|||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true
|
||||
"experimentalDecorators": true,
|
||||
// https://github.com/microsoft/TypeScript/issues/31869#issuecomment-515167432
|
||||
"baseUrl": "src/\u0000",
|
||||
"paths": {
|
||||
"vscode": [
|
||||
"../../../../src/vs/vscode.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,13 @@
|
|||
"main": "./out/extension.js",
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
"compile": "tsc -p ./",
|
||||
"watch": "tsc -watch -p ./"
|
||||
"compile": "gulp compile-extension:vscode-account",
|
||||
"watch": "gulp watch-extension:vscode-account"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.7.4",
|
||||
"tslint": "^5.12.1",
|
||||
"@types/node": "^10.12.21",
|
||||
"@types/keytar": "^4.0.1",
|
||||
"@types/vscode": "^1.41.0"
|
||||
"@types/keytar": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ interface IToken {
|
|||
accessToken: string;
|
||||
refreshToken: string;
|
||||
|
||||
displayName: string;
|
||||
accountName: string;
|
||||
scope: string;
|
||||
sessionId: string; // The account id + the scope
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ interface ITokenClaims {
|
|||
unique_name?: string;
|
||||
oid?: string;
|
||||
altsecid?: string;
|
||||
ipd?: string;
|
||||
scp: string;
|
||||
}
|
||||
|
||||
|
@ -52,6 +53,8 @@ function parseQuery(uri: vscode.Uri) {
|
|||
|
||||
export const onDidChangeSessions = new vscode.EventEmitter<void>();
|
||||
|
||||
export const REFRESH_NETWORK_FAILURE = 'Network failure';
|
||||
|
||||
class UriEventHandler extends vscode.EventEmitter<vscode.Uri> implements vscode.UriHandler {
|
||||
public handleUri(uri: vscode.Uri) {
|
||||
this.fire(uri);
|
||||
|
@ -90,7 +93,7 @@ export class AzureActiveDirectoryService {
|
|||
try {
|
||||
await this.refreshToken(session.refreshToken, session.scope);
|
||||
} catch (e) {
|
||||
await this.logout(session.id);
|
||||
this.handleTokenRefreshFailure(e, session.id, session.refreshToken, session.scope, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -133,7 +136,7 @@ export class AzureActiveDirectoryService {
|
|||
await this.refreshToken(session.refreshToken, session.scope);
|
||||
didChange = true;
|
||||
} catch (e) {
|
||||
await this.logout(session.id);
|
||||
this.handleTokenRefreshFailure(e, session.id, session.refreshToken, session.scope, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -169,11 +172,11 @@ export class AzureActiveDirectoryService {
|
|||
}, 1000 * 30);
|
||||
}
|
||||
|
||||
private convertToSession(token: IToken): vscode.Session {
|
||||
private convertToSession(token: IToken): vscode.AuthenticationSession {
|
||||
return {
|
||||
id: token.sessionId,
|
||||
accessToken: token.accessToken,
|
||||
displayName: token.displayName,
|
||||
accessToken: () => Promise.resolve(token.accessToken),
|
||||
accountName: token.accountName,
|
||||
scopes: token.scope.split(' ')
|
||||
};
|
||||
}
|
||||
|
@ -187,7 +190,7 @@ export class AzureActiveDirectoryService {
|
|||
}
|
||||
}
|
||||
|
||||
get sessions(): vscode.Session[] {
|
||||
get sessions(): vscode.AuthenticationSession[] {
|
||||
return this._tokens.map(token => this.convertToSession(token));
|
||||
}
|
||||
|
||||
|
@ -287,7 +290,7 @@ export class AzureActiveDirectoryService {
|
|||
});
|
||||
vscode.env.openExternal(uri);
|
||||
|
||||
const timeoutPromise = new Promise((resolve: (value: IToken) => void, reject) => {
|
||||
const timeoutPromise = new Promise((_: (value: IToken) => void, reject) => {
|
||||
const wait = setTimeout(() => {
|
||||
clearTimeout(wait);
|
||||
reject('Login timed out.');
|
||||
|
@ -334,18 +337,14 @@ export class AzureActiveDirectoryService {
|
|||
this._tokens.push(token);
|
||||
}
|
||||
|
||||
const existingTimeout = this._refreshTimeouts.get(token.sessionId);
|
||||
if (existingTimeout) {
|
||||
clearTimeout(existingTimeout);
|
||||
}
|
||||
this.clearSessionTimeout(token.sessionId);
|
||||
|
||||
this._refreshTimeouts.set(token.sessionId, setTimeout(async () => {
|
||||
try {
|
||||
await this.refreshToken(token.refreshToken, scope);
|
||||
} catch (e) {
|
||||
await this.logout(token.sessionId);
|
||||
} finally {
|
||||
onDidChangeSessions.fire();
|
||||
} catch (e) {
|
||||
this.handleTokenRefreshFailure(e, token.sessionId, token.refreshToken, scope, true);
|
||||
}
|
||||
}, 1000 * (parseInt(token.expiresIn) - 30)));
|
||||
|
||||
|
@ -360,8 +359,8 @@ export class AzureActiveDirectoryService {
|
|||
accessToken: json.access_token,
|
||||
refreshToken: json.refresh_token,
|
||||
scope,
|
||||
sessionId: claims.tid + (claims.oid || claims.altsecid) + scope,
|
||||
displayName: claims.email || claims.unique_name || 'user@example.com'
|
||||
sessionId: `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${scope}`,
|
||||
accountName: claims.email || claims.unique_name || 'user@example.com'
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -459,29 +458,73 @@ export class AzureActiveDirectoryService {
|
|||
post.end();
|
||||
post.on('error', err => {
|
||||
Logger.error(err.message);
|
||||
reject(err);
|
||||
reject(new Error(REFRESH_NETWORK_FAILURE));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async logout(sessionId: string) {
|
||||
Logger.info(`Logging out of session '${sessionId}'`);
|
||||
private clearSessionTimeout(sessionId: string): void {
|
||||
const timeout = this._refreshTimeouts.get(sessionId);
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
this._refreshTimeouts.delete(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
private removeInMemorySessionData(sessionId: string) {
|
||||
const tokenIndex = this._tokens.findIndex(token => token.sessionId === sessionId);
|
||||
if (tokenIndex > -1) {
|
||||
this._tokens.splice(tokenIndex, 1);
|
||||
}
|
||||
|
||||
this.clearSessionTimeout(sessionId);
|
||||
}
|
||||
|
||||
private async handleTokenRefreshFailure(e: Error, sessionId: string, refreshToken: string, scope: string, sendChangeEvent: boolean): Promise<void> {
|
||||
if (e.message === REFRESH_NETWORK_FAILURE) {
|
||||
this.handleRefreshNetworkError(sessionId, refreshToken, scope);
|
||||
} else {
|
||||
await this.logout(sessionId);
|
||||
if (sendChangeEvent) {
|
||||
onDidChangeSessions.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleRefreshNetworkError(sessionId: string, refreshToken: string, scope: string, attempts: number = 1) {
|
||||
if (attempts === 5) {
|
||||
Logger.error('Token refresh failed after 5 attempts');
|
||||
return;
|
||||
}
|
||||
|
||||
if (attempts === 1) {
|
||||
this.removeInMemorySessionData(sessionId);
|
||||
onDidChangeSessions.fire();
|
||||
}
|
||||
|
||||
const delayBeforeRetry = 5 * attempts * attempts;
|
||||
|
||||
this.clearSessionTimeout(sessionId);
|
||||
|
||||
this._refreshTimeouts.set(sessionId, setTimeout(async () => {
|
||||
try {
|
||||
await this.refreshToken(refreshToken, scope);
|
||||
onDidChangeSessions.fire();
|
||||
} catch (e) {
|
||||
await this.handleRefreshNetworkError(sessionId, refreshToken, scope, attempts + 1);
|
||||
}
|
||||
}, 1000 * delayBeforeRetry));
|
||||
}
|
||||
|
||||
public async logout(sessionId: string) {
|
||||
Logger.info(`Logging out of session '${sessionId}'`);
|
||||
this.removeInMemorySessionData(sessionId);
|
||||
|
||||
if (this._tokens.length === 0) {
|
||||
await keychain.deleteToken();
|
||||
} else {
|
||||
this.storeTokenData();
|
||||
}
|
||||
|
||||
const timeout = this._refreshTimeouts.get(sessionId);
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
this._refreshTimeouts.delete(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
public async clearSessions() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import { AzureActiveDirectoryService, onDidChangeSessions } from './AADHelper';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
export async function activate(_: vscode.ExtensionContext) {
|
||||
|
||||
const loginService = new AzureActiveDirectoryService();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// how we load it
|
||||
import * as keytarType from 'keytar';
|
||||
import { env } from 'vscode';
|
||||
import Logger from './logger';
|
||||
|
||||
function getKeytar(): Keytar | undefined {
|
||||
try {
|
||||
|
@ -44,22 +45,27 @@ export class Keychain {
|
|||
return await this.keytar.setPassword(SERVICE_ID, ACCOUNT_ID, token);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Setting token failed: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getToken() {
|
||||
async getToken(): Promise<string | null | undefined> {
|
||||
try {
|
||||
return await this.keytar.getPassword(SERVICE_ID, ACCOUNT_ID);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Getting token failed: ${e}`);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteToken() {
|
||||
async deleteToken(): Promise<boolean | undefined> {
|
||||
try {
|
||||
return await this.keytar.deletePassword(SERVICE_ID, ACCOUNT_ID);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
Logger.error(`Deleting token failed: ${e}`);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
extensions/vscode-account/src/typings/refs.d.ts
vendored
Normal file
7
extensions/vscode-account/src/typings/refs.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
|
|
@ -1,61 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* This is the place for API experiments and proposals.
|
||||
* These API are NOT stable and subject to change. They are only available in the Insiders
|
||||
* distribution and CANNOT be used in published extensions.
|
||||
*
|
||||
* To test these API in local environment:
|
||||
* - Use Insiders release of VS Code.
|
||||
* - Add `"enableProposedApi": true` to your package.json.
|
||||
* - Copy this file to your project.
|
||||
*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
accessToken: string;
|
||||
displayName: string;
|
||||
scopes: string[]
|
||||
}
|
||||
|
||||
export interface AuthenticationProvider {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
readonly onDidChangeSessions: Event<void>;
|
||||
|
||||
/**
|
||||
* Returns an array of current sessions.
|
||||
*/
|
||||
getSessions(): Promise<ReadonlyArray<Session>>;
|
||||
|
||||
/**
|
||||
* Prompts a user to login.
|
||||
*/
|
||||
login(scopes: string[]): Promise<Session>;
|
||||
logout(sessionId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export namespace authentication {
|
||||
export function registerAuthenticationProvider(provider: AuthenticationProvider): Disposable;
|
||||
|
||||
/**
|
||||
* Fires with the provider id that was registered or unregistered.
|
||||
*/
|
||||
export const onDidRegisterAuthenticationProvider: Event<string>;
|
||||
export const onDidUnregisterAuthenticationProvider: Event<string>;
|
||||
|
||||
export const providers: ReadonlyArray<AuthenticationProvider>;
|
||||
}
|
||||
|
||||
// #region Ben - extension auth flow (desktop+web)
|
||||
|
||||
export namespace env {
|
||||
|
||||
export function asExternalUri(target: Uri): Thenable<Uri>
|
||||
}
|
||||
}
|
|
@ -1,24 +1,13 @@
|
|||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6",
|
||||
"es2016",
|
||||
"dom"
|
||||
],
|
||||
"outDir": "./out",
|
||||
"experimentalDecorators": true,
|
||||
"typeRoots": [
|
||||
"node_modules/@types",
|
||||
"src/typings"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"noImplicitAny": true
|
||||
"./node_modules/@types"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -30,11 +30,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c"
|
||||
integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==
|
||||
|
||||
"@types/vscode@^1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.41.0.tgz#b0d75920220f84e07093285e59180c0f11d336cd"
|
||||
integrity sha512-7SfeY5u9jgiELwxyLB3z7l6l/GbN9CqpCQGkcRlB7tKRFBxzbz2PoBfGrLxI1vRfUCIq5+hg5vtDHExwq5j3+A==
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
declare const window: unknown;
|
||||
declare const TextEncoder: any;
|
||||
declare const TextDecoder: any;
|
||||
declare const URL: any;
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
const SCHEME = 'memfs';
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ suite('commands namespace tests', () => {
|
|||
});
|
||||
|
||||
test('api-command: vscode.open', function () {
|
||||
let uri = Uri.parse(workspace.workspaceFolders![0].uri.toString() + '/image.png');
|
||||
let uri = Uri.parse(workspace.workspaceFolders![0].uri.toString() + '/far.js');
|
||||
let a = commands.executeCommand('vscode.open', uri).then(() => assert.ok(true), () => assert.ok(false));
|
||||
let b = commands.executeCommand('vscode.open', uri, ViewColumn.Two).then(() => assert.ok(true), () => assert.ok(false));
|
||||
let c = commands.executeCommand('vscode.open').then(() => assert.ok(false), () => assert.ok(true));
|
||||
|
|
126
extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts
Normal file
126
extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { debug, workspace, Disposable, commands, window } from 'vscode';
|
||||
import { disposeAll } from '../utils';
|
||||
import { basename } from 'path';
|
||||
|
||||
suite('Debug', function () {
|
||||
|
||||
test('breakpoints', async function () {
|
||||
assert.equal(debug.breakpoints.length, 0);
|
||||
let onDidChangeBreakpointsCounter = 0;
|
||||
const toDispose: Disposable[] = [];
|
||||
|
||||
toDispose.push(debug.onDidChangeBreakpoints(() => {
|
||||
onDidChangeBreakpointsCounter++;
|
||||
}));
|
||||
|
||||
debug.addBreakpoints([{ id: '1', enabled: true }, { id: '2', enabled: false, condition: '2 < 5' }]);
|
||||
assert.equal(onDidChangeBreakpointsCounter, 1);
|
||||
assert.equal(debug.breakpoints.length, 2);
|
||||
assert.equal(debug.breakpoints[0].id, '1');
|
||||
assert.equal(debug.breakpoints[1].id, '2');
|
||||
assert.equal(debug.breakpoints[1].condition, '2 < 5');
|
||||
|
||||
debug.removeBreakpoints([{ id: '1', enabled: true }]);
|
||||
assert.equal(onDidChangeBreakpointsCounter, 2);
|
||||
assert.equal(debug.breakpoints.length, 1);
|
||||
|
||||
debug.removeBreakpoints([{ id: '2', enabled: false }]);
|
||||
assert.equal(onDidChangeBreakpointsCounter, 3);
|
||||
assert.equal(debug.breakpoints.length, 0);
|
||||
|
||||
disposeAll(toDispose);
|
||||
});
|
||||
|
||||
test('start debugging', async function () {
|
||||
assert.equal(debug.activeDebugSession, undefined);
|
||||
let stoppedEvents = 0;
|
||||
let variablesReceived: () => void;
|
||||
let initializedReceived: () => void;
|
||||
let configurationDoneReceived: () => void;
|
||||
|
||||
const firstVariablesRetrieved = new Promise<void>(resolve => variablesReceived = resolve);
|
||||
const toDispose: Disposable[] = [];
|
||||
toDispose.push(debug.registerDebugAdapterTrackerFactory('node2', {
|
||||
createDebugAdapterTracker: () => ({
|
||||
onDidSendMessage: m => {
|
||||
if (m.event === 'stopped') {
|
||||
stoppedEvents++;
|
||||
}
|
||||
if (m.type === 'response' && m.command === 'variables') {
|
||||
variablesReceived();
|
||||
}
|
||||
if (m.event === 'initialized') {
|
||||
initializedReceived();
|
||||
}
|
||||
if (m.command === 'configurationDone') {
|
||||
configurationDoneReceived();
|
||||
}
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
const initializedPromise = new Promise<void>(resolve => initializedReceived = resolve);
|
||||
const configurationDonePromise = new Promise<void>(resolve => configurationDoneReceived = resolve);
|
||||
// Do not await debug start to return due to https://github.com/microsoft/vscode/issues/90134
|
||||
debug.startDebugging(workspace.workspaceFolders![0], 'Launch debug.js');
|
||||
await initializedPromise;
|
||||
await configurationDonePromise;
|
||||
|
||||
// Do not verify activeDebugSession due to same flakiness that sometimes start debugging does not return
|
||||
// assert.notEqual(debug.activeDebugSession, undefined);
|
||||
// assert.equal(debug.activeDebugSession?.name, 'Launch debug.js');
|
||||
|
||||
await firstVariablesRetrieved;
|
||||
assert.equal(stoppedEvents, 1);
|
||||
|
||||
const secondVariablesRetrieved = new Promise<void>(resolve => variablesReceived = resolve);
|
||||
await commands.executeCommand('workbench.action.debug.stepOver');
|
||||
await secondVariablesRetrieved;
|
||||
assert.equal(stoppedEvents, 2);
|
||||
const editor = window.activeTextEditor;
|
||||
assert.notEqual(editor, undefined);
|
||||
assert.equal(basename(editor!.document.fileName), 'debug.js');
|
||||
|
||||
const thirdVariablesRetrieved = new Promise<void>(resolve => variablesReceived = resolve);
|
||||
await commands.executeCommand('workbench.action.debug.stepOver');
|
||||
await thirdVariablesRetrieved;
|
||||
assert.equal(stoppedEvents, 3);
|
||||
|
||||
const fourthVariablesRetrieved = new Promise<void>(resolve => variablesReceived = resolve);
|
||||
await commands.executeCommand('workbench.action.debug.stepInto');
|
||||
await fourthVariablesRetrieved;
|
||||
assert.equal(stoppedEvents, 4);
|
||||
|
||||
const fifthVariablesRetrieved = new Promise<void>(resolve => variablesReceived = resolve);
|
||||
await commands.executeCommand('workbench.action.debug.stepOut');
|
||||
await fifthVariablesRetrieved;
|
||||
assert.equal(stoppedEvents, 5);
|
||||
|
||||
let sessionTerminated: () => void;
|
||||
toDispose.push(debug.onDidTerminateDebugSession(() => {
|
||||
sessionTerminated();
|
||||
}));
|
||||
const sessionTerminatedPromise = new Promise<void>(resolve => sessionTerminated = resolve);
|
||||
await commands.executeCommand('workbench.action.debug.stop');
|
||||
await sessionTerminatedPromise;
|
||||
assert.equal(debug.activeDebugSession, undefined);
|
||||
|
||||
disposeAll(toDispose);
|
||||
});
|
||||
|
||||
test('start debugging failure', async function () {
|
||||
let errorCount = 0;
|
||||
try {
|
||||
await debug.startDebugging(workspace.workspaceFolders![0], 'non existent');
|
||||
} catch (e) {
|
||||
errorCount++;
|
||||
}
|
||||
assert.equal(errorCount, 1);
|
||||
});
|
||||
});
|
|
@ -13,7 +13,8 @@ const webviewId = 'myWebview';
|
|||
|
||||
const testDocument = join(vscode.workspace.rootPath || '', './bower.json');
|
||||
|
||||
suite('Webview tests', () => {
|
||||
// TODO: Re-enable after https://github.com/microsoft/vscode/issues/88415
|
||||
('electron' in process.versions ? suite.skip : suite)('Webview tests', () => {
|
||||
const disposables: vscode.Disposable[] = [];
|
||||
|
||||
function _register<T extends vscode.Disposable>(disposable: T) {
|
||||
|
|
15
extensions/vscode-api-tests/testWorkspace/.vscode/launch.json
vendored
Normal file
15
extensions/vscode-api-tests/testWorkspace/.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch debug.js",
|
||||
"stopOnEntry": true,
|
||||
"program": "${workspaceFolder}/debug.js"
|
||||
}
|
||||
]
|
||||
}
|
10
extensions/vscode-api-tests/testWorkspace/debug.js
Normal file
10
extensions/vscode-api-tests/testWorkspace/debug.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
let y = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
console.log(y);
|
||||
y = y + i;
|
||||
}
|
22
package.json
22
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.43.0",
|
||||
"distro": "efecc155935e7eb2f21b904b59991b07b0d58e58",
|
||||
"distro": "b975cdab7c0c0e7705fa7eac4c8411ad8a790f4b",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -10,12 +10,13 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"test-browser": "node test/unit/browser/index.js",
|
||||
"preinstall": "node build/npm/preinstall.js",
|
||||
"postinstall": "node build/npm/postinstall.js",
|
||||
"compile": "gulp compile --max_old_space_size=4095",
|
||||
"watch": "gulp watch --max_old_space_size=4095",
|
||||
"watch-client": "gulp watch-client --max_old_space_size=4095",
|
||||
"monaco-editor-test": "mocha --only-monaco-editor",
|
||||
"mocha": "mocha test/unit/node/all.js --delay",
|
||||
"precommit": "node build/gulpfile.hygiene.js",
|
||||
"gulp": "gulp --max_old_space_size=8192",
|
||||
"electron": "node build/lib/electron",
|
||||
|
@ -34,7 +35,7 @@
|
|||
"dependencies": {
|
||||
"applicationinsights": "1.0.8",
|
||||
"chokidar": "3.2.3",
|
||||
"graceful-fs": "4.1.11",
|
||||
"graceful-fs": "4.2.3",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
"iconv-lite": "0.5.0",
|
||||
|
@ -55,10 +56,11 @@
|
|||
"vscode-ripgrep": "^1.5.7",
|
||||
"vscode-sqlite3": "4.0.9",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0-beta.15",
|
||||
"xterm-addon-search": "0.4.0-beta4",
|
||||
"xterm": "4.4.0",
|
||||
"xterm-addon-search": "0.4.0",
|
||||
"xterm-addon-unicode11": "0.1.1",
|
||||
"xterm-addon-web-links": "0.2.1",
|
||||
"xterm-addon-webgl": "0.5.0-beta.7",
|
||||
"xterm-addon-webgl": "0.5.0",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
@ -67,6 +69,7 @@
|
|||
"@types/applicationinsights": "0.20.0",
|
||||
"@types/chokidar": "2.1.3",
|
||||
"@types/cookie": "^0.3.3",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/graceful-fs": "4.1.2",
|
||||
"@types/http-proxy-agent": "^2.0.1",
|
||||
"@types/iconv-lite": "0.0.1",
|
||||
|
@ -91,11 +94,10 @@
|
|||
"coveralls": "^2.11.11",
|
||||
"cson-parser": "^1.3.3",
|
||||
"debounce": "^1.0.0",
|
||||
"electron": "6.1.6",
|
||||
"electron": "7.1.11",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-jsdoc": "^19.1.0",
|
||||
"event-stream": "3.3.4",
|
||||
"express": "^4.13.1",
|
||||
"fancy-log": "^1.3.3",
|
||||
"fast-plist": "0.1.2",
|
||||
"glob": "^5.0.13",
|
||||
|
@ -137,6 +139,7 @@
|
|||
"opn": "^6.0.0",
|
||||
"optimist": "0.3.5",
|
||||
"p-all": "^1.0.0",
|
||||
"playwright": "^0.10.0",
|
||||
"pump": "^1.0.1",
|
||||
"queue": "3.0.6",
|
||||
"rcedit": "^1.1.0",
|
||||
|
@ -154,7 +157,8 @@
|
|||
"vscode-nls-dev": "^3.3.1",
|
||||
"webpack": "^4.16.5",
|
||||
"webpack-cli": "^3.3.8",
|
||||
"webpack-stream": "^5.1.1"
|
||||
"webpack-stream": "^5.1.1",
|
||||
"yaserver": "^0.2.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"applicationinsights": "1.0.8",
|
||||
"chokidar": "3.2.3",
|
||||
"cookie": "^0.4.0",
|
||||
"graceful-fs": "4.1.11",
|
||||
"graceful-fs": "4.2.3",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
"iconv-lite": "0.5.0",
|
||||
|
@ -20,10 +20,11 @@
|
|||
"vscode-proxy-agent": "^0.5.2",
|
||||
"vscode-ripgrep": "^1.5.7",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0-beta.15",
|
||||
"xterm-addon-search": "0.4.0-beta4",
|
||||
"xterm": "4.4.0",
|
||||
"xterm-addon-search": "0.4.0",
|
||||
"xterm-addon-unicode11": "0.1.1",
|
||||
"xterm-addon-web-links": "0.2.1",
|
||||
"xterm-addon-webgl": "0.5.0-beta.7",
|
||||
"xterm-addon-webgl": "0.5.0",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
"onigasm-umd": "2.2.5",
|
||||
"semver-umd": "^5.5.5",
|
||||
"vscode-textmate": "4.4.0",
|
||||
"xterm": "4.4.0-beta.15",
|
||||
"xterm-addon-search": "0.4.0-beta4",
|
||||
"xterm": "4.4.0",
|
||||
"xterm-addon-search": "0.4.0",
|
||||
"xterm-addon-unicode11": "0.1.1",
|
||||
"xterm-addon-web-links": "0.2.1",
|
||||
"xterm-addon-webgl": "0.5.0-beta.7"
|
||||
"xterm-addon-webgl": "0.5.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,22 +31,27 @@ vscode-textmate@4.4.0:
|
|||
dependencies:
|
||||
oniguruma "^7.2.0"
|
||||
|
||||
xterm-addon-search@0.4.0-beta4:
|
||||
version "0.4.0-beta4"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta4.tgz#7762ea342c6b4f5e824d83466bd93793c9d7d779"
|
||||
integrity sha512-TIbEBVhydGIxcyu/CfKJbD+BKHisMGbkAfaWlCPaWis2Xmw8yE7CKrCPn+lhZYl1MdjDVEmb8lQI6WetbC2OZA==
|
||||
xterm-addon-search@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1"
|
||||
integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg==
|
||||
|
||||
xterm-addon-unicode11@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.1.1.tgz#b209ef137db38096f68636af4ef4d0c0acba85ad"
|
||||
integrity sha512-z6vJTL+dpNljwAYzYoyDjJP8A2XjZuEosl0sRa+FGRf3jEyEVWquDM53MfUd1ztVdAPQ839qR6eYK1BXV04Bhw==
|
||||
|
||||
xterm-addon-web-links@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
|
||||
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
|
||||
|
||||
xterm-addon-webgl@0.5.0-beta.7:
|
||||
version "0.5.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0-beta.7.tgz#b7b95a362e942ad6f86fa286d7b7bd8ee3e7cf67"
|
||||
integrity sha512-v6aCvhm1C6mvaurGwUYQfyhb2cAUyuVnzf3Ob/hy5ebtyzUj4wW0N9NbqDEJk67UeMi1lV2xZqrO5gNeTpVqFA==
|
||||
xterm-addon-webgl@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||
|
||||
xterm@4.4.0-beta.15:
|
||||
version "4.4.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0-beta.15.tgz#5897bf79d29d1a2496ccd54665aded28c341b1cc"
|
||||
integrity sha512-Dvz1CMCYKeoxPF7uIDznbRgUA2Mct49Bq93K2nnrDU0pDMM3Sf1t9fkEyz59wxSx5XEHVdLS80jywsz4sjXBjQ==
|
||||
xterm@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
||||
|
|
|
@ -155,12 +155,7 @@ glob-parent@~5.1.0:
|
|||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
graceful-fs@4.1.11:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
graceful-fs@4.2.3, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
|
||||
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
|
||||
|
@ -418,25 +413,30 @@ vscode-windows-registry@1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a"
|
||||
integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA==
|
||||
|
||||
xterm-addon-search@0.4.0-beta4:
|
||||
version "0.4.0-beta4"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta4.tgz#7762ea342c6b4f5e824d83466bd93793c9d7d779"
|
||||
integrity sha512-TIbEBVhydGIxcyu/CfKJbD+BKHisMGbkAfaWlCPaWis2Xmw8yE7CKrCPn+lhZYl1MdjDVEmb8lQI6WetbC2OZA==
|
||||
xterm-addon-search@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0.tgz#a7beadb3caa7330eb31fb1f17d92de25537684a1"
|
||||
integrity sha512-g07qb/Z4aSfrQ25e6Z6rz6KiExm2DvesQXkx+eA715VABBr5VM/9Jf0INoCiDSYy/nn7rpna+kXiGVJejIffKg==
|
||||
|
||||
xterm-addon-unicode11@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.1.1.tgz#b209ef137db38096f68636af4ef4d0c0acba85ad"
|
||||
integrity sha512-z6vJTL+dpNljwAYzYoyDjJP8A2XjZuEosl0sRa+FGRf3jEyEVWquDM53MfUd1ztVdAPQ839qR6eYK1BXV04Bhw==
|
||||
|
||||
xterm-addon-web-links@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2"
|
||||
integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ==
|
||||
|
||||
xterm-addon-webgl@0.5.0-beta.7:
|
||||
version "0.5.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0-beta.7.tgz#b7b95a362e942ad6f86fa286d7b7bd8ee3e7cf67"
|
||||
integrity sha512-v6aCvhm1C6mvaurGwUYQfyhb2cAUyuVnzf3Ob/hy5ebtyzUj4wW0N9NbqDEJk67UeMi1lV2xZqrO5gNeTpVqFA==
|
||||
xterm-addon-webgl@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.5.0.tgz#c1031dc7599cce3509824643ab5f15361c928e3e"
|
||||
integrity sha512-hQrvabKCnwXFaEZ+YtoJM9Pm0CIBXL5KSwoU+RiGStU3KYTAcqYP2GsH3dWdvKX6kTWhWLS81dtDsGkfbOciuA==
|
||||
|
||||
xterm@4.4.0-beta.15:
|
||||
version "4.4.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0-beta.15.tgz#5897bf79d29d1a2496ccd54665aded28c341b1cc"
|
||||
integrity sha512-Dvz1CMCYKeoxPF7uIDznbRgUA2Mct49Bq93K2nnrDU0pDMM3Sf1t9fkEyz59wxSx5XEHVdLS80jywsz4sjXBjQ==
|
||||
xterm@4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.4.0.tgz#5915d3c4c8800fadbcf555a0a603c672ab9df589"
|
||||
integrity sha512-JGIpigWM3EBWvnS3rtBuefkiToIILSK1HYMXy4BCsUpO+O4UeeV+/U1AdAXgCB6qJrnPNb7yLgBsVCQUNMteig==
|
||||
|
||||
yauzl@^2.9.2:
|
||||
version "2.10.0"
|
||||
|
|
|
@ -3,7 +3,7 @@ setlocal
|
|||
|
||||
pushd %~dp0\..
|
||||
|
||||
set VSCODEUSERDATADIR=%TMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,5%
|
||||
set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2%
|
||||
|
||||
:: Figure out which Electron to use for running tests
|
||||
if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
||||
|
@ -12,7 +12,7 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
|||
set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat
|
||||
set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1
|
||||
|
||||
echo "Running integration tests out of sources."
|
||||
echo Running integration tests out of sources.
|
||||
) else (
|
||||
:: Run from a built: need to compile all test extensions
|
||||
call yarn gulp compile-extension:vscode-api-tests
|
||||
|
@ -22,13 +22,14 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
|
|||
call yarn gulp compile-extension:css-language-features-server
|
||||
call yarn gulp compile-extension:html-language-features-server
|
||||
call yarn gulp compile-extension:json-language-features-server
|
||||
call yarn gulp compile-extension:git
|
||||
|
||||
:: Configuration for more verbose output
|
||||
set VSCODE_CLI=1
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
set ELECTRON_ENABLE_STACK_DUMPING=1
|
||||
|
||||
echo "Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build."
|
||||
echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build.
|
||||
)
|
||||
|
||||
:: Integration & performance tests in AMD
|
||||
|
@ -49,6 +50,12 @@ if %errorlevel% neq 0 exit /b %errorlevel%
|
|||
call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% .
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
|
||||
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
|
||||
mkdir %GITWORKSPACE%
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
:: Tests in commonJS (HTML, CSS, JSON language server tests...)
|
||||
call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
|
|
@ -4,13 +4,12 @@ set -e
|
|||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname $(dirname $(realpath "$0")))
|
||||
VSCODEUSERDATADIR=`mktemp -d -t 'myuserdatadir'`
|
||||
else
|
||||
ROOT=$(dirname $(dirname $(readlink -f $0)))
|
||||
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
|
||||
LINUX_NO_SANDBOX="--no-sandbox" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox.
|
||||
fi
|
||||
|
||||
VSCODEUSERDATADIR=`mktemp -d 2>/dev/null`
|
||||
cd $ROOT
|
||||
|
||||
# Figure out which Electron to use for running tests
|
||||
|
@ -29,6 +28,7 @@ else
|
|||
yarn gulp compile-extension:css-language-features-server
|
||||
yarn gulp compile-extension:html-language-features-server
|
||||
yarn gulp compile-extension:json-language-features-server
|
||||
yarn gulp compile-extension:git
|
||||
|
||||
# Configuration for more verbose output
|
||||
export VSCODE_CLI=1
|
||||
|
@ -46,6 +46,7 @@ fi
|
|||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||
|
||||
mkdir -p $ROOT/extensions/emmet/test-fixtures
|
||||
"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR
|
||||
|
|
|
@ -17,7 +17,7 @@ if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron
|
|||
|
||||
:: Run tests
|
||||
set ELECTRON_ENABLE_LOGGING=1
|
||||
%CODE% .\test\electron\index.js %*
|
||||
%CODE% .\test\unit\electron\index.js %*
|
||||
|
||||
popd
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
|||
cd $ROOT ; ulimit -n 4096 ; \
|
||||
ELECTRON_ENABLE_LOGGING=1 \
|
||||
"$CODE" \
|
||||
test/electron/index.js "$@"
|
||||
test/unit/electron/index.js "$@"
|
||||
else
|
||||
cd $ROOT ; \
|
||||
ELECTRON_ENABLE_LOGGING=1 \
|
||||
"$CODE" \
|
||||
test/electron/index.js --no-sandbox "$@" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox.
|
||||
test/unit/electron/index.js --no-sandbox "$@" # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox.
|
||||
fi
|
||||
|
|
|
@ -120,6 +120,6 @@ export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0);
|
|||
export const isChrome = (userAgent.indexOf('Chrome') >= 0);
|
||||
export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));
|
||||
export const isWebkitWebView = (!isChrome && !isSafari && isWebKit);
|
||||
export const isIPad = (userAgent.indexOf('iPad') >= 0);
|
||||
export const isIPad = (userAgent.indexOf('iPad') >= 0 || (isSafari && navigator.maxTouchPoints > 0));
|
||||
export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0);
|
||||
export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);
|
||||
|
|
|
@ -28,6 +28,7 @@ export class FastDomNode<T extends HTMLElement> {
|
|||
private _backgroundColor: string;
|
||||
private _layerHint: boolean;
|
||||
private _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint';
|
||||
private _boxShadow: string;
|
||||
|
||||
constructor(domNode: T) {
|
||||
this.domNode = domNode;
|
||||
|
@ -51,6 +52,7 @@ export class FastDomNode<T extends HTMLElement> {
|
|||
this._backgroundColor = '';
|
||||
this._layerHint = false;
|
||||
this._contain = 'none';
|
||||
this._boxShadow = '';
|
||||
}
|
||||
|
||||
public setMaxWidth(maxWidth: number): void {
|
||||
|
@ -218,6 +220,14 @@ export class FastDomNode<T extends HTMLElement> {
|
|||
this.domNode.style.transform = this._layerHint ? 'translate3d(0px, 0px, 0px)' : '';
|
||||
}
|
||||
|
||||
public setBoxShadow(boxShadow: string): void {
|
||||
if (this._boxShadow === boxShadow) {
|
||||
return;
|
||||
}
|
||||
this._boxShadow = boxShadow;
|
||||
this.domNode.style.boxShadow = boxShadow;
|
||||
}
|
||||
|
||||
public setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void {
|
||||
if (this._contain === contain) {
|
||||
return;
|
||||
|
|
|
@ -88,7 +88,7 @@ export class MenuBar extends Disposable {
|
|||
|
||||
private numMenusShown: number = 0;
|
||||
private menuStyle: IMenuStyles | undefined;
|
||||
private overflowLayoutScheduled: IDisposable | null = null;
|
||||
private overflowLayoutScheduled: IDisposable | undefined = undefined;
|
||||
|
||||
constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) {
|
||||
super();
|
||||
|
@ -419,9 +419,8 @@ export class MenuBar extends Disposable {
|
|||
DOM.removeNode(this.overflowMenu.titleElement);
|
||||
DOM.removeNode(this.overflowMenu.buttonElement);
|
||||
|
||||
if (this.overflowLayoutScheduled) {
|
||||
this.overflowLayoutScheduled = dispose(this.overflowLayoutScheduled);
|
||||
}
|
||||
dispose(this.overflowLayoutScheduled);
|
||||
this.overflowLayoutScheduled = undefined;
|
||||
}
|
||||
|
||||
blur(): void {
|
||||
|
@ -561,7 +560,7 @@ export class MenuBar extends Disposable {
|
|||
if (!this.overflowLayoutScheduled) {
|
||||
this.overflowLayoutScheduled = DOM.scheduleAtNextAnimationFrame(() => {
|
||||
this.updateOverflowAction();
|
||||
this.overflowLayoutScheduled = null;
|
||||
this.overflowLayoutScheduled = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -287,6 +287,7 @@ export abstract class AbstractScrollableElement extends Widget {
|
|||
this._options.handleMouseWheel = massagedOptions.handleMouseWheel;
|
||||
this._options.mouseWheelScrollSensitivity = massagedOptions.mouseWheelScrollSensitivity;
|
||||
this._options.fastScrollSensitivity = massagedOptions.fastScrollSensitivity;
|
||||
this._options.scrollPredominantAxis = massagedOptions.scrollPredominantAxis;
|
||||
this._setListeningToMouseWheel(this._options.handleMouseWheel);
|
||||
|
||||
if (!this._options.lazyRender) {
|
||||
|
@ -338,6 +339,14 @@ export abstract class AbstractScrollableElement extends Widget {
|
|||
let deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;
|
||||
let deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;
|
||||
|
||||
if (this._options.scrollPredominantAxis) {
|
||||
if (Math.abs(deltaY) >= Math.abs(deltaX)) {
|
||||
deltaX = 0;
|
||||
} else {
|
||||
deltaY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._options.flipAxes) {
|
||||
[deltaY, deltaX] = [deltaX, deltaY];
|
||||
}
|
||||
|
@ -557,6 +566,7 @@ function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableEleme
|
|||
scrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),
|
||||
mouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),
|
||||
fastScrollSensitivity: (typeof opts.fastScrollSensitivity !== 'undefined' ? opts.fastScrollSensitivity : 5),
|
||||
scrollPredominantAxis: (typeof opts.scrollPredominantAxis !== 'undefined' ? opts.scrollPredominantAxis : true),
|
||||
mouseWheelSmoothScroll: (typeof opts.mouseWheelSmoothScroll !== 'undefined' ? opts.mouseWheelSmoothScroll : true),
|
||||
arrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),
|
||||
|
||||
|
|
|
@ -55,6 +55,13 @@ export interface ScrollableElementCreationOptions {
|
|||
* Defaults to 5.
|
||||
*/
|
||||
fastScrollSensitivity?: number;
|
||||
/**
|
||||
* Whether the scrollable will only scroll along the predominant axis when scrolling both
|
||||
* vertically and horizontally at the same time.
|
||||
* Prevents horizontal drift when scrolling vertically on a trackpad.
|
||||
* Defaults to true.
|
||||
*/
|
||||
scrollPredominantAxis?: boolean;
|
||||
/**
|
||||
* Height for vertical arrows (top/bottom) and width for horizontal arrows (left/right).
|
||||
* Defaults to 11.
|
||||
|
@ -113,6 +120,7 @@ export interface ScrollableElementChangeOptions {
|
|||
handleMouseWheel?: boolean;
|
||||
mouseWheelScrollSensitivity?: number;
|
||||
fastScrollSensitivity: number;
|
||||
scrollPredominantAxis: boolean;
|
||||
}
|
||||
|
||||
export interface ScrollableElementResolvedOptions {
|
||||
|
@ -125,6 +133,7 @@ export interface ScrollableElementResolvedOptions {
|
|||
alwaysConsumeMouseWheel: boolean;
|
||||
mouseWheelScrollSensitivity: number;
|
||||
fastScrollSensitivity: number;
|
||||
scrollPredominantAxis: boolean;
|
||||
mouseWheelSmoothScroll: boolean;
|
||||
arrowSize: number;
|
||||
listenOnDomNode: HTMLElement | null;
|
||||
|
|
|
@ -585,6 +585,6 @@ export function asArray<T>(x: T | T[]): T[] {
|
|||
return Array.isArray(x) ? x : [x];
|
||||
}
|
||||
|
||||
export function getRandomElement<T>(arr: T[]): T {
|
||||
export function getRandomElement<T>(arr: T[]): T | undefined {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
|
|
@ -91,6 +91,9 @@ export function toDisposable(fn: () => void): IDisposable {
|
|||
}
|
||||
|
||||
export class DisposableStore implements IDisposable {
|
||||
|
||||
static DISABLE_DISPOSED_WARNING = false;
|
||||
|
||||
private _toDispose = new Set<IDisposable>();
|
||||
private _isDisposed = false;
|
||||
|
||||
|
@ -127,7 +130,9 @@ export class DisposableStore implements IDisposable {
|
|||
|
||||
markTracked(t);
|
||||
if (this._isDisposed) {
|
||||
console.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack);
|
||||
if (!DisposableStore.DISABLE_DISPOSED_WARNING) {
|
||||
console.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack);
|
||||
}
|
||||
} else {
|
||||
this._toDispose.add(t);
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ export function relativePath(from: URI, to: URI, ignoreCase = hasToIgnoreCase(fr
|
|||
return undefined;
|
||||
}
|
||||
if (from.scheme === Schemas.file) {
|
||||
const relativePath = paths.relative(from.path, to.path);
|
||||
const relativePath = paths.relative(originalFSPath(from), originalFSPath(to));
|
||||
return isWindows ? extpath.toSlashes(relativePath) : relativePath;
|
||||
}
|
||||
let fromPath = from.path || '/', toPath = to.path || '/';
|
||||
|
|
|
@ -126,8 +126,8 @@ export class ConfigWatcher<T> extends Disposable implements IConfigWatcher<T> {
|
|||
}
|
||||
|
||||
private async handleSymbolicLink(): Promise<void> {
|
||||
const { stat, isSymbolicLink } = await statLink(this._path);
|
||||
if (isSymbolicLink && !stat.isDirectory()) {
|
||||
const { stat, symbolicLink } = await statLink(this._path);
|
||||
if (symbolicLink && !stat.isDirectory()) {
|
||||
const realPath = await realpath(this._path);
|
||||
|
||||
this.watch(realPath, false);
|
||||
|
|
|
@ -14,7 +14,18 @@ import { promisify } from 'util';
|
|||
import { isRootOrDriveLetter } from 'vs/base/common/extpath';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { normalizeNFC } from 'vs/base/common/normalization';
|
||||
import { encode, encodeStream } from 'vs/base/node/encoding';
|
||||
import { encode } from 'vs/base/node/encoding';
|
||||
|
||||
// See https://github.com/Microsoft/vscode/issues/30180
|
||||
const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB
|
||||
const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB
|
||||
|
||||
// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149
|
||||
const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB
|
||||
const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB
|
||||
|
||||
export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE;
|
||||
export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE;
|
||||
|
||||
export enum RimRafMode {
|
||||
|
||||
|
@ -178,30 +189,52 @@ export function stat(path: string): Promise<fs.Stats> {
|
|||
}
|
||||
|
||||
export interface IStatAndLink {
|
||||
|
||||
// The stats of the file. If the file is a symbolic
|
||||
// link, the stats will be of that target file and
|
||||
// not the link itself.
|
||||
// If the file is a symbolic link pointing to a non
|
||||
// existing file, the stat will be of the link and
|
||||
// the `dangling` flag will indicate this.
|
||||
stat: fs.Stats;
|
||||
isSymbolicLink: boolean;
|
||||
|
||||
// Will be provided if the resource is a symbolic link
|
||||
// on disk. Use the `dangling` flag to find out if it
|
||||
// points to a resource that does not exist on disk.
|
||||
symbolicLink?: { dangling: boolean };
|
||||
}
|
||||
|
||||
export async function statLink(path: string): Promise<IStatAndLink> {
|
||||
|
||||
// First stat the link
|
||||
let linkStat: fs.Stats | undefined;
|
||||
let linkStatError: NodeJS.ErrnoException | undefined;
|
||||
let lstats: fs.Stats | undefined;
|
||||
try {
|
||||
linkStat = await lstat(path);
|
||||
lstats = await lstat(path);
|
||||
|
||||
// Return early if the stat is not a symbolic link at all
|
||||
if (!lstats.isSymbolicLink()) {
|
||||
return { stat: lstats };
|
||||
}
|
||||
} catch (error) {
|
||||
linkStatError = error;
|
||||
/* ignore - use stat() instead */
|
||||
}
|
||||
|
||||
// Then stat the target and return that
|
||||
const isLink = !!(linkStat && linkStat.isSymbolicLink());
|
||||
if (linkStatError || isLink) {
|
||||
const fileStat = await stat(path);
|
||||
// If the stat is a symbolic link or failed to stat, use fs.stat()
|
||||
// which for symbolic links will stat the target they point to
|
||||
try {
|
||||
const stats = await stat(path);
|
||||
|
||||
return { stat: fileStat, isSymbolicLink: isLink };
|
||||
return { stat: stats, symbolicLink: lstats?.isSymbolicLink() ? { dangling: false } : undefined };
|
||||
} catch (error) {
|
||||
|
||||
// If the link points to a non-existing file we still want
|
||||
// to return it as result while setting dangling: true flag
|
||||
if (error.code === 'ENOENT' && lstats) {
|
||||
return { stat: lstats, symbolicLink: { dangling: true } };
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
return { stat: linkStat!, isSymbolicLink: false };
|
||||
}
|
||||
|
||||
export function lstat(path: string): Promise<fs.Stats> {
|
||||
|
@ -213,9 +246,7 @@ export function rename(oldPath: string, newPath: string): Promise<void> {
|
|||
}
|
||||
|
||||
export function renameIgnoreError(oldPath: string, newPath: string): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
fs.rename(oldPath, newPath, () => resolve());
|
||||
});
|
||||
return new Promise(resolve => fs.rename(oldPath, newPath, () => resolve()));
|
||||
}
|
||||
|
||||
export function unlink(path: string): Promise<void> {
|
||||
|
@ -236,6 +267,10 @@ export function readFile(path: string, encoding?: string): Promise<Buffer | stri
|
|||
return promisify(fs.readFile)(path, encoding);
|
||||
}
|
||||
|
||||
export async function mkdirp(path: string, mode?: number): Promise<void> {
|
||||
return promisify(fs.mkdir)(path, { mode, recursive: true });
|
||||
}
|
||||
|
||||
// According to node.js docs (https://nodejs.org/docs/v6.5.0/api/fs.html#fs_fs_writefile_file_data_options_callback)
|
||||
// it is not safe to call writeFile() on the same path multiple times without waiting for the callback to return.
|
||||
// Therefor we use a Queue on the path that is given to us to sequentialize calls to the same path properly.
|
||||
|
@ -244,12 +279,15 @@ const writeFilePathQueues: Map<string, Queue<void>> = new Map();
|
|||
export function writeFile(path: string, data: string, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: Buffer, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: Uint8Array, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: NodeJS.ReadableStream, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: string | Buffer | NodeJS.ReadableStream | Uint8Array, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: string | Buffer | NodeJS.ReadableStream | Uint8Array, options?: IWriteFileOptions): Promise<void> {
|
||||
export function writeFile(path: string, data: string | Buffer | Uint8Array, options?: IWriteFileOptions): Promise<void>;
|
||||
export function writeFile(path: string, data: string | Buffer | Uint8Array, options?: IWriteFileOptions): Promise<void> {
|
||||
const queueKey = toQueueKey(path);
|
||||
|
||||
return ensureWriteFileQueue(queueKey).queue(() => writeFileAndFlush(path, data, options));
|
||||
return ensureWriteFileQueue(queueKey).queue(() => {
|
||||
const ensuredOptions = ensureWriteOptions(options);
|
||||
|
||||
return new Promise((resolve, reject) => doWriteFileAndFlush(path, data, ensuredOptions, error => error ? reject(error) : resolve()));
|
||||
});
|
||||
}
|
||||
|
||||
function toQueueKey(path: string): string {
|
||||
|
@ -294,103 +332,6 @@ interface IEnsuredWriteFileOptions extends IWriteFileOptions {
|
|||
}
|
||||
|
||||
let canFlush = true;
|
||||
function writeFileAndFlush(path: string, data: string | Buffer | NodeJS.ReadableStream | Uint8Array, options: IWriteFileOptions | undefined): Promise<void> {
|
||||
const ensuredOptions = ensureWriteOptions(options);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof data === 'string' || Buffer.isBuffer(data) || data instanceof Uint8Array) {
|
||||
doWriteFileAndFlush(path, data, ensuredOptions, error => error ? reject(error) : resolve());
|
||||
} else {
|
||||
doWriteFileStreamAndFlush(path, data, ensuredOptions, error => error ? reject(error) : resolve());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doWriteFileStreamAndFlush(path: string, reader: NodeJS.ReadableStream, options: IEnsuredWriteFileOptions, callback: (error?: Error) => void): void {
|
||||
|
||||
// finish only once
|
||||
let finished = false;
|
||||
const finish = (error?: Error) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
|
||||
// in error cases we need to manually close streams
|
||||
// if the write stream was successfully opened
|
||||
if (error) {
|
||||
if (isOpen) {
|
||||
writer.once('close', () => callback(error));
|
||||
writer.destroy();
|
||||
} else {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise just return without error
|
||||
else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// create writer to target. we set autoClose: false because we want to use the streams
|
||||
// file descriptor to call fs.fdatasync to ensure the data is flushed to disk
|
||||
const writer = fs.createWriteStream(path, { mode: options.mode, flags: options.flag, autoClose: false });
|
||||
|
||||
// Event: 'open'
|
||||
// Purpose: save the fd for later use and start piping
|
||||
// Notes: will not be called when there is an error opening the file descriptor!
|
||||
let fd: number;
|
||||
let isOpen: boolean;
|
||||
writer.once('open', descriptor => {
|
||||
fd = descriptor;
|
||||
isOpen = true;
|
||||
|
||||
// if an encoding is provided, we need to pipe the stream through
|
||||
// an encoder stream and forward the encoding related options
|
||||
if (options.encoding) {
|
||||
reader = reader.pipe(encodeStream(options.encoding.charset, { addBOM: options.encoding.addBOM }));
|
||||
}
|
||||
|
||||
// start data piping only when we got a successful open. this ensures that we do
|
||||
// not consume the stream when an error happens and helps to fix this issue:
|
||||
// https://github.com/Microsoft/vscode/issues/42542
|
||||
reader.pipe(writer);
|
||||
});
|
||||
|
||||
// Event: 'error'
|
||||
// Purpose: to return the error to the outside and to close the write stream (does not happen automatically)
|
||||
reader.once('error', error => finish(error));
|
||||
writer.once('error', error => finish(error));
|
||||
|
||||
// Event: 'finish'
|
||||
// Purpose: use fs.fdatasync to flush the contents to disk
|
||||
// Notes: event is called when the writer has finished writing to the underlying resource. we must call writer.close()
|
||||
// because we have created the WriteStream with autoClose: false
|
||||
writer.once('finish', () => {
|
||||
|
||||
// flush to disk
|
||||
if (canFlush && isOpen) {
|
||||
fs.fdatasync(fd, (syncError: Error) => {
|
||||
|
||||
// In some exotic setups it is well possible that node fails to sync
|
||||
// In that case we disable flushing and warn to the console
|
||||
if (syncError) {
|
||||
console.warn('[node.js fs] fdatasync is now disabled for this session because it failed: ', syncError);
|
||||
canFlush = false;
|
||||
}
|
||||
|
||||
writer.destroy();
|
||||
});
|
||||
} else {
|
||||
writer.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// Event: 'close'
|
||||
// Purpose: signal we are done to the outside
|
||||
// Notes: event is called when the writer's filedescriptor is closed
|
||||
writer.once('close', () => finish());
|
||||
}
|
||||
|
||||
// Calls fs.writeFile() followed by a fs.sync() call to flush the changes to disk
|
||||
// We do this in cases where we want to make sure the data is really on disk and
|
||||
|
@ -631,18 +572,3 @@ async function doCopyFile(source: string, target: string, mode: number): Promise
|
|||
reader.pipe(writer);
|
||||
});
|
||||
}
|
||||
|
||||
export async function mkdirp(path: string, mode?: number): Promise<void> {
|
||||
return promisify(fs.mkdir)(path, { mode, recursive: true });
|
||||
}
|
||||
|
||||
// See https://github.com/Microsoft/vscode/issues/30180
|
||||
const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB
|
||||
const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB
|
||||
|
||||
// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149
|
||||
const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB
|
||||
const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB
|
||||
|
||||
export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE;
|
||||
export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE;
|
||||
|
|
|
@ -10,6 +10,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
|
|||
import * as errors from 'vs/base/common/errors';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { getRandomElement } from 'vs/base/common/arrays';
|
||||
import { isFunction } from 'vs/base/common/types';
|
||||
|
||||
/**
|
||||
* An `IChannel` is an abstraction over a collection of commands.
|
||||
|
@ -700,14 +701,34 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
|
|||
});
|
||||
}
|
||||
|
||||
getChannel<T extends IChannel>(channelName: string, router?: IClientRouter<TContext>): T {
|
||||
/**
|
||||
* Get a channel from a remote client. When passed a router,
|
||||
* one can specify which client it wants to call and listen to/from.
|
||||
* Otherwise, when calling without a router, a random client will
|
||||
* be selected and when listening without a router, every client
|
||||
* will be listened to.
|
||||
*/
|
||||
getChannel<T extends IChannel>(channelName: string, router: IClientRouter<TContext>): T;
|
||||
getChannel<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean): T;
|
||||
getChannel<T extends IChannel>(channelName: string, routerOrClientFilter: IClientRouter<TContext> | ((client: Client<TContext>) => boolean)): T {
|
||||
const that = this;
|
||||
|
||||
return {
|
||||
call(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T> {
|
||||
const connectionPromise = router
|
||||
? router.routeCall(that, command, arg)
|
||||
: Promise.resolve(getRandomElement(that.connections));
|
||||
let connectionPromise: Promise<Client<TContext>>;
|
||||
|
||||
if (isFunction(routerOrClientFilter)) {
|
||||
// when no router is provided, we go random client picking
|
||||
let connection = getRandomElement(that.connections.filter(routerOrClientFilter));
|
||||
|
||||
connectionPromise = connection
|
||||
// if we found a client, let's call on it
|
||||
? Promise.resolve(connection)
|
||||
// else, let's wait for a client to come along
|
||||
: Event.toPromise(Event.filter(that.onDidAddConnection, routerOrClientFilter));
|
||||
} else {
|
||||
connectionPromise = routerOrClientFilter.routeCall(that, command, arg);
|
||||
}
|
||||
|
||||
const channelPromise = connectionPromise
|
||||
.then(connection => (connection as Connection<TContext>).channelClient.getChannel(channelName));
|
||||
|
@ -716,11 +737,11 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
|
|||
.call(command, arg, cancellationToken);
|
||||
},
|
||||
listen(event: string, arg: any): Event<T> {
|
||||
if (!router) {
|
||||
return that.getMulticastEvent(channelName, event, arg);
|
||||
if (isFunction(routerOrClientFilter)) {
|
||||
return that.getMulticastEvent(channelName, routerOrClientFilter, event, arg);
|
||||
}
|
||||
|
||||
const channelPromise = router.routeEvent(that, event, arg)
|
||||
const channelPromise = routerOrClientFilter.routeEvent(that, event, arg)
|
||||
.then(connection => (connection as Connection<TContext>).channelClient.getChannel(channelName));
|
||||
|
||||
return getDelayedChannel(channelPromise)
|
||||
|
@ -729,7 +750,7 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
|
|||
} as T;
|
||||
}
|
||||
|
||||
private getMulticastEvent<T extends IChannel>(channelName: string, eventName: string, arg: any): Event<T> {
|
||||
private getMulticastEvent<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean, eventName: string, arg: any): Event<T> {
|
||||
const that = this;
|
||||
let disposables = new DisposableStore();
|
||||
|
||||
|
@ -766,8 +787,8 @@ export class IPCServer<TContext = string> implements IChannelServer<TContext>, I
|
|||
map.delete(connection);
|
||||
};
|
||||
|
||||
that.connections.forEach(onDidAddConnection);
|
||||
that.onDidAddConnection(onDidAddConnection, undefined, disposables);
|
||||
that.connections.filter(clientFilter).forEach(onDidAddConnection);
|
||||
Event.filter(that.onDidAddConnection, clientFilter)(onDidAddConnection, undefined, disposables);
|
||||
that.onDidRemoveConnection(onDidRemoveConnection, undefined, disposables);
|
||||
eventMultiplexer.event(emitter.fire, emitter, disposables);
|
||||
|
||||
|
|
|
@ -454,7 +454,7 @@ suite('Base IPC', function () {
|
|||
client1.registerChannel('channel', clientChannel1);
|
||||
|
||||
const pings: string[] = [];
|
||||
const channel = server.getChannel('channel');
|
||||
const channel = server.getChannel('channel', () => true);
|
||||
const service = new TestChannelClient(channel);
|
||||
service.onPong(msg => pings.push(msg));
|
||||
|
||||
|
|
Before Width: | Height: | Size: 594 B After Width: | Height: | Size: 594 B |
Before Width: | Height: | Size: 594 B After Width: | Height: | Size: 594 B |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue