@spyglassmc/nbt 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/checker/index.d.ts +4 -7
- package/lib/checker/index.js +76 -33
- package/lib/checker/mcdocUtil.js +12 -37
- package/lib/node/index.d.ts +7 -7
- package/lib/node/index.js +10 -3
- package/lib/parser/collection.js +28 -4
- package/lib/parser/compound.js +4 -1
- package/lib/parser/entry.js +5 -5
- package/lib/parser/path.js +16 -7
- package/lib/parser/primitive.js +68 -12
- package/package.json +4 -4
package/lib/checker/index.d.ts
CHANGED
|
@@ -11,9 +11,9 @@ declare global {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* @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`.
|
|
15
|
-
* If set to `undefined` or an empty array, all mcdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
|
|
16
|
-
*/
|
|
14
|
+
* @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`.
|
|
15
|
+
* If set to `undefined` or an empty array, all mcdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
|
|
16
|
+
*/
|
|
17
17
|
export declare function index(registry: string, id: core.FullResourceLocation | readonly core.FullResourceLocation[] | undefined, options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
18
18
|
export declare function index(registry: string, id: core.FullResourceLocation, options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
19
19
|
/**
|
|
@@ -21,10 +21,7 @@ export declare function index(registry: string, id: core.FullResourceLocation, o
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function definition(identifier: `::${string}::${string}`, options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
23
23
|
export declare function blockStates(blocks: string[], _options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
24
|
-
|
|
25
|
-
* @param path The {@link core.SymbolPath} to the compound definition.
|
|
26
|
-
*/
|
|
27
|
-
export declare function compound(data: any, options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
24
|
+
export declare function compound(typeDef: mcdoc.StructType, options?: Options): core.SyncChecker<NbtCompoundNode>;
|
|
28
25
|
export declare function enum_(path: core.SymbolPath | undefined, _options?: Options): core.SyncChecker<NbtPrimitiveNode>;
|
|
29
26
|
/**
|
|
30
27
|
* @param id If set to `undefined` or an empty array, all mcdoc compound definitions for this registry will be merged for checking, and unknown keys are allowed.
|
package/lib/checker/index.js
CHANGED
|
@@ -3,14 +3,12 @@ import { localeQuote, localize } from '@spyglassmc/locales';
|
|
|
3
3
|
import * as mcdoc from '@spyglassmc/mcdoc';
|
|
4
4
|
import { NbtListNode } from '../node/index.js';
|
|
5
5
|
import { localizeTag } from '../util.js';
|
|
6
|
-
import { getBlocksFromItem, getEntityFromItem, getSpecialStringParser } from './mcdocUtil.js';
|
|
6
|
+
import { getBlocksFromItem, getEntityFromItem, getSpecialStringParser, } from './mcdocUtil.js';
|
|
7
7
|
export function index(registry, id, options = {}) {
|
|
8
8
|
switch (registry) {
|
|
9
9
|
case 'custom:blockitemstates':
|
|
10
10
|
const blockIds = getBlocksFromItem(id);
|
|
11
|
-
return blockIds
|
|
12
|
-
? blockStates(blockIds, options)
|
|
13
|
-
: core.checker.noop;
|
|
11
|
+
return blockIds ? blockStates(blockIds, options) : core.checker.noop;
|
|
14
12
|
case 'custom:blockstates':
|
|
15
13
|
return blockStates([id], options);
|
|
16
14
|
case 'custom:spawnitemtag':
|
|
@@ -19,25 +17,44 @@ export function index(registry, id, options = {}) {
|
|
|
19
17
|
? index('entity_type', entityId, options)
|
|
20
18
|
: core.checker.noop;
|
|
21
19
|
default:
|
|
20
|
+
const identifier = getRegistryIdentifier(registry);
|
|
21
|
+
if (!identifier) {
|
|
22
|
+
return core.checker.noop;
|
|
23
|
+
}
|
|
22
24
|
return (node, ctx) => {
|
|
23
|
-
|
|
24
|
-
// options.allowUnknownKey ||= allowUnknownKey
|
|
25
|
-
// compound(value, options)(node, ctx)
|
|
25
|
+
definition(identifier, options)(node, ctx);
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
function getRegistryIdentifier(registry) {
|
|
30
|
+
switch (registry) {
|
|
31
|
+
case 'block':
|
|
32
|
+
return '::java::server::world::block::BlockEntity';
|
|
33
|
+
case 'entity_type':
|
|
34
|
+
return '::java::server::world::entity::AnyEntity';
|
|
35
|
+
case 'item':
|
|
36
|
+
return '::java::server::world::item::AnyItem';
|
|
37
|
+
default:
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
29
41
|
/**
|
|
30
42
|
* @param identifier An identifier of mcdoc compound definition. e.g. `::minecraft::util::invitem::InventoryItem`
|
|
31
43
|
*/
|
|
32
44
|
export function definition(identifier, options = {}) {
|
|
33
|
-
const index = identifier.lastIndexOf('::');
|
|
34
|
-
const module = identifier.slice(0, index);
|
|
35
|
-
const compoundDef = identifier.slice(index + 2);
|
|
36
|
-
const path = { category: 'mcdoc', path: [module, compoundDef] };
|
|
37
45
|
return (node, ctx) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
const symbol = ctx.symbols.query(ctx.doc, 'mcdoc', identifier);
|
|
47
|
+
const typeDef = symbol.getData(mcdoc.binder.TypeDefSymbolData.is)?.typeDef;
|
|
48
|
+
if (!typeDef) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
switch (typeDef.kind) {
|
|
52
|
+
case 'struct':
|
|
53
|
+
compound(typeDef, options)(node, ctx);
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
ctx.logger.error(`[nbt.checker.definition] Expected a struct type, but got ${typeDef.kind}`);
|
|
57
|
+
}
|
|
41
58
|
};
|
|
42
59
|
}
|
|
43
60
|
export function blockStates(blocks, _options = {}) {
|
|
@@ -48,7 +65,9 @@ export function blockStates(blocks, _options = {}) {
|
|
|
48
65
|
continue;
|
|
49
66
|
}
|
|
50
67
|
// Type check.
|
|
51
|
-
if (valueNode.type === 'nbt:byte' &&
|
|
68
|
+
if (valueNode.type === 'nbt:byte' &&
|
|
69
|
+
(ctx.src.slice(valueNode.range).toLowerCase() === 'false' ||
|
|
70
|
+
ctx.src.slice(valueNode.range).toLowerCase() === 'true')) {
|
|
52
71
|
ctx.err.report(localize('nbt.checker.block-states.fake-boolean'), valueNode, 2 /* core.ErrorSeverity.Warning */);
|
|
53
72
|
continue;
|
|
54
73
|
}
|
|
@@ -70,25 +89,25 @@ export function blockStates(blocks, _options = {}) {
|
|
|
70
89
|
}
|
|
71
90
|
};
|
|
72
91
|
}
|
|
73
|
-
|
|
74
|
-
* @param path The {@link core.SymbolPath} to the compound definition.
|
|
75
|
-
*/
|
|
76
|
-
export function compound(data, options = {}) {
|
|
92
|
+
export function compound(typeDef, options = {}) {
|
|
77
93
|
return (node, ctx) => {
|
|
78
94
|
for (const { key: keyNode, value: valueNode } of node.children) {
|
|
79
95
|
if (!keyNode || !valueNode) {
|
|
80
96
|
continue;
|
|
81
97
|
}
|
|
82
98
|
const key = keyNode.value;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
// TODO: handle spread types
|
|
100
|
+
const fieldDef = typeDef.fields.find((p) => p.kind === 'pair' && p.key === key);
|
|
101
|
+
if (fieldDef) {
|
|
102
|
+
// TODO: enter a reference to the mcdoc key
|
|
103
|
+
fieldValue(fieldDef.type, options)(valueNode, ctx);
|
|
87
104
|
}
|
|
88
105
|
else if (!options.allowUnknownKey) {
|
|
89
106
|
ctx.err.report(localize('unknown-key', localeQuote(key)), keyNode, 2 /* core.ErrorSeverity.Warning */);
|
|
90
107
|
}
|
|
91
108
|
}
|
|
109
|
+
// TODO: check for required fields
|
|
110
|
+
// requires an update to vanilla-mcdoc to make most fields optional
|
|
92
111
|
};
|
|
93
112
|
}
|
|
94
113
|
export function enum_(path, _options = {}) {
|
|
@@ -243,7 +262,8 @@ export function path(registry, id) {
|
|
|
243
262
|
export function fieldValue(type, options) {
|
|
244
263
|
const isInRange = (value, { kind, min = -Infinity, max = Infinity }) => {
|
|
245
264
|
const comparator = (a, b, exclusive) => exclusive ? a < b : a <= b;
|
|
246
|
-
return comparator(min, value, kind & 0b10) &&
|
|
265
|
+
return (comparator(min, value, kind & 0b10) &&
|
|
266
|
+
comparator(value, max, kind & 0b01));
|
|
247
267
|
};
|
|
248
268
|
const ExpectedTypes = {
|
|
249
269
|
boolean: 'nbt:byte',
|
|
@@ -263,7 +283,18 @@ export function fieldValue(type, options) {
|
|
|
263
283
|
};
|
|
264
284
|
return (node, ctx) => {
|
|
265
285
|
// Rough type check.
|
|
266
|
-
if (type.kind !== 'any' &&
|
|
286
|
+
if (type.kind !== 'any' &&
|
|
287
|
+
type.kind !== 'dispatcher' &&
|
|
288
|
+
type.kind !== 'enum' &&
|
|
289
|
+
type.kind !== 'literal' &&
|
|
290
|
+
type.kind !== 'reference' &&
|
|
291
|
+
type.kind !== 'union' &&
|
|
292
|
+
type.kind !== 'attributed' &&
|
|
293
|
+
type.kind !== 'unsafe' &&
|
|
294
|
+
type.kind !== 'concrete' &&
|
|
295
|
+
type.kind !== 'indexed' &&
|
|
296
|
+
type.kind !== 'template' &&
|
|
297
|
+
node.type !== ExpectedTypes[type.kind]) {
|
|
267
298
|
ctx.err.report(localize('expected', localizeTag(ExpectedTypes[type.kind])), node, 2 /* core.ErrorSeverity.Warning */);
|
|
268
299
|
return;
|
|
269
300
|
}
|
|
@@ -278,12 +309,14 @@ export function fieldValue(type, options) {
|
|
|
278
309
|
case 'int_array':
|
|
279
310
|
case 'long_array':
|
|
280
311
|
node = node;
|
|
281
|
-
if (type.lengthRange &&
|
|
312
|
+
if (type.lengthRange &&
|
|
313
|
+
!isInRange(node.children.length, type.lengthRange)) {
|
|
282
314
|
ctx.err.report(localize('expected', localize('nbt.checker.collection.length-between', localizeTag(node.type), type.lengthRange.min ?? '-∞', type.lengthRange.max ?? '+∞')), node, 2 /* core.ErrorSeverity.Warning */);
|
|
283
315
|
}
|
|
284
316
|
if (type.valueRange) {
|
|
285
317
|
for (const { value: childNode } of node.children) {
|
|
286
|
-
if (childNode &&
|
|
318
|
+
if (childNode &&
|
|
319
|
+
!isInRange(Number(childNode.value), type.valueRange)) {
|
|
287
320
|
ctx.err.report(localize('number.between', type.valueRange.min ?? '-∞', type.valueRange.max ?? '+∞'), node, 2 /* core.ErrorSeverity.Warning */);
|
|
288
321
|
}
|
|
289
322
|
}
|
|
@@ -296,7 +329,8 @@ export function fieldValue(type, options) {
|
|
|
296
329
|
case 'float':
|
|
297
330
|
case 'double':
|
|
298
331
|
node = node;
|
|
299
|
-
if (type.valueRange &&
|
|
332
|
+
if (type.valueRange &&
|
|
333
|
+
!isInRange(Number(node.value), type.valueRange)) {
|
|
300
334
|
ctx.err.report(localize('number.between', type.valueRange.min ?? '-∞', type.valueRange.max ?? '+∞'), node, 2 /* core.ErrorSeverity.Warning */);
|
|
301
335
|
}
|
|
302
336
|
break;
|
|
@@ -314,7 +348,8 @@ export function fieldValue(type, options) {
|
|
|
314
348
|
case 'list':
|
|
315
349
|
node = node;
|
|
316
350
|
type = mcdoc.simplifyListType(type);
|
|
317
|
-
if (type.lengthRange &&
|
|
351
|
+
if (type.lengthRange &&
|
|
352
|
+
!isInRange(node.children.length, type.lengthRange)) {
|
|
318
353
|
ctx.err.report(localize('expected', localize('nbt.checker.collection.length-between', localizeTag(node.type), type.lengthRange.min ?? '-∞', type.lengthRange.max ?? '+∞')), node, 2 /* core.ErrorSeverity.Warning */);
|
|
319
354
|
}
|
|
320
355
|
for (const { value: childNode } of node.children) {
|
|
@@ -327,12 +362,15 @@ export function fieldValue(type, options) {
|
|
|
327
362
|
node = node;
|
|
328
363
|
let suffix = '';
|
|
329
364
|
let valueNode = node;
|
|
330
|
-
if (core.ItemNode.is(node.parent) &&
|
|
365
|
+
if (core.ItemNode.is(node.parent) &&
|
|
366
|
+
NbtListNode.is(node.parent.parent)) {
|
|
331
367
|
suffix = '[]';
|
|
332
368
|
valueNode = node.parent.parent;
|
|
333
369
|
}
|
|
334
370
|
if (core.PairNode.is(valueNode.parent)) {
|
|
335
|
-
const structMcdocPath = valueNode.parent.key?.symbol
|
|
371
|
+
const structMcdocPath = valueNode.parent.key?.symbol
|
|
372
|
+
?.parentSymbol
|
|
373
|
+
?.path.join('::');
|
|
336
374
|
const key = valueNode.parent.key?.value;
|
|
337
375
|
const path = `${structMcdocPath}.${key}${suffix}`;
|
|
338
376
|
const parserName = getSpecialStringParser(path);
|
|
@@ -362,13 +400,18 @@ export function fieldValue(type, options) {
|
|
|
362
400
|
type = mcdoc.flattenUnionType(type);
|
|
363
401
|
if (type.members.length === 0) {
|
|
364
402
|
ctx.err.report(localize('nbt.checker.compound.field.union-empty-members'), core.PairNode.is(node.parent)
|
|
365
|
-
?
|
|
403
|
+
? node.parent.key ?? node.parent
|
|
366
404
|
: node, 2 /* core.ErrorSeverity.Warning */);
|
|
367
405
|
}
|
|
368
406
|
else {
|
|
369
|
-
|
|
407
|
+
;
|
|
408
|
+
core.checker.any(type.members.map((t) => fieldValue(t, options)))(node, ctx);
|
|
370
409
|
}
|
|
371
410
|
break;
|
|
411
|
+
case 'attributed':
|
|
412
|
+
// TODO: don't just ignore the attribute
|
|
413
|
+
fieldValue(type.child, options)(node, ctx);
|
|
414
|
+
break;
|
|
372
415
|
}
|
|
373
416
|
};
|
|
374
417
|
}
|
package/lib/checker/mcdocUtil.js
CHANGED
|
@@ -63,10 +63,7 @@ const BlockItems = {
|
|
|
63
63
|
'minecraft:dead_tube_coral_wall_fan',
|
|
64
64
|
],
|
|
65
65
|
// Torches.
|
|
66
|
-
'minecraft:torch': [
|
|
67
|
-
'minecraft:torch',
|
|
68
|
-
'minecraft:wall_torch',
|
|
69
|
-
],
|
|
66
|
+
'minecraft:torch': ['minecraft:torch', 'minecraft:wall_torch'],
|
|
70
67
|
'minecraft:soul_torch': [
|
|
71
68
|
'minecraft:soul_torch',
|
|
72
69
|
'minecraft:soul_wall_torch',
|
|
@@ -75,39 +72,17 @@ const BlockItems = {
|
|
|
75
72
|
'minecraft:redstone_torch',
|
|
76
73
|
'minecraft:redstone_wall_torch',
|
|
77
74
|
],
|
|
78
|
-
'minecraft:beetroot_seeds': [
|
|
79
|
-
|
|
80
|
-
],
|
|
81
|
-
'minecraft:
|
|
82
|
-
|
|
83
|
-
],
|
|
84
|
-
'minecraft:
|
|
85
|
-
|
|
86
|
-
],
|
|
87
|
-
'minecraft:
|
|
88
|
-
|
|
89
|
-
],
|
|
90
|
-
'minecraft:melon_seeds': [
|
|
91
|
-
'minecraft:melon_stem',
|
|
92
|
-
],
|
|
93
|
-
'minecraft:potato': [
|
|
94
|
-
'minecraft:potatoes',
|
|
95
|
-
],
|
|
96
|
-
'minecraft:pumpkin_seeds': [
|
|
97
|
-
'minecraft:pumpkin_stem',
|
|
98
|
-
],
|
|
99
|
-
'minecraft:redstone': [
|
|
100
|
-
'minecraft:redstone_wire',
|
|
101
|
-
],
|
|
102
|
-
'minecraft:string': [
|
|
103
|
-
'minecraft:tripwire',
|
|
104
|
-
],
|
|
105
|
-
'minecraft:sweat_berries': [
|
|
106
|
-
'minecraft:sweat_berry_bush',
|
|
107
|
-
],
|
|
108
|
-
'minecraft:wheat_seeds': [
|
|
109
|
-
'minecraft:wheat',
|
|
110
|
-
],
|
|
75
|
+
'minecraft:beetroot_seeds': ['minecraft:beetroots'],
|
|
76
|
+
'minecraft:carrot': ['minecraft:carrots'],
|
|
77
|
+
'minecraft:cocoa_beans': ['minecraft:cocoa'],
|
|
78
|
+
'minecraft:glow_berries': ['minecraft:cave_vines'],
|
|
79
|
+
'minecraft:melon_seeds': ['minecraft:melon_stem'],
|
|
80
|
+
'minecraft:potato': ['minecraft:potatoes'],
|
|
81
|
+
'minecraft:pumpkin_seeds': ['minecraft:pumpkin_stem'],
|
|
82
|
+
'minecraft:redstone': ['minecraft:redstone_wire'],
|
|
83
|
+
'minecraft:string': ['minecraft:tripwire'],
|
|
84
|
+
'minecraft:sweat_berries': ['minecraft:sweat_berry_bush'],
|
|
85
|
+
'minecraft:wheat_seeds': ['minecraft:wheat'],
|
|
111
86
|
};
|
|
112
87
|
export function getBlocksFromItem(item) {
|
|
113
88
|
return BlockItems[item];
|
package/lib/node/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import * as core from '@spyglassmc/core';
|
|
2
2
|
import type * as mcdoc from '@spyglassmc/mcdoc';
|
|
3
|
-
export
|
|
3
|
+
export type NbtNode = NbtPrimitiveNode | NbtCompoundNode | NbtCollectionNode;
|
|
4
4
|
export declare namespace NbtNode {
|
|
5
5
|
function is(node: core.AstNode | undefined): node is NbtNode;
|
|
6
6
|
}
|
|
7
|
-
export
|
|
7
|
+
export type NbtPrimitiveNode = NbtNumberNode | core.StringNode;
|
|
8
8
|
export declare namespace NbtPrimitiveNode {
|
|
9
9
|
function is(node: core.AstNode | undefined): node is NbtPrimitiveNode;
|
|
10
10
|
}
|
|
11
|
-
export
|
|
11
|
+
export type NbtNumberNode = NbtIntegerAlikeNode | NbtFloatAlikeNode;
|
|
12
12
|
export declare namespace NbtNumberNode {
|
|
13
13
|
function is(node: core.AstNode | undefined): node is NbtNumberNode;
|
|
14
14
|
}
|
|
15
|
-
export
|
|
15
|
+
export type NbtIntegerAlikeNode = NbtByteNode | NbtShortNode | NbtIntNode | NbtLongNode;
|
|
16
16
|
export declare namespace NbtIntegerAlikeNode {
|
|
17
17
|
function is(node: core.AstNode | undefined): node is NbtIntegerAlikeNode;
|
|
18
18
|
}
|
|
@@ -40,7 +40,7 @@ export interface NbtLongNode extends core.LongBaseNode {
|
|
|
40
40
|
export declare namespace NbtLongNode {
|
|
41
41
|
function is(node: core.AstNode | undefined): node is NbtLongNode;
|
|
42
42
|
}
|
|
43
|
-
export
|
|
43
|
+
export type NbtFloatAlikeNode = NbtFloatNode | NbtDoubleNode;
|
|
44
44
|
export declare namespace NbtFloatAlikeNode {
|
|
45
45
|
function is(node: core.AstNode | undefined): node is NbtFloatAlikeNode;
|
|
46
46
|
}
|
|
@@ -62,7 +62,7 @@ export interface NbtCompoundNode extends core.RecordBaseNode<core.StringNode, Nb
|
|
|
62
62
|
export declare namespace NbtCompoundNode {
|
|
63
63
|
function is(node: core.AstNode | undefined): node is NbtCompoundNode;
|
|
64
64
|
}
|
|
65
|
-
export
|
|
65
|
+
export type NbtCollectionNode = NbtListNode | NbtPrimitiveArrayNode;
|
|
66
66
|
export declare namespace NbtCollectionNode {
|
|
67
67
|
function is(node: core.AstNode | undefined): node is NbtCollectionNode;
|
|
68
68
|
}
|
|
@@ -73,7 +73,7 @@ export interface NbtListNode extends core.ListNode<NbtNode> {
|
|
|
73
73
|
export declare namespace NbtListNode {
|
|
74
74
|
function is(node: core.AstNode | undefined): node is NbtListNode;
|
|
75
75
|
}
|
|
76
|
-
export
|
|
76
|
+
export type NbtPrimitiveArrayNode = NbtByteArrayNode | NbtIntArrayNode | NbtLongArrayNode;
|
|
77
77
|
export declare namespace NbtPrimitiveArrayNode {
|
|
78
78
|
function is(node: core.AstNode | undefined): node is NbtPrimitiveArrayNode;
|
|
79
79
|
}
|
package/lib/node/index.js
CHANGED
|
@@ -3,7 +3,9 @@ export var NbtNode;
|
|
|
3
3
|
(function (NbtNode) {
|
|
4
4
|
/* istanbul ignore next */
|
|
5
5
|
function is(node) {
|
|
6
|
-
return NbtPrimitiveNode.is(node) ||
|
|
6
|
+
return (NbtPrimitiveNode.is(node) ||
|
|
7
|
+
NbtCompoundNode.is(node) ||
|
|
8
|
+
NbtCollectionNode.is(node));
|
|
7
9
|
}
|
|
8
10
|
NbtNode.is = is;
|
|
9
11
|
})(NbtNode || (NbtNode = {}));
|
|
@@ -27,7 +29,10 @@ export var NbtIntegerAlikeNode;
|
|
|
27
29
|
(function (NbtIntegerAlikeNode) {
|
|
28
30
|
/* istanbul ignore next */
|
|
29
31
|
function is(node) {
|
|
30
|
-
return NbtByteNode.is(node) ||
|
|
32
|
+
return (NbtByteNode.is(node) ||
|
|
33
|
+
NbtShortNode.is(node) ||
|
|
34
|
+
NbtIntNode.is(node) ||
|
|
35
|
+
NbtLongNode.is(node));
|
|
31
36
|
}
|
|
32
37
|
NbtIntegerAlikeNode.is = is;
|
|
33
38
|
})(NbtIntegerAlikeNode || (NbtIntegerAlikeNode = {}));
|
|
@@ -115,7 +120,9 @@ export var NbtPrimitiveArrayNode;
|
|
|
115
120
|
(function (NbtPrimitiveArrayNode) {
|
|
116
121
|
/* istanbul ignore next */
|
|
117
122
|
function is(node) {
|
|
118
|
-
return NbtByteArrayNode.is(node) ||
|
|
123
|
+
return (NbtByteArrayNode.is(node) ||
|
|
124
|
+
NbtIntArrayNode.is(node) ||
|
|
125
|
+
NbtLongArrayNode.is(node));
|
|
119
126
|
}
|
|
120
127
|
NbtPrimitiveArrayNode.is = is;
|
|
121
128
|
})(NbtPrimitiveArrayNode || (NbtPrimitiveArrayNode = {}));
|
package/lib/parser/collection.js
CHANGED
|
@@ -4,7 +4,13 @@ import { localizeTag } from '../util.js';
|
|
|
4
4
|
import { entry } from './entry.js';
|
|
5
5
|
import { primitive } from './primitive.js';
|
|
6
6
|
export const list = (src, ctx) => {
|
|
7
|
-
const parser = core.list({
|
|
7
|
+
const parser = core.list({
|
|
8
|
+
start: '[',
|
|
9
|
+
value: entry,
|
|
10
|
+
sep: ',',
|
|
11
|
+
trailingSep: false,
|
|
12
|
+
end: ']',
|
|
13
|
+
});
|
|
8
14
|
const ans = parser(src, ctx);
|
|
9
15
|
ans.type = 'nbt:list';
|
|
10
16
|
ans.valueType = ans.children[0]?.value?.type;
|
|
@@ -19,7 +25,13 @@ export const list = (src, ctx) => {
|
|
|
19
25
|
return ans;
|
|
20
26
|
};
|
|
21
27
|
export const byteArray = (src, ctx) => {
|
|
22
|
-
const parser = core.list({
|
|
28
|
+
const parser = core.list({
|
|
29
|
+
start: '[B;',
|
|
30
|
+
value: primitive,
|
|
31
|
+
sep: ',',
|
|
32
|
+
trailingSep: false,
|
|
33
|
+
end: ']',
|
|
34
|
+
});
|
|
23
35
|
const ans = parser(src, ctx);
|
|
24
36
|
ans.type = 'nbt:byte_array';
|
|
25
37
|
// Check if every element is of the required type.
|
|
@@ -31,7 +43,13 @@ export const byteArray = (src, ctx) => {
|
|
|
31
43
|
return ans;
|
|
32
44
|
};
|
|
33
45
|
export const intArray = (src, ctx) => {
|
|
34
|
-
const parser = core.list({
|
|
46
|
+
const parser = core.list({
|
|
47
|
+
start: '[I;',
|
|
48
|
+
value: primitive,
|
|
49
|
+
sep: ',',
|
|
50
|
+
trailingSep: false,
|
|
51
|
+
end: ']',
|
|
52
|
+
});
|
|
35
53
|
const ans = parser(src, ctx);
|
|
36
54
|
ans.type = 'nbt:int_array';
|
|
37
55
|
// Check if every element is of the required type.
|
|
@@ -43,7 +61,13 @@ export const intArray = (src, ctx) => {
|
|
|
43
61
|
return ans;
|
|
44
62
|
};
|
|
45
63
|
export const longArray = (src, ctx) => {
|
|
46
|
-
const parser = core.list({
|
|
64
|
+
const parser = core.list({
|
|
65
|
+
start: '[L;',
|
|
66
|
+
value: primitive,
|
|
67
|
+
sep: ',',
|
|
68
|
+
trailingSep: false,
|
|
69
|
+
end: ']',
|
|
70
|
+
});
|
|
47
71
|
const ans = parser(src, ctx);
|
|
48
72
|
ans.type = 'nbt:long_array';
|
|
49
73
|
// Check if every element is of the required type.
|
package/lib/parser/compound.js
CHANGED
|
@@ -4,7 +4,10 @@ export const compound = (src, ctx) => {
|
|
|
4
4
|
return core.setType('nbt:compound', core.record({
|
|
5
5
|
start: '{',
|
|
6
6
|
pair: {
|
|
7
|
-
key: core.failOnEmpty(core.string({
|
|
7
|
+
key: core.failOnEmpty(core.string({
|
|
8
|
+
...core.BrigadierStringOptions,
|
|
9
|
+
colorTokenType: 'property',
|
|
10
|
+
})),
|
|
8
11
|
sep: ':',
|
|
9
12
|
value: entry,
|
|
10
13
|
end: ',',
|
package/lib/parser/entry.js
CHANGED
|
@@ -3,11 +3,11 @@ import { byteArray, intArray, list, longArray } from './collection.js';
|
|
|
3
3
|
import { compound } from './compound.js';
|
|
4
4
|
import { primitive } from './primitive.js';
|
|
5
5
|
export const entry = (src, ctx) => core.failOnEmpty(core.select([
|
|
6
|
-
{ predicate: src => src.tryPeek('[B;'), parser: byteArray },
|
|
7
|
-
{ predicate: src => src.tryPeek('[I;'), parser: intArray },
|
|
8
|
-
{ predicate: src => src.tryPeek('[L;'), parser: longArray },
|
|
9
|
-
{ predicate: src => src.tryPeek('['), parser: list },
|
|
10
|
-
{ predicate: src => src.tryPeek('{'), parser: compound },
|
|
6
|
+
{ predicate: (src) => src.tryPeek('[B;'), parser: byteArray },
|
|
7
|
+
{ predicate: (src) => src.tryPeek('[I;'), parser: intArray },
|
|
8
|
+
{ predicate: (src) => src.tryPeek('[L;'), parser: longArray },
|
|
9
|
+
{ predicate: (src) => src.tryPeek('['), parser: list },
|
|
10
|
+
{ predicate: (src) => src.tryPeek('{'), parser: compound },
|
|
11
11
|
{ parser: primitive },
|
|
12
12
|
]))(src, ctx);
|
|
13
13
|
//# sourceMappingURL=entry.js.map
|
package/lib/parser/path.js
CHANGED
|
@@ -51,9 +51,7 @@ const index = (children, src, ctx) => {
|
|
|
51
51
|
}
|
|
52
52
|
node.range.end = src.cursor;
|
|
53
53
|
children.push(node);
|
|
54
|
-
return src.trySkip('.')
|
|
55
|
-
? ['index', 'key']
|
|
56
|
-
: ['end', 'index'];
|
|
54
|
+
return src.trySkip('.') ? ['index', 'key'] : ['end', 'index'];
|
|
57
55
|
};
|
|
58
56
|
const key = (children, src, ctx) => {
|
|
59
57
|
const node = core.string({
|
|
@@ -61,12 +59,23 @@ const key = (children, src, ctx) => {
|
|
|
61
59
|
escapable: {},
|
|
62
60
|
// No single quotes: https://bugs.mojang.com/browse/MC-175504
|
|
63
61
|
quotes: ['"'],
|
|
64
|
-
unquotable: {
|
|
62
|
+
unquotable: {
|
|
63
|
+
blockList: new Set([
|
|
64
|
+
'\n',
|
|
65
|
+
'\r',
|
|
66
|
+
'\t',
|
|
67
|
+
' ',
|
|
68
|
+
'"',
|
|
69
|
+
'[',
|
|
70
|
+
']',
|
|
71
|
+
'.',
|
|
72
|
+
'{',
|
|
73
|
+
'}',
|
|
74
|
+
]),
|
|
75
|
+
},
|
|
65
76
|
})(src, ctx);
|
|
66
77
|
children.push(node);
|
|
67
|
-
return src.trySkip('.')
|
|
68
|
-
? ['index', 'key']
|
|
69
|
-
: ['end', 'filter', 'index'];
|
|
78
|
+
return src.trySkip('.') ? ['index', 'key'] : ['end', 'filter', 'index'];
|
|
70
79
|
};
|
|
71
80
|
function nextPart(src) {
|
|
72
81
|
switch (src.peek()) {
|
package/lib/parser/primitive.js
CHANGED
|
@@ -1,15 +1,64 @@
|
|
|
1
1
|
import * as core from '@spyglassmc/core';
|
|
2
2
|
import { localize } from '@spyglassmc/locales';
|
|
3
3
|
import { localizeTag } from '../util.js';
|
|
4
|
-
const FloatMaximum = (2 -
|
|
4
|
+
const FloatMaximum = (2 - 2 ** -23) * 2 ** 127;
|
|
5
5
|
const NumeralPatterns = [
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
{
|
|
7
|
+
pattern: /^[-+]?(?:0|[1-9][0-9]*)b$/i,
|
|
8
|
+
type: 'nbt:byte',
|
|
9
|
+
hasSuffix: true,
|
|
10
|
+
group: 2 /* Group.IntegerAlike */,
|
|
11
|
+
min: -128,
|
|
12
|
+
max: 127,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
pattern: /^[-+]?(?:0|[1-9][0-9]*)s$/i,
|
|
16
|
+
type: 'nbt:short',
|
|
17
|
+
hasSuffix: true,
|
|
18
|
+
group: 2 /* Group.IntegerAlike */,
|
|
19
|
+
min: -32768,
|
|
20
|
+
max: 32767,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
pattern: /^[-+]?(?:0|[1-9][0-9]*)$/,
|
|
24
|
+
type: 'nbt:int',
|
|
25
|
+
hasSuffix: false,
|
|
26
|
+
group: 2 /* Group.IntegerAlike */,
|
|
27
|
+
min: -2147483648,
|
|
28
|
+
max: 2147483647,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
pattern: /^[-+]?(?:0|[1-9][0-9]*)l$/i,
|
|
32
|
+
type: 'nbt:long',
|
|
33
|
+
hasSuffix: true,
|
|
34
|
+
group: 3 /* Group.LongAlike */,
|
|
35
|
+
min: -9223372036854775808n,
|
|
36
|
+
max: 9223372036854775807n,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
pattern: /^[-+]?(?:[0-9]+\.?|[0-9]*\.[0-9]+)(?:e[-+]?[0-9]+)?f$/i,
|
|
40
|
+
type: 'nbt:float',
|
|
41
|
+
hasSuffix: true,
|
|
42
|
+
group: 1 /* Group.FloatAlike */,
|
|
43
|
+
min: -FloatMaximum,
|
|
44
|
+
max: FloatMaximum,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
pattern: /^[-+]?(?:[0-9]+\.|[0-9]*\.[0-9]+)(?:e[-+]?[0-9]+)?$/i,
|
|
48
|
+
type: 'nbt:double',
|
|
49
|
+
hasSuffix: false,
|
|
50
|
+
group: 1 /* Group.FloatAlike */,
|
|
51
|
+
min: -Number.MAX_VALUE,
|
|
52
|
+
max: Number.MAX_VALUE,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: /^[-+]?(?:[0-9]+\.?|[0-9]*\.[0-9]+)(?:e[-+]?[0-9]+)?d$/i,
|
|
56
|
+
type: 'nbt:double',
|
|
57
|
+
hasSuffix: true,
|
|
58
|
+
group: 1 /* Group.FloatAlike */,
|
|
59
|
+
min: -Number.MAX_VALUE,
|
|
60
|
+
max: Number.MAX_VALUE,
|
|
61
|
+
},
|
|
13
62
|
{ pattern: /^true$/i, type: 'nbt:byte', value: 1, group: 0 /* Group.Boolean */ },
|
|
14
63
|
{ pattern: /^false$/i, type: 'nbt:byte', value: 0, group: 0 /* Group.Boolean */ },
|
|
15
64
|
];
|
|
@@ -18,7 +67,8 @@ export const primitive = (src, ctx) => {
|
|
|
18
67
|
if (core.Source.isBrigadierQuote(src.peek())) {
|
|
19
68
|
return string(src, ctx);
|
|
20
69
|
}
|
|
21
|
-
const { result: unquotedResult, updateSrcAndCtx: updateUnquoted } = core
|
|
70
|
+
const { result: unquotedResult, updateSrcAndCtx: updateUnquoted } = core
|
|
71
|
+
.attempt(string, src, ctx);
|
|
22
72
|
for (const e of NumeralPatterns) {
|
|
23
73
|
if (e.pattern.test(unquotedResult.value)) {
|
|
24
74
|
if (e.group === 0 /* Group.Boolean */) {
|
|
@@ -31,15 +81,21 @@ export const primitive = (src, ctx) => {
|
|
|
31
81
|
return ans;
|
|
32
82
|
}
|
|
33
83
|
let isOutOfRange = false;
|
|
34
|
-
const onOutOfRange = () => isOutOfRange = true;
|
|
84
|
+
const onOutOfRange = () => (isOutOfRange = true);
|
|
35
85
|
const numeralParser = e.group === 2 /* Group.IntegerAlike */
|
|
36
86
|
// As we already checked the format of the value with `e.pattern` in the if-block, there is no need to check
|
|
37
87
|
// it again here in the parser, therefore we just pass in a simple /./ regex.
|
|
38
|
-
? core.integer({
|
|
88
|
+
? core.integer({
|
|
89
|
+
pattern: /./,
|
|
90
|
+
min: e.min,
|
|
91
|
+
max: e.max,
|
|
92
|
+
onOutOfRange,
|
|
93
|
+
})
|
|
39
94
|
: e.group === 3 /* Group.LongAlike */
|
|
40
95
|
? core.long({ pattern: /./, min: e.min, max: e.max, onOutOfRange })
|
|
41
96
|
: core.float({ pattern: /./, min: e.min, max: e.max, onOutOfRange });
|
|
42
|
-
const { result: numeralResult, updateSrcAndCtx: updateNumeral } = core
|
|
97
|
+
const { result: numeralResult, updateSrcAndCtx: updateNumeral } = core
|
|
98
|
+
.attempt(numeralParser, src, ctx);
|
|
43
99
|
if (isOutOfRange) {
|
|
44
100
|
ctx.err.report(localize('nbt.parser.number.out-of-range', localizeTag(e.type), localize('nbt.node.string'), e.min, e.max), unquotedResult, 2 /* core.ErrorSeverity.Warning */);
|
|
45
101
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spyglassmc/nbt",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/SpyglassMC/Spyglass/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@spyglassmc/core": "0.4.
|
|
29
|
-
"@spyglassmc/locales": "0.3.
|
|
30
|
-
"@spyglassmc/mcdoc": "0.3.
|
|
28
|
+
"@spyglassmc/core": "0.4.2",
|
|
29
|
+
"@spyglassmc/locales": "0.3.2",
|
|
30
|
+
"@spyglassmc/mcdoc": "0.3.3"
|
|
31
31
|
}
|
|
32
32
|
}
|