@player-lang/json-language-service 0.0.2-next.0
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/cjs/index.cjs +2314 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/index.legacy-esm.js +2249 -0
- package/dist/index.mjs +2249 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +40 -0
- package/src/__tests__/__snapshots__/service.test.ts.snap +213 -0
- package/src/__tests__/service.test.ts +298 -0
- package/src/constants.ts +38 -0
- package/src/index.ts +490 -0
- package/src/parser/__tests__/parse.test.ts +18 -0
- package/src/parser/document.ts +456 -0
- package/src/parser/edits.ts +31 -0
- package/src/parser/index.ts +38 -0
- package/src/parser/jsonParseErrors.ts +69 -0
- package/src/parser/types.ts +314 -0
- package/src/parser/utils.ts +94 -0
- package/src/plugins/__tests__/asset-wrapper-array-plugin.test.ts +112 -0
- package/src/plugins/__tests__/binding-schema-plugin.test.ts +62 -0
- package/src/plugins/__tests__/duplicate-id-plugin.test.ts +195 -0
- package/src/plugins/__tests__/missing-asset-wrapper-plugin.test.ts +190 -0
- package/src/plugins/__tests__/nav-state-plugin.test.ts +136 -0
- package/src/plugins/__tests__/view-node-plugin.test.ts +154 -0
- package/src/plugins/asset-wrapper-array-plugin.ts +123 -0
- package/src/plugins/binding-schema-plugin.ts +289 -0
- package/src/plugins/duplicate-id-plugin.ts +158 -0
- package/src/plugins/missing-asset-wrapper-plugin.ts +96 -0
- package/src/plugins/nav-state-plugin.ts +139 -0
- package/src/plugins/view-node-plugin.ts +225 -0
- package/src/plugins/xlr-plugin.ts +371 -0
- package/src/types.ts +119 -0
- package/src/utils.ts +143 -0
- package/src/xlr/__tests__/__snapshots__/transform.test.ts.snap +390 -0
- package/src/xlr/__tests__/transform.test.ts +108 -0
- package/src/xlr/index.ts +3 -0
- package/src/xlr/registry.ts +99 -0
- package/src/xlr/service.ts +190 -0
- package/src/xlr/transforms.ts +169 -0
- package/types/constants.d.ts +7 -0
- package/types/index.d.ts +69 -0
- package/types/parser/document.d.ts +25 -0
- package/types/parser/edits.d.ts +10 -0
- package/types/parser/index.d.ts +16 -0
- package/types/parser/jsonParseErrors.d.ts +27 -0
- package/types/parser/types.d.ts +188 -0
- package/types/parser/utils.d.ts +26 -0
- package/types/plugins/asset-wrapper-array-plugin.d.ts +9 -0
- package/types/plugins/binding-schema-plugin.d.ts +15 -0
- package/types/plugins/duplicate-id-plugin.d.ts +7 -0
- package/types/plugins/missing-asset-wrapper-plugin.d.ts +9 -0
- package/types/plugins/nav-state-plugin.d.ts +9 -0
- package/types/plugins/view-node-plugin.d.ts +9 -0
- package/types/plugins/xlr-plugin.d.ts +7 -0
- package/types/types.d.ts +81 -0
- package/types/utils.d.ts +24 -0
- package/types/xlr/index.d.ts +4 -0
- package/types/xlr/registry.d.ts +17 -0
- package/types/xlr/service.d.ts +22 -0
- package/types/xlr/transforms.d.ts +18 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Range as JSONRange,
|
|
3
|
+
FormattingOptions as JSONFormattingOptions,
|
|
4
|
+
} from "jsonc-parser";
|
|
5
|
+
import { format as formatJSON } from "jsonc-parser";
|
|
6
|
+
import type { TextDocument } from "vscode-languageserver-textdocument";
|
|
7
|
+
import {
|
|
8
|
+
AsyncParallelHook,
|
|
9
|
+
SyncBailHook,
|
|
10
|
+
SyncHook,
|
|
11
|
+
SyncWaterfallHook,
|
|
12
|
+
} from "tapable-ts";
|
|
13
|
+
import type {
|
|
14
|
+
CodeAction,
|
|
15
|
+
CodeActionContext,
|
|
16
|
+
CompletionItem,
|
|
17
|
+
Diagnostic,
|
|
18
|
+
FormattingOptions,
|
|
19
|
+
Hover,
|
|
20
|
+
Position,
|
|
21
|
+
Location,
|
|
22
|
+
} from "vscode-languageserver-types";
|
|
23
|
+
import {
|
|
24
|
+
CompletionList,
|
|
25
|
+
Range,
|
|
26
|
+
TextEdit,
|
|
27
|
+
CodeActionKind,
|
|
28
|
+
} from "vscode-languageserver-types";
|
|
29
|
+
|
|
30
|
+
import type { TransformFunction } from "@xlr-lib/xlr";
|
|
31
|
+
import type {
|
|
32
|
+
DocumentContext,
|
|
33
|
+
ValidationContext,
|
|
34
|
+
CompletionContext,
|
|
35
|
+
EnhancedDocumentContextWithPosition,
|
|
36
|
+
Violation,
|
|
37
|
+
ASTVisitor,
|
|
38
|
+
} from "./types";
|
|
39
|
+
import { DEFAULT_FILTERS, PLUGINS, TRANSFORM_FUNCTIONS } from "./constants";
|
|
40
|
+
|
|
41
|
+
import type { ASTNode, PlayerContent } from "./parser";
|
|
42
|
+
import { parse, toRange, toTextEdit, walk } from "./parser";
|
|
43
|
+
|
|
44
|
+
import { containsRange, isKnownRootType, typeToVisitorMap } from "./utils";
|
|
45
|
+
import { XLRService } from "./xlr";
|
|
46
|
+
import { TSManifest } from "@xlr-lib/xlr";
|
|
47
|
+
|
|
48
|
+
export * from "./utils";
|
|
49
|
+
export * from "./constants";
|
|
50
|
+
export * from "./types";
|
|
51
|
+
export * from "./parser";
|
|
52
|
+
export * from "./xlr/index";
|
|
53
|
+
|
|
54
|
+
export interface PlayerLanguageServicePlugin {
|
|
55
|
+
/** The name of the plugin */
|
|
56
|
+
name: string;
|
|
57
|
+
|
|
58
|
+
/** the handle to get the LSP */
|
|
59
|
+
apply(languageService: PlayerLanguageService): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The thing that handles most of the LSP work */
|
|
63
|
+
export class PlayerLanguageService {
|
|
64
|
+
public readonly XLRService: XLRService;
|
|
65
|
+
|
|
66
|
+
private parseCache = new Map<
|
|
67
|
+
string,
|
|
68
|
+
{
|
|
69
|
+
/** the version of the document */
|
|
70
|
+
version: number;
|
|
71
|
+
|
|
72
|
+
/** The parsed document */
|
|
73
|
+
parsed: PlayerContent;
|
|
74
|
+
}
|
|
75
|
+
>();
|
|
76
|
+
|
|
77
|
+
private fixableViolationsForDocument = new Map<
|
|
78
|
+
string,
|
|
79
|
+
Map<Diagnostic, Violation>
|
|
80
|
+
>();
|
|
81
|
+
|
|
82
|
+
public readonly hooks: {
|
|
83
|
+
onDocumentUpdate: SyncHook<[DocumentContext], Record<string, any>>;
|
|
84
|
+
validate: AsyncParallelHook<[DocumentContext, ValidationContext], void>;
|
|
85
|
+
onValidateEnd: SyncWaterfallHook<
|
|
86
|
+
[
|
|
87
|
+
Diagnostic[],
|
|
88
|
+
{
|
|
89
|
+
/** The context of the document */
|
|
90
|
+
documentContext: DocumentContext;
|
|
91
|
+
/** A callback for adding a new fixable rule */
|
|
92
|
+
addFixableViolation: (diag: Diagnostic, violation: Violation) => void;
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
Record<string, any>
|
|
96
|
+
>;
|
|
97
|
+
complete: AsyncParallelHook<
|
|
98
|
+
[EnhancedDocumentContextWithPosition, CompletionContext],
|
|
99
|
+
void
|
|
100
|
+
>;
|
|
101
|
+
hover: SyncBailHook<
|
|
102
|
+
[EnhancedDocumentContextWithPosition],
|
|
103
|
+
Hover | undefined,
|
|
104
|
+
Record<string, any>
|
|
105
|
+
>;
|
|
106
|
+
definition: SyncBailHook<
|
|
107
|
+
[EnhancedDocumentContextWithPosition],
|
|
108
|
+
Location | undefined,
|
|
109
|
+
Record<string, any>
|
|
110
|
+
>;
|
|
111
|
+
} = {
|
|
112
|
+
onDocumentUpdate: new SyncHook<[DocumentContext]>(),
|
|
113
|
+
|
|
114
|
+
validate: new AsyncParallelHook<
|
|
115
|
+
[DocumentContext, ValidationContext],
|
|
116
|
+
void
|
|
117
|
+
>(),
|
|
118
|
+
|
|
119
|
+
onValidateEnd: new SyncWaterfallHook<
|
|
120
|
+
[
|
|
121
|
+
Diagnostic[],
|
|
122
|
+
{
|
|
123
|
+
/** The context of the document */
|
|
124
|
+
documentContext: DocumentContext;
|
|
125
|
+
/** A callback for adding a new fixable rule */
|
|
126
|
+
addFixableViolation: (diag: Diagnostic, violation: Violation) => void;
|
|
127
|
+
},
|
|
128
|
+
]
|
|
129
|
+
>(),
|
|
130
|
+
|
|
131
|
+
complete: new AsyncParallelHook<
|
|
132
|
+
[EnhancedDocumentContextWithPosition, CompletionContext],
|
|
133
|
+
void
|
|
134
|
+
>(),
|
|
135
|
+
|
|
136
|
+
hover: new SyncBailHook<
|
|
137
|
+
[EnhancedDocumentContextWithPosition],
|
|
138
|
+
Hover | undefined
|
|
139
|
+
>(),
|
|
140
|
+
|
|
141
|
+
definition: new SyncBailHook<
|
|
142
|
+
[EnhancedDocumentContextWithPosition],
|
|
143
|
+
Location | undefined
|
|
144
|
+
>(),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
constructor(config?: {
|
|
148
|
+
/** A list of plugins to include */
|
|
149
|
+
plugins?: Array<PlayerLanguageServicePlugin>;
|
|
150
|
+
}) {
|
|
151
|
+
// load base definitions?
|
|
152
|
+
this.XLRService = new XLRService();
|
|
153
|
+
|
|
154
|
+
PLUGINS.forEach((p) => p.apply(this));
|
|
155
|
+
config?.plugins?.forEach((p) => p.apply(this));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private parseTextDocument(document: TextDocument): PlayerContent {
|
|
159
|
+
if (!this.parseCache.has(document.uri)) {
|
|
160
|
+
const parsed = parse(document);
|
|
161
|
+
this.parseCache.set(document.uri, { version: document.version, parsed });
|
|
162
|
+
return parsed;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const cached = this.parseCache.get(document.uri);
|
|
166
|
+
|
|
167
|
+
if (!cached || cached.version < document.version) {
|
|
168
|
+
this.parseCache.delete(document.uri);
|
|
169
|
+
return this.parseTextDocument(document);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return cached.parsed;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private async updateSource(document: TextDocument): Promise<DocumentContext> {
|
|
176
|
+
const parsed = this.parseTextDocument(document);
|
|
177
|
+
const documentContext: DocumentContext = {
|
|
178
|
+
log: {
|
|
179
|
+
debug: console.log,
|
|
180
|
+
info: console.log,
|
|
181
|
+
warn: console.warn,
|
|
182
|
+
error: console.error,
|
|
183
|
+
},
|
|
184
|
+
document,
|
|
185
|
+
PlayerContent: parsed,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const ctx = {
|
|
189
|
+
...documentContext,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
this.hooks.onDocumentUpdate.call(ctx);
|
|
193
|
+
return ctx;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private async getJSONPositionInfo(
|
|
197
|
+
ctx: DocumentContext,
|
|
198
|
+
position: Position,
|
|
199
|
+
): Promise<{
|
|
200
|
+
/** the node at the given node */
|
|
201
|
+
node?: ASTNode;
|
|
202
|
+
}> {
|
|
203
|
+
const { document, PlayerContent } = ctx;
|
|
204
|
+
const node = PlayerContent.getNodeFromOffset(document.offsetAt(position));
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
node,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private async updateSourceWithPosition(
|
|
212
|
+
document: TextDocument,
|
|
213
|
+
position: Position,
|
|
214
|
+
): Promise<EnhancedDocumentContextWithPosition | undefined> {
|
|
215
|
+
const ctx = await this.updateSource(document);
|
|
216
|
+
|
|
217
|
+
const { node } = await this.getJSONPositionInfo(ctx, position);
|
|
218
|
+
|
|
219
|
+
const XLRInfo = this.XLRService.getTypeInfoAtPosition(node);
|
|
220
|
+
if (!node || !XLRInfo) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
...ctx,
|
|
226
|
+
node,
|
|
227
|
+
position,
|
|
228
|
+
XLR: XLRInfo,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public onClose(document: TextDocument): void {
|
|
233
|
+
this.fixableViolationsForDocument.delete(document.uri);
|
|
234
|
+
this.parseCache.delete(document.uri);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async formatTextDocument(
|
|
238
|
+
document: TextDocument,
|
|
239
|
+
options: FormattingOptions,
|
|
240
|
+
range?: Range,
|
|
241
|
+
): Promise<Array<TextEdit> | undefined> {
|
|
242
|
+
const formattingOptions: JSONFormattingOptions = {
|
|
243
|
+
tabSize: options.tabSize,
|
|
244
|
+
insertSpaces: options.insertSpaces,
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
let formatRange: JSONRange | undefined;
|
|
248
|
+
|
|
249
|
+
if (range) {
|
|
250
|
+
const startOffset = document.offsetAt(range.start);
|
|
251
|
+
formatRange = {
|
|
252
|
+
offset: startOffset,
|
|
253
|
+
length: document.offsetAt(range.end) - startOffset,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return formatJSON(document.getText(), formatRange, formattingOptions).map(
|
|
258
|
+
(edit) => {
|
|
259
|
+
return TextEdit.replace(
|
|
260
|
+
Range.create(
|
|
261
|
+
document.positionAt(edit.offset),
|
|
262
|
+
document.positionAt(edit.offset + edit.length),
|
|
263
|
+
),
|
|
264
|
+
edit.content,
|
|
265
|
+
);
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async validateTextDocument(
|
|
271
|
+
document: TextDocument,
|
|
272
|
+
): Promise<Array<Diagnostic> | undefined> {
|
|
273
|
+
const ctx = await this.updateSource(document);
|
|
274
|
+
this.fixableViolationsForDocument.delete(document.uri);
|
|
275
|
+
|
|
276
|
+
if (!isKnownRootType(ctx.PlayerContent)) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const diagnostics = [...ctx.PlayerContent.syntaxErrors];
|
|
281
|
+
const astVisitors: Array<ASTVisitor> = [];
|
|
282
|
+
|
|
283
|
+
/** Add a matching violation fix to the original diagnostic */
|
|
284
|
+
const addFixableViolation = (
|
|
285
|
+
diagnostic: Diagnostic,
|
|
286
|
+
violation: Violation,
|
|
287
|
+
) => {
|
|
288
|
+
if (!this.fixableViolationsForDocument.has(document.uri)) {
|
|
289
|
+
this.fixableViolationsForDocument.set(document.uri, new Map());
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const fixableDiags = this.fixableViolationsForDocument.get(document.uri);
|
|
293
|
+
|
|
294
|
+
fixableDiags?.set(diagnostic, violation);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
if (ctx.PlayerContent.root) {
|
|
298
|
+
const validationContext: ValidationContext = {
|
|
299
|
+
addViolation: (violation) => {
|
|
300
|
+
const { message, node, severity, fix } = violation;
|
|
301
|
+
|
|
302
|
+
const range: Range = toRange(document, node);
|
|
303
|
+
|
|
304
|
+
const diagnostic: Diagnostic = {
|
|
305
|
+
message,
|
|
306
|
+
severity,
|
|
307
|
+
range,
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
if (fix) {
|
|
311
|
+
addFixableViolation(diagnostic, violation);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
diagnostics.push(diagnostic);
|
|
315
|
+
},
|
|
316
|
+
useASTVisitor: (visitor) => {
|
|
317
|
+
astVisitors.push(visitor);
|
|
318
|
+
},
|
|
319
|
+
addDiagnostic(d) {
|
|
320
|
+
diagnostics.push(d);
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
await this.hooks.validate.call(ctx, validationContext);
|
|
325
|
+
|
|
326
|
+
// Walk the tree using any of the registered visitors
|
|
327
|
+
// This is for perf so we only walk the tree once
|
|
328
|
+
|
|
329
|
+
await walk(ctx.PlayerContent.root, async (node) => {
|
|
330
|
+
const visitorProp = typeToVisitorMap[node.type];
|
|
331
|
+
|
|
332
|
+
astVisitors.forEach(async (visitor) => {
|
|
333
|
+
try {
|
|
334
|
+
await visitor[visitorProp]?.(node as any);
|
|
335
|
+
} catch (e: any) {
|
|
336
|
+
ctx.log?.error(
|
|
337
|
+
`Error running rules for ${visitorProp}: ${e.message}, Stack ${e.stack}`,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
return false;
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return this.hooks.onValidateEnd.call(diagnostics, {
|
|
347
|
+
documentContext: ctx,
|
|
348
|
+
addFixableViolation,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async getCompletionsAtPosition(
|
|
353
|
+
document: TextDocument,
|
|
354
|
+
position: Position,
|
|
355
|
+
): Promise<CompletionList> {
|
|
356
|
+
const ctxWithPos = await this.updateSourceWithPosition(document, position);
|
|
357
|
+
|
|
358
|
+
if (!ctxWithPos) {
|
|
359
|
+
return CompletionList.create();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const completionItems: Array<CompletionItem> = [];
|
|
363
|
+
|
|
364
|
+
const completionContext: CompletionContext = {
|
|
365
|
+
addCompletionItem: (i) => {
|
|
366
|
+
completionItems.push(i);
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
await this.hooks.complete.call(ctxWithPos, completionContext);
|
|
370
|
+
|
|
371
|
+
return CompletionList.create(completionItems);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async resolveCompletionItem(
|
|
375
|
+
completionItem: CompletionItem,
|
|
376
|
+
): Promise<CompletionItem> {
|
|
377
|
+
return completionItem;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async getHoverInfoAtPosition(
|
|
381
|
+
document: TextDocument,
|
|
382
|
+
position: Position,
|
|
383
|
+
): Promise<Hover | undefined | null> {
|
|
384
|
+
const context = await this.updateSourceWithPosition(document, position);
|
|
385
|
+
|
|
386
|
+
if (!context) {
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return this.hooks.hover.call(context);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async getCodeActionsInRange(
|
|
394
|
+
document: TextDocument,
|
|
395
|
+
context: CodeActionContext,
|
|
396
|
+
): Promise<CodeAction[]> {
|
|
397
|
+
const diagsForDocument = this.fixableViolationsForDocument.get(
|
|
398
|
+
document.uri,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (
|
|
402
|
+
!diagsForDocument ||
|
|
403
|
+
diagsForDocument.size === 0 ||
|
|
404
|
+
context.diagnostics.length === 0
|
|
405
|
+
) {
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const actions: CodeAction[] = [];
|
|
410
|
+
// Get all overlapping rules
|
|
411
|
+
|
|
412
|
+
diagsForDocument.forEach((violation, diagnostic) => {
|
|
413
|
+
const matching = context.diagnostics.find((diag) =>
|
|
414
|
+
containsRange(diagnostic.range, diag.range),
|
|
415
|
+
);
|
|
416
|
+
const fixedAction = violation.fix?.();
|
|
417
|
+
|
|
418
|
+
if (!matching || !fixedAction) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
actions.push({
|
|
423
|
+
title: fixedAction.name,
|
|
424
|
+
kind: CodeActionKind.QuickFix,
|
|
425
|
+
edit: {
|
|
426
|
+
changes: {
|
|
427
|
+
[document.uri]: [toTextEdit(document, fixedAction.edit)],
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
return actions;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public async getDefinitionAtPosition(
|
|
437
|
+
document: TextDocument,
|
|
438
|
+
position: Position,
|
|
439
|
+
): Promise<Location | undefined | null> {
|
|
440
|
+
const context = await this.updateSourceWithPosition(document, position);
|
|
441
|
+
|
|
442
|
+
if (!context) {
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return this.hooks.definition.call(context);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
public addXLRTransforms(transforms: Record<string, TransformFunction>): void {
|
|
450
|
+
Object.entries(transforms).forEach(([name, fn]) =>
|
|
451
|
+
this.XLRService.XLRSDK.addTransformFunction(name, fn),
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
public addLSPPlugin(plugin: PlayerLanguageServicePlugin): void {
|
|
456
|
+
plugin.apply(this);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
async setAssetTypes(typeFiles: Array<string>): Promise<void> {
|
|
460
|
+
// await this.typescriptService.setAssetTypes(typeFiles);
|
|
461
|
+
typeFiles.forEach((file) => {
|
|
462
|
+
// Find a better way of loading default types
|
|
463
|
+
if (file.includes("types")) {
|
|
464
|
+
this.XLRService.XLRSDK.loadDefinitionsFromDisk(file, {});
|
|
465
|
+
} else {
|
|
466
|
+
this.XLRService.XLRSDK.loadDefinitionsFromDisk(
|
|
467
|
+
file,
|
|
468
|
+
DEFAULT_FILTERS,
|
|
469
|
+
TRANSFORM_FUNCTIONS,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
async setAssetTypesFromModule(manifest: Array<TSManifest>): Promise<void> {
|
|
476
|
+
await Promise.allSettled(
|
|
477
|
+
manifest.map((m) => {
|
|
478
|
+
if (m.capabilities["Types"]?.length) {
|
|
479
|
+
return this.XLRService.XLRSDK.loadDefinitionsFromModule(m);
|
|
480
|
+
} else {
|
|
481
|
+
return this.XLRService.XLRSDK.loadDefinitionsFromModule(
|
|
482
|
+
m,
|
|
483
|
+
DEFAULT_FILTERS,
|
|
484
|
+
TRANSFORM_FUNCTIONS,
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}),
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { test, expect } from "vitest";
|
|
2
|
+
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
3
|
+
import { parse } from "../document";
|
|
4
|
+
|
|
5
|
+
test("parses simple content", () => {
|
|
6
|
+
const document = parse(
|
|
7
|
+
TextDocument.create(
|
|
8
|
+
"foo.json",
|
|
9
|
+
"json",
|
|
10
|
+
1,
|
|
11
|
+
JSON.stringify({
|
|
12
|
+
views: [{ id: "foo" }],
|
|
13
|
+
}),
|
|
14
|
+
),
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(document.root.type).toBe("content");
|
|
18
|
+
});
|