@spyglassmc/mcdoc 0.1.1 → 0.3.1

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.
@@ -1,19 +1,706 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./uriBinder"), exports);
18
- __exportStar(require("./util"), exports);
1
+ import { AsyncBinder, atArray, Dev, Range, ResourceLocationNode, SymbolUtil, traversePreOrder } from '@spyglassmc/core';
2
+ import { localeQuote, localize } from '@spyglassmc/locales';
3
+ import { AttributeNode, AttributeTreeNamedValuesNode, AttributeTreeNode, AttributeTreePosValuesNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, DynamicIndexNode, EnumBlockNode, EnumFieldNode, EnumInjectionNode, EnumNode, FloatRangeNode, IndexBodyNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StaticIndexNode, StringTypeNode, StructBlockNode, StructMapKeyNode, StructNode, StructPairFieldNode, StructSpreadFieldNode, TopLevelNode, TupleTypeNode, TypeAliasNode, TypeBaseNode, TypedNumberNode, TypeParamBlockNode, TypeParamNode, UnionTypeNode, UseStatementNode } from '../node/index.js';
4
+ const ModuleSymbolData = Object.freeze({
5
+ is(data) {
6
+ return !!data && typeof data === 'object' && typeof data.nextAnonymousIndex === 'number';
7
+ },
8
+ });
9
+ const TypeDefSymbolData = Object.freeze({
10
+ is(data) {
11
+ return !!data && typeof data === 'object' && typeof data.typeDef === 'object';
12
+ },
13
+ });
14
+ export const fileModule = AsyncBinder.create(async (node, ctx) => {
15
+ const moduleIdentifier = uriToIdentifier(ctx.doc.uri, ctx);
16
+ if (!moduleIdentifier) {
17
+ ctx.err.report(localize('mcdoc.binder.out-of-root', localeQuote(ctx.doc.uri)), Range.Beginning, 0 /* ErrorSeverity.Hint */);
18
+ return;
19
+ }
20
+ const mcdocCtx = {
21
+ ...ctx,
22
+ moduleIdentifier,
23
+ };
24
+ return module_(node, mcdocCtx);
25
+ });
26
+ export async function module_(node, ctx) {
27
+ const data = { nextAnonymousIndex: 0 };
28
+ ctx.symbols
29
+ .query({ doc: ctx.doc, node }, 'mcdoc', ctx.moduleIdentifier)
30
+ .amend({ data: { data } });
31
+ hoist(node, ctx);
32
+ for (const child of node.children) {
33
+ switch (child.type) {
34
+ case 'mcdoc:dispatch_statement':
35
+ await bindDispatchStatement(child, ctx);
36
+ break;
37
+ case 'mcdoc:enum':
38
+ bindEnum(child, ctx);
39
+ break;
40
+ case 'mcdoc:injection':
41
+ await bindInjection(child, ctx);
42
+ break;
43
+ case 'mcdoc:struct':
44
+ await bindStruct(child, ctx);
45
+ break;
46
+ case 'mcdoc:type_alias':
47
+ await bindTypeAlias(child, ctx);
48
+ break;
49
+ case 'mcdoc:use_statement':
50
+ await bindUseStatement(child, ctx);
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Hoist enums, structs, type aliases, and use statements under the module scope.
57
+ */
58
+ function hoist(node, ctx) {
59
+ traversePreOrder(node, () => true, TopLevelNode.is, child => {
60
+ switch (child.type) {
61
+ case 'mcdoc:enum':
62
+ hoistEnum(child);
63
+ break;
64
+ case 'mcdoc:struct':
65
+ hoistStruct(child);
66
+ break;
67
+ case 'mcdoc:type_alias':
68
+ hoistTypeAlias(child);
69
+ break;
70
+ case 'mcdoc:use_statement':
71
+ hoistUseStatement(child);
72
+ break;
73
+ }
74
+ });
75
+ function hoistEnum(node) {
76
+ hoistFor('enum', node, EnumNode.destruct, n => ({ typeDef: convertEnum(n, ctx) }));
77
+ }
78
+ function hoistStruct(node) {
79
+ hoistFor('struct', node, StructNode.destruct, n => ({ typeDef: convertStruct(n, ctx) }));
80
+ }
81
+ function hoistTypeAlias(node) {
82
+ hoistFor('type_alias', node, TypeAliasNode.destruct, n => {
83
+ const { rhs } = TypeAliasNode.destruct(n);
84
+ if (!rhs) {
85
+ return undefined;
86
+ }
87
+ return { typeDef: convertType(rhs, ctx) };
88
+ });
89
+ }
90
+ function hoistUseStatement(node) {
91
+ const { binding, path } = UseStatementNode.destruct(node);
92
+ if (!path) {
93
+ return;
94
+ }
95
+ const { lastIdentifier } = PathNode.destruct(path);
96
+ const identifier = binding ?? lastIdentifier;
97
+ if (!identifier) {
98
+ return;
99
+ }
100
+ // hoistUseStatement associates the AST node with the binding definition in the file symbol table,
101
+ // which may get overridden by bindUseStatement in the later stage as an reference to the imported symbol in the global symbol table.
102
+ // This way when the user tries to go to definition on the path in the use statement,
103
+ // they will go to the definition in the imported file.
104
+ ctx.symbols
105
+ .query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`)
106
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
107
+ .elseEnter({
108
+ data: { subcategory: 'use_statement_binding', visibility: 1 /* SymbolVisibility.File */ },
109
+ usage: { type: 'definition', node: identifier, fullRange: node },
110
+ });
111
+ }
112
+ function hoistFor(subcategory, node, destructor, getData) {
113
+ const { docComments, identifier, keyword } = destructor(node);
114
+ const name = identifier?.value ?? nextAnonymousIdentifier(node, ctx);
115
+ ctx.symbols
116
+ .query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${name}`)
117
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier ?? node))
118
+ .elseEnter({
119
+ data: { data: getData(node), desc: DocCommentsNode.asText(docComments), subcategory },
120
+ // If the current syntax structure is named, then the identifier node is entered as a definition;
121
+ // otherwise, an anonymous identifier is generated for the symbol and the keyword node is entered as a definition.
122
+ usage: { type: 'definition', node: identifier ?? keyword, fullRange: identifier && node },
123
+ });
124
+ }
125
+ function nextAnonymousIndex(node, ctx) {
126
+ const data = ctx.symbols
127
+ .query({ doc: ctx.doc, node }, 'mcdoc', ctx.moduleIdentifier)
128
+ .getData(ModuleSymbolData.is);
129
+ if (!data) {
130
+ throw new Error(`No symbol data for module '${ctx.moduleIdentifier}'`);
131
+ }
132
+ return data.nextAnonymousIndex++;
133
+ }
134
+ function nextAnonymousIdentifier(node, ctx) {
135
+ return `<anonymous ${nextAnonymousIndex(node, ctx)}>`;
136
+ }
137
+ }
138
+ async function bindDispatchStatement(node, ctx) {
139
+ const { attributes, location, index, target } = DispatchStatementNode.destruct(node);
140
+ if (!(location && index && target)) {
141
+ return;
142
+ }
143
+ const locationStr = ResourceLocationNode.toString(location, 'full');
144
+ ctx.symbols
145
+ .query(ctx.doc, 'mcdoc/dispatcher', locationStr)
146
+ .enter({
147
+ usage: { type: 'reference', node: location, fullRange: node },
148
+ });
149
+ const { parallelIndices } = IndexBodyNode.destruct(index);
150
+ for (const key of parallelIndices) {
151
+ if (DynamicIndexNode.is(key)) {
152
+ // Ignore dynamic indices in dispatch statements.
153
+ continue;
154
+ }
155
+ ctx.symbols
156
+ .query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
157
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key, { localeString: 'mcdoc.binder.dispatcher-statement.duplicated-key' }))
158
+ .elseEnter({
159
+ data: {
160
+ data: {
161
+ attributes: convertAttributes(attributes, ctx),
162
+ typeDef: convertType(target, ctx),
163
+ },
164
+ },
165
+ usage: { type: 'definition', node: key, fullRange: node },
166
+ });
167
+ }
168
+ await bindType(target, ctx);
169
+ }
170
+ async function bindType(node, ctx) {
171
+ if (DispatcherTypeNode.is(node)) {
172
+ bindDispatcherType(node, ctx);
173
+ }
174
+ else if (EnumNode.is(node)) {
175
+ bindEnum(node, ctx);
176
+ }
177
+ else if (ListTypeNode.is(node)) {
178
+ const { item } = ListTypeNode.destruct(node);
179
+ await bindType(item, ctx);
180
+ }
181
+ else if (ReferenceTypeNode.is(node)) {
182
+ const { path, typeParameters } = ReferenceTypeNode.destruct(node);
183
+ await bindPath(path, ctx);
184
+ for (const param of typeParameters) {
185
+ await bindType(param, ctx);
186
+ }
187
+ }
188
+ else if (StructNode.is(node)) {
189
+ await bindStruct(node, ctx);
190
+ }
191
+ else if (TupleTypeNode.is(node)) {
192
+ const { items } = TupleTypeNode.destruct(node);
193
+ for (const item of items) {
194
+ await bindType(item, ctx);
195
+ }
196
+ }
197
+ else if (UnionTypeNode.is(node)) {
198
+ const { members } = UnionTypeNode.destruct(node);
199
+ for (const member of members) {
200
+ await bindType(member, ctx);
201
+ }
202
+ }
203
+ }
204
+ function bindDispatcherType(node, ctx) {
205
+ const { index, location } = DispatcherTypeNode.destruct(node);
206
+ const locationStr = ResourceLocationNode.toString(location, 'full');
207
+ const { parallelIndices } = IndexBodyNode.destruct(index);
208
+ for (const key of parallelIndices) {
209
+ if (DynamicIndexNode.is(key)) {
210
+ // Although it is technically possible to bind some of the dynamic indices as references
211
+ // of struct keys, it is rather complicated to do so. We will ignore them for now.
212
+ continue;
213
+ }
214
+ ctx.symbols
215
+ .query(ctx.doc, 'mcdoc/dispatcher', locationStr, asString(key))
216
+ .enter({ usage: { type: 'reference', node: key, fullRange: node } });
217
+ }
218
+ }
219
+ async function bindPath(node, ctx) {
220
+ for (const { identifiers, node: identNode, indexRight } of resolvePathByStep(node, ctx, { reportErrors: true })) {
221
+ if (!identifiers?.length) {
222
+ continue;
223
+ }
224
+ if (indexRight === 1) {
225
+ // The second last identifier in a path points to a file module.
226
+ const referencedModuleFile = pathArrayToString(identifiers);
227
+ const referencedModuleUri = identifierToUri(referencedModuleFile, ctx);
228
+ if (!referencedModuleUri) {
229
+ ctx.err.report(localize('mcdoc.binder.path.unknown-module', localeQuote(referencedModuleFile)), node, 2 /* ErrorSeverity.Warning */);
230
+ return;
231
+ }
232
+ await ctx.ensureBindingStarted(referencedModuleUri);
233
+ }
234
+ ctx.symbols
235
+ .query({ doc: ctx.doc, node: identNode }, 'mcdoc', pathArrayToString(identifiers))
236
+ .ifDeclared((_, query) => query.enter({
237
+ usage: { type: 'reference', node: identNode, fullRange: node, skipRenaming: LiteralNode.is(identNode) },
238
+ }))
239
+ .else(() => {
240
+ if (indexRight === 0) {
241
+ ctx.err.report(localize('mcdoc.binder.path.unknown-identifier', localeQuote(atArray(identifiers, -1)), localeQuote(pathArrayToString(identifiers.slice(0, -1)))), node, 2 /* ErrorSeverity.Warning */);
242
+ }
243
+ });
244
+ }
245
+ }
246
+ function bindEnum(node, ctx) {
247
+ const { block, identifier, keyword } = EnumNode.destruct(node);
248
+ const symbol = identifier?.symbol ?? keyword.symbol;
249
+ if (symbol?.subcategory !== 'enum') {
250
+ return;
251
+ }
252
+ const query = ctx.symbols.query({ doc: ctx.doc, node }, 'mcdoc', ...symbol.path);
253
+ Dev.assertDefined(query.symbol);
254
+ bindEnumBlock(block, ctx, query);
255
+ }
256
+ function bindEnumBlock(node, ctx, query, options = {}) {
257
+ const { fields } = EnumBlockNode.destruct(node);
258
+ for (const field of fields) {
259
+ const { identifier } = EnumFieldNode.destruct(field);
260
+ query.member(identifier.value, fieldQuery => fieldQuery
261
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, identifier))
262
+ .elseEnter({ usage: { type: 'definition', node: identifier, fullRange: field } }));
263
+ }
264
+ }
265
+ async function bindInjection(node, ctx) {
266
+ const { injection } = InjectionNode.destruct(node);
267
+ if (EnumInjectionNode.is(injection)) {
268
+ // TODO
269
+ // const { } = EnumInjectionNode.destruct(injection)
270
+ // bindEnumBlock(block, ctx, query, { extendsTypeDefData: true })
271
+ }
272
+ }
273
+ async function bindStruct(node, ctx) {
274
+ const { block, identifier, keyword } = StructNode.destruct(node);
275
+ const symbol = identifier?.symbol ?? keyword.symbol;
276
+ if (symbol?.subcategory !== 'struct') {
277
+ return;
278
+ }
279
+ const query = ctx.symbols.query({ doc: ctx.doc, node }, 'mcdoc', ...symbol.path);
280
+ Dev.assertDefined(query.symbol);
281
+ await bindStructBlock(block, ctx, query);
282
+ }
283
+ async function bindStructBlock(node, ctx, query, options = {}) {
284
+ const { fields } = StructBlockNode.destruct(node);
285
+ for (const field of fields) {
286
+ if (StructPairFieldNode.is(field)) {
287
+ const { key, type } = StructPairFieldNode.destruct(field);
288
+ if (!StructMapKeyNode.is(key)) {
289
+ query.member(key.value, fieldQuery => fieldQuery
290
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, key))
291
+ .elseEnter({ usage: { type: 'definition', node: key, fullRange: field } }));
292
+ }
293
+ await bindType(type, ctx);
294
+ }
295
+ else {
296
+ const { type } = StructSpreadFieldNode.destruct(field);
297
+ await bindType(type, ctx);
298
+ }
299
+ }
300
+ }
301
+ async function bindTypeAlias(node, ctx) {
302
+ const { identifier, rhs, typeParams } = TypeAliasNode.destruct(node);
303
+ if (!identifier?.value) {
304
+ return;
305
+ }
306
+ if (typeParams) {
307
+ // Type parameters are added as local symbols on the type alias AST node.
308
+ node.locals = Object.create(null);
309
+ const { params } = TypeParamBlockNode.destruct(typeParams);
310
+ const query = ctx.symbols.query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${identifier.value}`);
311
+ if (query.symbol?.subcategory === 'type_alias') {
312
+ // Type parameters are also added to the symbol data.
313
+ const oldData = query.symbol.data;
314
+ if (!TypeDefSymbolData.is(oldData)) {
315
+ throw new Error('Failed to locate the typeDef data associated with a supposedly hoisted type alias symbol');
316
+ }
317
+ const data = {
318
+ ...oldData,
319
+ typeParams: [],
320
+ };
321
+ query.symbol.data = data;
322
+ for (const param of params) {
323
+ const { identifier: paramIdentifier } = TypeParamNode.destruct(param);
324
+ if (paramIdentifier.value) {
325
+ // Add the type parameter as a local symbol.
326
+ ctx.symbols
327
+ .query({ doc: ctx.doc, node }, 'mcdoc', `${ctx.moduleIdentifier}::${paramIdentifier.value}`)
328
+ .ifDeclared(symbol => reportDuplicatedDeclaration(ctx, symbol, paramIdentifier))
329
+ .elseEnter({ data: { visibility: 0 /* SymbolVisibility.Block */ }, usage: { type: 'declaration', node: paramIdentifier, fullRange: param } });
330
+ // Also add it to the symbol data.
331
+ data.typeParams.push({ identifier: paramIdentifier.value });
332
+ }
333
+ // if (constraint) {
334
+ // await bindPath(constraint, ctx)
335
+ // }
336
+ }
337
+ }
338
+ }
339
+ if (rhs) {
340
+ await bindType(rhs, ctx);
341
+ }
342
+ }
343
+ async function bindUseStatement(node, ctx) {
344
+ const { path } = UseStatementNode.destruct(node);
345
+ if (!path) {
346
+ return;
347
+ }
348
+ return bindPath(path, ctx);
349
+ }
350
+ export function registerMcdocBinders(meta) {
351
+ meta.registerBinder('mcdoc:module', fileModule);
352
+ }
353
+ function reportDuplicatedDeclaration(ctx, symbol, range, options = { localeString: 'mcdoc.binder.duplicated-declaration' }) {
354
+ ctx.err.report(localize(options.localeString, localeQuote(symbol.identifier)), range, 2 /* ErrorSeverity.Warning */, {
355
+ related: [{
356
+ location: SymbolUtil.getDeclaredLocation(symbol),
357
+ message: localize(`${options.localeString}.related`, localeQuote(symbol.identifier)),
358
+ }],
359
+ });
360
+ }
361
+ function* resolvePathByStep(path, ctx, options = {}) {
362
+ const { children, isAbsolute } = PathNode.destruct(path);
363
+ const identifiers = isAbsolute
364
+ ? []
365
+ : ctx.moduleIdentifier.slice(2).split('::');
366
+ for (const [i, child] of children.entries()) {
367
+ switch (child.type) {
368
+ case 'mcdoc:identifier':
369
+ identifiers.push(child.value);
370
+ break;
371
+ case 'mcdoc:literal':
372
+ // super
373
+ if (identifiers.length === 0) {
374
+ if (options.reportErrors) {
375
+ ctx.err.report(localize('mcdoc.binder.path.super-from-root'), child);
376
+ }
377
+ return;
378
+ }
379
+ identifiers.pop();
380
+ break;
381
+ default:
382
+ Dev.assertNever(child);
383
+ }
384
+ yield { identifiers, node: child, index: i, indexRight: children.length - 1 - i };
385
+ }
386
+ }
387
+ function resolvePath(path, ctx, options = {}) {
388
+ return atArray([...resolvePathByStep(path, ctx, options)], -1)?.identifiers;
389
+ }
390
+ function identifierToUri(module, ctx) {
391
+ return ctx.symbols.global.mcdoc?.[module]?.definition?.[0]?.uri;
392
+ }
393
+ function uriToIdentifier(uri, ctx) {
394
+ return Object
395
+ .values(ctx.symbols.global.mcdoc ?? {})
396
+ .find(symbol => {
397
+ return symbol.subcategory === 'module' && symbol.definition?.some(loc => loc.uri === uri);
398
+ })
399
+ ?.identifier;
400
+ }
401
+ function pathArrayToString(path) {
402
+ return path ? `::${path.join('::')}` : undefined;
403
+ }
404
+ function convertType(node, ctx) {
405
+ switch (node.type) {
406
+ case 'mcdoc:enum': return convertEnum(node, ctx);
407
+ case 'mcdoc:struct': return convertStruct(node, ctx);
408
+ case 'mcdoc:type/any': return convertAny(node, ctx);
409
+ case 'mcdoc:type/boolean': return convertBoolean(node, ctx);
410
+ case 'mcdoc:type/dispatcher': return convertDispatcher(node, ctx);
411
+ case 'mcdoc:type/list': return convertList(node, ctx);
412
+ case 'mcdoc:type/literal': return convertLiteral(node, ctx);
413
+ case 'mcdoc:type/numeric_type': return convertNumericType(node, ctx);
414
+ case 'mcdoc:type/primitive_array': return convertPrimitiveArray(node, ctx);
415
+ case 'mcdoc:type/string': return convertString(node, ctx);
416
+ case 'mcdoc:type/reference': return convertReference(node, ctx);
417
+ case 'mcdoc:type/tuple': return convertTuple(node, ctx);
418
+ case 'mcdoc:type/union': return convertUnion(node, ctx);
419
+ default: return Dev.assertNever(node);
420
+ }
421
+ }
422
+ function convertBase(node, ctx, options = {}) {
423
+ const { attributes, indices } = TypeBaseNode.destruct(node);
424
+ return {
425
+ attributes: convertAttributes(attributes, ctx),
426
+ indices: convertIndexBodies(options.skipFirstIndexBody ? indices.slice(1) : indices, ctx),
427
+ };
428
+ }
429
+ function convertAttributes(nodes, ctx) {
430
+ return undefineEmptyArray(nodes.map(n => convertAttribute(n, ctx)));
431
+ }
432
+ function undefineEmptyArray(array) {
433
+ return array.length ? array : undefined;
434
+ }
435
+ function convertAttribute(node, ctx) {
436
+ const { name, value } = AttributeNode.destruct(node);
437
+ return {
438
+ name: name.value,
439
+ value: value && convertAttributeValue(value, ctx),
440
+ };
441
+ }
442
+ function convertAttributeValue(node, ctx) {
443
+ if (node.type === 'mcdoc:attribute/tree') {
444
+ return {
445
+ kind: 'tree',
446
+ values: convertAttributeTree(node, ctx),
447
+ };
448
+ }
449
+ else {
450
+ return convertType(node, ctx);
451
+ }
452
+ }
453
+ function convertAttributeTree(node, ctx) {
454
+ const ans = {};
455
+ const { named, positional } = AttributeTreeNode.destruct(node);
456
+ if (positional) {
457
+ const { values } = AttributeTreePosValuesNode.destruct(positional);
458
+ for (const [i, child] of values.entries()) {
459
+ ans[i] = convertAttributeValue(child, ctx);
460
+ }
461
+ }
462
+ if (named) {
463
+ const { values } = AttributeTreeNamedValuesNode.destruct(named);
464
+ for (const { key, value } of values) {
465
+ ans[key.value] = convertAttributeValue(value, ctx);
466
+ }
467
+ }
468
+ return ans;
469
+ }
470
+ function convertIndexBodies(nodes, ctx) {
471
+ return undefineEmptyArray(nodes.map(n => convertIndexBody(n, ctx)));
472
+ }
473
+ function convertIndexBody(node, ctx) {
474
+ const { parallelIndices } = IndexBodyNode.destruct(node);
475
+ return parallelIndices.map(n => convertIndex(n, ctx));
476
+ }
477
+ function convertIndex(node, ctx) {
478
+ return StaticIndexNode.is(node)
479
+ ? convertStaticIndex(node, ctx)
480
+ : convertDynamicIndex(node, ctx);
481
+ }
482
+ function convertStaticIndex(node, ctx) {
483
+ return {
484
+ kind: 'static',
485
+ value: asString(node),
486
+ };
487
+ }
488
+ function convertDynamicIndex(node, ctx) {
489
+ const { keys } = DynamicIndexNode.destruct(node);
490
+ return {
491
+ kind: 'dynamic',
492
+ accessor: keys.map(asString),
493
+ };
494
+ }
495
+ function convertEnum(node, ctx) {
496
+ const { block, enumKind, identifier } = EnumNode.destruct(node);
497
+ // Shortcut if the typeDef has been added to the enum symbol.
498
+ const symbol = identifier?.symbol ?? node.symbol;
499
+ if (symbol && TypeDefSymbolData.is(symbol.data) && symbol.data.typeDef.kind === 'enum') {
500
+ return symbol.data.typeDef;
501
+ }
502
+ return {
503
+ ...convertBase(node, ctx),
504
+ kind: 'enum',
505
+ enumKind,
506
+ values: convertEnumBlock(block, ctx),
507
+ };
508
+ }
509
+ function convertEnumBlock(node, ctx) {
510
+ const { fields } = EnumBlockNode.destruct(node);
511
+ return fields.map(n => convertEnumField(n, ctx));
512
+ }
513
+ function convertEnumField(node, ctx) {
514
+ const { attributes, identifier, value } = EnumFieldNode.destruct(node);
515
+ return {
516
+ attributes: convertAttributes(attributes, ctx),
517
+ identifier: identifier.value,
518
+ value: convertEnumValue(value, ctx),
519
+ };
520
+ }
521
+ function convertEnumValue(node, ctx) {
522
+ if (TypedNumberNode.is(node)) {
523
+ const { value } = TypedNumberNode.destruct(node);
524
+ return value.value;
525
+ }
526
+ return node.value;
527
+ }
528
+ function convertStruct(node, ctx) {
529
+ const { block, identifier } = StructNode.destruct(node);
530
+ // Shortcut if the typeDef has been added to the struct symbol.
531
+ const symbol = identifier?.symbol ?? node.symbol;
532
+ if (symbol && TypeDefSymbolData.is(symbol.data) && symbol.data.typeDef.kind === 'struct') {
533
+ return symbol.data.typeDef;
534
+ }
535
+ return {
536
+ ...convertBase(node, ctx),
537
+ kind: 'struct',
538
+ fields: convertStructBlock(block, ctx),
539
+ };
540
+ }
541
+ function convertStructBlock(node, ctx) {
542
+ const { fields } = StructBlockNode.destruct(node);
543
+ return fields.map(n => convertStructField(n, ctx));
544
+ }
545
+ function convertStructField(node, ctx) {
546
+ return StructPairFieldNode.is(node)
547
+ ? convertStructPairField(node, ctx)
548
+ : convertStructSpreadField(node, ctx);
549
+ }
550
+ function convertStructPairField(node, ctx) {
551
+ const { attributes, key, type, isOptional } = StructPairFieldNode.destruct(node);
552
+ return {
553
+ kind: 'pair',
554
+ attributes: convertAttributes(attributes, ctx),
555
+ key: convertStructKey(key, ctx),
556
+ type: convertType(type, ctx),
557
+ optional: isOptional,
558
+ };
559
+ }
560
+ function convertStructKey(node, ctx) {
561
+ if (StructMapKeyNode.is(node)) {
562
+ const { type } = StructMapKeyNode.destruct(node);
563
+ return convertType(type, ctx);
564
+ }
565
+ else {
566
+ return asString(node);
567
+ }
568
+ }
569
+ function convertStructSpreadField(node, ctx) {
570
+ const { attributes, type } = StructSpreadFieldNode.destruct(node);
571
+ return {
572
+ kind: 'spread',
573
+ attributes: convertAttributes(attributes, ctx),
574
+ type: convertType(type, ctx),
575
+ };
576
+ }
577
+ function convertAny(node, ctx) {
578
+ return {
579
+ ...convertBase(node, ctx),
580
+ kind: 'any',
581
+ };
582
+ }
583
+ function convertBoolean(node, ctx) {
584
+ return {
585
+ ...convertBase(node, ctx),
586
+ kind: 'boolean',
587
+ };
588
+ }
589
+ function convertDispatcher(node, ctx) {
590
+ const { index, location } = DispatcherTypeNode.destruct(node);
591
+ return {
592
+ ...convertBase(node, ctx, {
593
+ skipFirstIndexBody: true,
594
+ }),
595
+ kind: 'dispatcher',
596
+ index: convertIndexBody(index, ctx),
597
+ registry: ResourceLocationNode.toString(location, 'full'),
598
+ };
599
+ }
600
+ function convertList(node, ctx) {
601
+ const { item, lengthRange } = ListTypeNode.destruct(node);
602
+ return {
603
+ ...convertBase(node, ctx),
604
+ kind: 'list',
605
+ item: convertType(item, ctx),
606
+ lengthRange: convertRange(lengthRange, ctx),
607
+ };
608
+ }
609
+ function convertRange(node, ctx) {
610
+ if (!node) {
611
+ return undefined;
612
+ }
613
+ const { kind, min, max } = FloatRangeNode.is(node) ? FloatRangeNode.destruct(node) : IntRangeNode.destruct(node);
614
+ return { kind, min: min?.value, max: max?.value };
615
+ }
616
+ function convertLiteral(node, ctx) {
617
+ const { value } = LiteralTypeNode.destruct(node);
618
+ return {
619
+ ...convertBase(node, ctx),
620
+ kind: 'literal',
621
+ value: convertLiteralValue(value, ctx),
622
+ };
623
+ }
624
+ function convertLiteralValue(node, ctx) {
625
+ if (LiteralNode.is(node)) {
626
+ return {
627
+ kind: 'boolean',
628
+ value: node.value === 'true',
629
+ };
630
+ }
631
+ else if (TypedNumberNode.is(node)) {
632
+ const { suffix, value } = TypedNumberNode.destruct(node);
633
+ return {
634
+ kind: 'number',
635
+ value: value.value,
636
+ suffix: convertLiteralNumberSuffix(suffix, ctx),
637
+ };
638
+ }
639
+ else {
640
+ return {
641
+ kind: 'string',
642
+ value: node.value,
643
+ };
644
+ }
645
+ }
646
+ function convertLiteralNumberSuffix(node, ctx) {
647
+ const suffix = node?.value;
648
+ return suffix?.toLowerCase();
649
+ }
650
+ function convertNumericType(node, ctx) {
651
+ const { numericKind, valueRange } = NumericTypeNode.destruct(node);
652
+ return {
653
+ ...convertBase(node, ctx),
654
+ kind: numericKind.value,
655
+ valueRange: convertRange(valueRange, ctx),
656
+ };
657
+ }
658
+ function convertPrimitiveArray(node, ctx) {
659
+ const { arrayKind, lengthRange, valueRange } = PrimitiveArrayTypeNode.destruct(node);
660
+ return {
661
+ ...convertBase(node, ctx),
662
+ kind: `${arrayKind.value}_array`,
663
+ lengthRange: convertRange(lengthRange, ctx),
664
+ valueRange: convertRange(valueRange, ctx),
665
+ };
666
+ }
667
+ function convertString(node, ctx) {
668
+ const { lengthRange } = StringTypeNode.destruct(node);
669
+ return {
670
+ ...convertBase(node, ctx),
671
+ kind: 'string',
672
+ lengthRange: convertRange(lengthRange, ctx),
673
+ };
674
+ }
675
+ function convertReference(node, ctx) {
676
+ const { path, typeParameters } = ReferenceTypeNode.destruct(node);
677
+ return {
678
+ ...convertBase(node, ctx),
679
+ kind: 'reference',
680
+ path: pathArrayToString(resolvePath(path, ctx)),
681
+ typeParameters: undefineEmptyArray(typeParameters.map(n => convertType(n, ctx))),
682
+ };
683
+ }
684
+ function convertTuple(node, ctx) {
685
+ const { items } = TupleTypeNode.destruct(node);
686
+ return {
687
+ ...convertBase(node, ctx),
688
+ kind: 'tuple',
689
+ items: items.map(n => convertType(n, ctx)),
690
+ };
691
+ }
692
+ function convertUnion(node, ctx) {
693
+ const { members } = UnionTypeNode.destruct(node);
694
+ return {
695
+ ...convertBase(node, ctx),
696
+ kind: 'union',
697
+ members: members.map(n => convertType(n, ctx)),
698
+ };
699
+ }
700
+ function asString(node) {
701
+ if (ResourceLocationNode.is(node)) {
702
+ return ResourceLocationNode.toString(node, 'short');
703
+ }
704
+ return node.value;
705
+ }
19
706
  //# sourceMappingURL=index.js.map