@spyglassmc/mcdoc 0.3.1 → 0.3.3

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,8 +1,8 @@
1
1
  import * as core from '@spyglassmc/core';
2
- import { any, Arrayable, failOnEmpty, failOnError, Failure, map, optional, Range, repeat, ResourceLocation, select, sequence, setType, stopBefore, validate } from '@spyglassmc/core';
2
+ import { any, Arrayable, failOnEmpty, failOnError, Failure, map, optional, Range, repeat, ResourceLocation, select, sequence, setType, stopBefore, validate, } from '@spyglassmc/core';
3
3
  import { arrayToMessage, localeQuote, localize } from '@spyglassmc/locales';
4
4
  import { RangeExclusiveChar } from '../node/index.js';
5
- import { LiteralNumberCaseInsensitiveSuffixes, NumericTypeFloatKinds, NumericTypeIntKinds, PrimitiveArrayValueKinds, StaticIndexKeywords } from '../type/index.js';
5
+ import { LiteralNumberCaseInsensitiveSuffixes, NumericTypeFloatKinds, NumericTypeIntKinds, PrimitiveArrayValueKinds, StaticIndexKeywords, } from '../type/index.js';
6
6
  /**
7
7
  * @returns A comment parser that accepts normal comments (`//`) and reports an error if it's a doc comment (`///`).
8
8
  *
@@ -20,7 +20,9 @@ delegatesDocComments = false) {
20
20
  return (src, ctx) => {
21
21
  const ans = [];
22
22
  src.skipWhitespace();
23
- while (src.canRead() && src.peek(2) === '//' && (!delegatesDocComments || src.peek(3) !== '///')) {
23
+ while (src.canRead() &&
24
+ src.peek(2) === '//' &&
25
+ (!delegatesDocComments || src.peek(3) !== '///')) {
24
26
  const result = comment(src, ctx);
25
27
  ans.push(result);
26
28
  src.skipWhitespace();
@@ -47,9 +49,10 @@ export function literal(literal, options) {
47
49
  value: '',
48
50
  colorTokenType: options?.colorTokenType,
49
51
  };
50
- ans.value = src.readIf(c => options?.allowedChars?.has(c) ?? (options?.specialChars?.has(c) || /[a-z]/i.test(c)));
52
+ ans.value = src.readIf((c) => options?.allowedChars?.has(c) ??
53
+ (options?.specialChars?.has(c) || /[a-z]/i.test(c)));
51
54
  ans.range.end = src.cursor;
52
- if (Arrayable.toArray(literal).every(l => l !== ans.value)) {
55
+ if (Arrayable.toArray(literal).every((l) => l !== ans.value)) {
53
56
  ctx.err.report(localize('expected-got', arrayToMessage(literal), localeQuote(ans.value)), ans);
54
57
  }
55
58
  return ans;
@@ -83,22 +86,54 @@ function marker(punctuation) {
83
86
  };
84
87
  }
85
88
  export function resLoc(options) {
86
- return validate(core.resourceLocation(options), res => res.namespace !== undefined, localize('mcdoc.parser.resource-location.colon-expected', localeQuote(ResourceLocation.NamespacePathSep)));
89
+ return validate(core.resourceLocation(options), (res) => res.namespace !== undefined, localize('mcdoc.parser.resource-location.colon-expected', localeQuote(ResourceLocation.NamespacePathSep)));
87
90
  }
88
91
  const UnicodeControlCharacters = Object.freeze([
89
- '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06',
90
- '\x07', '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D',
91
- '\x0E', '\x0F', '\x7F',
92
+ '\x00',
93
+ '\x01',
94
+ '\x02',
95
+ '\x03',
96
+ '\x04',
97
+ '\x05',
98
+ '\x06',
99
+ '\x07',
100
+ '\x08',
101
+ '\x09',
102
+ '\x0A',
103
+ '\x0B',
104
+ '\x0C',
105
+ '\x0D',
106
+ '\x0E',
107
+ '\x0F',
108
+ '\x7F',
92
109
  ]);
93
110
  export const string = stopBefore(core.string({
94
- escapable: { characters: ['b', 'f', 'n', 'r', 't', '\\', '"'], unicode: true },
111
+ escapable: {
112
+ characters: ['b', 'f', 'n', 'r', 't', '\\', '"'],
113
+ unicode: true,
114
+ },
95
115
  quotes: ['"'],
96
116
  }), ...UnicodeControlCharacters);
97
117
  export const identifier = (src, ctx) => {
98
118
  // https://spyglassmc.com/user/mcdoc/#identifier
99
119
  const IdentifierStart = /^[\p{L}\p{Nl}]$/u;
100
120
  const IdentifierContinue = /^[\p{L}\p{Nl}\u200C\u200D\p{Mn}\p{Mc}\p{Nd}\p{Pc}]$/u;
101
- const ReservedWords = new Set(['any', 'boolean', 'byte', 'double', 'enum', 'false', 'float', 'int', 'long', 'short', 'string', 'struct', 'super', 'true']);
121
+ const ReservedWords = new Set([
122
+ 'any',
123
+ 'boolean',
124
+ 'byte',
125
+ 'double',
126
+ 'enum',
127
+ 'false',
128
+ 'float',
129
+ 'int',
130
+ 'long',
131
+ 'short',
132
+ 'string',
133
+ 'struct',
134
+ 'super',
135
+ 'true',
136
+ ]);
102
137
  const ans = {
103
138
  type: 'mcdoc:identifier',
104
139
  range: Range.create(src),
@@ -145,7 +180,7 @@ function indexBody(options) {
145
180
  const index = select([
146
181
  {
147
182
  prefix: '%',
148
- parser: literal(StaticIndexKeywords.map(v => `%${v}`), { specialChars: new Set(['%']) }),
183
+ parser: literal(StaticIndexKeywords.map((v) => `%${v}`), { specialChars: new Set(['%']) }),
149
184
  },
150
185
  {
151
186
  prefix: '"',
@@ -158,7 +193,13 @@ function indexBody(options) {
158
193
  : dynamicIndex,
159
194
  },
160
195
  {
161
- parser: any([resLoc({ category: 'mcdoc/dispatcher', accessType: options?.accessType }), identifier]),
196
+ parser: any([
197
+ resLoc({
198
+ category: 'mcdoc/dispatcher',
199
+ accessType: options?.accessType,
200
+ }),
201
+ identifier,
202
+ ]),
162
203
  },
163
204
  ]);
164
205
  return setType('mcdoc:index_body', syntax([
@@ -178,10 +219,7 @@ export const path = (src, ctx) => {
178
219
  if (src.trySkip('::')) {
179
220
  isAbsolute = true;
180
221
  }
181
- return map(sequence([
182
- pathSegment,
183
- repeat(sequence([marker('::'), pathSegment])),
184
- ]), res => {
222
+ return map(sequence([pathSegment, repeat(sequence([marker('::'), pathSegment]))]), (res) => {
185
223
  const ans = {
186
224
  type: 'mcdoc:path',
187
225
  children: res.children,
@@ -196,12 +234,12 @@ const attributeTreePosValues = setType('mcdoc:attribute/tree/pos', syntax([
196
234
  syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(attributeValue) }], true), true),
197
235
  ], true));
198
236
  const attributeNamedValue = syntax([
237
+ select([{ prefix: '"', parser: string }, { parser: identifier }]),
199
238
  select([
200
- { prefix: '"', parser: string },
201
- { parser: identifier },
202
- ]),
203
- select([
204
- { prefix: '=', parser: syntax([punctuation('='), { get: () => attributeValue }], true) },
239
+ {
240
+ prefix: '=',
241
+ parser: syntax([punctuation('='), { get: () => attributeValue }], true),
242
+ },
205
243
  { parser: { get: () => attributeTree } },
206
244
  ]),
207
245
  ], true);
@@ -211,7 +249,12 @@ const attributeTreeNamedValues = setType('mcdoc:attribute/tree/named', syntax([
211
249
  ], true));
212
250
  const treeBody = any([
213
251
  syntax([attributeTreeNamedValues, optional(marker(','))]),
214
- syntax([attributeTreePosValues, punctuation(','), attributeTreeNamedValues, optional(marker(','))]),
252
+ syntax([
253
+ attributeTreePosValues,
254
+ punctuation(','),
255
+ attributeTreeNamedValues,
256
+ optional(marker(',')),
257
+ ]),
215
258
  syntax([attributeTreePosValues, optional(marker(','))]),
216
259
  ]);
217
260
  const AttributeTreeClosure = Object.freeze({
@@ -220,7 +263,13 @@ const AttributeTreeClosure = Object.freeze({
220
263
  '{': '}',
221
264
  });
222
265
  const attributeTree = (src, ctx) => {
223
- const delim = src.trySkip('(') ? '(' : (src.trySkip('[') ? '[' : (src.trySkip('{') ? '{' : undefined));
266
+ const delim = src.trySkip('(')
267
+ ? '('
268
+ : src.trySkip('[')
269
+ ? '['
270
+ : src.trySkip('{')
271
+ ? '{'
272
+ : undefined;
224
273
  if (!delim) {
225
274
  return Failure;
226
275
  }
@@ -235,24 +284,60 @@ const attributeTree = (src, ctx) => {
235
284
  return ans;
236
285
  };
237
286
  const attributeValue = select([
238
- { predicate: src => ['(', '[', '{'].includes(src.peek()), parser: attributeTree },
287
+ {
288
+ predicate: (src) => ['(', '[', '{'].includes(src.peek()),
289
+ parser: attributeTree,
290
+ },
239
291
  { parser: { get: () => type } },
240
292
  ]);
241
293
  export const attribute = setType('mcdoc:attribute', syntax([
242
294
  marker('#['),
243
295
  identifier,
244
296
  select([
245
- { prefix: '=', parser: syntax([punctuation('='), attributeValue, punctuation(']')], true) },
246
- { predicate: src => ['(', '[', '{'].includes(src.peek()), parser: syntax([attributeTree, punctuation(']')], true) },
297
+ {
298
+ prefix: '=',
299
+ parser: syntax([punctuation('='), attributeValue, punctuation(']')], true),
300
+ },
301
+ {
302
+ predicate: (src) => ['(', '[', '{'].includes(src.peek()),
303
+ parser: syntax([
304
+ attributeTree,
305
+ punctuation(']'),
306
+ ], true),
307
+ },
247
308
  { parser: punctuation(']') },
248
309
  ]),
249
310
  ], true));
250
311
  const attributes = repeat(attribute);
312
+ const typeParam = setType('mcdoc:type_param', syntax([
313
+ identifier,
314
+ // optional(syntax([failOnError(literal('extends')), { get: () => type }])),
315
+ ]));
316
+ const typeParamBlock = setType('mcdoc:type_param_block', syntax([
317
+ punctuation('<'),
318
+ select([
319
+ { prefix: '>', parser: punctuation('>') },
320
+ {
321
+ parser: syntax([
322
+ typeParam,
323
+ syntaxRepeat(syntax([marker(','), failOnEmpty(typeParam)])),
324
+ optional(marker(',')),
325
+ punctuation('>'),
326
+ ]),
327
+ },
328
+ ]),
329
+ ]));
330
+ const noop = () => undefined;
331
+ const optionalTypeParamBlock = select([{ prefix: '<', parser: typeParamBlock }, { parser: noop }]);
251
332
  export const dispatchStatement = setType('mcdoc:dispatch_statement', syntax([
252
333
  attributes,
253
334
  keyword('dispatch'),
254
- resLoc({ category: 'mcdoc/dispatcher', accessType: 1 /* SymbolAccessType.Write */ }),
335
+ resLoc({
336
+ category: 'mcdoc/dispatcher',
337
+ accessType: 1 /* SymbolAccessType.Write */,
338
+ }),
255
339
  indexBody({ noDynamic: true }),
340
+ optionalTypeParamBlock,
256
341
  literal('to'),
257
342
  { get: () => type },
258
343
  ], true));
@@ -260,40 +345,26 @@ export const docComment = core.comment({
260
345
  singleLinePrefixes: new Set(['///']),
261
346
  includesEol: true,
262
347
  });
263
- export const docComments = setType('mcdoc:doc_comments', repeat(docComment, src => {
348
+ export const docComments = setType('mcdoc:doc_comments', repeat(docComment, (src) => {
264
349
  src.skipWhitespace();
265
350
  return [];
266
351
  }));
267
- const prelim = syntax([
268
- optional(failOnEmpty(docComments)),
269
- attributes,
270
- ]);
271
- const enumType = literal([
272
- 'byte',
273
- 'short',
274
- 'int',
275
- 'long',
276
- 'string',
277
- 'float',
278
- 'double',
279
- ], { colorTokenType: 'type' });
352
+ const prelim = syntax([optional(failOnEmpty(docComments)), attributes]);
353
+ const enumType = literal(['byte', 'short', 'int', 'long', 'string', 'float', 'double'], { colorTokenType: 'type' });
280
354
  export const float = core.float({
281
355
  pattern: /^[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)?|[0-9]*\.[0-9]+(?:[eE][-+]?[0-9]+)?)$/,
282
356
  });
283
357
  export const typedNumber = setType('mcdoc:typed_number', sequence([
284
358
  float,
285
- optional(keyword(LiteralNumberCaseInsensitiveSuffixes, { colorTokenType: 'keyword' })),
359
+ optional(keyword(LiteralNumberCaseInsensitiveSuffixes, {
360
+ colorTokenType: 'keyword',
361
+ })),
286
362
  ]));
287
363
  const enumValue = select([
288
364
  { prefix: '"', parser: string },
289
365
  { parser: typedNumber },
290
366
  ]);
291
- const enumField = setType('mcdoc:enum/field', syntax([
292
- prelim,
293
- identifier,
294
- punctuation('='),
295
- enumValue,
296
- ], true));
367
+ const enumField = setType('mcdoc:enum/field', syntax([prelim, identifier, punctuation('='), enumValue], true));
297
368
  const enumBlock = setType('mcdoc:enum/block', syntax([
298
369
  punctuation('{'),
299
370
  select([
@@ -317,11 +388,7 @@ export const enum_ = setType('mcdoc:enum', syntax([
317
388
  optional(failOnError(identifier)),
318
389
  enumBlock,
319
390
  ], true));
320
- const structMapKey = setType('mcdoc:struct/map_key', syntax([
321
- punctuation('['),
322
- { get: () => type },
323
- punctuation(']'),
324
- ], true));
391
+ const structMapKey = setType('mcdoc:struct/map_key', syntax([punctuation('['), { get: () => type }, punctuation(']')], true));
325
392
  const structKey = select([
326
393
  { prefix: '"', parser: string },
327
394
  { prefix: '[', parser: structMapKey },
@@ -329,17 +396,11 @@ const structKey = select([
329
396
  ]);
330
397
  const structPairField = (src, ctx) => {
331
398
  let isOptional;
332
- const result0 = syntax([
333
- prelim,
334
- structKey,
335
- ], true)(src, ctx);
399
+ const result0 = syntax([prelim, structKey], true)(src, ctx);
336
400
  if (src.trySkip('?')) {
337
401
  isOptional = true;
338
402
  }
339
- const result1 = syntax([
340
- punctuation(':'),
341
- { get: () => type },
342
- ], true)(src, ctx);
403
+ const result1 = syntax([punctuation(':'), { get: () => type }], true)(src, ctx);
343
404
  const ans = {
344
405
  type: 'mcdoc:struct/field/pair',
345
406
  children: [...result0.children, ...result1.children],
@@ -348,15 +409,8 @@ const structPairField = (src, ctx) => {
348
409
  };
349
410
  return ans;
350
411
  };
351
- const structSpreadField = setType('mcdoc:struct/field/spread', syntax([
352
- attributes,
353
- marker('...'),
354
- { get: () => type },
355
- ], true));
356
- const structField = any([
357
- structSpreadField,
358
- structPairField,
359
- ]);
412
+ const structSpreadField = setType('mcdoc:struct/field/spread', syntax([attributes, marker('...'), { get: () => type }], true));
413
+ const structField = any([structSpreadField, structPairField]);
360
414
  const structBlock = setType('mcdoc:struct/block', syntax([
361
415
  punctuation('{'),
362
416
  select([
@@ -385,11 +439,7 @@ const enumInjection = setType('mcdoc:injection/enum', syntax([
385
439
  path,
386
440
  enumBlock,
387
441
  ]));
388
- const structInjection = setType('mcdoc:injection/struct', syntax([
389
- literal('struct'),
390
- path,
391
- structBlock,
392
- ]));
442
+ const structInjection = setType('mcdoc:injection/struct', syntax([literal('struct'), path, structBlock]));
393
443
  export const injection = setType('mcdoc:injection', syntax([
394
444
  keyword('inject'),
395
445
  select([
@@ -397,31 +447,8 @@ export const injection = setType('mcdoc:injection', syntax([
397
447
  { parser: structInjection },
398
448
  ]),
399
449
  ]));
400
- const typeParam = setType('mcdoc:type_param', syntax([
401
- identifier,
402
- // optional(syntax([failOnError(literal('extends')), { get: () => type }])),
403
- ]));
404
- const typeParamBlock = setType('mcdoc:type_param_block', syntax([
405
- punctuation('<'),
406
- select([
407
- { prefix: '>', parser: punctuation('>') },
408
- {
409
- parser: syntax([
410
- typeParam,
411
- syntaxRepeat(syntax([marker(','), failOnEmpty(typeParam)])),
412
- optional(marker(',')),
413
- punctuation('>'),
414
- ]),
415
- },
416
- ]),
417
- ]));
418
- const noop = () => undefined;
419
- const optionalTypeParamBlock = select([
420
- { prefix: '<', parser: typeParamBlock },
421
- { parser: noop },
422
- ]);
423
- export const typeAlias = setType('mcdoc:type_alias', syntax([
424
- docComments,
450
+ export const typeAliasStatement = setType('mcdoc:type_alias', syntax([
451
+ prelim,
425
452
  keyword('type'),
426
453
  identifier,
427
454
  optionalTypeParamBlock,
@@ -442,16 +469,33 @@ const topLevel = any([
442
469
  enum_,
443
470
  injection,
444
471
  struct,
445
- typeAlias,
472
+ typeAliasStatement,
446
473
  useStatement,
447
474
  ]);
448
475
  export const module_ = setType('mcdoc:module', syntaxRepeat(topLevel, true));
476
+ const typeArgBlock = setType('mcdoc:type_arg_block', syntax([
477
+ marker('<'),
478
+ select([
479
+ { prefix: '>', parser: punctuation('>') },
480
+ {
481
+ parser: syntax([
482
+ { get: () => type },
483
+ syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
484
+ optional(marker(',')),
485
+ punctuation('>'),
486
+ ], true),
487
+ },
488
+ ]),
489
+ ]));
449
490
  /* eslint-enable @typescript-eslint/indent */
450
491
  function typeBase(type, parser) {
451
492
  return setType(type, syntax([
452
493
  attributes,
453
494
  parser,
454
- syntaxRepeat(failOnError(indexBody())),
495
+ syntaxRepeat(select([
496
+ { prefix: '<', parser: typeArgBlock },
497
+ { parser: failOnError(indexBody()) },
498
+ ])),
455
499
  ], true));
456
500
  }
457
501
  export const anyType = typeBase('mcdoc:type/any', keyword('any', { colorTokenType: 'type' }));
@@ -472,10 +516,7 @@ function range(type, number) {
472
516
  return setType(type, select([
473
517
  {
474
518
  predicate: delimiterPredicate,
475
- parser: sequence([
476
- delimiterParser,
477
- number,
478
- ]),
519
+ parser: sequence([delimiterParser, number]),
479
520
  },
480
521
  {
481
522
  parser: sequence([
@@ -502,12 +543,12 @@ const atIntRange = optional((src, ctx) => {
502
543
  src.skipWhitespace();
503
544
  return intRange(src, ctx);
504
545
  });
505
- export const stringType = typeBase('mcdoc:type/string', syntax([
506
- keyword('string', { colorTokenType: 'type' }),
507
- atIntRange,
508
- ]));
546
+ export const stringType = typeBase('mcdoc:type/string', syntax([keyword('string', { colorTokenType: 'type' }), atIntRange]));
509
547
  export const literalType = typeBase('mcdoc:type/literal', select([
510
- { predicate: src => src.tryPeek('false') || src.tryPeek('true'), parser: keyword(['false', 'true'], { colorTokenType: 'type' }) },
548
+ {
549
+ predicate: (src) => src.tryPeek('false') || src.tryPeek('true'),
550
+ parser: keyword(['false', 'true'], { colorTokenType: 'type' }),
551
+ },
511
552
  { prefix: '"', parser: failOnEmpty(string) },
512
553
  { parser: failOnError(typedNumber) },
513
554
  ]));
@@ -521,7 +562,7 @@ const atFloatRange = optional((src, ctx) => {
521
562
  });
522
563
  export const numericType = typeBase('mcdoc:type/numeric_type', select([
523
564
  {
524
- predicate: src => NumericTypeFloatKinds.some(k => src.tryPeek(k)),
565
+ predicate: (src) => NumericTypeFloatKinds.some((k) => src.tryPeek(k)),
525
566
  parser: syntax([
526
567
  keyword(NumericTypeFloatKinds, { colorTokenType: 'type' }),
527
568
  atFloatRange,
@@ -537,15 +578,13 @@ export const numericType = typeBase('mcdoc:type/numeric_type', select([
537
578
  export const primitiveArrayType = typeBase('mcdoc:type/primitive_array', syntax([
538
579
  literal(PrimitiveArrayValueKinds),
539
580
  atIntRange,
540
- keyword('[]', { allowedChars: new Set(['[', ']']), colorTokenType: 'type' }),
581
+ keyword('[]', {
582
+ allowedChars: new Set(['[', ']']),
583
+ colorTokenType: 'type',
584
+ }),
541
585
  atIntRange,
542
586
  ]));
543
- export const listType = typeBase('mcdoc:type/list', syntax([
544
- marker('['),
545
- { get: () => type },
546
- punctuation(']'),
547
- atIntRange,
548
- ], true));
587
+ export const listType = typeBase('mcdoc:type/list', syntax([marker('['), { get: () => type }, punctuation(']'), atIntRange], true));
549
588
  export const tupleType = typeBase('mcdoc:type/tuple', syntax([
550
589
  marker('['),
551
590
  { get: () => type },
@@ -562,10 +601,7 @@ export const tupleType = typeBase('mcdoc:type/tuple', syntax([
562
601
  },
563
602
  ]),
564
603
  ], true));
565
- export const dispatcherType = typeBase('mcdoc:type/dispatcher', syntax([
566
- failOnError(resLoc({ category: 'mcdoc/dispatcher' })),
567
- indexBody(),
568
- ]));
604
+ export const dispatcherType = typeBase('mcdoc:type/dispatcher', syntax([failOnError(resLoc({ category: 'mcdoc/dispatcher' })), indexBody()]));
569
605
  export const unionType = typeBase('mcdoc:type/union', syntax([
570
606
  marker('('),
571
607
  select([
@@ -580,23 +616,7 @@ export const unionType = typeBase('mcdoc:type/union', syntax([
580
616
  },
581
617
  ]),
582
618
  ]));
583
- export const referenceType = typeBase('mcdoc:type/reference', syntax([
584
- path,
585
- optional(syntax([
586
- marker('<'),
587
- select([
588
- { prefix: '>', parser: punctuation('>') },
589
- {
590
- parser: syntax([
591
- { get: () => type },
592
- syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
593
- optional(marker(',')),
594
- punctuation('>'),
595
- ], true),
596
- },
597
- ]),
598
- ])),
599
- ]));
619
+ export const referenceType = typeBase('mcdoc:type/reference', syntax([path]));
600
620
  export const type = any([
601
621
  anyType,
602
622
  booleanType,