@spyglassmc/nbt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # `@spyglassmc/nbt`
2
+
3
+ ![banner](https://raw.githubusercontent.com/SpyglassMC/logo/main/banner.png)
4
+
5
+ [![npm](https://img.shields.io/npm/v/@spyglassmc/nbt.svg?logo=npm&style=flat-square)](https://npmjs.com/package/@spyglassmc/nbt)
6
+
7
+ This package contains parsers and processors for [stringified NBT][nbt-format].
8
+
9
+ # Contributions
10
+
11
+ ## Languages
12
+
13
+ - `nbt` language that is associated with the `.snbt` file extension.
14
+
15
+ ## AST Nodes
16
+
17
+ ## Processors
18
+
19
+ [nbt-format]: https://minecraft.gamepedia.com/NBT_format
@@ -0,0 +1,40 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import * as nbtdoc from '@spyglassmc/nbtdoc';
3
+ import type { NbtNode, NbtPathNode } from '../node';
4
+ import { NbtCompoundNode, NbtPrimitiveNode } from '../node';
5
+ interface Options {
6
+ allowUnknownKey?: boolean;
7
+ isPredicate?: boolean;
8
+ }
9
+ declare global {
10
+ interface ArrayConstructor {
11
+ isArray(arg: unknown): arg is unknown[] | readonly unknown[];
12
+ }
13
+ }
14
+ /**
15
+ * @param id If the registry is under the `custom` namespace, `id` can only be a string. Otherwise it can be a string, string array, or `undefined`.
16
+ * If set to `undefined` or an empty array, all nbtdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
17
+ */
18
+ export declare function index(registry: nbtdoc.ExtendableRootRegistry, id: core.FullResourceLocation | readonly core.FullResourceLocation[] | undefined, options?: Options): core.SyncChecker<NbtCompoundNode>;
19
+ export declare function index(registry: nbtdoc.ResolvedRootRegistry, id: core.FullResourceLocation, options?: Options): core.SyncChecker<NbtCompoundNode>;
20
+ /**
21
+ * @param identifier An identifier of nbtdoc compound definition. e.g. `::minecraft::util::invitem::InventoryItem`
22
+ */
23
+ export declare function definition(identifier: `::${string}::${string}`, options?: Options): core.SyncChecker<NbtCompoundNode>;
24
+ export declare function blockStates(blocks: string[], _options?: Options): core.SyncChecker<NbtCompoundNode>;
25
+ /**
26
+ * @param path The {@link core.SymbolPath} to the compound definition.
27
+ */
28
+ export declare function compound(data: ResolvedCompoundData, options?: Options): core.SyncChecker<NbtCompoundNode>;
29
+ export declare function enum_(path: core.SymbolPath | undefined, _options?: Options): core.SyncChecker<NbtPrimitiveNode>;
30
+ /**
31
+ * @param id If set to `undefined` or an empty array, all nbtdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
32
+ */
33
+ export declare function path(registry: nbtdoc.ExtendableRootRegistry, id: core.FullResourceLocation | readonly core.FullResourceLocation[] | undefined): core.SyncChecker<NbtPathNode>;
34
+ export declare function fieldValue(type: nbtdoc.NbtdocType, options: Options): core.SyncChecker<NbtNode>;
35
+ declare type ResolvedCompoundData = Record<string, {
36
+ data: nbtdoc.NbtdocType;
37
+ query?: core.SymbolQuery;
38
+ }>;
39
+ export {};
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,593 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.fieldValue = exports.path = exports.enum_ = exports.compound = exports.blockStates = exports.definition = exports.index = void 0;
23
+ const core = __importStar(require("@spyglassmc/core"));
24
+ const nbtdoc = __importStar(require("@spyglassmc/nbtdoc"));
25
+ const lib_1 = require("../../../locales/lib");
26
+ const node_1 = require("../node");
27
+ const util_1 = require("../util");
28
+ const nbtdocUtil_1 = require("./nbtdocUtil");
29
+ function index(registry, id, options = {}) {
30
+ switch (registry) {
31
+ case 'custom:blockitemstates':
32
+ const blockIds = (0, nbtdocUtil_1.getBlocksFromItem)(id);
33
+ return blockIds
34
+ ? blockStates(blockIds, options)
35
+ : core.checker.noop;
36
+ case 'custom:blockstates':
37
+ return blockStates([id], options);
38
+ case 'custom:spawnitemtag':
39
+ const entityId = (0, nbtdocUtil_1.getEntityFromItem)(id);
40
+ return entityId
41
+ ? index('entity_type', entityId, options)
42
+ : core.checker.noop;
43
+ default:
44
+ return (node, ctx) => {
45
+ const { allowUnknownKey, value } = resolveRootRegistry(registry, id, ctx, node);
46
+ options.allowUnknownKey || (options.allowUnknownKey = allowUnknownKey);
47
+ compound(value, options)(node, ctx);
48
+ };
49
+ }
50
+ }
51
+ exports.index = index;
52
+ /**
53
+ * @param identifier An identifier of nbtdoc compound definition. e.g. `::minecraft::util::invitem::InventoryItem`
54
+ */
55
+ function definition(identifier, options = {}) {
56
+ const index = identifier.lastIndexOf('::');
57
+ const module = identifier.slice(0, index);
58
+ const compoundDef = identifier.slice(index + 2);
59
+ const path = { category: 'nbtdoc', path: [module, compoundDef] };
60
+ return (node, ctx) => {
61
+ const { allowUnknownKey, value } = resolveSymbolPaths([path], ctx, node);
62
+ options.allowUnknownKey || (options.allowUnknownKey = allowUnknownKey);
63
+ compound(value, options)(node, ctx);
64
+ };
65
+ }
66
+ exports.definition = definition;
67
+ function blockStates(blocks, _options = {}) {
68
+ return (node, ctx) => {
69
+ const states = core.getStates('block', blocks, ctx);
70
+ for (const { key: keyNode, value: valueNode } of node.children) {
71
+ if (!keyNode || !valueNode) {
72
+ continue;
73
+ }
74
+ // Type check.
75
+ if (valueNode.type === 'nbt:byte' && (ctx.src.slice(valueNode.range).toLowerCase() === 'false' || ctx.src.slice(valueNode.range).toLowerCase() === 'true')) {
76
+ ctx.err.report((0, lib_1.localize)('nbt.checker.block-states.fake-boolean'), valueNode, 2 /* Warning */);
77
+ continue;
78
+ }
79
+ else if (valueNode.type !== 'string' && valueNode.type !== 'nbt:int') {
80
+ ctx.err.report((0, lib_1.localize)('nbt.checker.block-states.unexpected-value-type'), valueNode, 2 /* Warning */);
81
+ continue;
82
+ }
83
+ if (Object.keys(states).includes(keyNode.value)) {
84
+ // The current state exists. Check the value.
85
+ const stateValues = states[keyNode.value];
86
+ if (!stateValues.includes(valueNode.value.toString())) {
87
+ ctx.err.report((0, lib_1.localize)('expected-got', stateValues, (0, lib_1.localeQuote)(valueNode.value.toString())), valueNode, 2 /* Warning */);
88
+ }
89
+ }
90
+ else {
91
+ // The current state doesn't exist.
92
+ ctx.err.report((0, lib_1.localize)('nbt.checker.block-states.unknown-state', (0, lib_1.localeQuote)(keyNode.value), blocks), keyNode, 2 /* Warning */);
93
+ }
94
+ }
95
+ };
96
+ }
97
+ exports.blockStates = blockStates;
98
+ /**
99
+ * @param path The {@link core.SymbolPath} to the compound definition.
100
+ */
101
+ function compound(data, options = {}) {
102
+ return (node, ctx) => {
103
+ for (const { key: keyNode, value: valueNode } of node.children) {
104
+ if (!keyNode || !valueNode) {
105
+ continue;
106
+ }
107
+ const key = keyNode.value;
108
+ const fieldData = data[key];
109
+ if (fieldData) {
110
+ fieldData.query?.enter({ usage: { type: 'reference', node: keyNode } });
111
+ fieldValue(fieldData.data, options)(valueNode, ctx);
112
+ }
113
+ else if (!options.allowUnknownKey) {
114
+ ctx.err.report((0, lib_1.localize)('unknown-key', (0, lib_1.localeQuote)(key)), keyNode, 2 /* Warning */);
115
+ }
116
+ }
117
+ };
118
+ }
119
+ exports.compound = compound;
120
+ function enum_(path, _options = {}) {
121
+ if (!path) {
122
+ return core.checker.noop;
123
+ }
124
+ return (node, ctx) => {
125
+ const query = ctx.symbols.query(ctx.doc, path.category, ...path.path);
126
+ const data = query.symbol?.data;
127
+ // Check type.
128
+ if (data?.enumType && node.type !== data.enumType && node.type !== `nbt:${data.enumType}`) {
129
+ ctx.err.report((0, lib_1.localize)('expected', (0, lib_1.localize)(`nbt.node.${data.enumType}`)), node, 2 /* Warning */);
130
+ }
131
+ // Get all enum members.
132
+ const enumMembers = {};
133
+ query.forEachMember((name, memberQuery) => {
134
+ const value = memberQuery.symbol?.data?.value;
135
+ if (value !== undefined) {
136
+ enumMembers[name] = value.toString();
137
+ }
138
+ });
139
+ // Check value.
140
+ if (!Object.values(enumMembers).includes(node.value.toString())) {
141
+ ctx.err.report((0, lib_1.localize)('expected', Object.entries(enumMembers).map(([k, v]) => `${k} = ${v}`)), node, 2 /* Warning */);
142
+ }
143
+ };
144
+ }
145
+ exports.enum_ = enum_;
146
+ /**
147
+ * @param id If set to `undefined` or an empty array, all nbtdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
148
+ */
149
+ function path(registry, id) {
150
+ return (node, ctx) => {
151
+ const resolveResult = resolveRootRegistry(registry, id, ctx, undefined);
152
+ let data = { type: 'resolved_compound', data: resolveResult.value };
153
+ let targetType = { type: 'compound', symbol: { category: 'nbtdoc', path: [] } };
154
+ const options = { allowUnknownKey: resolveResult.allowUnknownKey, isPredicate: true };
155
+ let currentCompound;
156
+ for (const child of node.children) {
157
+ if (node_1.NbtCompoundNode.is(child)) {
158
+ // Compound filter.
159
+ currentCompound = child;
160
+ if (data?.type === 'resolved_compound') {
161
+ compound(data.data, options)(child, ctx);
162
+ }
163
+ else {
164
+ ctx.err.report((0, lib_1.localize)('nbt.checker.path.unexpected-filter'), child, 2 /* Warning */);
165
+ }
166
+ }
167
+ else if (core.StringNode.is(child)) {
168
+ // Key.
169
+ if (data?.type === 'resolved_compound') {
170
+ const fieldData = data.data[child.value];
171
+ if (fieldData) {
172
+ fieldData.query?.enter({ usage: { type: 'reference', node: child } });
173
+ if (fieldData.data.type === 'byte_array' || fieldData.data.type === 'int_array' || fieldData.data.type === 'long_array' || fieldData.data.type === 'list') {
174
+ data = fieldData.data;
175
+ }
176
+ else {
177
+ const resolveResult = resolveSymbolData(fieldData.data, ctx, currentCompound);
178
+ if (resolveResult.value) {
179
+ options.allowUnknownKey || (options.allowUnknownKey = resolveResult.allowUnknownKey);
180
+ data.data = resolveResult.value;
181
+ }
182
+ else {
183
+ data = undefined;
184
+ }
185
+ }
186
+ targetType = fieldData.data;
187
+ }
188
+ else {
189
+ if (!options.allowUnknownKey) {
190
+ ctx.err.report((0, lib_1.localize)('unknown-key', (0, lib_1.localeQuote)(child.value)), child, 2 /* Warning */);
191
+ }
192
+ targetType = undefined;
193
+ break;
194
+ }
195
+ }
196
+ else {
197
+ ctx.err.report((0, lib_1.localize)('nbt.checker.path.unexpected-key'), child, 2 /* Warning */);
198
+ targetType = undefined;
199
+ break;
200
+ }
201
+ currentCompound = undefined;
202
+ }
203
+ else {
204
+ // Index.
205
+ if (data?.type === 'byte_array' || data?.type === 'int_array' || data?.type === 'long_array' || data?.type === 'list') {
206
+ // Check content.
207
+ if (child.children !== undefined) {
208
+ const [content] = child.children;
209
+ if (content.type === 'integer') {
210
+ const absIndex = content.value < 0 ? -1 - content.value : content.value;
211
+ const [, maxLength] = data.lengthRange ?? [undefined, undefined];
212
+ if (maxLength !== undefined && absIndex >= maxLength) {
213
+ ctx.err.report((0, lib_1.localize)('nbt.checker.path.index-out-of-bound', content.value, maxLength), content, 2 /* Warning */);
214
+ }
215
+ }
216
+ else {
217
+ let isUnexpectedFilter = true;
218
+ if (data.type === 'list') {
219
+ const { allowUnknownKey, value } = resolveSymbolData(data.item, ctx, currentCompound);
220
+ options.allowUnknownKey || (options.allowUnknownKey = allowUnknownKey);
221
+ if (value) {
222
+ isUnexpectedFilter = false;
223
+ compound(value, options)(content, ctx);
224
+ }
225
+ }
226
+ if (isUnexpectedFilter) {
227
+ ctx.err.report((0, lib_1.localize)('nbt.checker.path.unexpected-filter'), content, 2 /* Warning */);
228
+ targetType = undefined;
229
+ break;
230
+ }
231
+ currentCompound = content;
232
+ }
233
+ }
234
+ // Set data for the next iteration.
235
+ if (data.type === 'list') {
236
+ const { allowUnknownKey, value } = resolveSymbolData(data.item, ctx, currentCompound);
237
+ options.allowUnknownKey || (options.allowUnknownKey = allowUnknownKey);
238
+ targetType = data.item;
239
+ if (value) {
240
+ data = { type: 'resolved_compound', data: value };
241
+ }
242
+ else {
243
+ data = undefined;
244
+ }
245
+ }
246
+ else {
247
+ targetType = {
248
+ type: data.type.split('_')[0],
249
+ valueRange: data.valueRange,
250
+ };
251
+ data = undefined;
252
+ }
253
+ }
254
+ else {
255
+ ctx.err.report((0, lib_1.localize)('nbt.checker.path.unexpected-index'), child, 2 /* Warning */);
256
+ targetType = undefined;
257
+ break;
258
+ }
259
+ }
260
+ }
261
+ ctx.ops.set(node, 'targetType', targetType);
262
+ };
263
+ }
264
+ exports.path = path;
265
+ function fieldValue(type, options) {
266
+ const isInRange = (value, [min, max]) => (min ?? -Infinity) <= value && value <= (max ?? Infinity);
267
+ const ExpectedTypes = {
268
+ boolean: 'nbt:byte',
269
+ byte: 'nbt:byte',
270
+ byte_array: 'nbt:byte_array',
271
+ compound: 'nbt:compound',
272
+ double: 'nbt:double',
273
+ float: 'nbt:float',
274
+ id: 'string',
275
+ index: 'nbt:compound',
276
+ int: 'nbt:int',
277
+ int_array: 'nbt:int_array',
278
+ list: 'nbt:list',
279
+ long: 'nbt:long',
280
+ long_array: 'nbt:long_array',
281
+ short: 'nbt:short',
282
+ string: 'string',
283
+ };
284
+ return (node, ctx) => {
285
+ // Rough type check.
286
+ if (type.type !== 'enum' && type.type !== 'union' && node.type !== ExpectedTypes[type.type]) {
287
+ ctx.err.report((0, lib_1.localize)('expected', (0, util_1.localizeTag)(ExpectedTypes[type.type])), node, 2 /* Warning */);
288
+ return;
289
+ }
290
+ switch (type.type) {
291
+ case 'boolean':
292
+ node = node;
293
+ if (node.value !== 0 && node.value !== 1) {
294
+ ctx.err.report((0, lib_1.localize)('nbt.checker.boolean.out-of-range', (0, lib_1.localeQuote)('0b'), (0, lib_1.localeQuote)('1b')), node, 2 /* Warning */);
295
+ }
296
+ break;
297
+ case 'byte_array':
298
+ case 'int_array':
299
+ case 'long_array':
300
+ node = node;
301
+ if (type.lengthRange && !isInRange(node.children.length, type.lengthRange)) {
302
+ ctx.err.report((0, lib_1.localize)('expected', (0, lib_1.localize)('nbt.checker.collection.length-between', (0, util_1.localizeTag)(node.type), type.lengthRange[0] ?? '-∞', type.lengthRange[1] ?? '+∞')), node, 2 /* Warning */);
303
+ }
304
+ if (type.valueRange) {
305
+ for (const { value: childNode } of node.children) {
306
+ if (childNode && !isInRange(Number(childNode.value), type.valueRange)) {
307
+ ctx.err.report((0, lib_1.localize)('number.between', type.valueRange[0] ?? '-∞', type.valueRange[1] ?? '+∞'), node, 2 /* Warning */);
308
+ }
309
+ }
310
+ }
311
+ break;
312
+ case 'byte':
313
+ case 'short':
314
+ case 'int':
315
+ case 'long':
316
+ case 'float':
317
+ case 'double':
318
+ node = node;
319
+ if (type.valueRange && !isInRange(Number(node.value), type.valueRange)) {
320
+ ctx.err.report((0, lib_1.localize)('number.between', type.valueRange[0] ?? '-∞', type.valueRange[1] ?? '+∞'), node, 2 /* Warning */);
321
+ }
322
+ break;
323
+ case 'index':
324
+ node = node;
325
+ const id = resolveFieldPath(node.parent?.parent, type.index.path);
326
+ if (type.index.registry && id) {
327
+ index(type.index.registry, core.ResourceLocation.lengthen(id), options)(node, ctx);
328
+ }
329
+ break;
330
+ case 'id':
331
+ node = node;
332
+ core.parseStringValue(core.resourceLocation(type.registry
333
+ ? { category: type.registry, isPredicate: options.isPredicate }
334
+ : { allowUnknown: true, pool: [], isPredicate: options.isPredicate }), node.value, node.valueMap, ctx);
335
+ break;
336
+ case 'list':
337
+ node = node;
338
+ type = nbtdoc.simplifyListType(type);
339
+ if (type.lengthRange && !isInRange(node.children.length, type.lengthRange)) {
340
+ ctx.err.report((0, lib_1.localize)('expected', (0, lib_1.localize)('nbt.checker.collection.length-between', (0, util_1.localizeTag)(node.type), type.lengthRange[0] ?? '-∞', type.lengthRange[1] ?? '+∞')), node, 2 /* Warning */);
341
+ }
342
+ for (const { value: childNode } of node.children) {
343
+ if (childNode) {
344
+ fieldValue(type.item, options)(childNode, ctx);
345
+ }
346
+ }
347
+ break;
348
+ case 'string':
349
+ node = node;
350
+ let suffix = '';
351
+ let valueNode = node;
352
+ if (core.ItemNode.is(node.parent) && node_1.NbtListNode.is(node.parent.parent)) {
353
+ suffix = '[]';
354
+ valueNode = node.parent.parent;
355
+ }
356
+ if (core.PairNode.is(valueNode.parent)) {
357
+ const compoundNbtdocPath = valueNode.parent.key?.symbol?.parentSymbol?.path.join('::');
358
+ const key = valueNode.parent.key?.value;
359
+ const path = `${compoundNbtdocPath}.${key}${suffix}`;
360
+ const parserName = (0, nbtdocUtil_1.getSpecialStringParser)(path);
361
+ if (parserName) {
362
+ try {
363
+ const parser = ctx.meta.getParser(parserName);
364
+ const result = core.parseStringValue(parser, node.value, node.valueMap, ctx);
365
+ if (result !== core.Failure) {
366
+ ctx.ops.set(node, 'children', [result]);
367
+ result.parent = node;
368
+ }
369
+ }
370
+ catch (e) {
371
+ ctx.logger.error('[nbt.checker.fieldValue#string]', e);
372
+ }
373
+ }
374
+ }
375
+ break;
376
+ case 'compound':
377
+ node = node;
378
+ if (type.symbol) {
379
+ const { allowUnknownKey, value } = resolveSymbolPaths([type.symbol], ctx, node);
380
+ compound(value, { ...options, allowUnknownKey: options.allowUnknownKey || allowUnknownKey })(node, ctx);
381
+ }
382
+ break;
383
+ case 'enum':
384
+ node = node;
385
+ enum_(type.symbol, options)(node, ctx);
386
+ break;
387
+ case 'union':
388
+ type = nbtdoc.flattenUnionType(type);
389
+ if (type.members.length === 0) {
390
+ ctx.err.report((0, lib_1.localize)('nbt.checker.compound.field.union-empty-members'), core.PairNode.is(node.parent)
391
+ ? (node.parent.key ?? node.parent)
392
+ : node, 2 /* Warning */);
393
+ }
394
+ else {
395
+ core.checker.any(type.members.map(t => fieldValue(t, options)))(node, ctx);
396
+ }
397
+ break;
398
+ }
399
+ };
400
+ }
401
+ exports.fieldValue = fieldValue;
402
+ function resolveFieldPath(compound, fieldPath) {
403
+ let node = compound;
404
+ for (const path of fieldPath) {
405
+ if (!node) {
406
+ break;
407
+ }
408
+ if (typeof path === 'object') {
409
+ // Super.
410
+ node = node.parent;
411
+ }
412
+ else {
413
+ // Field key.
414
+ if (!node_1.NbtCompoundNode.is(node)) {
415
+ break;
416
+ }
417
+ node = node.children.find(({ key }) => key?.value === path)?.value;
418
+ }
419
+ }
420
+ return node && node_1.NbtPrimitiveNode.is(node)
421
+ ? node.value.toString()
422
+ : undefined;
423
+ }
424
+ const getUnwrapper = (out) => (result) => {
425
+ out.allowUnknownKey || (out.allowUnknownKey = result.allowUnknownKey);
426
+ return result.value;
427
+ };
428
+ const map = (result, cb) => {
429
+ const ans = cb(result.value);
430
+ return {
431
+ allowUnknownKey: result.allowUnknownKey || ans.allowUnknownKey,
432
+ value: ans.value,
433
+ };
434
+ };
435
+ function getPathsFromRootRegistry(registry, inputIds, ctx) {
436
+ if (!registry) {
437
+ return { allowUnknownKey: true, value: [] };
438
+ }
439
+ const normalizeIds = (input, descriptionQuery) => {
440
+ let allowUnknownKey = false;
441
+ let ids;
442
+ if (input === undefined || (Array.isArray(input) && input.length === 0)) {
443
+ ids = Object.keys(descriptionQuery.visibleMembers);
444
+ allowUnknownKey = true;
445
+ }
446
+ else if (!Array.isArray(input)) {
447
+ ids = [input];
448
+ }
449
+ else {
450
+ ids = input;
451
+ }
452
+ return { allowUnknownKey, value: ids };
453
+ };
454
+ const collectPaths = (ids, descriptionQuery) => {
455
+ let allowUnknownKey = false;
456
+ const paths = new core.SymbolPathCollector();
457
+ descriptionQuery.ifKnown(() => {
458
+ for (const id of ids) {
459
+ descriptionQuery.member(id, member => member
460
+ .ifKnown(symbol => paths.add(symbol.relations?.describedBy))
461
+ .else(() => descriptionQuery.member('@default', defaultMember => {
462
+ allowUnknownKey = true;
463
+ paths.add(defaultMember.symbol?.relations?.describedBy);
464
+ })));
465
+ }
466
+ });
467
+ return { allowUnknownKey, value: paths.collect() };
468
+ };
469
+ const descriptionQuery = ctx.symbols.query(ctx.doc, 'nbtdoc/description', registry);
470
+ return map(normalizeIds(inputIds, descriptionQuery), ids => collectPaths(ids, descriptionQuery));
471
+ }
472
+ function resolveSymbolPaths(paths, ctx, compound) {
473
+ if (paths.length === 0) {
474
+ return { allowUnknownKey: true, value: {} };
475
+ }
476
+ const getDefinitionQuery = (path) => {
477
+ return {
478
+ allowUnknownKey: (0, nbtdocUtil_1.isExpandableCompound)(path.path.join('::')),
479
+ value: ctx.symbols.query(ctx.doc, path.category, ...path.path),
480
+ };
481
+ };
482
+ const getPathsFromSuper = (extendable) => {
483
+ if (extendable.type === 'compound') {
484
+ return { allowUnknownKey: false, value: extendable.symbol ? [extendable.symbol] : [] };
485
+ }
486
+ else {
487
+ const id = resolveFieldPath(compound, extendable.index.path);
488
+ return getPathsFromRootRegistry(extendable.index.registry, id ? core.ResourceLocation.lengthen(id) : undefined, ctx);
489
+ }
490
+ };
491
+ const getPathsRecursively = (paths) => {
492
+ const collector = new core.SymbolPathCollector();
493
+ const out = { allowUnknownKey: false };
494
+ const unwrap = getUnwrapper(out);
495
+ const iterate = (paths) => {
496
+ for (const path of paths) {
497
+ if (collector.has(path)) {
498
+ continue;
499
+ }
500
+ collector.add(path);
501
+ const query = unwrap(getDefinitionQuery(path));
502
+ const data = query.symbol?.data;
503
+ if (data) {
504
+ const superPaths = data.extends ? unwrap(getPathsFromSuper(data.extends)) : [];
505
+ iterate(superPaths);
506
+ }
507
+ else {
508
+ out.allowUnknownKey = true;
509
+ }
510
+ }
511
+ };
512
+ iterate(paths);
513
+ return { allowUnknownKey: out.allowUnknownKey, value: collector.collect() };
514
+ };
515
+ const ans = Object.create(null);
516
+ const out = { allowUnknownKey: false };
517
+ const unwrap = getUnwrapper(out);
518
+ const allPaths = unwrap(getPathsRecursively(paths));
519
+ for (const path of allPaths) {
520
+ const query = unwrap(getDefinitionQuery(path));
521
+ query.forEachMember((key, keyQuery) => {
522
+ const data = keyQuery.symbol?.data;
523
+ if (!data) {
524
+ return;
525
+ }
526
+ if (ans[key]) {
527
+ delete ans[key].query;
528
+ const existingData = ans[key].data;
529
+ if (existingData.type === 'union') {
530
+ existingData.members.push(data.fieldType);
531
+ }
532
+ else {
533
+ ans[key].data = { type: 'union', members: [existingData, data.fieldType] };
534
+ }
535
+ }
536
+ else {
537
+ ans[key] = { data: data.fieldType, query: keyQuery };
538
+ }
539
+ });
540
+ }
541
+ return { allowUnknownKey: out.allowUnknownKey, value: ans };
542
+ }
543
+ /**
544
+ * @param registry If `undefined`, allows unknown key.
545
+ * @param id If `undefined` or an empty array, merges all available definitions and allows unknown key.
546
+ */
547
+ function resolveRootRegistry(registry, inputIds, ctx, compound) {
548
+ const out = { allowUnknownKey: false };
549
+ const unwrap = getUnwrapper(out);
550
+ const paths = unwrap(getPathsFromRootRegistry(registry, inputIds, ctx));
551
+ const data = unwrap(resolveSymbolPaths(paths, ctx, compound));
552
+ return { allowUnknownKey: out.allowUnknownKey, value: data };
553
+ }
554
+ function resolveSymbolData(data, ctx, compound) {
555
+ const out = { allowUnknownKey: false };
556
+ const unwrap = getUnwrapper(out);
557
+ const paths = unwrap(getPathsFromSymbolData(data, ctx, compound));
558
+ if (!paths) {
559
+ return { allowUnknownKey: out.allowUnknownKey, value: undefined };
560
+ }
561
+ const ans = unwrap(resolveSymbolPaths(paths, ctx, compound));
562
+ return { allowUnknownKey: out.allowUnknownKey, value: ans };
563
+ }
564
+ function getPathsFromSymbolData(data, ctx, compound) {
565
+ const collector = new core.SymbolPathCollector();
566
+ const out = { allowUnknownKey: false };
567
+ const unwrap = getUnwrapper(out);
568
+ const iterate = (data) => {
569
+ if (data.type === 'compound') {
570
+ collector.add(data.symbol);
571
+ return true;
572
+ }
573
+ else if (data.type === 'index') {
574
+ const id = resolveFieldPath(compound, data.index.path);
575
+ const paths = unwrap(getPathsFromRootRegistry(data.index.registry, id ? core.ResourceLocation.lengthen(id) : undefined, ctx));
576
+ for (const path of paths) {
577
+ collector.add(path);
578
+ }
579
+ return true;
580
+ }
581
+ else if (data.type === 'union') {
582
+ let ans = false;
583
+ for (const member of data.members) {
584
+ ans || (ans = iterate(member));
585
+ }
586
+ return ans;
587
+ }
588
+ return false;
589
+ };
590
+ const isCompoundData = iterate(data);
591
+ return { allowUnknownKey: out.allowUnknownKey, value: isCompoundData ? collector.collect() : undefined };
592
+ }
593
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ import type * as core from '../../../core/lib';
2
+ export declare function getBlocksFromItem(item: core.FullResourceLocation): core.FullResourceLocation[] | undefined;
3
+ export declare function getEntityFromItem(item: core.FullResourceLocation): core.FullResourceLocation | undefined;
4
+ export declare function getSpecialStringParser(nbtdocPath: string): string | undefined;
5
+ /**
6
+ * @param nbtdocPath Path of the nbtdoc compound definition.
7
+ */
8
+ export declare function isExpandableCompound(nbtdocPath: string): boolean;
9
+ //# sourceMappingURL=nbtdocUtil.d.ts.map