Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@ -0,0 +1,204 @@
/*---------------------------------------------------------------------------------------------
* 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 * as path from 'path';
import { URI } from 'vscode-uri';
import { TextDocument, CompletionList, TextEdit } from 'vscode-languageserver-types';
import { WorkspaceFolder } from 'vscode-languageserver-protocol';
import { getCSSLanguageService, LanguageServiceOptions, getSCSSLanguageService } from 'vscode-css-languageservice';
import { getNodeFSRequestService } from '../node/nodeFs';
import { getDocumentContext } from '../utils/documentContext';
export interface ItemDescription {
label: string;
resultText?: string;
}
suite('Completions', () => {
let assertCompletion = function (completions: CompletionList, expected: ItemDescription, document: TextDocument, _offset: number) {
let matches = completions.items.filter(completion => {
return completion.label === expected.label;
});
assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`);
let match = matches[0];
if (expected.resultText && TextEdit.is(match.textEdit)) {
assert.equal(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText);
}
};
async function assertCompletions(value: string, expected: { count?: number, items?: ItemDescription[] }, testUri: string, workspaceFolders?: WorkspaceFolder[], lang: string = 'css'): Promise<any> {
const offset = value.indexOf('|');
value = value.substr(0, offset) + value.substr(offset + 1);
const document = TextDocument.create(testUri, lang, 0, value);
const position = document.positionAt(offset);
if (!workspaceFolders) {
workspaceFolders = [{ name: 'x', uri: testUri.substr(0, testUri.lastIndexOf('/')) }];
}
const lsOptions: LanguageServiceOptions = { fileSystemProvider: getNodeFSRequestService() };
const cssLanguageService = lang === 'scss' ? getSCSSLanguageService(lsOptions) : getCSSLanguageService(lsOptions);
const context = getDocumentContext(testUri, workspaceFolders);
const stylesheet = cssLanguageService.parseStylesheet(document);
let list = await cssLanguageService.doComplete2(document, position, stylesheet, context);
if (expected.count) {
assert.equal(list.items.length, expected.count);
}
if (expected.items) {
for (let item of expected.items) {
assertCompletion(list, item, document, offset);
}
}
}
test('CSS url() Path completion', async function () {
let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString();
let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }];
await assertCompletions('html { background-image: url("./|")', {
items: [
{ label: 'about.html', resultText: 'html { background-image: url("./about.html")' }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('../|')`, {
items: [
{ label: 'about/', resultText: `html { background-image: url('../about/')` },
{ label: 'index.html', resultText: `html { background-image: url('../index.html')` },
{ label: 'src/', resultText: `html { background-image: url('../src/')` }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('../src/a|')`, {
items: [
{ label: 'feature.js', resultText: `html { background-image: url('../src/feature.js')` },
{ label: 'data/', resultText: `html { background-image: url('../src/data/')` },
{ label: 'test.js', resultText: `html { background-image: url('../src/test.js')` }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('../src/data/f|.asar')`, {
items: [
{ label: 'foo.asar', resultText: `html { background-image: url('../src/data/foo.asar')` }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('|')`, {
items: [
{ label: 'about.html', resultText: `html { background-image: url('about.html')` },
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('/|')`, {
items: [
{ label: 'pathCompletionFixtures/', resultText: `html { background-image: url('/pathCompletionFixtures/')` }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url('/pathCompletionFixtures/|')`, {
items: [
{ label: 'about/', resultText: `html { background-image: url('/pathCompletionFixtures/about/')` },
{ label: 'index.html', resultText: `html { background-image: url('/pathCompletionFixtures/index.html')` },
{ label: 'src/', resultText: `html { background-image: url('/pathCompletionFixtures/src/')` }
]
}, testUri, folders);
await assertCompletions(`html { background-image: url("/|")`, {
items: [
{ label: 'pathCompletionFixtures/', resultText: `html { background-image: url("/pathCompletionFixtures/")` }
]
}, testUri, folders);
});
test('CSS url() Path Completion - Unquoted url', async function () {
let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString();
let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }];
await assertCompletions('html { background-image: url(./|)', {
items: [
{ label: 'about.html', resultText: 'html { background-image: url(./about.html)' }
]
}, testUri, folders);
await assertCompletions('html { background-image: url(./a|)', {
items: [
{ label: 'about.html', resultText: 'html { background-image: url(./about.html)' }
]
}, testUri, folders);
await assertCompletions('html { background-image: url(../|src/)', {
items: [
{ label: 'about/', resultText: 'html { background-image: url(../about/)' }
]
}, testUri, folders);
await assertCompletions('html { background-image: url(../s|rc/)', {
items: [
{ label: 'about/', resultText: 'html { background-image: url(../about/)' }
]
}, testUri, folders);
});
test('CSS @import Path completion', async function () {
let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString();
let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }];
await assertCompletions(`@import './|'`, {
items: [
{ label: 'about.html', resultText: `@import './about.html'` },
]
}, testUri, folders);
await assertCompletions(`@import '../|'`, {
items: [
{ label: 'about/', resultText: `@import '../about/'` },
{ label: 'scss/', resultText: `@import '../scss/'` },
{ label: 'index.html', resultText: `@import '../index.html'` },
{ label: 'src/', resultText: `@import '../src/'` }
]
}, testUri, folders);
});
/**
* For SCSS, `@import 'foo';` can be used for importing partial file `_foo.scss`
*/
test('SCSS @import Path completion', async function () {
let testCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString();
let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }];
/**
* We are in a CSS file, so no special treatment for SCSS partial files
*/
await assertCompletions(`@import '../scss/|'`, {
items: [
{ label: 'main.scss', resultText: `@import '../scss/main.scss'` },
{ label: '_foo.scss', resultText: `@import '../scss/_foo.scss'` }
]
}, testCSSUri, folders);
let testSCSSUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/scss/main.scss')).toString();
await assertCompletions(`@import './|'`, {
items: [
{ label: '_foo.scss', resultText: `@import './foo'` }
]
}, testSCSSUri, folders, 'scss');
});
test('Completion should ignore files/folders starting with dot', async function () {
let testUri = URI.file(path.resolve(__dirname, '../../test/pathCompletionFixtures/about/about.css')).toString();
let folders = [{ name: 'x', uri: URI.file(path.resolve(__dirname, '../../test')).toString() }];
await assertCompletions('html { background-image: url("../|")', {
count: 4
}, testUri, folders);
});
});

View File

@ -0,0 +1,90 @@
/*---------------------------------------------------------------------------------------------
* 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 { URI } from 'vscode-uri';
import { resolve } from 'path';
import { TextDocument, DocumentLink } from 'vscode-languageserver-types';
import { WorkspaceFolder } from 'vscode-languageserver-protocol';
import { getCSSLanguageService } from 'vscode-css-languageservice';
import { getDocumentContext } from '../utils/documentContext';
import { getNodeFSRequestService } from '../node/nodeFs';
export interface ItemDescription {
offset: number;
value: string;
target: string;
}
suite('Links', () => {
const cssLanguageService = getCSSLanguageService({ fileSystemProvider: getNodeFSRequestService() });
let assertLink = function (links: DocumentLink[], expected: ItemDescription, document: TextDocument) {
let matches = links.filter(link => {
return document.offsetAt(link.range.start) === expected.offset;
});
assert.equal(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`);
let match = matches[0];
assert.equal(document.getText(match.range), expected.value);
assert.equal(match.target, expected.target);
};
async function assertLinks(value: string, expected: ItemDescription[], testUri: string, workspaceFolders?: WorkspaceFolder[], lang: string = 'css'): Promise<void> {
const offset = value.indexOf('|');
value = value.substr(0, offset) + value.substr(offset + 1);
const document = TextDocument.create(testUri, lang, 0, value);
if (!workspaceFolders) {
workspaceFolders = [{ name: 'x', uri: testUri.substr(0, testUri.lastIndexOf('/')) }];
}
const context = getDocumentContext(testUri, workspaceFolders);
const stylesheet = cssLanguageService.parseStylesheet(document);
let links = await cssLanguageService.findDocumentLinks2(document, stylesheet, context)!;
assert.equal(links.length, expected.length);
for (let item of expected) {
assertLink(links, item, document);
}
}
function getTestResource(path: string) {
return URI.file(resolve(__dirname, '../../test/linksTestFixtures', path)).toString();
}
test('url links', async function () {
let testUri = getTestResource('about.css');
let folders = [{ name: 'x', uri: getTestResource('') }];
await assertLinks('html { background-image: url("hello.html|")',
[{ offset: 29, value: '"hello.html"', target: getTestResource('hello.html') }], testUri, folders
);
});
test('node module resolving', async function () {
let testUri = getTestResource('about.css');
let folders = [{ name: 'x', uri: getTestResource('') }];
await assertLinks('html { background-image: url("~foo/hello.html|")',
[{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders
);
});
test('node module subfolder resolving', async function () {
let testUri = getTestResource('subdir/about.css');
let folders = [{ name: 'x', uri: getTestResource('') }];
await assertLinks('html { background-image: url("~foo/hello.html|")',
[{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders
);
});
});

View File

@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* 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 { joinPath, normalizePath, resolvePath, extname } from '../requests';
suite('requests', () => {
test('join', async function () {
assert.equal(joinPath('foo://a/foo/bar', 'x'), 'foo://a/foo/bar/x');
assert.equal(joinPath('foo://a/foo/bar/', 'x'), 'foo://a/foo/bar/x');
assert.equal(joinPath('foo://a/foo/bar/', '/x'), 'foo://a/foo/bar/x');
assert.equal(joinPath('foo://a/foo/bar/', 'x/'), 'foo://a/foo/bar/x/');
assert.equal(joinPath('foo://a/foo/bar/', 'x', 'y'), 'foo://a/foo/bar/x/y');
assert.equal(joinPath('foo://a/foo/bar/', 'x/', '/y'), 'foo://a/foo/bar/x/y');
assert.equal(joinPath('foo://a/foo/bar/', '.', '/y'), 'foo://a/foo/bar/y');
assert.equal(joinPath('foo://a/foo/bar/', 'x/y/z', '..'), 'foo://a/foo/bar/x/y');
});
test('resolve', async function () {
assert.equal(resolvePath('foo://a/foo/bar', 'x'), 'foo://a/foo/bar/x');
assert.equal(resolvePath('foo://a/foo/bar/', 'x'), 'foo://a/foo/bar/x');
assert.equal(resolvePath('foo://a/foo/bar/', '/x'), 'foo://a/x');
assert.equal(resolvePath('foo://a/foo/bar/', 'x/'), 'foo://a/foo/bar/x/');
});
test('normalize', async function () {
function assertNormalize(path: string, expected: string) {
assert.equal(normalizePath(path.split('/')), expected, path);
}
assertNormalize('a', 'a');
assertNormalize('/a', '/a');
assertNormalize('a/', 'a/');
assertNormalize('a/b', 'a/b');
assertNormalize('/a/foo/bar/x', '/a/foo/bar/x');
assertNormalize('/a/foo/bar//x', '/a/foo/bar/x');
assertNormalize('/a/foo/bar///x', '/a/foo/bar/x');
assertNormalize('/a/foo/bar/x/', '/a/foo/bar/x/');
assertNormalize('a/foo/bar/x/', 'a/foo/bar/x/');
assertNormalize('a/foo/bar/x//', 'a/foo/bar/x/');
assertNormalize('//a/foo/bar/x//', '/a/foo/bar/x/');
assertNormalize('a/.', 'a');
assertNormalize('a/./b', 'a/b');
assertNormalize('a/././b', 'a/b');
assertNormalize('a/n/../b', 'a/b');
assertNormalize('a/n/../', 'a/');
assertNormalize('a/n/../', 'a/');
assertNormalize('/a/n/../..', '/');
assertNormalize('..', '');
assertNormalize('/..', '/');
});
test('extname', async function () {
function assertExtName(input: string, expected: string) {
assert.equal(extname(input), expected, input);
}
assertExtName('foo://a/foo/bar', '');
assertExtName('foo://a/foo/bar.foo', '.foo');
assertExtName('foo://a/foo/.foo', '');
});
});