@spyglassmc/mcdoc 0.3.7 → 0.3.9

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.
@@ -2,15 +2,13 @@ import * as core from '@spyglassmc/core';
2
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 { 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
  *
9
9
  * `Failure` when there isn't a comment.
10
10
  */
11
- export const comment = validate(core.comment({
12
- singleLinePrefixes: new Set(['//']),
13
- }), (res, src) => !src.slice(res).startsWith('///'), localize('mcdoc.parser.syntax.doc-comment-unexpected'));
11
+ export const comment = validate(core.comment({ singleLinePrefixes: new Set(['//']) }), (res, src) => !src.slice(res).startsWith('///'), localize('mcdoc.parser.syntax.doc-comment-unexpected'));
14
12
  /**
15
13
  * @returns A parser that parses the gap between **SYNTAX** rules, which may contains whitespace and regular comments.
16
14
  */
@@ -20,9 +18,7 @@ delegatesDocComments = false) {
20
18
  return (src, ctx) => {
21
19
  const ans = [];
22
20
  src.skipWhitespace();
23
- while (src.canRead() &&
24
- src.peek(2) === '//' &&
25
- (!delegatesDocComments || src.peek(3) !== '///')) {
21
+ while (src.canRead() && src.peek(2) === '//' && (!delegatesDocComments || src.peek(3) !== '///')) {
26
22
  const result = comment(src, ctx);
27
23
  ans.push(result);
28
24
  src.skipWhitespace();
@@ -49,8 +45,7 @@ export function literal(literal, options) {
49
45
  value: '',
50
46
  colorTokenType: options?.colorTokenType,
51
47
  };
52
- ans.value = src.readIf((c) => options?.allowedChars?.has(c) ??
53
- (options?.specialChars?.has(c) || /[a-z]/i.test(c)));
48
+ ans.value = src.readIf((c) => options?.allowedChars?.has(c) ?? (options?.specialChars?.has(c) || /[a-z]/i.test(c)));
54
49
  ans.range.end = src.cursor;
55
50
  if (Arrayable.toArray(literal).every((l) => l !== ans.value)) {
56
51
  ctx.err.report(localize('expected-got', arrayToMessage(literal), localeQuote(ans.value)), ans);
@@ -108,10 +103,7 @@ const UnicodeControlCharacters = Object.freeze([
108
103
  '\x7F',
109
104
  ]);
110
105
  export const string = stopBefore(core.string({
111
- escapable: {
112
- characters: ['b', 'f', 'n', 'r', 't', '\\', '"'],
113
- unicode: true,
114
- },
106
+ escapable: { characters: ['b', 'f', 'n', 'r', 't', '\\', '"'], unicode: true },
115
107
  quotes: ['"'],
116
108
  }), ...UnicodeControlCharacters);
117
109
  export const identifier = (src, ctx) => {
@@ -159,17 +151,9 @@ export const identifier = (src, ctx) => {
159
151
  };
160
152
  function indexBody(options) {
161
153
  const accessorKey = select([
162
- {
163
- prefix: '%',
164
- parser: literal(['%key', '%parent'], { specialChars: new Set(['%']) }),
165
- },
166
- {
167
- prefix: '"',
168
- parser: string,
169
- },
170
- {
171
- parser: identifier,
172
- },
154
+ { prefix: '%', parser: literal(['%key', '%parent'], { specialChars: new Set(['%']) }) },
155
+ { prefix: '"', parser: string },
156
+ { parser: identifier },
173
157
  ]);
174
158
  const dynamicIndex = setType('mcdoc:dynamic_index', syntax([
175
159
  punctuation('['),
@@ -182,10 +166,7 @@ function indexBody(options) {
182
166
  prefix: '%',
183
167
  parser: literal(StaticIndexKeywords.map((v) => `%${v}`), { specialChars: new Set(['%']) }),
184
168
  },
185
- {
186
- prefix: '"',
187
- parser: string,
188
- },
169
+ { prefix: '"', parser: string },
189
170
  {
190
171
  prefix: '[',
191
172
  parser: options?.noDynamic
@@ -194,10 +175,7 @@ function indexBody(options) {
194
175
  },
195
176
  {
196
177
  parser: any([
197
- resLoc({
198
- category: 'mcdoc/dispatcher',
199
- accessType: options?.accessType,
200
- }),
178
+ resLoc({ category: 'mcdoc/dispatcher', accessType: options?.accessType }),
201
179
  identifier,
202
180
  ]),
203
181
  },
@@ -210,10 +188,10 @@ function indexBody(options) {
210
188
  punctuation(']'),
211
189
  ]));
212
190
  }
213
- const pathSegment = select([
214
- { prefix: 'super', parser: literal('super') },
215
- { parser: identifier },
216
- ]);
191
+ const pathSegment = select([{
192
+ prefix: 'super',
193
+ parser: literal('super'),
194
+ }, { parser: identifier }]);
217
195
  export const path = (src, ctx) => {
218
196
  let isAbsolute;
219
197
  if (src.trySkip('::')) {
@@ -235,13 +213,10 @@ const attributeTreePosValues = setType('mcdoc:attribute/tree/pos', syntax([
235
213
  ], true));
236
214
  const attributeNamedValue = syntax([
237
215
  select([{ prefix: '"', parser: string }, { parser: identifier }]),
238
- select([
239
- {
216
+ select([{
240
217
  prefix: '=',
241
218
  parser: syntax([punctuation('='), { get: () => attributeValue }], true),
242
- },
243
- { parser: { get: () => attributeTree } },
244
- ]),
219
+ }, { parser: { get: () => attributeTree } }]),
245
220
  ], true);
246
221
  const attributeTreeNamedValues = setType('mcdoc:attribute/tree/named', syntax([
247
222
  attributeNamedValue,
@@ -257,11 +232,7 @@ const treeBody = any([
257
232
  ]),
258
233
  syntax([attributeTreePosValues, optional(marker(','))]),
259
234
  ]);
260
- const AttributeTreeClosure = Object.freeze({
261
- '(': ')',
262
- '[': ']',
263
- '{': '}',
264
- });
235
+ const AttributeTreeClosure = Object.freeze({ '(': ')', '[': ']', '{': '}' });
265
236
  const attributeTree = (src, ctx) => {
266
237
  const delim = src.trySkip('(')
267
238
  ? '('
@@ -283,30 +254,20 @@ const attributeTree = (src, ctx) => {
283
254
  src.trySkip(AttributeTreeClosure[delim]);
284
255
  return ans;
285
256
  };
286
- const attributeValue = select([
287
- {
257
+ const attributeValue = select([{
288
258
  predicate: (src) => ['(', '[', '{'].includes(src.peek()),
289
259
  parser: attributeTree,
290
- },
291
- { parser: { get: () => type } },
292
- ]);
260
+ }, { parser: { get: () => type } }]);
293
261
  export const attribute = setType('mcdoc:attribute', syntax([
294
262
  marker('#['),
295
263
  identifier,
296
- select([
297
- {
264
+ select([{
298
265
  prefix: '=',
299
266
  parser: syntax([punctuation('='), attributeValue, punctuation(']')], true),
300
- },
301
- {
267
+ }, {
302
268
  predicate: (src) => ['(', '[', '{'].includes(src.peek()),
303
- parser: syntax([
304
- attributeTree,
305
- punctuation(']'),
306
- ], true),
307
- },
308
- { parser: punctuation(']') },
309
- ]),
269
+ parser: syntax([attributeTree, punctuation(']')], true),
270
+ }, { parser: punctuation(']') }]),
310
271
  ], true));
311
272
  const attributes = repeat(attribute);
312
273
  const typeParam = setType('mcdoc:type_param', syntax([
@@ -315,17 +276,14 @@ const typeParam = setType('mcdoc:type_param', syntax([
315
276
  ]));
316
277
  const typeParamBlock = setType('mcdoc:type_param_block', syntax([
317
278
  punctuation('<'),
318
- select([
319
- { prefix: '>', parser: punctuation('>') },
320
- {
279
+ select([{ prefix: '>', parser: punctuation('>') }, {
321
280
  parser: syntax([
322
281
  typeParam,
323
282
  syntaxRepeat(syntax([marker(','), failOnEmpty(typeParam)])),
324
283
  optional(marker(',')),
325
284
  punctuation('>'),
326
285
  ]),
327
- },
328
- ]),
286
+ }]),
329
287
  ]));
330
288
  const noop = () => undefined;
331
289
  export const docComment = core.comment({
@@ -336,48 +294,74 @@ export const docComments = setType('mcdoc:doc_comments', repeat(docComment, (src
336
294
  src.skipWhitespace();
337
295
  return [];
338
296
  }));
339
- const prelim = syntax([optional(failOnEmpty(docComments)), attributes]);
340
- const optionalTypeParamBlock = select([{ prefix: '<', parser: typeParamBlock }, { parser: noop }]);
297
+ const prelim = syntax([
298
+ optional(failOnEmpty(docComments)),
299
+ attributes,
300
+ ]);
301
+ const optionalTypeParamBlock = select([{
302
+ prefix: '<',
303
+ parser: typeParamBlock,
304
+ }, { parser: noop }]);
341
305
  export const dispatchStatement = setType('mcdoc:dispatch_statement', syntax([
342
306
  prelim,
343
307
  keyword('dispatch'),
344
- resLoc({
345
- category: 'mcdoc/dispatcher',
346
- accessType: 1 /* SymbolAccessType.Write */,
347
- }),
308
+ resLoc({ category: 'mcdoc/dispatcher', accessType: 1 /* SymbolAccessType.Write */ }),
348
309
  indexBody({ noDynamic: true }),
349
310
  optionalTypeParamBlock,
350
311
  literal('to'),
351
312
  { get: () => type },
352
313
  ], true));
353
- const enumType = literal(['byte', 'short', 'int', 'long', 'string', 'float', 'double'], { colorTokenType: 'type' });
314
+ const enumType = literal([
315
+ 'byte',
316
+ 'short',
317
+ 'int',
318
+ 'long',
319
+ 'string',
320
+ 'float',
321
+ 'double',
322
+ ], { colorTokenType: 'type' });
354
323
  export const float = core.float({
355
324
  pattern: /^[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)?|[0-9]*\.[0-9]+(?:[eE][-+]?[0-9]+)?)$/,
356
325
  });
357
- export const typedNumber = setType('mcdoc:typed_number', sequence([
358
- float,
359
- optional(keyword(LiteralNumberCaseInsensitiveSuffixes, {
360
- colorTokenType: 'keyword',
361
- })),
362
- ]));
363
- const enumValue = select([
364
- { prefix: '"', parser: string },
365
- { parser: typedNumber },
326
+ export const integer = core.integer({
327
+ pattern: /^(?:0|[-+]?[1-9][0-9]*)$/,
328
+ });
329
+ export const LiteralIntSuffixes = Object.freeze(['b', 's', 'l']);
330
+ export const LiteralIntCaseInsensitiveSuffixes = Object.freeze([...LiteralIntSuffixes, 'B', 'S', 'L']);
331
+ export const LiteralFloatSuffixes = Object.freeze(['f', 'd']);
332
+ export const LiteralFloatCaseInsensitiveSuffixes = Object.freeze([...LiteralFloatSuffixes, 'F', 'D']);
333
+ export const LiteralNumberSuffixes = Object.freeze([...LiteralIntSuffixes, ...LiteralFloatSuffixes]);
334
+ export const LiteralNumberCaseInsensitiveSuffixes = Object.freeze([
335
+ ...LiteralNumberSuffixes,
336
+ ...LiteralIntCaseInsensitiveSuffixes,
337
+ ...LiteralFloatCaseInsensitiveSuffixes,
366
338
  ]);
339
+ export const typedNumber = setType('mcdoc:typed_number', select([{
340
+ regex: /^(?:\+|-)?\d+(?!\d|[.dfe])/i,
341
+ parser: sequence([
342
+ integer,
343
+ optional(keyword(LiteralIntCaseInsensitiveSuffixes, { colorTokenType: 'keyword' })),
344
+ ]),
345
+ }, {
346
+ parser: sequence([
347
+ float,
348
+ optional(keyword(LiteralFloatCaseInsensitiveSuffixes, { colorTokenType: 'keyword' })),
349
+ ]),
350
+ }]));
351
+ const enumValue = select([{ prefix: '"', parser: string }, {
352
+ parser: typedNumber,
353
+ }]);
367
354
  const enumField = setType('mcdoc:enum/field', syntax([prelim, identifier, punctuation('='), enumValue], true));
368
355
  const enumBlock = setType('mcdoc:enum/block', syntax([
369
356
  punctuation('{'),
370
- select([
371
- { prefix: '}', parser: punctuation('}') },
372
- {
357
+ select([{ prefix: '}', parser: punctuation('}') }, {
373
358
  parser: syntax([
374
359
  enumField,
375
360
  syntaxRepeat(syntax([marker(','), failOnEmpty(enumField)], true), true),
376
361
  optional(marker(',')),
377
362
  punctuation('}'),
378
363
  ], true),
379
- },
380
- ]),
364
+ }]),
381
365
  ], true));
382
366
  export const enum_ = setType('mcdoc:enum', syntax([
383
367
  prelim,
@@ -389,11 +373,10 @@ export const enum_ = setType('mcdoc:enum', syntax([
389
373
  enumBlock,
390
374
  ], true));
391
375
  const structMapKey = setType('mcdoc:struct/map_key', syntax([punctuation('['), { get: () => type }, punctuation(']')], true));
392
- const structKey = select([
393
- { prefix: '"', parser: string },
394
- { prefix: '[', parser: structMapKey },
395
- { parser: identifier },
396
- ]);
376
+ const structKey = select([{ prefix: '"', parser: string }, {
377
+ prefix: '[',
378
+ parser: structMapKey,
379
+ }, { parser: identifier }]);
397
380
  const structPairField = (src, ctx) => {
398
381
  let isOptional;
399
382
  const result0 = syntax([prelim, structKey], true)(src, ctx);
@@ -410,58 +393,35 @@ const structPairField = (src, ctx) => {
410
393
  return ans;
411
394
  };
412
395
  const structSpreadField = setType('mcdoc:struct/field/spread', syntax([attributes, marker('...'), { get: () => type }], true));
413
- const structField = any([structSpreadField, structPairField]);
396
+ const structField = any([
397
+ structSpreadField,
398
+ structPairField,
399
+ ]);
414
400
  const structBlock = setType('mcdoc:struct/block', syntax([
415
401
  punctuation('{'),
416
- select([
417
- { prefix: '}', parser: punctuation('}') },
418
- {
402
+ select([{ prefix: '}', parser: punctuation('}') }, {
419
403
  parser: syntax([
420
404
  structField,
421
405
  syntaxRepeat(syntax([marker(','), failOnEmpty(structField)], true), true),
422
406
  optional(marker(',')),
423
407
  punctuation('}'),
424
408
  ], true),
425
- },
426
- ]),
427
- ], true));
428
- export const struct = setType('mcdoc:struct', syntax([
429
- prelim,
430
- keyword('struct'),
431
- optional(failOnEmpty(identifier)),
432
- structBlock,
409
+ }]),
433
410
  ], true));
434
- const enumInjection = setType('mcdoc:injection/enum', syntax([
435
- literal('enum'),
436
- punctuation('('),
437
- enumType,
438
- punctuation(')'),
439
- path,
440
- enumBlock,
441
- ]));
411
+ export const struct = setType('mcdoc:struct', syntax([prelim, keyword('struct'), optional(failOnEmpty(identifier)), structBlock], true));
412
+ const enumInjection = setType('mcdoc:injection/enum', syntax([literal('enum'), punctuation('('), enumType, punctuation(')'), path, enumBlock]));
442
413
  const structInjection = setType('mcdoc:injection/struct', syntax([literal('struct'), path, structBlock]));
443
414
  export const injection = setType('mcdoc:injection', syntax([
444
415
  keyword('inject'),
445
- select([
446
- { prefix: 'enum', parser: enumInjection },
447
- { parser: structInjection },
448
- ]),
416
+ select([{ prefix: 'enum', parser: enumInjection }, { parser: structInjection }]),
449
417
  ]));
450
- export const typeAliasStatement = setType('mcdoc:type_alias', syntax([
451
- prelim,
452
- keyword('type'),
453
- identifier,
454
- optionalTypeParamBlock,
455
- punctuation('='),
456
- { get: () => type },
457
- ], true));
418
+ export const typeAliasStatement = setType('mcdoc:type_alias', syntax([prelim, keyword('type'), identifier, optionalTypeParamBlock, punctuation('='), {
419
+ get: () => type,
420
+ }], true));
458
421
  export const useStatement = setType('mcdoc:use_statement', syntax([
459
422
  keyword('use'),
460
423
  path,
461
- select([
462
- { prefix: 'as', parser: syntax([literal('as'), identifier]) },
463
- { parser: noop },
464
- ]),
424
+ select([{ prefix: 'as', parser: syntax([literal('as'), identifier]) }, { parser: noop }]),
465
425
  ], true));
466
426
  const topLevel = any([
467
427
  comment,
@@ -475,34 +435,25 @@ const topLevel = any([
475
435
  export const module_ = setType('mcdoc:module', syntaxRepeat(topLevel, true));
476
436
  const typeArgBlock = setType('mcdoc:type_arg_block', syntax([
477
437
  marker('<'),
478
- select([
479
- { prefix: '>', parser: punctuation('>') },
480
- {
438
+ select([{ prefix: '>', parser: punctuation('>') }, {
481
439
  parser: syntax([
482
440
  { get: () => type },
483
441
  syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
484
442
  optional(marker(',')),
485
443
  punctuation('>'),
486
444
  ], true),
487
- },
488
- ]),
445
+ }]),
489
446
  ]));
490
447
  /* eslint-enable @typescript-eslint/indent */
491
448
  function typeBase(type, parser) {
492
449
  return setType(type, syntax([
493
450
  attributes,
494
451
  parser,
495
- syntaxRepeat(select([
496
- { prefix: '<', parser: typeArgBlock },
497
- { parser: failOnError(indexBody()) },
498
- ]), true),
452
+ syntaxRepeat(select([{ prefix: '<', parser: typeArgBlock }, { parser: failOnError(indexBody()) }]), true),
499
453
  ], true));
500
454
  }
501
455
  export const anyType = typeBase('mcdoc:type/any', keyword('any', { colorTokenType: 'type' }));
502
456
  export const booleanType = typeBase('mcdoc:type/boolean', keyword('boolean', { colorTokenType: 'type' }));
503
- export const integer = core.integer({
504
- pattern: /^(?:0|[-+]?[1-9][0-9]*)$/,
505
- });
506
457
  function range(type, number) {
507
458
  const delimiterPredicate = (src) => src.tryPeek('..') || src.tryPeek(`${RangeExclusiveChar}..`);
508
459
  const delimiterParser = literal([
@@ -510,30 +461,16 @@ function range(type, number) {
510
461
  `..${RangeExclusiveChar}`,
511
462
  `${RangeExclusiveChar}..`,
512
463
  `${RangeExclusiveChar}..${RangeExclusiveChar}`,
513
- ], {
514
- allowedChars: new Set(['.', RangeExclusiveChar]),
515
- });
516
- return setType(type, select([
517
- {
518
- predicate: delimiterPredicate,
519
- parser: sequence([delimiterParser, number]),
520
- },
521
- {
464
+ ], { allowedChars: new Set(['.', RangeExclusiveChar]) });
465
+ return setType(type, select([{ predicate: delimiterPredicate, parser: sequence([delimiterParser, number]) }, {
522
466
  parser: sequence([
523
467
  stopBefore(number, '..'),
524
- select([
525
- {
468
+ select([{
526
469
  predicate: delimiterPredicate,
527
- parser: sequence([
528
- delimiterParser,
529
- optional(failOnEmpty(number)),
530
- ]),
531
- },
532
- { parser: noop },
533
- ]),
470
+ parser: sequence([delimiterParser, optional(failOnEmpty(number))]),
471
+ }, { parser: noop }]),
534
472
  ]),
535
- },
536
- ]));
473
+ }]));
537
474
  }
538
475
  export const intRange = range('mcdoc:int_range', integer);
539
476
  const atIntRange = optional((src, ctx) => {
@@ -543,7 +480,10 @@ const atIntRange = optional((src, ctx) => {
543
480
  src.skipWhitespace();
544
481
  return intRange(src, ctx);
545
482
  });
546
- export const stringType = typeBase('mcdoc:type/string', syntax([keyword('string', { colorTokenType: 'type' }), atIntRange]));
483
+ export const stringType = typeBase('mcdoc:type/string', syntax([
484
+ keyword('string', { colorTokenType: 'type' }),
485
+ atIntRange,
486
+ ], true));
547
487
  export const literalType = typeBase('mcdoc:type/literal', select([
548
488
  {
549
489
  predicate: (src) => src.tryPeek('false') || src.tryPeek('true'),
@@ -560,28 +500,16 @@ const atFloatRange = optional((src, ctx) => {
560
500
  src.skipWhitespace();
561
501
  return floatRange(src, ctx);
562
502
  });
563
- export const numericType = typeBase('mcdoc:type/numeric_type', select([
564
- {
503
+ export const numericType = typeBase('mcdoc:type/numeric_type', select([{
565
504
  predicate: (src) => NumericTypeFloatKinds.some((k) => src.tryPeek(k)),
566
- parser: syntax([
567
- keyword(NumericTypeFloatKinds, { colorTokenType: 'type' }),
568
- atFloatRange,
569
- ], true),
570
- },
571
- {
572
- parser: syntax([
573
- keyword(NumericTypeIntKinds, { colorTokenType: 'type' }),
574
- atIntRange,
575
- ], true),
576
- },
577
- ]));
505
+ parser: syntax([keyword(NumericTypeFloatKinds, { colorTokenType: 'type' }), atFloatRange], true),
506
+ }, {
507
+ parser: syntax([keyword(NumericTypeIntKinds, { colorTokenType: 'type' }), atIntRange], true),
508
+ }]));
578
509
  export const primitiveArrayType = typeBase('mcdoc:type/primitive_array', syntax([
579
510
  literal(PrimitiveArrayValueKinds),
580
511
  atIntRange,
581
- keyword('[]', {
582
- allowedChars: new Set(['[', ']']),
583
- colorTokenType: 'type',
584
- }),
512
+ keyword('[]', { allowedChars: new Set(['[', ']']), colorTokenType: 'type' }),
585
513
  atIntRange,
586
514
  ]));
587
515
  export const listType = typeBase('mcdoc:type/list', syntax([marker('['), { get: () => type }, punctuation(']'), atIntRange], true));
@@ -589,32 +517,26 @@ export const tupleType = typeBase('mcdoc:type/tuple', syntax([
589
517
  marker('['),
590
518
  { get: () => type },
591
519
  marker(','),
592
- select([
593
- { prefix: ']', parser: punctuation(']') },
594
- {
520
+ select([{ prefix: ']', parser: punctuation(']') }, {
595
521
  parser: syntax([
596
522
  { get: () => type },
597
523
  syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
598
524
  optional(marker(',')),
599
525
  punctuation(']'),
600
526
  ], true),
601
- },
602
- ]),
527
+ }]),
603
528
  ], true));
604
529
  export const dispatcherType = typeBase('mcdoc:type/dispatcher', syntax([failOnError(resLoc({ category: 'mcdoc/dispatcher' })), indexBody()]));
605
530
  export const unionType = typeBase('mcdoc:type/union', syntax([
606
531
  marker('('),
607
- select([
608
- { prefix: ')', parser: punctuation(')') },
609
- {
532
+ select([{ prefix: ')', parser: punctuation(')') }, {
610
533
  parser: syntax([
611
534
  { get: () => type },
612
535
  syntaxRepeat(syntax([marker('|'), { get: () => failOnEmpty(type) }], true), true),
613
536
  optional(marker('|')),
614
537
  punctuation(')'),
615
538
  ], true),
616
- },
617
- ]),
539
+ }]),
618
540
  ]));
619
541
  export const referenceType = typeBase('mcdoc:type/reference', syntax([path]));
620
542
  export const type = any([
@@ -0,0 +1,3 @@
1
+ import * as core from '@spyglassmc/core';
2
+ export declare function registerBuiltinAttributes(meta: core.MetaRegistry): void;
3
+ //# sourceMappingURL=builtin.d.ts.map
@@ -0,0 +1,130 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import { registerAttribute, validator } from './index.js';
3
+ const idValidator = validator.alternatives(validator.map(validator.string, v => ({ registry: v })), validator.tree({
4
+ registry: validator.string,
5
+ tags: validator.optional(validator.options('allowed', 'implicit', 'required')),
6
+ definition: validator.optional(validator.boolean),
7
+ prefix: validator.optional(validator.options('!')),
8
+ }), () => ({}));
9
+ function getResourceLocationOptions({ registry, tags, definition }, requireCanonical, ctx, typeDef) {
10
+ if (!registry) {
11
+ if (typeDef?.kind === 'enum' && typeDef.enumKind === 'string') {
12
+ return {
13
+ pool: typeDef.values.map(v => core.ResourceLocation.lengthen(`${v.value}`)),
14
+ allowUnknown: true, // the mcdoc checker will already report errors for this
15
+ };
16
+ }
17
+ if (typeDef?.kind === 'literal' && typeDef.value.kind === 'string') {
18
+ return {
19
+ pool: [core.ResourceLocation.lengthen(typeDef.value.value)],
20
+ allowUnknown: true,
21
+ };
22
+ }
23
+ return { pool: [], allowUnknown: true };
24
+ }
25
+ if (tags === 'implicit') {
26
+ registry = `tag/${registry}`;
27
+ }
28
+ // TODO: disallow non-tags when tags=required
29
+ if (tags === 'allowed' || tags === 'required') {
30
+ if (core.TaggableResourceLocationCategory.is(registry)) {
31
+ return {
32
+ category: registry,
33
+ requireCanonical,
34
+ allowTag: true,
35
+ };
36
+ }
37
+ }
38
+ else if (core.ResourceLocationCategory.is(registry)) {
39
+ return {
40
+ category: registry,
41
+ requireCanonical,
42
+ usageType: definition ? 'definition' : 'reference',
43
+ };
44
+ }
45
+ ctx.logger.warn(`[mcdoc id] Unhandled registry ${registry}`);
46
+ return undefined;
47
+ }
48
+ export function registerBuiltinAttributes(meta) {
49
+ registerAttribute(meta, 'canonical', () => undefined, {
50
+ // Has hardcoded behavior in the runtime checker
51
+ });
52
+ registerAttribute(meta, 'dispatcher_key', validator.string, {
53
+ stringMocker: (config, _, ctx) => {
54
+ const symbol = ctx.symbols.query(ctx.doc, 'mcdoc/dispatcher', config).symbol;
55
+ const keys = Object.keys(symbol?.members ?? {}).filter(m => !m.startsWith('%'));
56
+ return core.LiteralNode.mock(ctx.offset, { pool: keys });
57
+ },
58
+ });
59
+ registerAttribute(meta, 'id', idValidator, {
60
+ checkInferred: (config, inferred, ctx) => {
61
+ if (inferred.kind === 'string') {
62
+ // Internal mcdoc isAssignable check
63
+ const idAttr = inferred.attributes?.find(a => a.name === 'id');
64
+ if (idAttr) {
65
+ const inferredConfig = idValidator(idAttr.value, ctx);
66
+ return inferredConfig === core.Failure || inferredConfig.prefix === config.prefix;
67
+ // Prefix doesn't match
68
+ }
69
+ }
70
+ if (inferred.kind !== 'literal' || inferred.value.kind !== 'string') {
71
+ return true; // Ignore attribute when not a string
72
+ }
73
+ if (config.prefix && !inferred.value.value.startsWith(config.prefix)) {
74
+ return false; // Missing prefix
75
+ }
76
+ if (!config.prefix && inferred.value.value.startsWith('!')) {
77
+ return false; // Unexpected prefix
78
+ }
79
+ if (!inferred.value.value.includes(':')) {
80
+ if (config.prefix) {
81
+ inferred.value.value = config.prefix + 'minecraft:'
82
+ + inferred.value.value.slice(config.prefix.length);
83
+ }
84
+ else {
85
+ inferred.value.value = 'minecraft:' + inferred.value.value;
86
+ }
87
+ }
88
+ return true;
89
+ },
90
+ mapType: (config, typeDef, ctx) => {
91
+ if (typeDef.kind === 'literal' && typeDef.value.kind === 'string') {
92
+ const value = core.ResourceLocation.lengthen(typeDef.value.value);
93
+ return { ...typeDef, value: { kind: 'string', value } };
94
+ }
95
+ if (typeDef.kind === 'enum' && typeDef.enumKind === 'string') {
96
+ const values = typeDef.values.map(v => ({
97
+ ...v,
98
+ value: core.ResourceLocation.lengthen(`${v.value}`),
99
+ }));
100
+ return { ...typeDef, values };
101
+ }
102
+ return typeDef;
103
+ },
104
+ stringParser: (config, typeDef, ctx) => {
105
+ const options = getResourceLocationOptions(config, ctx.requireCanonical, ctx, typeDef);
106
+ if (!options) {
107
+ return;
108
+ }
109
+ const resourceLocation = core.resourceLocation(options);
110
+ return (src, ctx) => {
111
+ if (config.prefix) {
112
+ return core.prefixed({ prefix: config.prefix, child: resourceLocation })(src, ctx);
113
+ }
114
+ return resourceLocation(src, ctx);
115
+ };
116
+ },
117
+ stringMocker: (config, typeDef, ctx) => {
118
+ const options = getResourceLocationOptions(config, ctx.requireCanonical ?? false, ctx, typeDef);
119
+ if (!options) {
120
+ return undefined;
121
+ }
122
+ const resourceLocation = core.ResourceLocationNode.mock(ctx.offset, options);
123
+ if (config.prefix) {
124
+ return core.PrefixedNode.mock(ctx.offset, config.prefix, resourceLocation);
125
+ }
126
+ return resourceLocation;
127
+ },
128
+ });
129
+ }
130
+ //# sourceMappingURL=builtin.js.map