@spyglassmc/mcdoc 0.3.8 → 0.3.10
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/binder/index.js +108 -192
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -4
- package/lib/node/index.d.ts +5 -0
- package/lib/node/index.js +76 -131
- package/lib/parser/index.js +97 -217
- package/lib/runtime/attribute/builtin.d.ts +3 -0
- package/lib/runtime/attribute/builtin.js +130 -0
- package/lib/runtime/attribute/index.d.ts +22 -0
- package/lib/runtime/attribute/index.js +22 -0
- package/lib/runtime/attribute/validator.d.ts +16 -0
- package/lib/runtime/attribute/validator.js +85 -0
- package/lib/runtime/checker/context.d.ts +34 -0
- package/lib/runtime/checker/context.js +17 -0
- package/lib/runtime/checker/error.d.ts +70 -0
- package/lib/runtime/checker/error.js +352 -0
- package/lib/runtime/checker/index.d.ts +80 -0
- package/lib/runtime/checker/index.js +914 -0
- package/lib/runtime/completer/index.d.ts +20 -0
- package/lib/runtime/completer/index.js +123 -0
- package/lib/runtime/index.d.ts +5 -0
- package/lib/runtime/index.js +5 -0
- package/lib/type/index.d.ts +65 -82
- package/lib/type/index.js +341 -407
- package/lib/uri_processors.js +2 -8
- package/package.json +3 -3
package/lib/parser/index.js
CHANGED
|
@@ -8,9 +8,7 @@ import { NumericTypeFloatKinds, NumericTypeIntKinds, PrimitiveArrayValueKinds, S
|
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
215
|
-
|
|
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
|
-
|
|
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,93 +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([
|
|
340
|
-
|
|
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([
|
|
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
326
|
export const integer = core.integer({
|
|
358
327
|
pattern: /^(?:0|[-+]?[1-9][0-9]*)$/,
|
|
359
328
|
});
|
|
360
|
-
export const LiteralIntSuffixes = Object.freeze([
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
]);
|
|
365
|
-
export const LiteralIntCaseInsensitiveSuffixes = Object.freeze([
|
|
366
|
-
...LiteralIntSuffixes,
|
|
367
|
-
'B',
|
|
368
|
-
'S',
|
|
369
|
-
'L',
|
|
370
|
-
]);
|
|
371
|
-
export const LiteralFloatSuffixes = Object.freeze([
|
|
372
|
-
'f',
|
|
373
|
-
'd',
|
|
374
|
-
]);
|
|
375
|
-
export const LiteralFloatCaseInsensitiveSuffixes = Object.freeze([
|
|
376
|
-
...LiteralFloatSuffixes,
|
|
377
|
-
'F',
|
|
378
|
-
'D',
|
|
379
|
-
]);
|
|
380
|
-
export const LiteralNumberSuffixes = Object.freeze([
|
|
381
|
-
...LiteralIntSuffixes,
|
|
382
|
-
...LiteralFloatSuffixes,
|
|
383
|
-
]);
|
|
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]);
|
|
384
334
|
export const LiteralNumberCaseInsensitiveSuffixes = Object.freeze([
|
|
385
335
|
...LiteralNumberSuffixes,
|
|
386
336
|
...LiteralIntCaseInsensitiveSuffixes,
|
|
387
337
|
...LiteralFloatCaseInsensitiveSuffixes,
|
|
388
338
|
]);
|
|
389
|
-
export const typedNumber = setType('mcdoc:typed_number', select([
|
|
390
|
-
{
|
|
339
|
+
export const typedNumber = setType('mcdoc:typed_number', select([{
|
|
391
340
|
regex: /^(?:\+|-)?\d+(?!\d|[.dfe])/i,
|
|
392
341
|
parser: sequence([
|
|
393
342
|
integer,
|
|
394
|
-
optional(keyword(LiteralIntCaseInsensitiveSuffixes, {
|
|
395
|
-
colorTokenType: 'keyword',
|
|
396
|
-
})),
|
|
343
|
+
optional(keyword(LiteralIntCaseInsensitiveSuffixes, { colorTokenType: 'keyword' })),
|
|
397
344
|
]),
|
|
398
|
-
},
|
|
399
|
-
{
|
|
345
|
+
}, {
|
|
400
346
|
parser: sequence([
|
|
401
347
|
float,
|
|
402
|
-
optional(keyword(LiteralFloatCaseInsensitiveSuffixes, {
|
|
403
|
-
colorTokenType: 'keyword',
|
|
404
|
-
})),
|
|
348
|
+
optional(keyword(LiteralFloatCaseInsensitiveSuffixes, { colorTokenType: 'keyword' })),
|
|
405
349
|
]),
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
{ parser: typedNumber },
|
|
411
|
-
]);
|
|
350
|
+
}]));
|
|
351
|
+
const enumValue = select([{ prefix: '"', parser: string }, {
|
|
352
|
+
parser: typedNumber,
|
|
353
|
+
}]);
|
|
412
354
|
const enumField = setType('mcdoc:enum/field', syntax([prelim, identifier, punctuation('='), enumValue], true));
|
|
413
355
|
const enumBlock = setType('mcdoc:enum/block', syntax([
|
|
414
356
|
punctuation('{'),
|
|
415
|
-
select([
|
|
416
|
-
{ prefix: '}', parser: punctuation('}') },
|
|
417
|
-
{
|
|
357
|
+
select([{ prefix: '}', parser: punctuation('}') }, {
|
|
418
358
|
parser: syntax([
|
|
419
359
|
enumField,
|
|
420
360
|
syntaxRepeat(syntax([marker(','), failOnEmpty(enumField)], true), true),
|
|
421
361
|
optional(marker(',')),
|
|
422
362
|
punctuation('}'),
|
|
423
363
|
], true),
|
|
424
|
-
},
|
|
425
|
-
]),
|
|
364
|
+
}]),
|
|
426
365
|
], true));
|
|
427
366
|
export const enum_ = setType('mcdoc:enum', syntax([
|
|
428
367
|
prelim,
|
|
@@ -434,11 +373,10 @@ export const enum_ = setType('mcdoc:enum', syntax([
|
|
|
434
373
|
enumBlock,
|
|
435
374
|
], true));
|
|
436
375
|
const structMapKey = setType('mcdoc:struct/map_key', syntax([punctuation('['), { get: () => type }, punctuation(']')], true));
|
|
437
|
-
const structKey = select([
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
{ parser: identifier }
|
|
441
|
-
]);
|
|
376
|
+
const structKey = select([{ prefix: '"', parser: string }, {
|
|
377
|
+
prefix: '[',
|
|
378
|
+
parser: structMapKey,
|
|
379
|
+
}, { parser: identifier }]);
|
|
442
380
|
const structPairField = (src, ctx) => {
|
|
443
381
|
let isOptional;
|
|
444
382
|
const result0 = syntax([prelim, structKey], true)(src, ctx);
|
|
@@ -455,58 +393,35 @@ const structPairField = (src, ctx) => {
|
|
|
455
393
|
return ans;
|
|
456
394
|
};
|
|
457
395
|
const structSpreadField = setType('mcdoc:struct/field/spread', syntax([attributes, marker('...'), { get: () => type }], true));
|
|
458
|
-
const structField = any([
|
|
396
|
+
const structField = any([
|
|
397
|
+
structSpreadField,
|
|
398
|
+
structPairField,
|
|
399
|
+
]);
|
|
459
400
|
const structBlock = setType('mcdoc:struct/block', syntax([
|
|
460
401
|
punctuation('{'),
|
|
461
|
-
select([
|
|
462
|
-
{ prefix: '}', parser: punctuation('}') },
|
|
463
|
-
{
|
|
402
|
+
select([{ prefix: '}', parser: punctuation('}') }, {
|
|
464
403
|
parser: syntax([
|
|
465
404
|
structField,
|
|
466
405
|
syntaxRepeat(syntax([marker(','), failOnEmpty(structField)], true), true),
|
|
467
406
|
optional(marker(',')),
|
|
468
407
|
punctuation('}'),
|
|
469
408
|
], true),
|
|
470
|
-
},
|
|
471
|
-
]),
|
|
409
|
+
}]),
|
|
472
410
|
], true));
|
|
473
|
-
export const struct = setType('mcdoc:struct', syntax([
|
|
474
|
-
|
|
475
|
-
keyword('struct'),
|
|
476
|
-
optional(failOnEmpty(identifier)),
|
|
477
|
-
structBlock,
|
|
478
|
-
], true));
|
|
479
|
-
const enumInjection = setType('mcdoc:injection/enum', syntax([
|
|
480
|
-
literal('enum'),
|
|
481
|
-
punctuation('('),
|
|
482
|
-
enumType,
|
|
483
|
-
punctuation(')'),
|
|
484
|
-
path,
|
|
485
|
-
enumBlock,
|
|
486
|
-
]));
|
|
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]));
|
|
487
413
|
const structInjection = setType('mcdoc:injection/struct', syntax([literal('struct'), path, structBlock]));
|
|
488
414
|
export const injection = setType('mcdoc:injection', syntax([
|
|
489
415
|
keyword('inject'),
|
|
490
|
-
select([
|
|
491
|
-
{ prefix: 'enum', parser: enumInjection },
|
|
492
|
-
{ parser: structInjection },
|
|
493
|
-
]),
|
|
416
|
+
select([{ prefix: 'enum', parser: enumInjection }, { parser: structInjection }]),
|
|
494
417
|
]));
|
|
495
|
-
export const typeAliasStatement = setType('mcdoc:type_alias', syntax([
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
identifier,
|
|
499
|
-
optionalTypeParamBlock,
|
|
500
|
-
punctuation('='),
|
|
501
|
-
{ get: () => type },
|
|
502
|
-
], true));
|
|
418
|
+
export const typeAliasStatement = setType('mcdoc:type_alias', syntax([prelim, keyword('type'), identifier, optionalTypeParamBlock, punctuation('='), {
|
|
419
|
+
get: () => type,
|
|
420
|
+
}], true));
|
|
503
421
|
export const useStatement = setType('mcdoc:use_statement', syntax([
|
|
504
422
|
keyword('use'),
|
|
505
423
|
path,
|
|
506
|
-
select([
|
|
507
|
-
{ prefix: 'as', parser: syntax([literal('as'), identifier]) },
|
|
508
|
-
{ parser: noop },
|
|
509
|
-
]),
|
|
424
|
+
select([{ prefix: 'as', parser: syntax([literal('as'), identifier]) }, { parser: noop }]),
|
|
510
425
|
], true));
|
|
511
426
|
const topLevel = any([
|
|
512
427
|
comment,
|
|
@@ -520,27 +435,21 @@ const topLevel = any([
|
|
|
520
435
|
export const module_ = setType('mcdoc:module', syntaxRepeat(topLevel, true));
|
|
521
436
|
const typeArgBlock = setType('mcdoc:type_arg_block', syntax([
|
|
522
437
|
marker('<'),
|
|
523
|
-
select([
|
|
524
|
-
{ prefix: '>', parser: punctuation('>') },
|
|
525
|
-
{
|
|
438
|
+
select([{ prefix: '>', parser: punctuation('>') }, {
|
|
526
439
|
parser: syntax([
|
|
527
440
|
{ get: () => type },
|
|
528
441
|
syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
|
|
529
442
|
optional(marker(',')),
|
|
530
443
|
punctuation('>'),
|
|
531
444
|
], true),
|
|
532
|
-
},
|
|
533
|
-
]),
|
|
445
|
+
}]),
|
|
534
446
|
]));
|
|
535
447
|
/* eslint-enable @typescript-eslint/indent */
|
|
536
448
|
function typeBase(type, parser) {
|
|
537
449
|
return setType(type, syntax([
|
|
538
450
|
attributes,
|
|
539
451
|
parser,
|
|
540
|
-
syntaxRepeat(select([
|
|
541
|
-
{ prefix: '<', parser: typeArgBlock },
|
|
542
|
-
{ parser: failOnError(indexBody()) },
|
|
543
|
-
]), true),
|
|
452
|
+
syntaxRepeat(select([{ prefix: '<', parser: typeArgBlock }, { parser: failOnError(indexBody()) }]), true),
|
|
544
453
|
], true));
|
|
545
454
|
}
|
|
546
455
|
export const anyType = typeBase('mcdoc:type/any', keyword('any', { colorTokenType: 'type' }));
|
|
@@ -552,30 +461,16 @@ function range(type, number) {
|
|
|
552
461
|
`..${RangeExclusiveChar}`,
|
|
553
462
|
`${RangeExclusiveChar}..`,
|
|
554
463
|
`${RangeExclusiveChar}..${RangeExclusiveChar}`,
|
|
555
|
-
], {
|
|
556
|
-
|
|
557
|
-
});
|
|
558
|
-
return setType(type, select([
|
|
559
|
-
{
|
|
560
|
-
predicate: delimiterPredicate,
|
|
561
|
-
parser: sequence([delimiterParser, number]),
|
|
562
|
-
},
|
|
563
|
-
{
|
|
464
|
+
], { allowedChars: new Set(['.', RangeExclusiveChar]) });
|
|
465
|
+
return setType(type, select([{ predicate: delimiterPredicate, parser: sequence([delimiterParser, number]) }, {
|
|
564
466
|
parser: sequence([
|
|
565
467
|
stopBefore(number, '..'),
|
|
566
|
-
select([
|
|
567
|
-
{
|
|
468
|
+
select([{
|
|
568
469
|
predicate: delimiterPredicate,
|
|
569
|
-
parser: sequence([
|
|
570
|
-
|
|
571
|
-
optional(failOnEmpty(number)),
|
|
572
|
-
]),
|
|
573
|
-
},
|
|
574
|
-
{ parser: noop },
|
|
575
|
-
]),
|
|
470
|
+
parser: sequence([delimiterParser, optional(failOnEmpty(number))]),
|
|
471
|
+
}, { parser: noop }]),
|
|
576
472
|
]),
|
|
577
|
-
}
|
|
578
|
-
]));
|
|
473
|
+
}]));
|
|
579
474
|
}
|
|
580
475
|
export const intRange = range('mcdoc:int_range', integer);
|
|
581
476
|
const atIntRange = optional((src, ctx) => {
|
|
@@ -585,7 +480,10 @@ const atIntRange = optional((src, ctx) => {
|
|
|
585
480
|
src.skipWhitespace();
|
|
586
481
|
return intRange(src, ctx);
|
|
587
482
|
});
|
|
588
|
-
export const stringType = typeBase('mcdoc:type/string', syntax([
|
|
483
|
+
export const stringType = typeBase('mcdoc:type/string', syntax([
|
|
484
|
+
keyword('string', { colorTokenType: 'type' }),
|
|
485
|
+
atIntRange,
|
|
486
|
+
], true));
|
|
589
487
|
export const literalType = typeBase('mcdoc:type/literal', select([
|
|
590
488
|
{
|
|
591
489
|
predicate: (src) => src.tryPeek('false') || src.tryPeek('true'),
|
|
@@ -602,28 +500,16 @@ const atFloatRange = optional((src, ctx) => {
|
|
|
602
500
|
src.skipWhitespace();
|
|
603
501
|
return floatRange(src, ctx);
|
|
604
502
|
});
|
|
605
|
-
export const numericType = typeBase('mcdoc:type/numeric_type', select([
|
|
606
|
-
{
|
|
503
|
+
export const numericType = typeBase('mcdoc:type/numeric_type', select([{
|
|
607
504
|
predicate: (src) => NumericTypeFloatKinds.some((k) => src.tryPeek(k)),
|
|
608
|
-
parser: syntax([
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
},
|
|
613
|
-
{
|
|
614
|
-
parser: syntax([
|
|
615
|
-
keyword(NumericTypeIntKinds, { colorTokenType: 'type' }),
|
|
616
|
-
atIntRange,
|
|
617
|
-
], true),
|
|
618
|
-
},
|
|
619
|
-
]));
|
|
505
|
+
parser: syntax([keyword(NumericTypeFloatKinds, { colorTokenType: 'type' }), atFloatRange], true),
|
|
506
|
+
}, {
|
|
507
|
+
parser: syntax([keyword(NumericTypeIntKinds, { colorTokenType: 'type' }), atIntRange], true),
|
|
508
|
+
}]));
|
|
620
509
|
export const primitiveArrayType = typeBase('mcdoc:type/primitive_array', syntax([
|
|
621
510
|
literal(PrimitiveArrayValueKinds),
|
|
622
511
|
atIntRange,
|
|
623
|
-
keyword('[]', {
|
|
624
|
-
allowedChars: new Set(['[', ']']),
|
|
625
|
-
colorTokenType: 'type',
|
|
626
|
-
}),
|
|
512
|
+
keyword('[]', { allowedChars: new Set(['[', ']']), colorTokenType: 'type' }),
|
|
627
513
|
atIntRange,
|
|
628
514
|
]));
|
|
629
515
|
export const listType = typeBase('mcdoc:type/list', syntax([marker('['), { get: () => type }, punctuation(']'), atIntRange], true));
|
|
@@ -631,32 +517,26 @@ export const tupleType = typeBase('mcdoc:type/tuple', syntax([
|
|
|
631
517
|
marker('['),
|
|
632
518
|
{ get: () => type },
|
|
633
519
|
marker(','),
|
|
634
|
-
select([
|
|
635
|
-
{ prefix: ']', parser: punctuation(']') },
|
|
636
|
-
{
|
|
520
|
+
select([{ prefix: ']', parser: punctuation(']') }, {
|
|
637
521
|
parser: syntax([
|
|
638
522
|
{ get: () => type },
|
|
639
523
|
syntaxRepeat(syntax([marker(','), { get: () => failOnEmpty(type) }], true), true),
|
|
640
524
|
optional(marker(',')),
|
|
641
525
|
punctuation(']'),
|
|
642
526
|
], true),
|
|
643
|
-
},
|
|
644
|
-
]),
|
|
527
|
+
}]),
|
|
645
528
|
], true));
|
|
646
529
|
export const dispatcherType = typeBase('mcdoc:type/dispatcher', syntax([failOnError(resLoc({ category: 'mcdoc/dispatcher' })), indexBody()]));
|
|
647
530
|
export const unionType = typeBase('mcdoc:type/union', syntax([
|
|
648
531
|
marker('('),
|
|
649
|
-
select([
|
|
650
|
-
{ prefix: ')', parser: punctuation(')') },
|
|
651
|
-
{
|
|
532
|
+
select([{ prefix: ')', parser: punctuation(')') }, {
|
|
652
533
|
parser: syntax([
|
|
653
534
|
{ get: () => type },
|
|
654
535
|
syntaxRepeat(syntax([marker('|'), { get: () => failOnEmpty(type) }], true), true),
|
|
655
536
|
optional(marker('|')),
|
|
656
537
|
punctuation(')'),
|
|
657
538
|
], true),
|
|
658
|
-
},
|
|
659
|
-
]),
|
|
539
|
+
}]),
|
|
660
540
|
]));
|
|
661
541
|
export const referenceType = typeBase('mcdoc:type/reference', syntax([path]));
|
|
662
542
|
export const type = any([
|
|
@@ -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
|
+
if (tags === 'allowed' || tags === 'required') {
|
|
29
|
+
if (core.TaggableResourceLocationCategory.is(registry)) {
|
|
30
|
+
return {
|
|
31
|
+
category: registry,
|
|
32
|
+
requireCanonical,
|
|
33
|
+
allowTag: true,
|
|
34
|
+
requireTag: tags === 'required',
|
|
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
|