@spyglassmc/mcdoc 0.2.0 → 0.3.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/lib/node/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { CommentNode, ResourceLocationNode, StringNode } from '@spyglassmc/core';
1
+ import { atArray, CommentNode, FloatNode, ResourceLocationNode, StringNode } from '@spyglassmc/core';
2
2
  export const ModuleNode = Object.freeze({
3
3
  is(node) {
4
4
  return node?.type === 'mcdoc:module';
@@ -16,6 +16,14 @@ export const TopLevelNode = Object.freeze({
16
16
  },
17
17
  });
18
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
+ },
19
27
  is(node) {
20
28
  return node?.type === 'mcdoc:dispatch_statement';
21
29
  },
@@ -26,6 +34,11 @@ export const LiteralNode = Object.freeze({
26
34
  },
27
35
  });
28
36
  export const IndexBodyNode = Object.freeze({
37
+ destruct(node) {
38
+ return {
39
+ parallelIndices: node.children.filter(IndexNode.is),
40
+ };
41
+ },
29
42
  is(node) {
30
43
  return node?.type === 'mcdoc:index_body';
31
44
  },
@@ -46,6 +59,11 @@ export const IdentifierNode = Object.freeze({
46
59
  },
47
60
  });
48
61
  export const DynamicIndexNode = Object.freeze({
62
+ destruct(node) {
63
+ return {
64
+ keys: node.children.filter(AccessorKeyNode.is),
65
+ };
66
+ },
49
67
  is(node) {
50
68
  return node?.type === 'mcdoc:dynamic_index';
51
69
  },
@@ -67,15 +85,26 @@ export const TypeNode = Object.freeze({
67
85
  TupleTypeNode.is(node) ||
68
86
  EnumNode.is(node) ||
69
87
  StructNode.is(node) ||
70
- PathNode.is(node) ||
88
+ ReferenceTypeNode.is(node) ||
71
89
  DispatcherTypeNode.is(node) ||
72
90
  UnionTypeNode.is(node));
73
91
  },
74
- asType(node) {
75
- 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
+ };
76
99
  },
77
100
  });
78
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
+ },
79
108
  is(node) {
80
109
  return node?.type === 'mcdoc:attribute';
81
110
  },
@@ -86,16 +115,46 @@ export const AttributeValueNode = Object.freeze({
86
115
  },
87
116
  });
88
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
+ },
89
124
  is(node) {
90
125
  return node?.type === 'mcdoc:attribute/tree';
91
126
  },
92
127
  });
93
128
  export const AttributeTreePosValuesNode = Object.freeze({
129
+ destruct(node) {
130
+ return {
131
+ values: node.children.filter(AttributeValueNode.is),
132
+ };
133
+ },
94
134
  is(node) {
95
135
  return node?.type === 'mcdoc:attribute/tree/pos';
96
136
  },
97
137
  });
98
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
+ },
99
158
  is(node) {
100
159
  return node?.type === 'mcdoc:attribute/tree/named';
101
160
  },
@@ -110,68 +169,229 @@ export const BooleanTypeNode = Object.freeze({
110
169
  return node?.type === 'mcdoc:type/boolean';
111
170
  },
112
171
  });
113
- export const StringTypeNode = Object.freeze({
114
- is(node) {
115
- return node?.type === 'mcdoc:type/string';
116
- },
117
- });
118
172
  export const IntRangeNode = Object.freeze({
173
+ destruct(node) {
174
+ return destructRangeNode(node);
175
+ },
119
176
  is(node) {
120
177
  return node?.type === 'mcdoc:int_range';
121
178
  },
122
179
  });
123
180
  export const LiteralTypeNode = Object.freeze({
181
+ destruct(node) {
182
+ return {
183
+ value: node.children.find(LiteralTypeValueNode.is),
184
+ };
185
+ },
124
186
  is(node) {
125
187
  return node?.type === 'mcdoc:type/literal';
126
188
  },
127
189
  });
190
+ export const LiteralTypeValueNode = Object.freeze({
191
+ is(node) {
192
+ return LiteralNode.is(node) || TypedNumberNode.is(node) || StringNode.is(node);
193
+ },
194
+ });
128
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
+ },
129
202
  is(node) {
130
203
  return node?.type === 'mcdoc:typed_number';
131
204
  },
132
205
  });
133
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
+ },
134
213
  is(node) {
135
214
  return node?.type === 'mcdoc:type/numeric_type';
136
215
  },
137
216
  });
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
+ }
138
264
  export const FloatRangeNode = Object.freeze({
265
+ destruct(node) {
266
+ return destructRangeNode(node);
267
+ },
139
268
  is(node) {
140
269
  return node?.type === 'mcdoc:float_range';
141
270
  },
142
271
  });
143
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
+ },
144
296
  is(node) {
145
297
  return node?.type === 'mcdoc:type/primitive_array';
146
298
  },
147
299
  });
148
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
+ },
149
307
  is(node) {
150
308
  return node?.type === 'mcdoc:type/list';
151
309
  },
152
310
  });
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
+ });
153
321
  export const TupleTypeNode = Object.freeze({
322
+ destruct(node) {
323
+ return {
324
+ items: node.children.filter(TypeNode.is),
325
+ };
326
+ },
154
327
  is(node) {
155
328
  return node?.type === 'mcdoc:type/tuple';
156
329
  },
157
330
  });
331
+ const EnumKinds = new Set(['byte', 'short', 'int', 'long', 'float', 'double', 'string']);
158
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
+ };
341
+ function getEnumKind(node) {
342
+ for (const literal of node.children.filter(LiteralNode.is)) {
343
+ if (EnumKinds.has(literal.value)) {
344
+ return literal.value;
345
+ }
346
+ }
347
+ return undefined;
348
+ }
349
+ },
159
350
  is(node) {
160
351
  return node?.type === 'mcdoc:enum';
161
352
  },
162
- kinds: new Set(['byte', 'short', 'int', 'long', 'float', 'double', 'string']),
163
353
  });
164
354
  export const DocCommentsNode = Object.freeze({
355
+ /**
356
+ * @returns The text content of this doc comment block.
357
+ */
358
+ asText(node) {
359
+ if (!node) {
360
+ return undefined;
361
+ }
362
+ let comments = node.children.map(doc => doc.comment);
363
+ // If every comment contains a leading space or is empty, stripe the leading spaces off.
364
+ // e.g. /// This is an example doc comment.
365
+ // ///
366
+ // /// Another line.
367
+ // should be converted to "This is an example doc comment.\n\nAnother line."
368
+ if (comments.every(s => s.length === 0 || s.startsWith(' '))) {
369
+ comments = comments.map(s => s.slice(1));
370
+ }
371
+ return comments.join('\n');
372
+ },
165
373
  is(node) {
166
374
  return node?.type === 'mcdoc:doc_comments';
167
375
  },
168
376
  });
169
377
  export const EnumBlockNode = Object.freeze({
378
+ destruct(node) {
379
+ return {
380
+ fields: node.children.filter(EnumFieldNode.is),
381
+ };
382
+ },
170
383
  is(node) {
171
384
  return node?.type === 'mcdoc:enum/block';
172
385
  },
173
386
  });
174
387
  export const EnumFieldNode = Object.freeze({
388
+ destruct(node) {
389
+ return {
390
+ attributes: node.children.filter(AttributeNode.is),
391
+ identifier: node.children.find(IdentifierNode.is),
392
+ value: node.children.find(EnumValueNode.is),
393
+ };
394
+ },
175
395
  is(node) {
176
396
  return node?.type === 'mcdoc:enum/field';
177
397
  },
@@ -187,31 +407,68 @@ export const PrelimNode = Object.freeze({
187
407
  },
188
408
  });
189
409
  export const StructNode = Object.freeze({
410
+ destruct(node) {
411
+ return {
412
+ block: node.children.find(StructBlockNode.is),
413
+ docComments: node.children.find(DocCommentsNode.is),
414
+ identifier: node.children.find(IdentifierNode.is),
415
+ };
416
+ },
190
417
  is(node) {
191
418
  return node?.type === 'mcdoc:struct';
192
419
  },
193
420
  });
194
- export const PathTypeNode = Object.freeze({
421
+ export const ReferenceTypeNode = Object.freeze({
422
+ destruct(node) {
423
+ return {
424
+ path: node.children.find(PathNode.is),
425
+ typeParameters: node.children.filter(TypeNode.is),
426
+ };
427
+ },
195
428
  is(node) {
196
- return node?.type === 'mcdoc:type/path';
429
+ return node?.type === 'mcdoc:type/reference';
197
430
  },
198
431
  });
199
432
  export const TypeParamBlockNode = Object.freeze({
433
+ destruct(node) {
434
+ return {
435
+ params: node.children.filter(TypeParamNode.is),
436
+ };
437
+ },
200
438
  is(node) {
201
439
  return node?.type === 'mcdoc:type_param_block';
202
440
  },
203
441
  });
204
442
  export const TypeParamNode = Object.freeze({
443
+ destruct(node) {
444
+ return {
445
+ // constraint: node.children.find(TypeNode.is),
446
+ identifier: node.children.find(IdentifierNode.is),
447
+ };
448
+ },
205
449
  is(node) {
206
450
  return node?.type === 'mcdoc:type_param';
207
451
  },
208
452
  });
209
453
  export const PathNode = Object.freeze({
454
+ destruct(node) {
455
+ const lastChild = atArray(node?.children, -1);
456
+ return {
457
+ children: node?.children ?? [],
458
+ isAbsolute: node?.isAbsolute,
459
+ lastIdentifier: IdentifierNode.is(lastChild) ? lastChild : undefined,
460
+ };
461
+ },
210
462
  is(node) {
211
463
  return node?.type === 'mcdoc:path';
212
464
  },
213
465
  });
214
466
  export const StructBlockNode = Object.freeze({
467
+ destruct(node) {
468
+ return {
469
+ fields: node.children.filter(StructFieldNode.is),
470
+ };
471
+ },
215
472
  is(node) {
216
473
  return node?.type === 'mcdoc:struct/block';
217
474
  },
@@ -222,6 +479,14 @@ export const StructFieldNode = Object.freeze({
222
479
  },
223
480
  });
224
481
  export const StructPairFieldNode = Object.freeze({
482
+ destruct(node) {
483
+ return {
484
+ attributes: node.children.filter(AttributeNode.is),
485
+ key: node.children.find(StructKeyNode.is),
486
+ type: node.children.find(TypeNode.is),
487
+ isOptional: node.isOptional,
488
+ };
489
+ },
225
490
  is(node) {
226
491
  return node?.type === 'mcdoc:struct/field/pair';
227
492
  },
@@ -232,30 +497,62 @@ export const StructKeyNode = Object.freeze({
232
497
  },
233
498
  });
234
499
  export const StructMapKeyNode = Object.freeze({
500
+ destruct(node) {
501
+ return {
502
+ type: node.children.find(TypeNode.is),
503
+ };
504
+ },
235
505
  is(node) {
236
506
  return node?.type === 'mcdoc:struct/map_key';
237
507
  },
238
508
  });
239
509
  export const StructSpreadFieldNode = Object.freeze({
510
+ destruct(node) {
511
+ return {
512
+ attributes: node.children.filter(AttributeNode.is),
513
+ type: node.children.find(TypeNode.is),
514
+ };
515
+ },
240
516
  is(node) {
241
517
  return node?.type === 'mcdoc:struct/field/spread';
242
518
  },
243
519
  });
244
520
  export const DispatcherTypeNode = Object.freeze({
521
+ destruct(node) {
522
+ return {
523
+ location: node.children.find(ResourceLocationNode.is),
524
+ index: node.children.find(IndexBodyNode.is),
525
+ };
526
+ },
245
527
  is(node) {
246
528
  return node?.type === 'mcdoc:type/dispatcher';
247
529
  },
248
530
  });
249
531
  export const UnionTypeNode = Object.freeze({
532
+ destruct(node) {
533
+ return {
534
+ members: node.children.filter(TypeNode.is),
535
+ };
536
+ },
250
537
  is(node) {
251
538
  return node?.type === 'mcdoc:type/union';
252
539
  },
253
540
  });
254
541
  export const InjectionNode = Object.freeze({
542
+ destruct(node) {
543
+ return {
544
+ injection: node.children.find(InjectionContentNode.is),
545
+ };
546
+ },
255
547
  is(node) {
256
548
  return node?.type === 'mcdoc:injection';
257
549
  },
258
550
  });
551
+ export const InjectionContentNode = Object.freeze({
552
+ is(node) {
553
+ return EnumInjectionNode.is(node) || StructInjectionNode.is(node);
554
+ },
555
+ });
259
556
  export const EnumInjectionNode = Object.freeze({
260
557
  is(node) {
261
558
  return node?.type === 'mcdoc:injection/enum';
@@ -267,11 +564,25 @@ export const StructInjectionNode = Object.freeze({
267
564
  },
268
565
  });
269
566
  export const TypeAliasNode = Object.freeze({
567
+ destruct(node) {
568
+ return {
569
+ docComments: node.children.find(DocCommentsNode.is),
570
+ identifier: node.children.find(IdentifierNode.is),
571
+ typeParams: node.children.find(TypeParamBlockNode.is),
572
+ rhs: node.children.find(TypeNode.is),
573
+ };
574
+ },
270
575
  is(node) {
271
576
  return node?.type === 'mcdoc:type_alias';
272
577
  },
273
578
  });
274
579
  export const UseStatementNode = Object.freeze({
580
+ destruct(node) {
581
+ return {
582
+ binding: node.children.find(IdentifierNode.is),
583
+ path: node.children.find(PathNode.is),
584
+ };
585
+ },
275
586
  is(node) {
276
587
  return node?.type === 'mcdoc:use_statement';
277
588
  },
@@ -1,6 +1,6 @@
1
1
  import type { ColorTokenType, CommentNode, FloatNode, InfallibleParser, IntegerNode, Parser, ResourceLocationNode, ResourceLocationOptions, StringNode } from '@spyglassmc/core';
2
2
  import { Arrayable } from '@spyglassmc/core';
3
- import type { AnyTypeNode, AttributeNode, BooleanTypeNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, EnumNode, IdentifierNode, InjectionNode, ListTypeNode, LiteralNode, LiteralTypeNode, ModuleNode, NumericTypeNode, PathNode, PathTypeNode, PrimitiveArrayTypeNode, StringTypeNode, StructNode, TupleTypeNode, TypeAliasNode, TypedNumberNode, TypeNode, UnionTypeNode, UseStatementNode } from '../node/index.js';
3
+ import type { AnyTypeNode, AttributeNode, BooleanTypeNode, DispatcherTypeNode, DispatchStatementNode, DocCommentsNode, EnumNode, FloatRangeNode, IdentifierNode, InjectionNode, IntRangeNode, ListTypeNode, LiteralNode, LiteralTypeNode, ModuleNode, NumericTypeNode, PathNode, PrimitiveArrayTypeNode, ReferenceTypeNode, StringTypeNode, StructNode, TupleTypeNode, TypeAliasNode, TypedNumberNode, TypeNode, UnionTypeNode, UseStatementNode } from '../node/index.js';
4
4
  /**
5
5
  * @returns A comment parser that accepts normal comments (`//`) and reports an error if it's a doc comment (`///`).
6
6
  *
@@ -31,14 +31,16 @@ export declare const module_: Parser<ModuleNode>;
31
31
  export declare const anyType: Parser<AnyTypeNode>;
32
32
  export declare const booleanType: Parser<BooleanTypeNode>;
33
33
  export declare const integer: InfallibleParser<IntegerNode>;
34
+ export declare const intRange: InfallibleParser<IntRangeNode>;
34
35
  export declare const stringType: Parser<StringTypeNode>;
35
36
  export declare const literalType: Parser<LiteralTypeNode>;
37
+ export declare const floatRange: InfallibleParser<FloatRangeNode>;
36
38
  export declare const numericType: Parser<NumericTypeNode>;
37
39
  export declare const primitiveArrayType: Parser<PrimitiveArrayTypeNode>;
38
40
  export declare const listType: Parser<ListTypeNode>;
39
41
  export declare const tupleType: Parser<TupleTypeNode>;
40
42
  export declare const dispatcherType: Parser<DispatcherTypeNode>;
41
43
  export declare const unionType: Parser<UnionTypeNode>;
42
- export declare const pathType: InfallibleParser<PathTypeNode>;
44
+ export declare const referenceType: InfallibleParser<ReferenceTypeNode>;
43
45
  export declare const type: InfallibleParser<TypeNode>;
44
46
  //# sourceMappingURL=index.d.ts.map