@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.
package/lib/node/index.js CHANGED
@@ -1,275 +1,591 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UseStatementNode = exports.TypeAliasNode = exports.StructInjectionNode = exports.EnumInjectionNode = exports.InjectionNode = exports.UnionTypeNode = exports.DispatcherTypeNode = exports.StructSpreadFieldNode = exports.StructMapKeyNode = exports.StructKeyNode = exports.StructPairFieldNode = exports.StructFieldNode = exports.StructBlockNode = exports.PathNode = exports.TypeParamNode = exports.TypeParamBlockNode = exports.StructNode = exports.PrelimNode = exports.EnumValueNode = exports.EnumFieldNode = exports.EnumBlockNode = exports.DocCommentsNode = exports.EnumNode = exports.TupleTypeNode = exports.ListTypeNode = exports.PrimitiveArrayTypeNode = exports.FloatRangeNode = exports.NumericTypeNode = exports.TypedNumberNode = exports.LiteralTypeNode = exports.IntRangeNode = exports.StringTypeNode = exports.BooleanTypeNode = exports.AnyTypeNode = exports.AttributeTreeNamedValuesNode = exports.AttributeTreePosValuesNode = exports.AttributeTreeNode = exports.AttributeValueNode = exports.AttributeNode = exports.TypeNode = exports.AccessorKeyNode = exports.DynamicIndexNode = exports.IdentifierNode = exports.StaticIndexNode = exports.IndexNode = exports.IndexBodyNode = exports.LiteralNode = exports.DispatchStatementNode = exports.TopLevelNode = exports.ModuleNode = void 0;
4
- const core_1 = require("@spyglassmc/core");
5
- exports.ModuleNode = Object.freeze({
1
+ import { atArray, CommentNode, FloatNode, ResourceLocationNode, StringNode } from '@spyglassmc/core';
2
+ export const ModuleNode = Object.freeze({
6
3
  is(node) {
7
4
  return node?.type === 'mcdoc:module';
8
5
  },
9
6
  });
10
- exports.TopLevelNode = Object.freeze({
7
+ export const TopLevelNode = Object.freeze({
11
8
  is(node) {
12
- return (core_1.CommentNode.is(node) ||
13
- exports.DispatchStatementNode.is(node) ||
14
- exports.EnumNode.is(node) ||
15
- exports.InjectionNode.is(node) ||
16
- exports.StructNode.is(node) ||
17
- exports.TypeAliasNode.is(node) ||
18
- exports.UseStatementNode.is(node));
9
+ return (CommentNode.is(node) ||
10
+ DispatchStatementNode.is(node) ||
11
+ EnumNode.is(node) ||
12
+ InjectionNode.is(node) ||
13
+ StructNode.is(node) ||
14
+ TypeAliasNode.is(node) ||
15
+ UseStatementNode.is(node));
19
16
  },
20
17
  });
21
- exports.DispatchStatementNode = Object.freeze({
18
+ export const DispatchStatementNode = Object.freeze({
19
+ destruct(node) {
20
+ return {
21
+ attributes: node.children.filter(AttributeNode.is),
22
+ location: node.children.find(ResourceLocationNode.is),
23
+ index: node.children.find(IndexBodyNode.is),
24
+ target: node.children.find(TypeNode.is),
25
+ };
26
+ },
22
27
  is(node) {
23
28
  return node?.type === 'mcdoc:dispatch_statement';
24
29
  },
25
30
  });
26
- exports.LiteralNode = Object.freeze({
31
+ export const LiteralNode = Object.freeze({
27
32
  is(node) {
28
33
  return node?.type === 'mcdoc:literal';
29
34
  },
30
35
  });
31
- exports.IndexBodyNode = Object.freeze({
36
+ export const IndexBodyNode = Object.freeze({
37
+ destruct(node) {
38
+ return {
39
+ parallelIndices: node.children.filter(IndexNode.is),
40
+ };
41
+ },
32
42
  is(node) {
33
43
  return node?.type === 'mcdoc:index_body';
34
44
  },
35
45
  });
36
- exports.IndexNode = Object.freeze({
46
+ export const IndexNode = Object.freeze({
37
47
  is(node) {
38
- return exports.StaticIndexNode.is(node) || exports.DynamicIndexNode.is(node);
48
+ return StaticIndexNode.is(node) || DynamicIndexNode.is(node);
39
49
  },
40
50
  });
41
- exports.StaticIndexNode = Object.freeze({
51
+ export const StaticIndexNode = Object.freeze({
42
52
  is(node) {
43
- return exports.LiteralNode.is(node) || exports.IdentifierNode.is(node) || core_1.StringNode.is(node) || core_1.ResourceLocationNode.is(node);
53
+ return LiteralNode.is(node) || IdentifierNode.is(node) || StringNode.is(node) || ResourceLocationNode.is(node);
44
54
  },
45
55
  });
46
- exports.IdentifierNode = Object.freeze({
56
+ export const IdentifierNode = Object.freeze({
47
57
  is(node) {
48
58
  return node?.type === 'mcdoc:identifier';
49
59
  },
50
60
  });
51
- exports.DynamicIndexNode = Object.freeze({
61
+ export const DynamicIndexNode = Object.freeze({
62
+ destruct(node) {
63
+ return {
64
+ keys: node.children.filter(AccessorKeyNode.is),
65
+ };
66
+ },
52
67
  is(node) {
53
68
  return node?.type === 'mcdoc:dynamic_index';
54
69
  },
55
70
  });
56
- exports.AccessorKeyNode = Object.freeze({
71
+ export const AccessorKeyNode = Object.freeze({
57
72
  is(node) {
58
- return exports.LiteralNode.is(node) || exports.IdentifierNode.is(node) || core_1.StringNode.is(node);
73
+ return LiteralNode.is(node) || IdentifierNode.is(node) || StringNode.is(node);
59
74
  },
60
75
  });
61
- exports.TypeNode = Object.freeze({
76
+ export const TypeNode = Object.freeze({
62
77
  is(node) {
63
- return (exports.AnyTypeNode.is(node) ||
64
- exports.BooleanTypeNode.is(node) ||
65
- exports.StringTypeNode.is(node) ||
66
- exports.LiteralTypeNode.is(node) ||
67
- exports.NumericTypeNode.is(node) ||
68
- exports.PrimitiveArrayTypeNode.is(node) ||
69
- exports.ListTypeNode.is(node) ||
70
- exports.TupleTypeNode.is(node) ||
71
- exports.EnumNode.is(node) ||
72
- exports.StructNode.is(node) ||
73
- exports.PathNode.is(node) ||
74
- exports.DispatcherTypeNode.is(node) ||
75
- exports.UnionTypeNode.is(node));
78
+ return (AnyTypeNode.is(node) ||
79
+ BooleanTypeNode.is(node) ||
80
+ StringTypeNode.is(node) ||
81
+ LiteralTypeNode.is(node) ||
82
+ NumericTypeNode.is(node) ||
83
+ PrimitiveArrayTypeNode.is(node) ||
84
+ ListTypeNode.is(node) ||
85
+ TupleTypeNode.is(node) ||
86
+ EnumNode.is(node) ||
87
+ StructNode.is(node) ||
88
+ ReferenceTypeNode.is(node) ||
89
+ DispatcherTypeNode.is(node) ||
90
+ UnionTypeNode.is(node));
76
91
  },
77
- asType(node) {
78
- throw '// TODO';
92
+ });
93
+ export const TypeBaseNode = Object.freeze({
94
+ destruct(node) {
95
+ return {
96
+ attributes: node.children.filter(AttributeNode.is),
97
+ indices: node.children.filter(IndexBodyNode.is),
98
+ };
79
99
  },
80
100
  });
81
- exports.AttributeNode = Object.freeze({
101
+ export const AttributeNode = Object.freeze({
102
+ destruct(node) {
103
+ return {
104
+ name: node.children.find(IdentifierNode.is),
105
+ value: node.children.find(AttributeValueNode.is),
106
+ };
107
+ },
82
108
  is(node) {
83
109
  return node?.type === 'mcdoc:attribute';
84
110
  },
85
111
  });
86
- exports.AttributeValueNode = Object.freeze({
112
+ export const AttributeValueNode = Object.freeze({
87
113
  is(node) {
88
- return exports.TypeNode.is(node) || exports.AttributeTreeNode.is(node);
114
+ return TypeNode.is(node) || AttributeTreeNode.is(node);
89
115
  },
90
116
  });
91
- exports.AttributeTreeNode = Object.freeze({
117
+ export const AttributeTreeNode = Object.freeze({
118
+ destruct(node) {
119
+ return {
120
+ positional: node.children.find(AttributeTreePosValuesNode.is),
121
+ named: node.children.find(AttributeTreeNamedValuesNode.is),
122
+ };
123
+ },
92
124
  is(node) {
93
125
  return node?.type === 'mcdoc:attribute/tree';
94
126
  },
95
127
  });
96
- exports.AttributeTreePosValuesNode = Object.freeze({
128
+ export const AttributeTreePosValuesNode = Object.freeze({
129
+ destruct(node) {
130
+ return {
131
+ values: node.children.filter(AttributeValueNode.is),
132
+ };
133
+ },
97
134
  is(node) {
98
135
  return node?.type === 'mcdoc:attribute/tree/pos';
99
136
  },
100
137
  });
101
- exports.AttributeTreeNamedValuesNode = Object.freeze({
138
+ export const AttributeTreeNamedValuesNode = Object.freeze({
139
+ destruct(node) {
140
+ const ans = {
141
+ values: [],
142
+ };
143
+ let key;
144
+ for (const child of node.children) {
145
+ if (CommentNode.is(child)) {
146
+ continue;
147
+ }
148
+ if (IdentifierNode.is(child) || StringNode.is(child)) {
149
+ key = child;
150
+ }
151
+ else if (key) {
152
+ ans.values.push({ key, value: child });
153
+ key = undefined;
154
+ }
155
+ }
156
+ return ans;
157
+ },
102
158
  is(node) {
103
159
  return node?.type === 'mcdoc:attribute/tree/named';
104
160
  },
105
161
  });
106
- exports.AnyTypeNode = Object.freeze({
162
+ export const AnyTypeNode = Object.freeze({
107
163
  is(node) {
108
164
  return node?.type === 'mcdoc:type/any';
109
165
  },
110
166
  });
111
- exports.BooleanTypeNode = Object.freeze({
167
+ export const BooleanTypeNode = Object.freeze({
112
168
  is(node) {
113
169
  return node?.type === 'mcdoc:type/boolean';
114
170
  },
115
171
  });
116
- exports.StringTypeNode = Object.freeze({
117
- is(node) {
118
- return node?.type === 'mcdoc:type/string';
172
+ export const IntRangeNode = Object.freeze({
173
+ destruct(node) {
174
+ return destructRangeNode(node);
119
175
  },
120
- });
121
- exports.IntRangeNode = Object.freeze({
122
176
  is(node) {
123
177
  return node?.type === 'mcdoc:int_range';
124
178
  },
125
179
  });
126
- exports.LiteralTypeNode = Object.freeze({
180
+ export const LiteralTypeNode = Object.freeze({
181
+ destruct(node) {
182
+ return {
183
+ value: node.children.find(LiteralTypeValueNode.is),
184
+ };
185
+ },
127
186
  is(node) {
128
187
  return node?.type === 'mcdoc:type/literal';
129
188
  },
130
189
  });
131
- exports.TypedNumberNode = Object.freeze({
190
+ export const LiteralTypeValueNode = Object.freeze({
191
+ is(node) {
192
+ return LiteralNode.is(node) || TypedNumberNode.is(node) || StringNode.is(node);
193
+ },
194
+ });
195
+ export const TypedNumberNode = Object.freeze({
196
+ destruct(node) {
197
+ return {
198
+ value: node.children.find(FloatNode.is),
199
+ suffix: node.children.find(LiteralNode.is),
200
+ };
201
+ },
132
202
  is(node) {
133
203
  return node?.type === 'mcdoc:typed_number';
134
204
  },
135
205
  });
136
- exports.NumericTypeNode = Object.freeze({
206
+ export const NumericTypeNode = Object.freeze({
207
+ destruct(node) {
208
+ return {
209
+ numericKind: node.children.find(LiteralNode.is),
210
+ valueRange: node.children.find(FloatRangeNode.is) || node.children.find(IntRangeNode.is),
211
+ };
212
+ },
137
213
  is(node) {
138
214
  return node?.type === 'mcdoc:type/numeric_type';
139
215
  },
140
216
  });
141
- exports.FloatRangeNode = Object.freeze({
217
+ export const RangeExclusiveChar = '<';
218
+ export function getRangeDelimiter(kind) {
219
+ const prefix = kind & 0b10 ? RangeExclusiveChar : '';
220
+ const suffix = kind & 0b01 ? RangeExclusiveChar : '';
221
+ return `${prefix}..${suffix}`;
222
+ }
223
+ function destructRangeNode(node) {
224
+ let kind;
225
+ let min;
226
+ let max;
227
+ if (node.children.length === 1) {
228
+ // a
229
+ kind = 0b00;
230
+ min = max = node.children[0];
231
+ }
232
+ else if (node.children.length === 3) {
233
+ // a..b
234
+ kind = getKind(node.children[1]);
235
+ min = node.children[0];
236
+ max = node.children[2];
237
+ }
238
+ else if (LiteralNode.is(node.children[0])) {
239
+ // ..b
240
+ kind = getKind(node.children[0]);
241
+ max = node.children[1];
242
+ }
243
+ else {
244
+ // a..
245
+ kind = getKind(node.children[1]);
246
+ min = node.children[0];
247
+ }
248
+ return {
249
+ kind,
250
+ min,
251
+ max,
252
+ };
253
+ function getKind(delimiter) {
254
+ let ans = 0b00;
255
+ if (delimiter.value.startsWith(RangeExclusiveChar)) {
256
+ ans |= 0b10;
257
+ }
258
+ if (delimiter.value.endsWith(RangeExclusiveChar)) {
259
+ ans |= 0b01;
260
+ }
261
+ return ans;
262
+ }
263
+ }
264
+ export const FloatRangeNode = Object.freeze({
265
+ destruct(node) {
266
+ return destructRangeNode(node);
267
+ },
142
268
  is(node) {
143
269
  return node?.type === 'mcdoc:float_range';
144
270
  },
145
271
  });
146
- exports.PrimitiveArrayTypeNode = Object.freeze({
272
+ export const PrimitiveArrayTypeNode = Object.freeze({
273
+ destruct(node) {
274
+ let lengthRange;
275
+ let valueRange;
276
+ let afterBrackets = false;
277
+ for (const child of node.children) {
278
+ if (LiteralNode.is(child) && child.value === '[]') {
279
+ afterBrackets = true;
280
+ }
281
+ else if (IntRangeNode.is(child)) {
282
+ if (afterBrackets) {
283
+ lengthRange = child;
284
+ }
285
+ else {
286
+ valueRange = child;
287
+ }
288
+ }
289
+ }
290
+ return {
291
+ arrayKind: node.children.find(LiteralNode.is),
292
+ lengthRange,
293
+ valueRange,
294
+ };
295
+ },
147
296
  is(node) {
148
297
  return node?.type === 'mcdoc:type/primitive_array';
149
298
  },
150
299
  });
151
- exports.ListTypeNode = Object.freeze({
300
+ export const ListTypeNode = Object.freeze({
301
+ destruct(node) {
302
+ return {
303
+ item: node.children.find(TypeNode.is),
304
+ lengthRange: node.children.find(IntRangeNode.is),
305
+ };
306
+ },
152
307
  is(node) {
153
308
  return node?.type === 'mcdoc:type/list';
154
309
  },
155
310
  });
156
- exports.TupleTypeNode = Object.freeze({
311
+ export const StringTypeNode = Object.freeze({
312
+ destruct(node) {
313
+ return {
314
+ lengthRange: node.children.find(IntRangeNode.is),
315
+ };
316
+ },
317
+ is(node) {
318
+ return node?.type === 'mcdoc:type/string';
319
+ },
320
+ });
321
+ export const TupleTypeNode = Object.freeze({
322
+ destruct(node) {
323
+ return {
324
+ items: node.children.filter(TypeNode.is),
325
+ };
326
+ },
157
327
  is(node) {
158
328
  return node?.type === 'mcdoc:type/tuple';
159
329
  },
160
330
  });
161
- exports.EnumNode = Object.freeze({
331
+ const EnumKinds = new Set(['byte', 'short', 'int', 'long', 'float', 'double', 'string']);
332
+ export const EnumNode = Object.freeze({
333
+ kinds: EnumKinds,
334
+ destruct(node) {
335
+ return {
336
+ block: node.children.find(EnumBlockNode.is),
337
+ docComments: node.children.find(DocCommentsNode.is),
338
+ enumKind: getEnumKind(node),
339
+ identifier: node.children.find(IdentifierNode.is),
340
+ keyword: node.children.find(LiteralNode.is),
341
+ };
342
+ function getEnumKind(node) {
343
+ for (const literal of node.children.filter(LiteralNode.is)) {
344
+ if (EnumKinds.has(literal.value)) {
345
+ return literal.value;
346
+ }
347
+ }
348
+ return undefined;
349
+ }
350
+ },
162
351
  is(node) {
163
352
  return node?.type === 'mcdoc:enum';
164
353
  },
165
- kinds: new Set(['byte', 'short', 'int', 'long', 'float', 'double', 'string']),
166
354
  });
167
- exports.DocCommentsNode = Object.freeze({
355
+ export const DocCommentsNode = Object.freeze({
356
+ /**
357
+ * @returns The text content of this doc comment block.
358
+ */
359
+ asText(node) {
360
+ if (!node) {
361
+ return undefined;
362
+ }
363
+ let comments = node.children.map(doc => doc.comment);
364
+ // If every comment contains a leading space or is empty, stripe the leading spaces off.
365
+ // e.g. /// This is an example doc comment.
366
+ // ///
367
+ // /// Another line.
368
+ // should be converted to "This is an example doc comment.\n\nAnother line."
369
+ if (comments.every(s => s.length === 0 || s.startsWith(' '))) {
370
+ comments = comments.map(s => s.slice(1));
371
+ }
372
+ return comments.join('\n');
373
+ },
168
374
  is(node) {
169
375
  return node?.type === 'mcdoc:doc_comments';
170
376
  },
171
377
  });
172
- exports.EnumBlockNode = Object.freeze({
378
+ export const EnumBlockNode = Object.freeze({
379
+ destruct(node) {
380
+ return {
381
+ fields: node.children.filter(EnumFieldNode.is),
382
+ };
383
+ },
173
384
  is(node) {
174
385
  return node?.type === 'mcdoc:enum/block';
175
386
  },
176
387
  });
177
- exports.EnumFieldNode = Object.freeze({
388
+ export const EnumFieldNode = Object.freeze({
389
+ destruct(node) {
390
+ return {
391
+ attributes: node.children.filter(AttributeNode.is),
392
+ identifier: node.children.find(IdentifierNode.is),
393
+ value: node.children.find(EnumValueNode.is),
394
+ };
395
+ },
178
396
  is(node) {
179
397
  return node?.type === 'mcdoc:enum/field';
180
398
  },
181
399
  });
182
- exports.EnumValueNode = Object.freeze({
400
+ export const EnumValueNode = Object.freeze({
183
401
  is(node) {
184
- return exports.TypedNumberNode.is(node) || core_1.StringNode.is(node);
402
+ return TypedNumberNode.is(node) || StringNode.is(node);
185
403
  },
186
404
  });
187
- exports.PrelimNode = Object.freeze({
405
+ export const PrelimNode = Object.freeze({
188
406
  is(node) {
189
- return exports.AttributeNode.is(node) || exports.DocCommentsNode.is(node);
407
+ return AttributeNode.is(node) || DocCommentsNode.is(node);
190
408
  },
191
409
  });
192
- exports.StructNode = Object.freeze({
410
+ export const StructNode = Object.freeze({
411
+ destruct(node) {
412
+ return {
413
+ block: node.children.find(StructBlockNode.is),
414
+ docComments: node.children.find(DocCommentsNode.is),
415
+ identifier: node.children.find(IdentifierNode.is),
416
+ keyword: node.children.find(LiteralNode.is),
417
+ };
418
+ },
193
419
  is(node) {
194
420
  return node?.type === 'mcdoc:struct';
195
421
  },
196
422
  });
197
- exports.TypeParamBlockNode = Object.freeze({
423
+ export const ReferenceTypeNode = Object.freeze({
424
+ destruct(node) {
425
+ return {
426
+ path: node.children.find(PathNode.is),
427
+ typeParameters: node.children.filter(TypeNode.is),
428
+ };
429
+ },
430
+ is(node) {
431
+ return node?.type === 'mcdoc:type/reference';
432
+ },
433
+ });
434
+ export const TypeParamBlockNode = Object.freeze({
435
+ destruct(node) {
436
+ return {
437
+ params: node.children.filter(TypeParamNode.is),
438
+ };
439
+ },
198
440
  is(node) {
199
441
  return node?.type === 'mcdoc:type_param_block';
200
442
  },
201
443
  });
202
- exports.TypeParamNode = Object.freeze({
444
+ export const TypeParamNode = Object.freeze({
445
+ destruct(node) {
446
+ return {
447
+ // constraint: node.children.find(TypeNode.is),
448
+ identifier: node.children.find(IdentifierNode.is),
449
+ };
450
+ },
203
451
  is(node) {
204
452
  return node?.type === 'mcdoc:type_param';
205
453
  },
206
454
  });
207
- exports.PathNode = Object.freeze({
455
+ export const PathNode = Object.freeze({
456
+ destruct(node) {
457
+ const lastChild = atArray(node?.children, -1);
458
+ return {
459
+ children: node?.children ?? [],
460
+ isAbsolute: node?.isAbsolute,
461
+ lastIdentifier: IdentifierNode.is(lastChild) ? lastChild : undefined,
462
+ };
463
+ },
208
464
  is(node) {
209
465
  return node?.type === 'mcdoc:path';
210
466
  },
211
467
  });
212
- exports.StructBlockNode = Object.freeze({
468
+ export const StructBlockNode = Object.freeze({
469
+ destruct(node) {
470
+ return {
471
+ fields: node.children.filter(StructFieldNode.is),
472
+ };
473
+ },
213
474
  is(node) {
214
475
  return node?.type === 'mcdoc:struct/block';
215
476
  },
216
477
  });
217
- exports.StructFieldNode = Object.freeze({
478
+ export const StructFieldNode = Object.freeze({
218
479
  is(node) {
219
- return exports.StructPairFieldNode.is(node) || exports.StructSpreadFieldNode.is(node);
480
+ return StructPairFieldNode.is(node) || StructSpreadFieldNode.is(node);
220
481
  },
221
482
  });
222
- exports.StructPairFieldNode = Object.freeze({
483
+ export const StructPairFieldNode = Object.freeze({
484
+ destruct(node) {
485
+ return {
486
+ attributes: node.children.filter(AttributeNode.is),
487
+ key: node.children.find(StructKeyNode.is),
488
+ type: node.children.find(TypeNode.is),
489
+ isOptional: node.isOptional,
490
+ };
491
+ },
223
492
  is(node) {
224
493
  return node?.type === 'mcdoc:struct/field/pair';
225
494
  },
226
495
  });
227
- exports.StructKeyNode = Object.freeze({
496
+ export const StructKeyNode = Object.freeze({
228
497
  is(node) {
229
- return core_1.StringNode.is(node) || exports.IdentifierNode.is(node) || exports.StructMapKeyNode.is(node);
498
+ return StringNode.is(node) || IdentifierNode.is(node) || StructMapKeyNode.is(node);
230
499
  },
231
500
  });
232
- exports.StructMapKeyNode = Object.freeze({
501
+ export const StructMapKeyNode = Object.freeze({
502
+ destruct(node) {
503
+ return {
504
+ type: node.children.find(TypeNode.is),
505
+ };
506
+ },
233
507
  is(node) {
234
508
  return node?.type === 'mcdoc:struct/map_key';
235
509
  },
236
510
  });
237
- exports.StructSpreadFieldNode = Object.freeze({
511
+ export const StructSpreadFieldNode = Object.freeze({
512
+ destruct(node) {
513
+ return {
514
+ attributes: node.children.filter(AttributeNode.is),
515
+ type: node.children.find(TypeNode.is),
516
+ };
517
+ },
238
518
  is(node) {
239
519
  return node?.type === 'mcdoc:struct/field/spread';
240
520
  },
241
521
  });
242
- exports.DispatcherTypeNode = Object.freeze({
522
+ export const DispatcherTypeNode = Object.freeze({
523
+ destruct(node) {
524
+ return {
525
+ location: node.children.find(ResourceLocationNode.is),
526
+ index: node.children.find(IndexBodyNode.is),
527
+ };
528
+ },
243
529
  is(node) {
244
530
  return node?.type === 'mcdoc:type/dispatcher';
245
531
  },
246
532
  });
247
- exports.UnionTypeNode = Object.freeze({
533
+ export const UnionTypeNode = Object.freeze({
534
+ destruct(node) {
535
+ return {
536
+ members: node.children.filter(TypeNode.is),
537
+ };
538
+ },
248
539
  is(node) {
249
540
  return node?.type === 'mcdoc:type/union';
250
541
  },
251
542
  });
252
- exports.InjectionNode = Object.freeze({
543
+ export const InjectionNode = Object.freeze({
544
+ destruct(node) {
545
+ return {
546
+ injection: node.children.find(InjectionContentNode.is),
547
+ };
548
+ },
253
549
  is(node) {
254
550
  return node?.type === 'mcdoc:injection';
255
551
  },
256
552
  });
257
- exports.EnumInjectionNode = Object.freeze({
553
+ export const InjectionContentNode = Object.freeze({
554
+ is(node) {
555
+ return EnumInjectionNode.is(node) || StructInjectionNode.is(node);
556
+ },
557
+ });
558
+ export const EnumInjectionNode = Object.freeze({
258
559
  is(node) {
259
560
  return node?.type === 'mcdoc:injection/enum';
260
561
  },
261
562
  });
262
- exports.StructInjectionNode = Object.freeze({
563
+ export const StructInjectionNode = Object.freeze({
263
564
  is(node) {
264
565
  return node?.type === 'mcdoc:injection/struct';
265
566
  },
266
567
  });
267
- exports.TypeAliasNode = Object.freeze({
568
+ export const TypeAliasNode = Object.freeze({
569
+ destruct(node) {
570
+ return {
571
+ docComments: node.children.find(DocCommentsNode.is),
572
+ identifier: node.children.find(IdentifierNode.is),
573
+ keyword: node.children.find(LiteralNode.is),
574
+ typeParams: node.children.find(TypeParamBlockNode.is),
575
+ rhs: node.children.find(TypeNode.is),
576
+ };
577
+ },
268
578
  is(node) {
269
579
  return node?.type === 'mcdoc:type_alias';
270
580
  },
271
581
  });
272
- exports.UseStatementNode = Object.freeze({
582
+ export const UseStatementNode = Object.freeze({
583
+ destruct(node) {
584
+ return {
585
+ binding: node.children.find(IdentifierNode.is),
586
+ path: node.children.find(PathNode.is),
587
+ };
588
+ },
273
589
  is(node) {
274
590
  return node?.type === 'mcdoc:use_statement';
275
591
  },