Skip to content

Commit 8bbe5ce

Browse files
committed
tests
1 parent 2ca09d9 commit 8bbe5ce

4 files changed

Lines changed: 125 additions & 25 deletions

File tree

.vscode/launch.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,5 +299,16 @@
299299
"Run Unit Tests"
300300
]
301301
},
302+
{
303+
"type": "node",
304+
"request": "launch",
305+
"name": "HTML Unit Tests",
306+
"program": "${workspaceFolder}/extensions/html-language-features/server/node_modules/mocha/bin/_mocha",
307+
"stopOnEntry": false,
308+
"cwd": "${workspaceFolder}/extensions/html-language-features/server",
309+
"outFiles": [
310+
"${workspaceFolder}/extensions/html-language-features/server/out/**/*.js"
311+
]
312+
},
302313
]
303314
}

extensions/html-language-features/server/src/modes/javascriptSemanticTokens.ts

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,29 @@ export function getSemanticTokens(jsLanguageService: ts.LanguageService, current
1212
//https://ts-ast-viewer.com/#code/AQ0g2CmAuwGbALzAJwG4BQZQGNwEMBnQ4AQQEYBmYAb2C22zgEtJwATJVTRxgcwD27AQAp8AGmAAjAJS0A9POB8+7NQ168oscAJz5wANXwAnLug2bsJmAFcTAO2XAA1MHyvgu-UdOeWbOw8ViAAvpagocBAA
1313

1414
let resultTokens: SemanticTokenData[] = [];
15-
const tokens = jsLanguageService.getSemanticClassifications(fileName, { start: 0, length: currentTextDocument.getText().length });
16-
for (let token of tokens) {
17-
const typeIdx = tokenFromClassificationMapping[token.classificationType];
18-
if (typeIdx !== undefined) {
19-
resultTokens.push({ offset: token.textSpan.start, length: token.textSpan.length, typeIdx, modifierSet: 0 });
20-
}
21-
}
15+
// const tokens = jsLanguageService.getSemanticClassifications(fileName, { start: 0, length: currentTextDocument.getText().length });
16+
// for (let token of tokens) {
17+
// const typeIdx = tokenFromClassificationMapping[token.classificationType];
18+
// if (typeIdx !== undefined) {
19+
// resultTokens.push({ offset: token.textSpan.start, length: token.textSpan.length, typeIdx, modifierSet: 0 });
20+
// }
21+
// }
2222

2323
const program = jsLanguageService.getProgram();
2424
if (program) {
2525
const typeChecker = program.getTypeChecker();
2626

27-
2827
function visit(node: ts.Node) {
2928
if (node.kind === ts.SyntaxKind.Identifier) {
3029
const symbol = typeChecker.getSymbolAtLocation(node);
3130
if (symbol) {
3231
let typeIdx = tokenFromDeclarationMapping[symbol.valueDeclaration.kind];
3332
let modifierSet = 0;
34-
if (symbol.valueDeclaration === node.parent) {
33+
if (node.parent && (<ts.NamedDeclaration>node.parent).name === node) {
3534
modifierSet = TokenModifier.declaration;
3635
}
3736
if (typeIdx !== undefined) {
38-
resultTokens.push({ offset: node.pos, length: node.end - node.pos, typeIdx, modifierSet });
37+
resultTokens.push({ offset: node.getStart(), length: node.getWidth(), typeIdx, modifierSet });
3938
}
4039
}
4140
}
@@ -91,7 +90,7 @@ export function getSemanticTokenLegend() {
9190
}
9291

9392

94-
const tokenTypes: string[] = ['class', 'enum', 'interface', 'namespace', 'parameterType', 'type', 'parameter', 'variable', 'property', 'constant', 'function'];
93+
const tokenTypes: string[] = ['class', 'enum', 'interface', 'namespace', 'parameterType', 'type', 'parameter', 'variable', 'property', 'constant', 'function', 'member'];
9594
const tokenModifiers: string[] = ['declaration',];
9695

9796
enum TokenType {
@@ -106,22 +105,22 @@ enum TokenType {
106105
'property' = 8,
107106
'constant' = 9,
108107
'function' = 10,
108+
'member' = 11
109109
}
110110

111111
enum TokenModifier {
112-
'declaration' = 0x01,
113-
112+
'declaration' = 0x01
114113
}
115114

116-
const tokenFromClassificationMapping: { [name: string]: TokenType } = {
117-
[ts.ClassificationTypeNames.className]: TokenType.class,
118-
[ts.ClassificationTypeNames.enumName]: TokenType.enum,
119-
[ts.ClassificationTypeNames.interfaceName]: TokenType.interface,
120-
[ts.ClassificationTypeNames.moduleName]: TokenType.namespace,
121-
[ts.ClassificationTypeNames.typeParameterName]: TokenType.parameterType,
122-
[ts.ClassificationTypeNames.typeAliasName]: TokenType.type,
123-
[ts.ClassificationTypeNames.parameterName]: TokenType.parameter
124-
};
115+
// const tokenFromClassificationMapping: { [name: string]: TokenType } = {
116+
// [ts.ClassificationTypeNames.className]: TokenType.class,
117+
// [ts.ClassificationTypeNames.enumName]: TokenType.enum,
118+
// [ts.ClassificationTypeNames.interfaceName]: TokenType.interface,
119+
// [ts.ClassificationTypeNames.moduleName]: TokenType.namespace,
120+
// [ts.ClassificationTypeNames.typeParameterName]: TokenType.parameterType,
121+
// [ts.ClassificationTypeNames.typeAliasName]: TokenType.type,
122+
// [ts.ClassificationTypeNames.parameterName]: TokenType.parameter
123+
// };
125124

126125
const tokenFromDeclarationMapping: { [name: string]: TokenType } = {
127126
[ts.SyntaxKind.VariableDeclaration]: TokenType.variable,

extensions/html-language-features/server/src/test/folding.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55

66
import 'mocha';
77
import * as assert from 'assert';
8-
import { TextDocument } from 'vscode-html-languageservice';
98
import { getFoldingRanges } from '../modes/htmlFolding';
10-
import { getLanguageModes } from '../modes/languageModes';
9+
import { TextDocument, getLanguageModes } from '../modes/languageModes';
1110
import { ClientCapabilities } from 'vscode-css-languageservice';
1211

1312
interface ExpectedIndentRange {
@@ -17,7 +16,7 @@ interface ExpectedIndentRange {
1716
}
1817

1918
function assertRanges(lines: string[], expected: ExpectedIndentRange[], message?: string, nRanges?: number): void {
20-
const document = TextDocument.create('test://foo/bar.json', 'json', 1, lines.join('\n'));
19+
const document = TextDocument.create('test://foo/bar.html', 'html', 1, lines.join('\n'));
2120
const workspace = {
2221
settings: {},
2322
folders: [{ name: 'foo', uri: 'test://foo' }]
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import 'mocha';
7+
import * as assert from 'assert';
8+
import { TextDocument, getLanguageModes, ClientCapabilities, Range, Position } from '../modes/languageModes';
9+
10+
interface ExpectedToken {
11+
startLine: number;
12+
character: number;
13+
length: number;
14+
tokenClassifiction: string;
15+
}
16+
17+
function assertTokens(lines: string[], expected: ExpectedToken[], range?: Range, message?: string): void {
18+
const document = TextDocument.create('test://foo/bar.html', 'html', 1, lines.join('\n'));
19+
const workspace = {
20+
settings: {},
21+
folders: [{ name: 'foo', uri: 'test://foo' }]
22+
};
23+
const languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST);
24+
25+
if (!range) {
26+
range = Range.create(Position.create(0, 0), document.positionAt(document.getText().length));
27+
}
28+
29+
const jsMode = languageModes.getMode('javascript')!;
30+
31+
const legend = jsMode.getSemanticTokenLegend!();
32+
const actual = jsMode.getSemanticTokens!(document, [range]);
33+
34+
let actualRanges = [];
35+
let lastLine = 0;
36+
let lastCharacter = 0;
37+
for (let i = 0; i < actual.length; i += 5) {
38+
const lineDelta = actual[i], charDelta = actual[i + 1], len = actual[i + 2], typeIdx = actual[i + 3], modSet = actual[i + 4];
39+
const line = lastLine + lineDelta;
40+
const character = lineDelta === 0 ? lastCharacter + charDelta : charDelta;
41+
const tokenClassifiction = [legend.types[typeIdx], ...legend.modifiers.filter((_, i) => modSet & 1 << i)].join('.');
42+
actualRanges.push(t(line, character, len, tokenClassifiction));
43+
lastLine = line;
44+
lastCharacter = character;
45+
}
46+
assert.deepEqual(actualRanges, expected, message);
47+
}
48+
49+
function t(startLine: number, character: number, length: number, tokenClassifiction: string): ExpectedToken {
50+
return { startLine, character, length, tokenClassifiction };
51+
}
52+
53+
suite('JavaScript Semantic Tokens', () => {
54+
55+
test('variables', () => {
56+
const input = [
57+
/*0*/'<html>',
58+
/*1*/'<head>',
59+
/*2*/'<script>',
60+
/*3*/' var x = 9, y1 = x;',
61+
/*4*/' throw y1;',
62+
/*5*/'</script>',
63+
/*6*/'</head>',
64+
/*7*/'</html>',
65+
];
66+
assertTokens(input, [
67+
t(3, 6, 1, 'variable.declaration'), t(3, 13, 2, 'variable.declaration'), t(3, 18, 1, 'variable'),
68+
t(4, 8, 2, 'variable')
69+
]);
70+
});
71+
72+
test('function', () => {
73+
const input = [
74+
/*0*/'<html>',
75+
/*1*/'<head>',
76+
/*2*/'<script>',
77+
/*3*/' function foo(p1) {',
78+
/*4*/' return foo(Math.abs(p1))',
79+
/*5*/' }',
80+
/*6*/'</script>',
81+
/*7*/'</head>',
82+
/*8*/'</html>',
83+
];
84+
assertTokens(input, [
85+
t(3, 11, 3, 'function.declaration'), t(3, 15, 2, 'parameter.declaration'),
86+
t(4, 11, 3, 'function'), t(4, 15, 3, 'namespace'), t(4, 20, 3, 'member'), t(4, 24, 2, 'parameter')
87+
]);
88+
});
89+
90+
91+
});

0 commit comments

Comments
 (0)