@gi-tcg/gts-language-server 0.3.7 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +188 -75
- package/dist/node.js +150 -37
- package/package.json +3 -3
- package/src/browser.ts +6 -10
- package/src/node.ts +2 -8
- package/src/services/code_lens.ts +39 -0
- package/src/{diagnostics.ts → services/diagnostics.ts} +1 -1
- package/src/services/index.ts +18 -0
- package/src/services/semantic_tokens.ts +121 -0
- package/src/{typescript.ts → services/typescript.ts} +5 -0
- package/src/document_highlight.ts +0 -114
- /package/src/{completion.ts → services/completion.ts} +0 -0
package/dist/browser.js
CHANGED
|
@@ -2,10 +2,49 @@ import { createConnection, createServer, createTypeScriptProject, loadTsdkByUrl
|
|
|
2
2
|
import { GtsVirtualCode, createGtsLanguagePlugin } from "@gi-tcg/gts-language-plugin";
|
|
3
3
|
import path from "path-browserify-esm";
|
|
4
4
|
import "@gi-tcg/gts-transpiler";
|
|
5
|
+
import { fs } from "@zenfs/core";
|
|
5
6
|
import { DiagnosticSeverity } from "@volar/language-server";
|
|
6
7
|
import { URI } from "vscode-uri";
|
|
7
8
|
import { create } from "volar-service-typescript";
|
|
8
|
-
|
|
9
|
+
//#region src/zen_fs_provider.ts
|
|
10
|
+
function zenFsProvider(fs) {
|
|
11
|
+
return {
|
|
12
|
+
stat(uri) {
|
|
13
|
+
try {
|
|
14
|
+
const stats = fs.statSync(uri.path);
|
|
15
|
+
console.log("stat", uri.path, stats);
|
|
16
|
+
return {
|
|
17
|
+
type: stats.isFile() ? 1 : stats.isDirectory() ? 2 : stats.isSymbolicLink() ? 64 : 0,
|
|
18
|
+
ctime: stats.ctimeMs,
|
|
19
|
+
mtime: stats.mtimeMs,
|
|
20
|
+
size: stats.size
|
|
21
|
+
};
|
|
22
|
+
} catch {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
readFile(uri, encoding) {
|
|
27
|
+
try {
|
|
28
|
+
console.log("readFile", uri.path);
|
|
29
|
+
return fs.readFileSync(uri.path, { encoding: encoding ?? "utf-8" });
|
|
30
|
+
} catch {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
readDirectory(uri) {
|
|
35
|
+
try {
|
|
36
|
+
const files = fs.readdirSync(uri.path, { withFileTypes: true });
|
|
37
|
+
console.log("readDirectory", uri.path, files.map((f) => f.name));
|
|
38
|
+
return files.map((file) => {
|
|
39
|
+
return [file.name, file.isFile() ? 1 : file.isDirectory() ? 2 : file.isSymbolicLink() ? 64 : 0];
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
9
48
|
//#region src/utils.ts
|
|
10
49
|
/**
|
|
11
50
|
* Get virtual code from the encoded document URI
|
|
@@ -19,7 +58,73 @@ function getVirtualCode(document, context) {
|
|
|
19
58
|
return [virtualCode, sourceUri];
|
|
20
59
|
}
|
|
21
60
|
//#endregion
|
|
22
|
-
//#region src/
|
|
61
|
+
//#region src/services/code_lens.ts
|
|
62
|
+
const createCodeLensPlugin = () => {
|
|
63
|
+
return {
|
|
64
|
+
name: "gts-code-lens",
|
|
65
|
+
capabilities: { codeLensProvider: {} },
|
|
66
|
+
create: (context) => {
|
|
67
|
+
return { provideCodeLenses: async (document, token) => {
|
|
68
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
69
|
+
if (!virtualCode) return [];
|
|
70
|
+
const result = [];
|
|
71
|
+
for (const mapping of virtualCode.mappings) if (mapping.data.directActionStub) {
|
|
72
|
+
const startOffset = mapping.generatedOffsets[0];
|
|
73
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
74
|
+
const start = document.positionAt(startOffset);
|
|
75
|
+
const end = document.positionAt(startOffset + length);
|
|
76
|
+
result.push({
|
|
77
|
+
range: {
|
|
78
|
+
start,
|
|
79
|
+
end
|
|
80
|
+
},
|
|
81
|
+
command: {
|
|
82
|
+
title: "~action",
|
|
83
|
+
command: ""
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
} };
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/services/completion.ts
|
|
94
|
+
const createCompletionPlugin = () => {
|
|
95
|
+
return {
|
|
96
|
+
name: "gts-completion",
|
|
97
|
+
capabilities: { completionProvider: { triggerCharacters: [":"] } },
|
|
98
|
+
create: (context) => {
|
|
99
|
+
let tsProvideCompletionItems;
|
|
100
|
+
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.provideCompletionItems) {
|
|
101
|
+
let originalProvideCompletionItems = instance.provideCompletionItems;
|
|
102
|
+
tsProvideCompletionItems = instance.provideCompletionItems = async (...args) => {
|
|
103
|
+
const response = await originalProvideCompletionItems.apply(instance, args);
|
|
104
|
+
if (!response) return response;
|
|
105
|
+
const items = response.items.filter((item) => !item.label.startsWith("__gts_"));
|
|
106
|
+
return {
|
|
107
|
+
...response,
|
|
108
|
+
items
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (!tsProvideCompletionItems) {
|
|
113
|
+
console.warn(`TS's original provideCompletionItems not found`);
|
|
114
|
+
return {};
|
|
115
|
+
}
|
|
116
|
+
return { provideCompletionItems: async (document, position, context, token) => {
|
|
117
|
+
if (context.triggerCharacter === ":") {
|
|
118
|
+
context.triggerCharacter = ".";
|
|
119
|
+
return await tsProvideCompletionItems(document, position, context, token);
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
} };
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/services/diagnostics.ts
|
|
23
128
|
const createDiagnosticsPlugin = () => {
|
|
24
129
|
return {
|
|
25
130
|
name: "gts-diagnostics",
|
|
@@ -70,85 +175,97 @@ const createDiagnosticsPlugin = () => {
|
|
|
70
175
|
};
|
|
71
176
|
};
|
|
72
177
|
//#endregion
|
|
73
|
-
//#region src/
|
|
74
|
-
|
|
75
|
-
const services = create(ts);
|
|
76
|
-
const semanticService = services.find((service) => service.name === "typescript-semantic");
|
|
77
|
-
if (semanticService?.capabilities.signatureHelpProvider?.triggerCharacters) semanticService.capabilities.signatureHelpProvider.triggerCharacters.push(" ");
|
|
78
|
-
return services;
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/completion.ts
|
|
82
|
-
const createCompletionPlugin = () => {
|
|
178
|
+
//#region src/services/semantic_tokens.ts
|
|
179
|
+
const createSemanticTokensPlugin = () => {
|
|
83
180
|
return {
|
|
84
|
-
name: "gts-
|
|
85
|
-
capabilities: {
|
|
181
|
+
name: "gts-semantic-tokens",
|
|
182
|
+
capabilities: { semanticTokensProvider: { legend: {
|
|
183
|
+
tokenTypes: ["string"],
|
|
184
|
+
tokenModifiers: ["gtsAttribute"]
|
|
185
|
+
} } },
|
|
86
186
|
create: (context) => {
|
|
87
|
-
let
|
|
88
|
-
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.
|
|
89
|
-
let
|
|
90
|
-
|
|
91
|
-
const response = await
|
|
187
|
+
let tsSemanticTokens;
|
|
188
|
+
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.provideDocumentSemanticTokens) {
|
|
189
|
+
let originalProvideDocumentSemanticTokens = instance.provideDocumentSemanticTokens;
|
|
190
|
+
tsSemanticTokens = instance.provideDocumentSemanticTokens = async (document, range, legend, token) => {
|
|
191
|
+
const response = await originalProvideDocumentSemanticTokens.call(instance, document, range, legend, token);
|
|
92
192
|
if (!response) return response;
|
|
93
|
-
const
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
193
|
+
const gtsAttributeIndex = legend.tokenModifiers.indexOf("gtsAttribute");
|
|
194
|
+
if (gtsAttributeIndex === -1) return response;
|
|
195
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
196
|
+
if (!virtualCode) return response;
|
|
197
|
+
for (let i = 0; i < response.length; i++) {
|
|
198
|
+
const [line, character, length, tokenType, tokenModifiers] = response[i];
|
|
199
|
+
if (tokenType !== legend.tokenTypes.indexOf("method")) continue;
|
|
200
|
+
const offset = document.offsetAt({
|
|
201
|
+
line,
|
|
202
|
+
character
|
|
203
|
+
});
|
|
204
|
+
if (virtualCode.mappings.find((m) => m.generatedOffsets[0] === offset && m.data.gtsAttribute)) response[i][4] |= 1 << gtsAttributeIndex;
|
|
205
|
+
}
|
|
206
|
+
return response;
|
|
98
207
|
};
|
|
99
208
|
}
|
|
100
|
-
if (!
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
209
|
+
if (!tsSemanticTokens) console.warn(`TS's original provideDocumentSemanticTokens not found`);
|
|
210
|
+
return { provideDocumentSemanticTokens(document, range, legend, token) {
|
|
211
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
212
|
+
if (!virtualCode) return null;
|
|
213
|
+
const stringIdx = legend.tokenTypes.indexOf("string");
|
|
214
|
+
if (stringIdx === -1) return null;
|
|
215
|
+
const gtsAttributeIndex = legend.tokenModifiers.indexOf("gtsAttribute");
|
|
216
|
+
const result = [];
|
|
217
|
+
const text = document.getText();
|
|
218
|
+
for (const mapping of virtualCode.mappings) {
|
|
219
|
+
if (mapping.data.literalFromId) {
|
|
220
|
+
const offset = mapping.generatedOffsets[0];
|
|
221
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
222
|
+
const pos = document.positionAt(offset);
|
|
223
|
+
result.push([
|
|
224
|
+
pos.line,
|
|
225
|
+
pos.character,
|
|
226
|
+
length,
|
|
227
|
+
stringIdx,
|
|
228
|
+
0
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
if (gtsAttributeIndex >= 0 && mapping.data.gtsAttribute) {
|
|
232
|
+
const offset = mapping.generatedOffsets[0];
|
|
233
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
234
|
+
const pos = document.positionAt(offset);
|
|
235
|
+
const char = text[offset];
|
|
236
|
+
if (char === "\"" || char === "'") result.push([
|
|
237
|
+
pos.line,
|
|
238
|
+
pos.character,
|
|
239
|
+
length,
|
|
240
|
+
stringIdx,
|
|
241
|
+
1 << gtsAttributeIndex
|
|
242
|
+
]);
|
|
243
|
+
}
|
|
108
244
|
}
|
|
109
|
-
return
|
|
245
|
+
return result;
|
|
110
246
|
} };
|
|
111
247
|
}
|
|
112
248
|
};
|
|
113
249
|
};
|
|
114
250
|
//#endregion
|
|
115
|
-
//#region src/
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
console.log("readFile", uri.path);
|
|
135
|
-
return fs.readFileSync(uri.path, { encoding: encoding ?? "utf-8" });
|
|
136
|
-
} catch {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
readDirectory(uri) {
|
|
141
|
-
try {
|
|
142
|
-
const files = fs.readdirSync(uri.path, { withFileTypes: true });
|
|
143
|
-
console.log("readDirectory", uri.path, files.map((f) => f.name));
|
|
144
|
-
return files.map((file) => {
|
|
145
|
-
return [file.name, file.isFile() ? 1 : file.isDirectory() ? 2 : file.isSymbolicLink() ? 64 : 0];
|
|
146
|
-
});
|
|
147
|
-
} catch {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
251
|
+
//#region src/services/typescript.ts
|
|
252
|
+
function createTypeScriptServices(ts) {
|
|
253
|
+
const services = create(ts);
|
|
254
|
+
const semanticService = services.find((service) => service.name === "typescript-semantic");
|
|
255
|
+
if (semanticService?.capabilities.signatureHelpProvider?.triggerCharacters) semanticService.capabilities.signatureHelpProvider.triggerCharacters.push(" ");
|
|
256
|
+
if (semanticService?.capabilities.semanticTokensProvider?.legend) semanticService.capabilities.semanticTokensProvider.legend.tokenModifiers.push("gtsAttribute");
|
|
257
|
+
return services;
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/services/index.ts
|
|
261
|
+
function createLanguageServicePlugins(ts) {
|
|
262
|
+
return [
|
|
263
|
+
...createTypeScriptServices(ts),
|
|
264
|
+
createDiagnosticsPlugin(),
|
|
265
|
+
createCompletionPlugin(),
|
|
266
|
+
createSemanticTokensPlugin(),
|
|
267
|
+
createCodeLensPlugin()
|
|
268
|
+
];
|
|
152
269
|
}
|
|
153
270
|
//#endregion
|
|
154
271
|
//#region src/browser.ts
|
|
@@ -166,11 +283,7 @@ connection.onInitialize(async (params) => {
|
|
|
166
283
|
}
|
|
167
284
|
return server.initialize(params, createTypeScriptProject(tsdk.typescript, tsdk.diagnosticMessages, ({ env }) => {
|
|
168
285
|
return { languagePlugins: [createGtsLanguagePlugin(tsdk.typescript, inlineGtsConfig)] };
|
|
169
|
-
}),
|
|
170
|
-
...createTypeScriptServices(tsdk.typescript),
|
|
171
|
-
createDiagnosticsPlugin(),
|
|
172
|
-
createCompletionPlugin()
|
|
173
|
-
]);
|
|
286
|
+
}), createLanguageServicePlugins(tsdk.typescript));
|
|
174
287
|
});
|
|
175
288
|
connection.onInitialized(server.initialized);
|
|
176
289
|
connection.onShutdown(server.shutdown);
|
package/dist/node.js
CHANGED
|
@@ -16,7 +16,73 @@ function getVirtualCode(document, context) {
|
|
|
16
16
|
return [virtualCode, sourceUri];
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
|
-
//#region src/
|
|
19
|
+
//#region src/services/code_lens.ts
|
|
20
|
+
const createCodeLensPlugin = () => {
|
|
21
|
+
return {
|
|
22
|
+
name: "gts-code-lens",
|
|
23
|
+
capabilities: { codeLensProvider: {} },
|
|
24
|
+
create: (context) => {
|
|
25
|
+
return { provideCodeLenses: async (document, token) => {
|
|
26
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
27
|
+
if (!virtualCode) return [];
|
|
28
|
+
const result = [];
|
|
29
|
+
for (const mapping of virtualCode.mappings) if (mapping.data.directActionStub) {
|
|
30
|
+
const startOffset = mapping.generatedOffsets[0];
|
|
31
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
32
|
+
const start = document.positionAt(startOffset);
|
|
33
|
+
const end = document.positionAt(startOffset + length);
|
|
34
|
+
result.push({
|
|
35
|
+
range: {
|
|
36
|
+
start,
|
|
37
|
+
end
|
|
38
|
+
},
|
|
39
|
+
command: {
|
|
40
|
+
title: "~action",
|
|
41
|
+
command: ""
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
} };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/services/completion.ts
|
|
52
|
+
const createCompletionPlugin = () => {
|
|
53
|
+
return {
|
|
54
|
+
name: "gts-completion",
|
|
55
|
+
capabilities: { completionProvider: { triggerCharacters: [":"] } },
|
|
56
|
+
create: (context) => {
|
|
57
|
+
let tsProvideCompletionItems;
|
|
58
|
+
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.provideCompletionItems) {
|
|
59
|
+
let originalProvideCompletionItems = instance.provideCompletionItems;
|
|
60
|
+
tsProvideCompletionItems = instance.provideCompletionItems = async (...args) => {
|
|
61
|
+
const response = await originalProvideCompletionItems.apply(instance, args);
|
|
62
|
+
if (!response) return response;
|
|
63
|
+
const items = response.items.filter((item) => !item.label.startsWith("__gts_"));
|
|
64
|
+
return {
|
|
65
|
+
...response,
|
|
66
|
+
items
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (!tsProvideCompletionItems) {
|
|
71
|
+
console.warn(`TS's original provideCompletionItems not found`);
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
return { provideCompletionItems: async (document, position, context, token) => {
|
|
75
|
+
if (context.triggerCharacter === ":") {
|
|
76
|
+
context.triggerCharacter = ".";
|
|
77
|
+
return await tsProvideCompletionItems(document, position, context, token);
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
} };
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/services/diagnostics.ts
|
|
20
86
|
const createDiagnosticsPlugin = () => {
|
|
21
87
|
return {
|
|
22
88
|
name: "gts-diagnostics",
|
|
@@ -67,48 +133,99 @@ const createDiagnosticsPlugin = () => {
|
|
|
67
133
|
};
|
|
68
134
|
};
|
|
69
135
|
//#endregion
|
|
70
|
-
//#region src/
|
|
71
|
-
|
|
72
|
-
const services = create(ts);
|
|
73
|
-
const semanticService = services.find((service) => service.name === "typescript-semantic");
|
|
74
|
-
if (semanticService?.capabilities.signatureHelpProvider?.triggerCharacters) semanticService.capabilities.signatureHelpProvider.triggerCharacters.push(" ");
|
|
75
|
-
return services;
|
|
76
|
-
}
|
|
77
|
-
//#endregion
|
|
78
|
-
//#region src/completion.ts
|
|
79
|
-
const createCompletionPlugin = () => {
|
|
136
|
+
//#region src/services/semantic_tokens.ts
|
|
137
|
+
const createSemanticTokensPlugin = () => {
|
|
80
138
|
return {
|
|
81
|
-
name: "gts-
|
|
82
|
-
capabilities: {
|
|
139
|
+
name: "gts-semantic-tokens",
|
|
140
|
+
capabilities: { semanticTokensProvider: { legend: {
|
|
141
|
+
tokenTypes: ["string"],
|
|
142
|
+
tokenModifiers: ["gtsAttribute"]
|
|
143
|
+
} } },
|
|
83
144
|
create: (context) => {
|
|
84
|
-
let
|
|
85
|
-
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
const response = await
|
|
145
|
+
let tsSemanticTokens;
|
|
146
|
+
for (const [plugin, instance] of context.plugins) if (plugin.name === "typescript-semantic" && instance.provideDocumentSemanticTokens) {
|
|
147
|
+
let originalProvideDocumentSemanticTokens = instance.provideDocumentSemanticTokens;
|
|
148
|
+
tsSemanticTokens = instance.provideDocumentSemanticTokens = async (document, range, legend, token) => {
|
|
149
|
+
const response = await originalProvideDocumentSemanticTokens.call(instance, document, range, legend, token);
|
|
89
150
|
if (!response) return response;
|
|
90
|
-
const
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
151
|
+
const gtsAttributeIndex = legend.tokenModifiers.indexOf("gtsAttribute");
|
|
152
|
+
if (gtsAttributeIndex === -1) return response;
|
|
153
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
154
|
+
if (!virtualCode) return response;
|
|
155
|
+
for (let i = 0; i < response.length; i++) {
|
|
156
|
+
const [line, character, length, tokenType, tokenModifiers] = response[i];
|
|
157
|
+
if (tokenType !== legend.tokenTypes.indexOf("method")) continue;
|
|
158
|
+
const offset = document.offsetAt({
|
|
159
|
+
line,
|
|
160
|
+
character
|
|
161
|
+
});
|
|
162
|
+
if (virtualCode.mappings.find((m) => m.generatedOffsets[0] === offset && m.data.gtsAttribute)) response[i][4] |= 1 << gtsAttributeIndex;
|
|
163
|
+
}
|
|
164
|
+
return response;
|
|
95
165
|
};
|
|
96
166
|
}
|
|
97
|
-
if (!
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
167
|
+
if (!tsSemanticTokens) console.warn(`TS's original provideDocumentSemanticTokens not found`);
|
|
168
|
+
return { provideDocumentSemanticTokens(document, range, legend, token) {
|
|
169
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
170
|
+
if (!virtualCode) return null;
|
|
171
|
+
const stringIdx = legend.tokenTypes.indexOf("string");
|
|
172
|
+
if (stringIdx === -1) return null;
|
|
173
|
+
const gtsAttributeIndex = legend.tokenModifiers.indexOf("gtsAttribute");
|
|
174
|
+
const result = [];
|
|
175
|
+
const text = document.getText();
|
|
176
|
+
for (const mapping of virtualCode.mappings) {
|
|
177
|
+
if (mapping.data.literalFromId) {
|
|
178
|
+
const offset = mapping.generatedOffsets[0];
|
|
179
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
180
|
+
const pos = document.positionAt(offset);
|
|
181
|
+
result.push([
|
|
182
|
+
pos.line,
|
|
183
|
+
pos.character,
|
|
184
|
+
length,
|
|
185
|
+
stringIdx,
|
|
186
|
+
0
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
if (gtsAttributeIndex >= 0 && mapping.data.gtsAttribute) {
|
|
190
|
+
const offset = mapping.generatedOffsets[0];
|
|
191
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
192
|
+
const pos = document.positionAt(offset);
|
|
193
|
+
const char = text[offset];
|
|
194
|
+
if (char === "\"" || char === "'") result.push([
|
|
195
|
+
pos.line,
|
|
196
|
+
pos.character,
|
|
197
|
+
length,
|
|
198
|
+
stringIdx,
|
|
199
|
+
1 << gtsAttributeIndex
|
|
200
|
+
]);
|
|
201
|
+
}
|
|
105
202
|
}
|
|
106
|
-
return
|
|
203
|
+
return result;
|
|
107
204
|
} };
|
|
108
205
|
}
|
|
109
206
|
};
|
|
110
207
|
};
|
|
111
208
|
//#endregion
|
|
209
|
+
//#region src/services/typescript.ts
|
|
210
|
+
function createTypeScriptServices(ts) {
|
|
211
|
+
const services = create(ts);
|
|
212
|
+
const semanticService = services.find((service) => service.name === "typescript-semantic");
|
|
213
|
+
if (semanticService?.capabilities.signatureHelpProvider?.triggerCharacters) semanticService.capabilities.signatureHelpProvider.triggerCharacters.push(" ");
|
|
214
|
+
if (semanticService?.capabilities.semanticTokensProvider?.legend) semanticService.capabilities.semanticTokensProvider.legend.tokenModifiers.push("gtsAttribute");
|
|
215
|
+
return services;
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/services/index.ts
|
|
219
|
+
function createLanguageServicePlugins(ts) {
|
|
220
|
+
return [
|
|
221
|
+
...createTypeScriptServices(ts),
|
|
222
|
+
createDiagnosticsPlugin(),
|
|
223
|
+
createCompletionPlugin(),
|
|
224
|
+
createSemanticTokensPlugin(),
|
|
225
|
+
createCodeLensPlugin()
|
|
226
|
+
];
|
|
227
|
+
}
|
|
228
|
+
//#endregion
|
|
112
229
|
//#region src/node.ts
|
|
113
230
|
const connection = createConnection();
|
|
114
231
|
const server = createServer(connection);
|
|
@@ -117,11 +234,7 @@ connection.onInitialize((params) => {
|
|
|
117
234
|
const tsdk = loadTsdkByPath(params.initializationOptions.typescript.tsdk, params.locale);
|
|
118
235
|
return server.initialize(params, createTypeScriptProject(tsdk.typescript, tsdk.diagnosticMessages, () => {
|
|
119
236
|
return { languagePlugins: [createGtsLanguagePlugin(tsdk.typescript)] };
|
|
120
|
-
}),
|
|
121
|
-
...createTypeScriptServices(tsdk.typescript),
|
|
122
|
-
createDiagnosticsPlugin(),
|
|
123
|
-
createCompletionPlugin()
|
|
124
|
-
]);
|
|
237
|
+
}), createLanguageServicePlugins(tsdk.typescript));
|
|
125
238
|
});
|
|
126
239
|
connection.onInitialized(server.initialized);
|
|
127
240
|
connection.onShutdown(server.shutdown);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gi-tcg/gts-language-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/piovium/gts.git"
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"path-browserify-esm": "^1.0.6",
|
|
32
32
|
"volar-service-typescript": "volar-2.4",
|
|
33
33
|
"vscode-uri": "^3.0.8",
|
|
34
|
-
"@gi-tcg/gts-
|
|
35
|
-
"@gi-tcg/gts-
|
|
34
|
+
"@gi-tcg/gts-language-plugin": "0.3.9",
|
|
35
|
+
"@gi-tcg/gts-transpiler": "0.3.9"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"vscode-languageserver-textdocument": "^1.0.12"
|
package/src/browser.ts
CHANGED
|
@@ -11,12 +11,10 @@ import {
|
|
|
11
11
|
import { createGtsLanguagePlugin } from "@gi-tcg/gts-language-plugin";
|
|
12
12
|
import path from "path-browserify-esm";
|
|
13
13
|
import { type GtsConfig } from "@gi-tcg/gts-transpiler";
|
|
14
|
-
import {
|
|
15
|
-
import { createTypeScriptServices } from "./typescript.ts";
|
|
16
|
-
import { createCompletionPlugin } from "./completion.ts";
|
|
17
|
-
import { Dirent, fs as memfs } from "@zenfs/core";
|
|
14
|
+
import { fs as memfs } from "@zenfs/core";
|
|
18
15
|
import type ts from "typescript";
|
|
19
16
|
import zenFsProvider from "./zen_fs_provider.ts";
|
|
17
|
+
import { createLanguageServicePlugins } from "./services/index.ts";
|
|
20
18
|
|
|
21
19
|
export interface GtsLanguageServerBrowserInitializationOptions {
|
|
22
20
|
tsdkUrl?: string;
|
|
@@ -65,11 +63,7 @@ connection.onInitialize(
|
|
|
65
63
|
};
|
|
66
64
|
},
|
|
67
65
|
),
|
|
68
|
-
|
|
69
|
-
...createTypeScriptServices(tsdk.typescript),
|
|
70
|
-
createDiagnosticsPlugin(),
|
|
71
|
-
createCompletionPlugin(),
|
|
72
|
-
],
|
|
66
|
+
createLanguageServicePlugins(tsdk.typescript),
|
|
73
67
|
);
|
|
74
68
|
},
|
|
75
69
|
);
|
|
@@ -95,7 +89,9 @@ async function loadLibs(tsdkUrl: string) {
|
|
|
95
89
|
memfs.mkdirSync("/node_modules/typescript/lib", { recursive: true });
|
|
96
90
|
const libs = await Promise.all(
|
|
97
91
|
ALL_LIBS.map((lib) =>
|
|
98
|
-
fetch(`${tsdkUrl}/${lib}`)
|
|
92
|
+
fetch(`${tsdkUrl}/${lib}`)
|
|
93
|
+
.then((res) => res.text())
|
|
94
|
+
.then((content) => [lib, content] as const),
|
|
99
95
|
),
|
|
100
96
|
);
|
|
101
97
|
for (const [lib, content] of libs) {
|
package/src/node.ts
CHANGED
|
@@ -6,9 +6,7 @@ import {
|
|
|
6
6
|
loadTsdkByPath,
|
|
7
7
|
} from "@volar/language-server/node.js";
|
|
8
8
|
import { createGtsLanguagePlugin } from "@gi-tcg/gts-language-plugin";
|
|
9
|
-
import {
|
|
10
|
-
import { createTypeScriptServices } from "./typescript.ts";
|
|
11
|
-
import { createCompletionPlugin } from "./completion.ts";
|
|
9
|
+
import { createLanguageServicePlugins } from "./services/index.ts";
|
|
12
10
|
|
|
13
11
|
const connection = createConnection();
|
|
14
12
|
const server = createServer(connection);
|
|
@@ -27,11 +25,7 @@ connection.onInitialize((params) => {
|
|
|
27
25
|
languagePlugins: [createGtsLanguagePlugin(tsdk.typescript)],
|
|
28
26
|
};
|
|
29
27
|
}),
|
|
30
|
-
|
|
31
|
-
...createTypeScriptServices(tsdk.typescript),
|
|
32
|
-
createDiagnosticsPlugin(),
|
|
33
|
-
createCompletionPlugin(),
|
|
34
|
-
],
|
|
28
|
+
createLanguageServicePlugins(tsdk.typescript),
|
|
35
29
|
);
|
|
36
30
|
});
|
|
37
31
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CodeLens, type LanguageServicePlugin } from "@volar/language-server";
|
|
2
|
+
import { getVirtualCode } from "../utils.ts";
|
|
3
|
+
|
|
4
|
+
export const createCodeLensPlugin = (): LanguageServicePlugin => {
|
|
5
|
+
return {
|
|
6
|
+
name: "gts-code-lens",
|
|
7
|
+
capabilities: {
|
|
8
|
+
codeLensProvider: {},
|
|
9
|
+
},
|
|
10
|
+
create: (context) => {
|
|
11
|
+
return {
|
|
12
|
+
provideCodeLenses: async (document, token) => {
|
|
13
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
14
|
+
if (!virtualCode) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const result: CodeLens[] = [];
|
|
18
|
+
for (const mapping of virtualCode.mappings) {
|
|
19
|
+
if (mapping.data.directActionStub) {
|
|
20
|
+
const startOffset = mapping.generatedOffsets[0];
|
|
21
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
22
|
+
const start = document.positionAt(startOffset);
|
|
23
|
+
// two character: "0;"
|
|
24
|
+
const end = document.positionAt(startOffset + length);
|
|
25
|
+
result.push({
|
|
26
|
+
range: { start, end },
|
|
27
|
+
command: {
|
|
28
|
+
title: "~action",
|
|
29
|
+
command: "",
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Range,
|
|
4
4
|
type LanguageServicePlugin,
|
|
5
5
|
} from "@volar/language-server";
|
|
6
|
-
import { getVirtualCode } from "
|
|
6
|
+
import { getVirtualCode } from "../utils.ts";
|
|
7
7
|
export const createDiagnosticsPlugin = (): LanguageServicePlugin => {
|
|
8
8
|
return {
|
|
9
9
|
name: "gts-diagnostics",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createCodeLensPlugin } from "./code_lens.ts";
|
|
2
|
+
import { createCompletionPlugin } from "./completion.ts";
|
|
3
|
+
import { createDiagnosticsPlugin } from "./diagnostics.ts";
|
|
4
|
+
import { createSemanticTokensPlugin } from "./semantic_tokens.ts";
|
|
5
|
+
import { createTypeScriptServices } from "./typescript.ts";
|
|
6
|
+
import type { LanguageServicePlugin } from "@volar/language-server";
|
|
7
|
+
|
|
8
|
+
export function createLanguageServicePlugins(
|
|
9
|
+
ts: typeof import("typescript"),
|
|
10
|
+
): LanguageServicePlugin[] {
|
|
11
|
+
return [
|
|
12
|
+
...createTypeScriptServices(ts),
|
|
13
|
+
createDiagnosticsPlugin(),
|
|
14
|
+
createCompletionPlugin(),
|
|
15
|
+
createSemanticTokensPlugin(),
|
|
16
|
+
createCodeLensPlugin(),
|
|
17
|
+
];
|
|
18
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type LanguageServicePlugin,
|
|
3
|
+
type LanguageServicePluginInstance,
|
|
4
|
+
type SemanticToken,
|
|
5
|
+
} from "@volar/language-server";
|
|
6
|
+
import { getVirtualCode } from "../utils.ts";
|
|
7
|
+
|
|
8
|
+
export const createSemanticTokensPlugin = (): LanguageServicePlugin => {
|
|
9
|
+
return {
|
|
10
|
+
name: "gts-semantic-tokens",
|
|
11
|
+
capabilities: {
|
|
12
|
+
semanticTokensProvider: {
|
|
13
|
+
legend: {
|
|
14
|
+
tokenTypes: ["string"],
|
|
15
|
+
tokenModifiers: ["gtsAttribute"],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
create: (context) => {
|
|
20
|
+
let tsSemanticTokens: LanguageServicePluginInstance["provideDocumentSemanticTokens"];
|
|
21
|
+
|
|
22
|
+
for (const [plugin, instance] of context.plugins) {
|
|
23
|
+
if (
|
|
24
|
+
plugin.name === "typescript-semantic" &&
|
|
25
|
+
instance.provideDocumentSemanticTokens
|
|
26
|
+
) {
|
|
27
|
+
let originalProvideDocumentSemanticTokens =
|
|
28
|
+
instance.provideDocumentSemanticTokens;
|
|
29
|
+
tsSemanticTokens = instance.provideDocumentSemanticTokens = async (
|
|
30
|
+
document,
|
|
31
|
+
range,
|
|
32
|
+
legend,
|
|
33
|
+
token,
|
|
34
|
+
) => {
|
|
35
|
+
const response = await originalProvideDocumentSemanticTokens.call(
|
|
36
|
+
instance,
|
|
37
|
+
document,
|
|
38
|
+
range,
|
|
39
|
+
legend,
|
|
40
|
+
token,
|
|
41
|
+
);
|
|
42
|
+
if (!response) {
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
const gtsAttributeIndex =
|
|
46
|
+
legend.tokenModifiers.indexOf("gtsAttribute");
|
|
47
|
+
if (gtsAttributeIndex === -1) {
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
51
|
+
if (!virtualCode) {
|
|
52
|
+
return response;
|
|
53
|
+
}
|
|
54
|
+
for (let i = 0; i < response.length; i++) {
|
|
55
|
+
const [line, character, length, tokenType, tokenModifiers] =
|
|
56
|
+
response[i];
|
|
57
|
+
if (tokenType !== legend.tokenTypes.indexOf("method")) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const offset = document.offsetAt({ line, character });
|
|
61
|
+
const mapping = virtualCode.mappings.find(
|
|
62
|
+
(m) => m.generatedOffsets[0] === offset && m.data.gtsAttribute,
|
|
63
|
+
);
|
|
64
|
+
if (mapping) {
|
|
65
|
+
response[i][4] |= 1 << gtsAttributeIndex;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return response;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!tsSemanticTokens) {
|
|
73
|
+
console.warn(`TS's original provideDocumentSemanticTokens not found`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
// Attribute value that is a string literal but no wrapping quotation with it,
|
|
77
|
+
// add a semantic token of type "string" to them so they show same color as string literal
|
|
78
|
+
provideDocumentSemanticTokens(document, range, legend, token) {
|
|
79
|
+
const [virtualCode] = getVirtualCode(document, context);
|
|
80
|
+
if (!virtualCode) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const stringIdx = legend.tokenTypes.indexOf("string");
|
|
84
|
+
if (stringIdx === -1) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const gtsAttributeIndex =
|
|
88
|
+
legend.tokenModifiers.indexOf("gtsAttribute");
|
|
89
|
+
const result: SemanticToken[] = [];
|
|
90
|
+
const text = document.getText();
|
|
91
|
+
for (const mapping of virtualCode.mappings) {
|
|
92
|
+
if (mapping.data.literalFromId) {
|
|
93
|
+
const offset = mapping.generatedOffsets[0];
|
|
94
|
+
const length = mapping.generatedLengths?.[0] ?? mapping.lengths[0];
|
|
95
|
+
const pos = document.positionAt(offset);
|
|
96
|
+
result.push([pos.line, pos.character, length, stringIdx, 0]);
|
|
97
|
+
}
|
|
98
|
+
if (gtsAttributeIndex >= 0 && mapping.data.gtsAttribute) {
|
|
99
|
+
const offset = mapping.generatedOffsets[0];
|
|
100
|
+
const length = mapping.generatedLengths?.[0] ??mapping.lengths[0];
|
|
101
|
+
const pos = document.positionAt(offset);
|
|
102
|
+
const char = text[offset];
|
|
103
|
+
if (char === '"' || char === "'") {
|
|
104
|
+
// A GTS attribute name with quotation, that will not have TS semantic token ("member")
|
|
105
|
+
// we add it as "string" with "gtsAttribute" modifier too.
|
|
106
|
+
result.push([
|
|
107
|
+
pos.line,
|
|
108
|
+
pos.character,
|
|
109
|
+
length,
|
|
110
|
+
stringIdx,
|
|
111
|
+
1 << gtsAttributeIndex,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
};
|
|
@@ -16,5 +16,10 @@ export function createTypeScriptServices(
|
|
|
16
16
|
" ",
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
|
+
if (semanticService?.capabilities.semanticTokensProvider?.legend) {
|
|
20
|
+
semanticService.capabilities.semanticTokensProvider.legend.tokenModifiers.push(
|
|
21
|
+
"gtsAttribute",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
19
24
|
return services;
|
|
20
25
|
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
LanguageServicePluginInstance,
|
|
3
|
-
LanguageServicePlugin,
|
|
4
|
-
} from "@volar/language-server";
|
|
5
|
-
import { getVirtualCode, getWordFromPosition } from "./utils.ts";
|
|
6
|
-
|
|
7
|
-
export function createDocumentHighlightService(): LanguageServicePlugin {
|
|
8
|
-
return {
|
|
9
|
-
name: "gts-document-highlight",
|
|
10
|
-
capabilities: {
|
|
11
|
-
documentHighlightProvider: true,
|
|
12
|
-
},
|
|
13
|
-
create(context) {
|
|
14
|
-
let originalProvideDocumentHighlights: LanguageServicePluginInstance["provideDocumentHighlights"];
|
|
15
|
-
let originalInstance: LanguageServicePluginInstance;
|
|
16
|
-
|
|
17
|
-
// Get TypeScript's document highlights provider
|
|
18
|
-
for (const [plugin, instance] of context.plugins) {
|
|
19
|
-
if (
|
|
20
|
-
plugin.name === "typescript-semantic" &&
|
|
21
|
-
instance.provideDocumentHighlights
|
|
22
|
-
) {
|
|
23
|
-
originalInstance = instance;
|
|
24
|
-
originalProvideDocumentHighlights =
|
|
25
|
-
instance.provideDocumentHighlights;
|
|
26
|
-
instance.provideDocumentHighlights = undefined;
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!originalProvideDocumentHighlights) {
|
|
32
|
-
console?.log(
|
|
33
|
-
"'typescript-semantic plugin' was not found or has no 'provideDocumentHighlights'. \
|
|
34
|
-
Document highlights will be limited to custom GamingTS keywords only."
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
async provideDocumentHighlights(document, position, token) {
|
|
40
|
-
if (!originalProvideDocumentHighlights) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let tsHighlights = await originalProvideDocumentHighlights.call(
|
|
45
|
-
originalInstance,
|
|
46
|
-
document,
|
|
47
|
-
position,
|
|
48
|
-
token
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
if (!tsHighlights || tsHighlights.length > 0) {
|
|
52
|
-
// If TypeScript recognized tokens and provided highlights, return them
|
|
53
|
-
return tsHighlights;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const [virtualCode] = getVirtualCode(document, context);
|
|
57
|
-
|
|
58
|
-
if (!virtualCode) {
|
|
59
|
-
return tsHighlights;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Check if we're on a custom Ripple keyword
|
|
63
|
-
const offset = document.offsetAt(position);
|
|
64
|
-
const text = document.getText();
|
|
65
|
-
|
|
66
|
-
// Find word boundaries
|
|
67
|
-
const { word } = getWordFromPosition(text, offset);
|
|
68
|
-
|
|
69
|
-
// If the word is a Ripple keyword, find all occurrences in the document
|
|
70
|
-
|
|
71
|
-
const regex = new RegExp(`\\b${word}\\b`, "g");
|
|
72
|
-
let match;
|
|
73
|
-
|
|
74
|
-
// while ((match = regex.exec(text)) !== null) {
|
|
75
|
-
// const start = match.index;
|
|
76
|
-
// const end = match.index + word.length;
|
|
77
|
-
// const mapping = virtualCode.findMappingByGeneratedRange(start, end);
|
|
78
|
-
|
|
79
|
-
// if (!mapping) {
|
|
80
|
-
// // If no mapping, skip all others as well
|
|
81
|
-
// // This shouldn't happen as TS handles only mapped ranges
|
|
82
|
-
// return tsHighlights;
|
|
83
|
-
// }
|
|
84
|
-
|
|
85
|
-
// if (!mapping.data.customData?.wordHighlight?.kind) {
|
|
86
|
-
// // Skip if we didn't define word highlighting in segments
|
|
87
|
-
// continue;
|
|
88
|
-
// }
|
|
89
|
-
|
|
90
|
-
// if (!tsHighlights) {
|
|
91
|
-
// tsHighlights = [];
|
|
92
|
-
// }
|
|
93
|
-
|
|
94
|
-
// tsHighlights.push({
|
|
95
|
-
// range: {
|
|
96
|
-
// start: document.positionAt(start),
|
|
97
|
-
// end: document.positionAt(end),
|
|
98
|
-
// },
|
|
99
|
-
|
|
100
|
-
// kind: mapping.data.customData.wordHighlight.kind,
|
|
101
|
-
// });
|
|
102
|
-
// }
|
|
103
|
-
|
|
104
|
-
if (tsHighlights.length > 0) {
|
|
105
|
-
console?.log(`Found ${tsHighlights.length} occurrences of '${word}'`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Return TypeScript highlights if no custom keyword was found
|
|
109
|
-
return [...tsHighlights];
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
}
|
|
File without changes
|