@player-tools/json-language-service 0.13.0-next.3 → 0.13.0-next.5

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.
@@ -0,0 +1,508 @@
1
+ import { DiagnosticSeverity } from "vscode-languageserver-types";
2
+ import type { PlayerLanguageService, PlayerLanguageServicePlugin } from "..";
3
+ import type { ValidationContext, ASTVisitor } from "../types";
4
+ import type { ContentASTNode, ObjectASTNode, StringASTNode } from "../parser";
5
+ import { getProperty } from "../utils";
6
+ import type { ValidationMessage, XLRSDK } from "@player-tools/xlr-sdk";
7
+ import { NamedType, ObjectType, OrType, RefType } from "@player-tools/xlr";
8
+ import { translateSeverity } from "./xlr-plugin";
9
+ import { isObjectType, isPrimitiveTypeNode } from "@player-tools/xlr-utils";
10
+
11
+ function formatErrorMessage(message: string): string {
12
+ return `Schema Validation Error: ${message}`;
13
+ }
14
+
15
+ function makeValidationRefObject(
16
+ baseObject: ObjectType,
17
+ validationFunction: ObjectType,
18
+ ): ObjectType {
19
+ return {
20
+ ...baseObject,
21
+ properties: {
22
+ ...baseObject.properties,
23
+ ...validationFunction.properties,
24
+ },
25
+ additionalProperties: false,
26
+ } as ObjectType;
27
+ }
28
+
29
+ /**
30
+ * Validate that all claimed validations are registered and pass the correct props
31
+ */
32
+ function validateSchemaValidations(
33
+ validationNode: ObjectASTNode,
34
+ sdk: XLRSDK,
35
+ validationContext: ValidationContext,
36
+ ) {
37
+ const claimedValidator = getProperty(validationNode, "type");
38
+ if (!claimedValidator) {
39
+ validationContext.addViolation({
40
+ node: validationNode,
41
+ message: formatErrorMessage('Validation object missing "type" property'),
42
+ severity: DiagnosticSeverity.Error,
43
+ });
44
+ } else if (claimedValidator.valueNode?.type !== "string") {
45
+ validationContext.addViolation({
46
+ node: claimedValidator.valueNode ?? validationNode,
47
+ message: formatErrorMessage("Validation type must be a string"),
48
+ severity: DiagnosticSeverity.Error,
49
+ });
50
+ } else {
51
+ const validationXLR = sdk.getType(claimedValidator.valueNode.value, {
52
+ getRawType: true,
53
+ }) as NamedType<RefType>;
54
+ if (!validationXLR) {
55
+ validationContext.addViolation({
56
+ node: validationNode,
57
+ message: formatErrorMessage(
58
+ `Validation Function ${claimedValidator} is not a registered validator`,
59
+ ),
60
+ severity: DiagnosticSeverity.Error,
61
+ });
62
+ } else {
63
+ const valRef = sdk.getType("Validation.Reference", {
64
+ getRawType: true,
65
+ }) as NamedType<ObjectType> | undefined;
66
+ if (valRef) {
67
+ let validationIssues: ValidationMessage[];
68
+ const validatorFunctionProps = validationXLR.genericArguments?.[0] as
69
+ | ObjectType
70
+ | OrType
71
+ | undefined;
72
+
73
+ if (!validatorFunctionProps || isObjectType(validatorFunctionProps)) {
74
+ validationIssues = sdk.validateByType(
75
+ makeValidationRefObject(
76
+ valRef,
77
+ validatorFunctionProps ?? ({} as ObjectType),
78
+ ),
79
+ validationNode.jsonNode,
80
+ );
81
+ validationIssues.forEach((issue) => {
82
+ validationContext.addViolation({
83
+ node: validationNode,
84
+ message: formatErrorMessage(issue.message),
85
+ severity: translateSeverity(issue.severity),
86
+ });
87
+ });
88
+ } else {
89
+ // need to make sure that only one of the arg groups is right
90
+ const validationResults = validatorFunctionProps.or
91
+ .map((node) => {
92
+ if (isObjectType(node)) {
93
+ return sdk.validateByType(
94
+ makeValidationRefObject(valRef, node),
95
+ validationNode.jsonNode,
96
+ );
97
+ } else {
98
+ validationIssues.forEach((issue) => {
99
+ validationContext.addViolation({
100
+ node: validationNode,
101
+ message: formatErrorMessage(
102
+ `Internal Error - Validation function ${validationXLR.name} type argument is not an object`,
103
+ ),
104
+ severity: DiagnosticSeverity.Error,
105
+ });
106
+ });
107
+ return null;
108
+ }
109
+ })
110
+ .filter((o) => o !== null && Array.isArray(o) && o.length === 0);
111
+
112
+ if (validationResults.length !== 1) {
113
+ validationContext.addViolation({
114
+ node: validationNode,
115
+ message: formatErrorMessage(
116
+ `Validation function invalid function parameters for type ${validationXLR.name}`,
117
+ ),
118
+ severity: DiagnosticSeverity.Error,
119
+ });
120
+ }
121
+ }
122
+ } else {
123
+ validationContext.addViolation({
124
+ node: validationNode,
125
+ message: formatErrorMessage(
126
+ "Validation.Reference from @player-ui/types is not loaded into SDK",
127
+ ),
128
+ severity: DiagnosticSeverity.Error,
129
+ });
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Validate that the format function is registered and passes the correct props
137
+ */
138
+ function validateSchemaFormat(
139
+ formatNode: ObjectASTNode,
140
+ sdk: XLRSDK,
141
+ validationContext: ValidationContext,
142
+ ) {
143
+ const claimedFormatter = getProperty(formatNode, "type");
144
+ if (!claimedFormatter) {
145
+ validationContext.addViolation({
146
+ node: formatNode,
147
+ message: formatErrorMessage('Format object missing "type" property'),
148
+ severity: DiagnosticSeverity.Error,
149
+ });
150
+ } else if (claimedFormatter.valueNode?.type !== "string") {
151
+ validationContext.addViolation({
152
+ node: claimedFormatter.valueNode ?? claimedFormatter,
153
+ message: formatErrorMessage("Format type must be a string"),
154
+ severity: DiagnosticSeverity.Error,
155
+ });
156
+ } else {
157
+ const formatterXLR = sdk.getType(claimedFormatter.valueNode.value, {
158
+ getRawType: true,
159
+ }) as RefType;
160
+ if (!formatterXLR) {
161
+ validationContext.addViolation({
162
+ node: formatNode,
163
+ message: formatErrorMessage(
164
+ `Formatter ${claimedFormatter} is not a registered formatter`,
165
+ ),
166
+ severity: DiagnosticSeverity.Error,
167
+ });
168
+ } else if (
169
+ formatterXLR.genericArguments &&
170
+ formatterXLR.genericArguments.length === 3
171
+ ) {
172
+ const otherArgsXLR = formatterXLR.genericArguments[2] as ObjectType;
173
+ const validationIssues = sdk.validateByType(
174
+ {
175
+ ...otherArgsXLR,
176
+ properties: {
177
+ ...otherArgsXLR.properties,
178
+ type: {
179
+ required: true,
180
+ node: {
181
+ type: "string",
182
+ const: claimedFormatter.valueNode.value,
183
+ },
184
+ },
185
+ },
186
+ },
187
+ formatNode.jsonNode,
188
+ );
189
+
190
+ validationIssues.forEach((issue) => {
191
+ validationContext.addViolation({
192
+ node: formatNode,
193
+ message: formatErrorMessage(issue.message),
194
+ severity: translateSeverity(issue.severity),
195
+ });
196
+ });
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Collects all type names defined at the top level of the schema (ROOT and
203
+ * any custom type names). Used to validate that "type" references either
204
+ * point to a schema type or an XLR-loaded type.
205
+ */
206
+ function getSchemaTypeNames(schemaObj: ObjectASTNode): Set<string> {
207
+ const names = new Set<string>();
208
+ for (const prop of schemaObj.properties) {
209
+ const key = prop.keyNode?.value;
210
+ if (typeof key === "string") {
211
+ names.add(key);
212
+ }
213
+ }
214
+ return names;
215
+ }
216
+
217
+ /**
218
+ * Validates that a Schema.DataType object has the proper structure
219
+ */
220
+ function validateDataTypeStructure(
221
+ dataTypeNode: ObjectASTNode,
222
+ claimedDataType: NamedType<ObjectType>,
223
+ sdk: XLRSDK,
224
+ validationContext: ValidationContext,
225
+ ): void {
226
+ // Basic Structural Tests
227
+ const validationProp = getProperty(dataTypeNode, "validation");
228
+ if (validationProp?.valueNode && validationProp.valueNode.type !== "array") {
229
+ validationContext.addViolation({
230
+ node: validationProp.valueNode,
231
+ message: formatErrorMessage(
232
+ 'Schema.DataType "validation" must be an array.',
233
+ ),
234
+ severity: DiagnosticSeverity.Error,
235
+ });
236
+ } else if (validationProp?.valueNode) {
237
+ validationProp.valueNode.children?.forEach((valRef) => {
238
+ if (valRef && valRef.type === "object") {
239
+ validateSchemaValidations(valRef, sdk, validationContext);
240
+ } else {
241
+ validationContext.addViolation({
242
+ node: validationProp.valueNode ?? dataTypeNode,
243
+ message: formatErrorMessage(
244
+ 'Schema.DataType "validation" must be an object.',
245
+ ),
246
+ severity: DiagnosticSeverity.Error,
247
+ });
248
+ }
249
+ });
250
+ }
251
+
252
+ const formatProp = getProperty(dataTypeNode, "format");
253
+ if (formatProp?.valueNode?.type === "object") {
254
+ validateSchemaFormat(formatProp.valueNode, sdk, validationContext);
255
+ } else {
256
+ if (formatProp) {
257
+ validationContext.addViolation({
258
+ node: formatProp?.valueNode ?? dataTypeNode,
259
+ message: formatErrorMessage(
260
+ 'Schema.DataType "format" must be an object.',
261
+ ),
262
+ severity: DiagnosticSeverity.Error,
263
+ });
264
+ }
265
+ }
266
+
267
+ // Check if default value conforms to the expected value
268
+ const defaultNode = claimedDataType.properties?.["default"]?.node;
269
+ const defaultProp = getProperty(dataTypeNode, "default");
270
+ if (defaultNode && defaultProp?.valueNode) {
271
+ if (isPrimitiveTypeNode(defaultNode)) {
272
+ if (defaultProp.valueNode.type !== defaultNode.type) {
273
+ validationContext.addViolation({
274
+ node: defaultProp.valueNode,
275
+ message: formatErrorMessage(
276
+ `Default value doesn't match the expected type of ${defaultNode.type} for type ${claimedDataType.name}`,
277
+ ),
278
+ severity: DiagnosticSeverity.Error,
279
+ });
280
+ }
281
+ } else if (defaultNode.type === "or") {
282
+ if (!defaultNode.or.some((n) => n.type === defaultProp.valueNode?.type)) {
283
+ validationContext.addViolation({
284
+ node: defaultProp.valueNode,
285
+ message: formatErrorMessage(
286
+ `Default value doesn't match any of the expected types ${defaultNode.or.map((t) => t.type).join(", ")} for type ${claimedDataType.name}`,
287
+ ),
288
+ severity: DiagnosticSeverity.Error,
289
+ });
290
+ }
291
+ } else {
292
+ validationContext.addViolation({
293
+ node: defaultProp.valueNode,
294
+ message: formatErrorMessage(
295
+ `Unknown default node type ${defaultNode.type}`,
296
+ ),
297
+ severity: DiagnosticSeverity.Error,
298
+ });
299
+ }
300
+ }
301
+
302
+ // RecordType/ArrayType Checks
303
+ const isArrayProp = getProperty(dataTypeNode, "isArray");
304
+ const isRecordProp = getProperty(dataTypeNode, "isRecord");
305
+ if (isArrayProp?.valueNode && isArrayProp.valueNode.type !== "boolean") {
306
+ validationContext.addViolation({
307
+ node: isArrayProp.valueNode,
308
+ message: formatErrorMessage(
309
+ 'Schema.DataType "isArray" must be a boolean.',
310
+ ),
311
+ severity: DiagnosticSeverity.Error,
312
+ });
313
+ }
314
+ if (isRecordProp?.valueNode && isRecordProp.valueNode.type !== "boolean") {
315
+ validationContext.addViolation({
316
+ node: isRecordProp.valueNode,
317
+ message: formatErrorMessage(
318
+ 'Schema.DataType "isRecord" must be a boolean.',
319
+ ),
320
+ severity: DiagnosticSeverity.Error,
321
+ });
322
+ }
323
+
324
+ if (
325
+ isArrayProp?.valueNode &&
326
+ isRecordProp?.valueNode &&
327
+ (isArrayProp.valueNode as { value?: boolean }).value === true &&
328
+ (isRecordProp.valueNode as { value?: boolean }).value === true
329
+ ) {
330
+ validationContext.addViolation({
331
+ node: dataTypeNode,
332
+ message: formatErrorMessage(
333
+ 'Schema.DataType cannot have both "isArray" and "isRecord" true.',
334
+ ),
335
+ severity: DiagnosticSeverity.Error,
336
+ });
337
+ }
338
+ }
339
+
340
+ /**
341
+ * Validates a single schema node (e.g. ROOT or a custom type): each property
342
+ * must be an object with a "type" field (Schema.DataType), full structure
343
+ * validation, known type reference (schema or XLR), and when the type is an
344
+ * XLR type, validates the DataType object against the XLR definition via the SDK.
345
+ */
346
+ function validateSchemaNode(
347
+ node: ObjectASTNode,
348
+ schemaTypeNames: Set<string>,
349
+ sdk: XLRSDK,
350
+ validationContext: ValidationContext,
351
+ ): void {
352
+ for (const prop of node.properties) {
353
+ const valueNode = prop.valueNode;
354
+ if (!(valueNode && valueNode.type === "object")) {
355
+ if (valueNode) {
356
+ validationContext.addViolation({
357
+ node: valueNode,
358
+ message: formatErrorMessage(
359
+ `Schema property "${prop.keyNode.value}" must be an object (Schema.DataType) with a "type" field.`,
360
+ ),
361
+ severity: DiagnosticSeverity.Error,
362
+ });
363
+ }
364
+ continue;
365
+ }
366
+
367
+ const dataTypeNode = valueNode as ObjectASTNode;
368
+ const typeProp = getProperty(dataTypeNode, "type");
369
+ if (!typeProp) {
370
+ validationContext.addViolation({
371
+ node: valueNode,
372
+ message: formatErrorMessage(
373
+ 'Schema.DataType must have a "type" property (reference to schema or XLR type).',
374
+ ),
375
+ severity: DiagnosticSeverity.Error,
376
+ });
377
+ continue;
378
+ }
379
+
380
+ const typeValueNode = typeProp.valueNode;
381
+ if (!typeValueNode || typeValueNode.type !== "string") {
382
+ validationContext.addViolation({
383
+ node: typeValueNode ?? typeProp,
384
+ message: formatErrorMessage(
385
+ 'Schema "type" must be a string (schema type name or XLR type name).',
386
+ ),
387
+ severity: DiagnosticSeverity.Error,
388
+ });
389
+ continue;
390
+ }
391
+
392
+ const typeName = (typeValueNode as StringASTNode).value;
393
+ const isSchemaType = schemaTypeNames.has(typeName);
394
+ const XLRType = sdk.getType(typeName, { getRawType: true });
395
+
396
+ if (!isSchemaType && !XLRType) {
397
+ validationContext.addViolation({
398
+ node: typeValueNode,
399
+ message: formatErrorMessage(
400
+ `Unknown schema type "${typeName}". Type must be a schema type (key in this schema) or an XLR type loaded in the SDK.`,
401
+ ),
402
+ severity: DiagnosticSeverity.Error,
403
+ });
404
+ } else if (XLRType) {
405
+ /** Full DataType structure per @player-ui/types */
406
+ validateDataTypeStructure(
407
+ dataTypeNode,
408
+ XLRType as NamedType<ObjectType>,
409
+ sdk,
410
+ validationContext,
411
+ );
412
+ }
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Validates the Flow's schema property: structure per Schema.Schema,
418
+ * type references, full DataType structure, and XLR shape when type is an XLR type.
419
+ */
420
+ function validateFlowSchema(
421
+ contentNode: ContentASTNode,
422
+ sdk: XLRSDK,
423
+ validationContext: ValidationContext,
424
+ ): void {
425
+ const schemaProp = getProperty(contentNode, "schema");
426
+ if (!schemaProp?.valueNode) {
427
+ return;
428
+ }
429
+
430
+ const schemaValue = schemaProp.valueNode;
431
+ if (schemaValue.type !== "object") {
432
+ validationContext.addViolation({
433
+ node: schemaValue,
434
+ message: formatErrorMessage(
435
+ 'Flow "schema" must be an object with at least a "ROOT" key.',
436
+ ),
437
+ severity: DiagnosticSeverity.Error,
438
+ });
439
+ return;
440
+ }
441
+
442
+ const schemaObj = schemaValue as ObjectASTNode;
443
+ const hasRoot = schemaObj.properties.some((p) => p.keyNode.value === "ROOT");
444
+
445
+ if (!hasRoot) {
446
+ validationContext.addViolation({
447
+ node: schemaValue,
448
+ message: formatErrorMessage('Schema must have a "ROOT" key.'),
449
+ severity: DiagnosticSeverity.Error,
450
+ });
451
+ }
452
+
453
+ const schemaTypeNames = getSchemaTypeNames(schemaObj);
454
+
455
+ for (const prop of schemaObj.properties) {
456
+ const nodeValue = prop.valueNode;
457
+ if (!nodeValue || nodeValue.type !== "object") {
458
+ if (nodeValue) {
459
+ validationContext.addViolation({
460
+ node: nodeValue,
461
+ message: formatErrorMessage(
462
+ `Schema node "${prop.keyNode.value}" must be an object.`,
463
+ ),
464
+ severity: DiagnosticSeverity.Error,
465
+ });
466
+ }
467
+ continue;
468
+ }
469
+
470
+ validateSchemaNode(
471
+ nodeValue as ObjectASTNode,
472
+ schemaTypeNames,
473
+ sdk,
474
+ validationContext,
475
+ );
476
+ }
477
+ }
478
+
479
+ /**
480
+ * Plugin that registers schema validation with the Player Language Service.
481
+ */
482
+ export class SchemaValidationPlugin implements PlayerLanguageServicePlugin {
483
+ name = "schema-validation";
484
+
485
+ /** Resolved when CommonTypes have been loaded into the XLR SDK (once per plugin apply) */
486
+ private commonTypesLoaded: Promise<void> | null = null;
487
+
488
+ apply(service: PlayerLanguageService): void {
489
+ service.hooks.validate.tap(this.name, async (_ctx, validationContext) => {
490
+ await this.commonTypesLoaded;
491
+ validationContext.useASTVisitor(
492
+ this.createValidationVisitor(service, validationContext),
493
+ );
494
+ });
495
+ }
496
+
497
+ private createValidationVisitor(
498
+ service: PlayerLanguageService,
499
+ validationContext: ValidationContext,
500
+ ): ASTVisitor {
501
+ const sdk = service.XLRService.XLRSDK;
502
+ return {
503
+ ContentNode: (contentNode) => {
504
+ validateFlowSchema(contentNode, sdk, validationContext);
505
+ },
506
+ };
507
+ }
508
+ }
@@ -14,7 +14,7 @@ import type {
14
14
  PlayerLanguageServicePlugin,
15
15
  ValidationContext,
16
16
  } from "..";
17
- import { mapFlowStateToType } from "../utils";
17
+ import { findErrorNode, mapFlowStateToType } from "../utils";
18
18
  import type { ASTNode, ObjectASTNode } from "../parser";
19
19
  import type { EnhancedDocumentContextWithPosition } from "../types";
20
20
 
@@ -22,30 +22,11 @@ function isError(issue: ValidationMessage): boolean {
22
22
  return issue.severity === DiagnosticSeverity.Error;
23
23
  }
24
24
 
25
- /** BFS search to find a JSONC node in children of some AST Node */
26
- const findErrorNode = (rootNode: ASTNode, nodeToFind: Node): ASTNode => {
27
- const children: Array<ASTNode> = [rootNode];
28
-
29
- while (children.length > 0) {
30
- const child = children.pop() as ASTNode;
31
- if (child.jsonNode === nodeToFind) {
32
- return child;
33
- }
34
-
35
- if (child.children) {
36
- children.push(...child.children);
37
- }
38
- }
39
-
40
- // if the node can't be found return the original
41
- return rootNode;
42
- };
43
-
44
25
  /**
45
26
  * Translates an SDK severity level to an LSP severity level
46
27
  * Relies on both levels having the values associated to the underlying levels
47
28
  */
48
- const translateSeverity = (
29
+ export const translateSeverity = (
49
30
  severity: ValidationSeverity,
50
31
  ): DiagnosticSeverity => {
51
32
  return severity as DiagnosticSeverity;
package/src/utils.ts CHANGED
@@ -7,6 +7,7 @@ import type {
7
7
  ObjectASTNode,
8
8
  PropertyASTNode,
9
9
  } from "./parser";
10
+ import type { Node } from "jsonc-parser";
10
11
  import type { ASTVisitor } from "./types";
11
12
 
12
13
  export const typeToVisitorMap: Record<ASTNode["type"], keyof ASTVisitor> = {
@@ -141,3 +142,22 @@ export function mapFlowStateToType(
141
142
 
142
143
  return flowXLR;
143
144
  }
145
+
146
+ /** BFS search to find a JSONC node in children of some AST Node */
147
+ export const findErrorNode = (rootNode: ASTNode, nodeToFind: Node): ASTNode => {
148
+ const children: Array<ASTNode> = [rootNode];
149
+
150
+ while (children.length > 0) {
151
+ const child = children.pop() as ASTNode;
152
+ if (child.jsonNode === nodeToFind) {
153
+ return child;
154
+ }
155
+
156
+ if (child.children) {
157
+ children.push(...child.children);
158
+ }
159
+ }
160
+
161
+ // if the node can't be found return the original
162
+ return rootNode;
163
+ };
@@ -2,6 +2,8 @@ import type { Filters, TypeMetadata } from "@player-tools/xlr-sdk";
2
2
  import { BasicXLRRegistry } from "@player-tools/xlr-sdk";
3
3
  import type { NamedType, NodeType } from "@player-tools/xlr";
4
4
 
5
+ const SINGLE_INSTANCE_CAPABILITIES = ["DataTypes", "Formatters", "Validators"];
6
+
5
7
  /**
6
8
  * Player specific implementation of a XLRs Registry
7
9
  */
@@ -47,7 +49,10 @@ export class PlayerXLRRegistry extends BasicXLRRegistry {
47
49
  registeredName = type.extends.genericArguments[0].const;
48
50
  }
49
51
 
50
- if (this.registrationMap.has(registeredName)) {
52
+ if (
53
+ this.registrationMap.has(registeredName) &&
54
+ !SINGLE_INSTANCE_CAPABILITIES.includes(capability)
55
+ ) {
51
56
  const current = this.registrationMap.get(registeredName) as
52
57
  | string
53
58
  | string[];
@@ -0,0 +1,12 @@
1
+ import type { PlayerLanguageService, PlayerLanguageServicePlugin } from "..";
2
+ /**
3
+ * Plugin that registers schema validation with the Player Language Service.
4
+ */
5
+ export declare class SchemaValidationPlugin implements PlayerLanguageServicePlugin {
6
+ name: string;
7
+ /** Resolved when CommonTypes have been loaded into the XLR SDK (once per plugin apply) */
8
+ private commonTypesLoaded;
9
+ apply(service: PlayerLanguageService): void;
10
+ private createValidationVisitor;
11
+ }
12
+ //# sourceMappingURL=schema-validation-plugin.d.ts.map
@@ -1,4 +1,11 @@
1
+ import { ValidationSeverity } from "@player-tools/xlr-sdk";
2
+ import { DiagnosticSeverity } from "vscode-languageserver-types";
1
3
  import type { PlayerLanguageService, PlayerLanguageServicePlugin } from "..";
4
+ /**
5
+ * Translates an SDK severity level to an LSP severity level
6
+ * Relies on both levels having the values associated to the underlying levels
7
+ */
8
+ export declare const translateSeverity: (severity: ValidationSeverity) => DiagnosticSeverity;
2
9
  /** The plugin to enable duplicate id checking/fixing */
3
10
  export declare class XLRPlugin implements PlayerLanguageServicePlugin {
4
11
  name: string;
package/types/utils.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Range, Location } from "vscode-languageserver-types";
2
2
  import { TextDocument } from "vscode-languageserver-textdocument";
3
3
  import type { ASTNode, PlayerContent, PropertyASTNode } from "./parser";
4
+ import type { Node } from "jsonc-parser";
4
5
  import type { ASTVisitor } from "./types";
5
6
  export declare const typeToVisitorMap: Record<ASTNode["type"], keyof ASTVisitor>;
6
7
  /** Check to see if the source range contains the target one */
@@ -21,4 +22,6 @@ export declare function getLSLocationOfNode(document: TextDocument, node: ASTNod
21
22
  export declare function formatLikeNode(document: TextDocument, originalNode: ASTNode, replacement: Record<string, unknown>): string;
22
23
  /** Maps the string identifying the FlowType to the named type */
23
24
  export declare function mapFlowStateToType(flowType: string | undefined): string | undefined;
25
+ /** BFS search to find a JSONC node in children of some AST Node */
26
+ export declare const findErrorNode: (rootNode: ASTNode, nodeToFind: Node) => ASTNode;
24
27
  //# sourceMappingURL=utils.d.ts.map