@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.
- package/lib/binder/index.js +122 -191
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -4
- package/lib/node/index.d.ts +9 -4
- package/lib/node/index.js +77 -131
- package/lib/parser/index.d.ts +13 -1
- package/lib/parser/index.js +112 -190
- 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 +73 -92
- package/lib/type/index.js +341 -422
- package/lib/uri_processors.js +2 -8
- package/package.json +3 -3
package/lib/parser/index.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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,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([
|
|
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
|
-
export const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
])
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
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
|
-
|
|
394
|
-
|
|
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([
|
|
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
|
|
435
|
-
|
|
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
|
-
|
|
452
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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([
|
|
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
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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,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
|