@spyglassmc/java-edition 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/binder/index.d.ts +1 -1
- package/lib/binder/index.js +110 -19
- package/lib/common/index.js +10 -7
- package/lib/dependency/common.d.ts +1 -1
- package/lib/dependency/index.js +11 -9
- package/lib/dependency/mcmeta.d.ts +4 -4
- package/lib/dependency/mcmeta.js +32 -15
- package/lib/index.js +18 -6
- package/lib/json/checker/data/advancement.js +24 -13
- package/lib/json/checker/data/biome.js +3 -3
- package/lib/json/checker/data/common.js +29 -30
- package/lib/json/checker/data/dimension.js +7 -18
- package/lib/json/checker/data/feature.js +45 -27
- package/lib/json/checker/data/index.d.ts +1 -1
- package/lib/json/checker/data/index.js +3 -3
- package/lib/json/checker/data/loot_table.js +40 -21
- package/lib/json/checker/data/recipe.js +1 -1
- package/lib/json/checker/data/structure.js +24 -14
- package/lib/json/checker/data/tag.js +2 -2
- package/lib/json/checker/data/text_component.js +24 -8
- package/lib/json/checker/index.d.ts +10 -3
- package/lib/json/checker/index.js +231 -3
- package/lib/json/checker/util/advancement.js +3 -2
- package/lib/json/checker/util/block_states.d.ts +2 -2
- package/lib/json/checker/util/block_states.js +7 -5
- package/lib/json/checker/util/color.js +8 -2
- package/lib/json/checker/util/nbt.d.ts +1 -1
- package/lib/json/checker/util/nbt.js +4 -2
- package/lib/json/checker/util/recipe.js +7 -6
- package/lib/json/checker/util/version.d.ts +1 -1
- package/lib/json/checker/util/version.js +2 -2
- package/lib/mcfunction/checker/index.js +14 -11
- package/lib/mcfunction/colorizer/index.js +2 -4
- package/lib/mcfunction/common/index.js +46 -15
- package/lib/mcfunction/completer/argument.js +53 -24
- package/lib/mcfunction/index.js +13 -1
- package/lib/mcfunction/inlayHintProvider.js +8 -3
- package/lib/mcfunction/node/argument.d.ts +6 -6
- package/lib/mcfunction/node/argument.js +57 -17
- package/lib/mcfunction/parser/argument.js +158 -63
- package/lib/mcfunction/signatureHelpProvider.js +9 -4
- package/lib/mcfunction/tree/argument.d.ts +1 -1
- package/lib/mcfunction/tree/patch.js +132 -126
- package/package.json +7 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { integer } from '@spyglassmc/core';
|
|
2
|
-
import { any, as, boolean, dispatch, extract, having, int, listOf, literal, opt, pick, record, ref, resource, simpleString, string } from '@spyglassmc/json/lib/checker/primitives/index.js';
|
|
3
|
-
import { deprecated, nbt, nbtPath, stringColor, uuid, versioned } from '../util/index.js';
|
|
2
|
+
import { any, as, boolean, dispatch, extract, having, int, listOf, literal, opt, pick, record, ref, resource, simpleString, string, } from '@spyglassmc/json/lib/checker/primitives/index.js';
|
|
3
|
+
import { deprecated, nbt, nbtPath, stringColor, uuid, versioned, } from '../util/index.js';
|
|
4
4
|
const Keybinds = [
|
|
5
5
|
'key.jump',
|
|
6
6
|
'key.sneak',
|
|
@@ -69,11 +69,15 @@ const text_component_object = as('text_component', (node, ctx) => record({
|
|
|
69
69
|
},
|
|
70
70
|
entity: {
|
|
71
71
|
entity: simpleString,
|
|
72
|
-
nbt: nbtPath({
|
|
72
|
+
nbt: nbtPath({
|
|
73
|
+
registry: 'entity_type', /* FIXME: import { getTypesFromEntity } from '../../../../mcfunction/checker'; ids: getTypesFromEntity(somehowGetTheNodeHere, ctx) */
|
|
74
|
+
}),
|
|
73
75
|
},
|
|
74
76
|
storage: {
|
|
75
77
|
storage: resource('storage'),
|
|
76
|
-
nbt: nbtPath({
|
|
78
|
+
nbt: nbtPath({
|
|
79
|
+
registry: 'storage', /* FIXME:, id: extract('storage', props) */
|
|
80
|
+
}),
|
|
77
81
|
},
|
|
78
82
|
}),
|
|
79
83
|
interpret: opt(boolean, false),
|
|
@@ -89,7 +93,14 @@ const text_component_object = as('text_component', (node, ctx) => record({
|
|
|
89
93
|
obfuscated: opt(boolean),
|
|
90
94
|
insertion: opt(simpleString),
|
|
91
95
|
clickEvent: opt(dispatch('action', (action) => record({
|
|
92
|
-
action: literal([
|
|
96
|
+
action: literal([
|
|
97
|
+
'open_url',
|
|
98
|
+
'open_file',
|
|
99
|
+
'run_command',
|
|
100
|
+
'suggest_command',
|
|
101
|
+
'change_page',
|
|
102
|
+
'copy_to_clipboard',
|
|
103
|
+
]),
|
|
93
104
|
value: simpleString,
|
|
94
105
|
...pick(action, {
|
|
95
106
|
run_command: {
|
|
@@ -108,11 +119,16 @@ const text_component_object = as('text_component', (node, ctx) => record({
|
|
|
108
119
|
contents: opt(versioned(ctx, '1.16', text_component)),
|
|
109
120
|
},
|
|
110
121
|
show_item: {
|
|
111
|
-
value: deprecated(ctx, '1.16', nbt({
|
|
112
|
-
|
|
122
|
+
value: deprecated(ctx, '1.16', nbt({
|
|
123
|
+
definition: '::minecraft::util::invitem::InventoryItem',
|
|
124
|
+
})),
|
|
125
|
+
contents: opt(versioned(ctx, '1.16', dispatch((props) => record({
|
|
113
126
|
id: resource('item'),
|
|
114
127
|
count: opt(int),
|
|
115
|
-
tag: opt(nbt({
|
|
128
|
+
tag: opt(nbt({
|
|
129
|
+
registry: 'item',
|
|
130
|
+
id: extract('id', props),
|
|
131
|
+
})),
|
|
116
132
|
})))),
|
|
117
133
|
},
|
|
118
134
|
show_entity: {
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as core from '@spyglassmc/core';
|
|
2
2
|
import type { JsonNode } from '@spyglassmc/json';
|
|
3
|
-
|
|
4
|
-
export declare
|
|
3
|
+
import * as mcdoc from '@spyglassmc/mcdoc';
|
|
4
|
+
export declare const entry: core.Checker<JsonNode>;
|
|
5
|
+
export declare function register(meta: core.MetaRegistry): void;
|
|
6
|
+
/**
|
|
7
|
+
* @param identifier An identifier of mcdoc compound definition. e.g. `::minecraft::util::invitem::InventoryItem`
|
|
8
|
+
*/
|
|
9
|
+
export declare function definition(identifier: `::${string}::${string}`): core.SyncChecker<JsonNode>;
|
|
10
|
+
export declare function object(typeDef: mcdoc.StructType): core.SyncChecker<JsonNode>;
|
|
11
|
+
export declare function fieldValue(type: mcdoc.McdocType): core.SyncChecker<JsonNode>;
|
|
5
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,12 +1,62 @@
|
|
|
1
|
+
import * as core from '@spyglassmc/core';
|
|
2
|
+
import { JsonObjectNode } from '@spyglassmc/json';
|
|
3
|
+
import { localeQuote, localize } from '@spyglassmc/locales';
|
|
4
|
+
import * as mcdoc from '@spyglassmc/mcdoc';
|
|
1
5
|
import { dissectUri } from '../../binder/index.js';
|
|
2
|
-
|
|
6
|
+
const Checkers = new Map([
|
|
7
|
+
['advancement', '::java::data::advancement::Advancement'],
|
|
8
|
+
['dimension', '::java::data::worldgen::dimension::Dimension'],
|
|
9
|
+
['dimension_type', '::java::data::worldgen::dimension::DimensionType'],
|
|
10
|
+
['item_modifier', '::java::data::item_modifier::ItemModifier'],
|
|
11
|
+
['loot_table', '::java::data::loot::LootTable'],
|
|
12
|
+
['predicate', '::java::data::predicate::Predicate'],
|
|
13
|
+
['recipe', '::java::data::recipe::Recipe'],
|
|
14
|
+
['worldgen/biome', '::java::data::worldgen::biome::Biome'],
|
|
15
|
+
[
|
|
16
|
+
'worldgen/configured_carver',
|
|
17
|
+
'::java::data::worldgen::carver::ConfiguredCarver',
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
'worldgen/configured_surface_builder',
|
|
21
|
+
'::java::data::worldgen::surface_builder::ConfiguredSurfaceBuilder',
|
|
22
|
+
],
|
|
23
|
+
['worldgen/configured_feature', '::java::data::feature::ConfiguredFeature'],
|
|
24
|
+
[
|
|
25
|
+
'worldgen/configured_structure_feature',
|
|
26
|
+
'::java::data::worldgen::structure::Structure',
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
'worldgen/density_function',
|
|
30
|
+
'::java::data::worldgen::density_function::DensityFunction',
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
'worldgen/noise',
|
|
34
|
+
'::java::data::worldgen::dimension::biome_source::NoiseParameters',
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
'worldgen/noise_settings',
|
|
38
|
+
'::java::data::worldgen::noise_settings::NoiseGeneratorSettings',
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
'worldgen/processor_list',
|
|
42
|
+
'::java::data::worldgen::processor_list::ProcessorList',
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
'worldgen/template_pool',
|
|
46
|
+
'::java::data::worldgen::template_pool::TemplatePool',
|
|
47
|
+
],
|
|
48
|
+
]);
|
|
3
49
|
export const entry = (node, ctx) => {
|
|
4
50
|
const parts = dissectUri(ctx.doc.uri, ctx);
|
|
5
51
|
if (parts && Checkers.has(parts.category)) {
|
|
6
|
-
Checkers.get(parts.category)
|
|
52
|
+
const identifier = Checkers.get(parts.category);
|
|
53
|
+
return definition(identifier)(node, ctx);
|
|
54
|
+
}
|
|
55
|
+
else if (parts?.category.startsWith('tag/')) {
|
|
56
|
+
// TODO
|
|
7
57
|
}
|
|
8
58
|
else if (ctx.doc.uri.endsWith('/pack.mcmeta')) {
|
|
9
|
-
|
|
59
|
+
return definition('::java::Pack')(node, ctx);
|
|
10
60
|
}
|
|
11
61
|
else {
|
|
12
62
|
return;
|
|
@@ -20,4 +70,182 @@ export function register(meta) {
|
|
|
20
70
|
meta.registerChecker('json:object', entry);
|
|
21
71
|
meta.registerChecker('json:string', entry);
|
|
22
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* @param identifier An identifier of mcdoc compound definition. e.g. `::minecraft::util::invitem::InventoryItem`
|
|
75
|
+
*/
|
|
76
|
+
export function definition(identifier) {
|
|
77
|
+
return (node, ctx) => {
|
|
78
|
+
const symbol = ctx.symbols.query(ctx.doc, 'mcdoc', identifier);
|
|
79
|
+
const typeDef = symbol.getData(mcdoc.binder.TypeDefSymbolData.is)?.typeDef;
|
|
80
|
+
if (!typeDef) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
switch (typeDef.kind) {
|
|
84
|
+
case 'struct':
|
|
85
|
+
object(typeDef)(node, ctx);
|
|
86
|
+
break;
|
|
87
|
+
default:
|
|
88
|
+
ctx.logger.error(`[json.checker.definition] Expected a struct type, but got ${typeDef.kind}`);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export function object(typeDef) {
|
|
93
|
+
return (node, ctx) => {
|
|
94
|
+
if (!JsonObjectNode.is(node)) {
|
|
95
|
+
// TODO
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
for (const { key: keyNode, value: valueNode } of node.children) {
|
|
99
|
+
if (!keyNode || !valueNode) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const key = keyNode.value;
|
|
103
|
+
// TODO: handle spread types
|
|
104
|
+
const fieldDef = typeDef.fields.find((p) => p.kind === 'pair' && p.key === key);
|
|
105
|
+
if (fieldDef) {
|
|
106
|
+
// TODO: enter a reference to the mcdoc key
|
|
107
|
+
fieldValue(fieldDef.type)(valueNode, ctx);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
ctx.err.report(localize('unknown-key', localeQuote(key)), keyNode, 2 /* core.ErrorSeverity.Warning */);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// TODO: check for required fields
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export function fieldValue(type) {
|
|
117
|
+
const isInRange = (value, { kind, min = -Infinity, max = Infinity }) => {
|
|
118
|
+
const comparator = (a, b, exclusive) => exclusive ? a < b : a <= b;
|
|
119
|
+
return (comparator(min, value, kind & 0b10) &&
|
|
120
|
+
comparator(value, max, kind & 0b01));
|
|
121
|
+
};
|
|
122
|
+
const ExpectedTypes = {
|
|
123
|
+
boolean: 'json:boolean',
|
|
124
|
+
byte: 'json:number',
|
|
125
|
+
byte_array: 'json:array',
|
|
126
|
+
double: 'json:number',
|
|
127
|
+
float: 'json:number',
|
|
128
|
+
int: 'json:number',
|
|
129
|
+
int_array: 'json:array',
|
|
130
|
+
list: 'json:array',
|
|
131
|
+
long: 'json:number',
|
|
132
|
+
long_array: 'json:array',
|
|
133
|
+
short: 'json:number',
|
|
134
|
+
string: 'json:string',
|
|
135
|
+
struct: 'json:object',
|
|
136
|
+
tuple: 'json:array',
|
|
137
|
+
};
|
|
138
|
+
return (node, ctx) => {
|
|
139
|
+
// Rough type check.
|
|
140
|
+
if (type.kind !== 'any' &&
|
|
141
|
+
type.kind !== 'dispatcher' &&
|
|
142
|
+
type.kind !== 'enum' &&
|
|
143
|
+
type.kind !== 'literal' &&
|
|
144
|
+
type.kind !== 'reference' &&
|
|
145
|
+
type.kind !== 'union' &&
|
|
146
|
+
type.kind !== 'attributed' &&
|
|
147
|
+
type.kind !== 'unsafe' &&
|
|
148
|
+
type.kind !== 'concrete' &&
|
|
149
|
+
type.kind !== 'indexed' &&
|
|
150
|
+
type.kind !== 'template' &&
|
|
151
|
+
node.type !== ExpectedTypes[type.kind]) {
|
|
152
|
+
ctx.err.report(localize('expected', localizeTag(ExpectedTypes[type.kind])), node, 2 /* core.ErrorSeverity.Warning */);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
switch (type.kind) {
|
|
156
|
+
case 'boolean':
|
|
157
|
+
break;
|
|
158
|
+
case 'byte_array':
|
|
159
|
+
case 'int_array':
|
|
160
|
+
case 'long_array':
|
|
161
|
+
node = node;
|
|
162
|
+
if (type.lengthRange &&
|
|
163
|
+
!isInRange(node.children.length, type.lengthRange)) {
|
|
164
|
+
ctx.err.report(localize('expected', localize('json.checker.array.length-between', localizeTag(node.type), type.lengthRange.min ?? '-∞', type.lengthRange.max ?? '+∞')), node, 2 /* core.ErrorSeverity.Warning */);
|
|
165
|
+
}
|
|
166
|
+
if (type.valueRange) {
|
|
167
|
+
for (const { value: childNode } of node.children) {
|
|
168
|
+
if (childNode?.type !== 'json:number') {
|
|
169
|
+
ctx.err.report(localize('expected', localizeTag('json:number')), node, 2 /* core.ErrorSeverity.Warning */);
|
|
170
|
+
}
|
|
171
|
+
else if (childNode &&
|
|
172
|
+
!isInRange(Number(childNode.value), type.valueRange)) {
|
|
173
|
+
ctx.err.report(localize('number.between', type.valueRange.min ?? '-∞', type.valueRange.max ?? '+∞'), node, 2 /* core.ErrorSeverity.Warning */);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case 'byte':
|
|
179
|
+
case 'short':
|
|
180
|
+
case 'int':
|
|
181
|
+
case 'long':
|
|
182
|
+
case 'float':
|
|
183
|
+
case 'double':
|
|
184
|
+
node = node;
|
|
185
|
+
if (type.valueRange &&
|
|
186
|
+
!isInRange(Number(node.value), type.valueRange)) {
|
|
187
|
+
ctx.err.report(localize('number.between', type.valueRange.min ?? '-∞', type.valueRange.max ?? '+∞'), node, 2 /* core.ErrorSeverity.Warning */);
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
case 'dispatcher':
|
|
191
|
+
node = node;
|
|
192
|
+
// const id = resolveFieldPath(node.parent?.parent, type.index.path)
|
|
193
|
+
// if (type.index.registry) {
|
|
194
|
+
// if (ExtendableRootRegistry.is(type.index.registry)) {
|
|
195
|
+
// index(type.index.registry, id ? core.ResourceLocation.lengthen(id) : undefined, options)(node, ctx)
|
|
196
|
+
// } else if (id) {
|
|
197
|
+
// index(type.index.registry, core.ResourceLocation.lengthen(id), options)(node, ctx)
|
|
198
|
+
// }
|
|
199
|
+
// }
|
|
200
|
+
break;
|
|
201
|
+
case 'list':
|
|
202
|
+
node = node;
|
|
203
|
+
type = mcdoc.simplifyListType(type);
|
|
204
|
+
if (type.lengthRange &&
|
|
205
|
+
!isInRange(node.children.length, type.lengthRange)) {
|
|
206
|
+
ctx.err.report(localize('expected', localize('json.checker.collection.length-between', localizeTag(node.type), type.lengthRange.min ?? '-∞', type.lengthRange.max ?? '+∞')), node, 2 /* core.ErrorSeverity.Warning */);
|
|
207
|
+
}
|
|
208
|
+
for (const { value: childNode } of node.children) {
|
|
209
|
+
if (childNode) {
|
|
210
|
+
fieldValue(type.item)(childNode, ctx);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
case 'struct':
|
|
215
|
+
node = node;
|
|
216
|
+
object(type)(node, ctx);
|
|
217
|
+
break;
|
|
218
|
+
case 'string':
|
|
219
|
+
break;
|
|
220
|
+
case 'reference':
|
|
221
|
+
// node = node as JsonObjectNode
|
|
222
|
+
// if (type.symbol) {
|
|
223
|
+
// const { allowUnknownKey, value } = resolveSymbolPaths([type.symbol], ctx, node)
|
|
224
|
+
// compound(value, { ...options, allowUnknownKey: options.allowUnknownKey || allowUnknownKey })(node, ctx)
|
|
225
|
+
// }
|
|
226
|
+
break;
|
|
227
|
+
case 'union':
|
|
228
|
+
type = mcdoc.flattenUnionType(type);
|
|
229
|
+
if (type.members.length === 0) {
|
|
230
|
+
ctx.err.report(localize('json.checker.object.field.union-empty-members'), core.PairNode.is(node.parent)
|
|
231
|
+
? node.parent.key ?? node.parent
|
|
232
|
+
: node, 2 /* core.ErrorSeverity.Warning */);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
;
|
|
236
|
+
core.checker.any(type.members.map((t) => fieldValue(t)))(node, ctx);
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case 'attributed':
|
|
240
|
+
// TODO: don't just ignore the attribute
|
|
241
|
+
fieldValue(type.child)(node, ctx);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function localizeTag(type) {
|
|
247
|
+
const key = `json.node.${type.replace(/^json:/, '')}`;
|
|
248
|
+
const res = localize(key);
|
|
249
|
+
return res;
|
|
250
|
+
}
|
|
23
251
|
//# sourceMappingURL=index.js.map
|
|
@@ -7,9 +7,10 @@ export function criterionReference(advancement) {
|
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
const criteria = Object.values(ctx.symbols.query(ctx.doc, 'advancement', advancement).symbol
|
|
10
|
-
?.members ??
|
|
10
|
+
?.members ??
|
|
11
|
+
{})
|
|
11
12
|
.filter((m) => m?.subcategory === 'criterion')
|
|
12
|
-
.map(s => s.identifier);
|
|
13
|
+
.map((s) => s.identifier);
|
|
13
14
|
literal(criteria)(node, ctx);
|
|
14
15
|
};
|
|
15
16
|
}
|
|
@@ -7,7 +7,7 @@ interface Options {
|
|
|
7
7
|
mixedTypes?: boolean;
|
|
8
8
|
requireAll?: boolean;
|
|
9
9
|
}
|
|
10
|
-
export declare function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll }: Options): JsonChecker;
|
|
11
|
-
export declare function blockStateList({ category, id, ids, tag }: Options): JsonChecker;
|
|
10
|
+
export declare function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll, }: Options): JsonChecker;
|
|
11
|
+
export declare function blockStateList({ category, id, ids, tag, }: Options): JsonChecker;
|
|
12
12
|
export {};
|
|
13
13
|
//# sourceMappingURL=block_states.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as core from '@spyglassmc/core';
|
|
2
|
-
import { any, boolean, intRange, listOf, literal, object, opt, record, simpleString } from '@spyglassmc/json/lib/checker/index.js';
|
|
2
|
+
import { any, boolean, intRange, listOf, literal, object, opt, record, simpleString, } from '@spyglassmc/json/lib/checker/index.js';
|
|
3
3
|
import { getTagValues } from '../../../common/index.js';
|
|
4
|
-
export function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll }) {
|
|
4
|
+
export function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll, }) {
|
|
5
5
|
return (node, ctx) => {
|
|
6
6
|
if (tag) {
|
|
7
7
|
ids = getTagValues(`tag/${category ?? 'block'}`, tag, ctx);
|
|
@@ -11,8 +11,10 @@ export function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll }
|
|
|
11
11
|
}
|
|
12
12
|
// FIXME: Temporary solution to make tests pass when ensureBindingStarted is not given.
|
|
13
13
|
if (!ids?.length || !ctx.ensureBindingStarted) {
|
|
14
|
-
const values = mixedTypes
|
|
15
|
-
|
|
14
|
+
const values = mixedTypes
|
|
15
|
+
? any([boolean, simpleString, intBounds()])
|
|
16
|
+
: simpleString;
|
|
17
|
+
object(simpleString, () => (requireAll ? values : opt(values)))(node, ctx);
|
|
16
18
|
return;
|
|
17
19
|
}
|
|
18
20
|
const states = core.getStates(category ?? 'block', ids, ctx);
|
|
@@ -32,7 +34,7 @@ export function blockStateMap({ category, id, ids, tag, mixedTypes, requireAll }
|
|
|
32
34
|
})(node, ctx);
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
|
-
export function blockStateList({ category, id, ids, tag }) {
|
|
37
|
+
export function blockStateList({ category, id, ids, tag, }) {
|
|
36
38
|
return (node, ctx) => {
|
|
37
39
|
if (tag) {
|
|
38
40
|
ids = getTagValues(`tag/${category ?? 'block'}`, tag, ctx);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, ColorFormat, Failure, parseStringValue, Range } from '@spyglassmc/core';
|
|
1
|
+
import { Color, ColorFormat, Failure, parseStringValue, Range, } from '@spyglassmc/core';
|
|
2
2
|
import { JsonNumberNode, JsonStringNode } from '@spyglassmc/json';
|
|
3
3
|
import { localize } from '@spyglassmc/locales';
|
|
4
4
|
export function stringColor() {
|
|
@@ -27,7 +27,13 @@ export function stringColor() {
|
|
|
27
27
|
return Color.fromCompositeInt(value);
|
|
28
28
|
};
|
|
29
29
|
return (node, ctx) => {
|
|
30
|
-
node.expectation = [
|
|
30
|
+
node.expectation = [
|
|
31
|
+
{
|
|
32
|
+
type: 'json:string',
|
|
33
|
+
typedoc: 'String("Color")',
|
|
34
|
+
pool: Color.ColorNames,
|
|
35
|
+
},
|
|
36
|
+
];
|
|
31
37
|
if (!JsonStringNode.is(node)) {
|
|
32
38
|
ctx.err.report(localize('expected', localize('string')), node);
|
|
33
39
|
}
|
|
@@ -9,7 +9,7 @@ interface RegistryOptions {
|
|
|
9
9
|
ids?: readonly string[] | undefined;
|
|
10
10
|
tag?: string | undefined;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
type Options = DefinitionOptions | RegistryOptions;
|
|
13
13
|
export declare function nbt(options: Options): JsonChecker;
|
|
14
14
|
export declare function nbtPath(options: RegistryOptions): JsonChecker;
|
|
15
15
|
export {};
|
|
@@ -53,9 +53,11 @@ export function nbtPath(options) {
|
|
|
53
53
|
}
|
|
54
54
|
function getIds({ registry, id, idOrTag, ids, tag }, ctx) {
|
|
55
55
|
if (idOrTag) {
|
|
56
|
-
idOrTag.startsWith('#') ? tag = idOrTag.slice(1) : id = idOrTag;
|
|
56
|
+
idOrTag.startsWith('#') ? (tag = idOrTag.slice(1)) : (id = idOrTag);
|
|
57
57
|
}
|
|
58
|
-
if (tag &&
|
|
58
|
+
if (tag &&
|
|
59
|
+
(registry === 'block' || registry === 'item' ||
|
|
60
|
+
registry === 'entity_type')) {
|
|
59
61
|
ids = getTagValues(`tag/${registry}`, tag, ctx);
|
|
60
62
|
}
|
|
61
63
|
else if (id) {
|
|
@@ -2,11 +2,12 @@ import { symbol } from '@spyglassmc/core';
|
|
|
2
2
|
import { string } from '@spyglassmc/json/lib/checker/index.js';
|
|
3
3
|
export const recipeGroup = string('recipe_group', symbol('recipe_group'));
|
|
4
4
|
export function patternKeys(props) {
|
|
5
|
-
return [
|
|
6
|
-
|
|
7
|
-
.map(n => n.value)
|
|
8
|
-
.filter(n => n && n.type === 'json:string')
|
|
9
|
-
.flatMap(n => [...n.value])
|
|
10
|
-
.filter(v => v !== ' '))
|
|
5
|
+
return [
|
|
6
|
+
...new Set((props.find((p) => p.key?.value === 'pattern' && p.value?.type === 'json:array')?.value?.children ?? [])
|
|
7
|
+
.map((n) => n.value)
|
|
8
|
+
.filter((n) => n && n.type === 'json:string')
|
|
9
|
+
.flatMap((n) => [...n.value])
|
|
10
|
+
.filter((v) => v !== ' ')),
|
|
11
|
+
];
|
|
11
12
|
}
|
|
12
13
|
//# sourceMappingURL=recipe.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { JsonChecker, JsonCheckerContext, record } from '@spyglassmc/json/lib/checker/index.js';
|
|
2
2
|
import { ReleaseVersion } from '../../../dependency/index.js';
|
|
3
|
-
|
|
3
|
+
type CheckerRecord = Parameters<typeof record>[0];
|
|
4
4
|
export declare function versioned(ctx: JsonCheckerContext, version: ReleaseVersion, checker: string[]): string[];
|
|
5
5
|
export declare function versioned(ctx: JsonCheckerContext, version: ReleaseVersion, checker: JsonChecker | undefined): JsonChecker | undefined;
|
|
6
6
|
export declare function versioned(ctx: JsonCheckerContext, version: ReleaseVersion, checker: CheckerRecord | undefined): CheckerRecord | undefined;
|
|
@@ -25,10 +25,10 @@ export function versioned(ctx, arg1, arg2, arg3) {
|
|
|
25
25
|
return arg1;
|
|
26
26
|
}
|
|
27
27
|
else if (Array.isArray(arg1)) {
|
|
28
|
-
return check ? arg1 :
|
|
28
|
+
return check ? arg1 : arg3 ?? [];
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
31
|
-
return check ? arg1 :
|
|
31
|
+
return check ? arg1 : arg3 ?? undefined;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -19,7 +19,7 @@ const getNode = (nodes, index) => {
|
|
|
19
19
|
return nodes[index]?.children[0];
|
|
20
20
|
};
|
|
21
21
|
const rootCommand = (nodes, index, ctx) => {
|
|
22
|
-
for (const { children: [node] } of nodes) {
|
|
22
|
+
for (const { children: [node], } of nodes) {
|
|
23
23
|
if (BlockNode.is(node)) {
|
|
24
24
|
block(node, ctx);
|
|
25
25
|
}
|
|
@@ -108,7 +108,8 @@ const rootCommand = (nodes, index, ctx) => {
|
|
|
108
108
|
}
|
|
109
109
|
else if (getName(nodes, index) === 'execute') {
|
|
110
110
|
for (let i = index + 1; i < nodes.length; i++) {
|
|
111
|
-
if ((getName(nodes, i) === 'if' || getName(nodes, i) === 'unless') &&
|
|
111
|
+
if ((getName(nodes, i) === 'if' || getName(nodes, i) === 'unless') &&
|
|
112
|
+
getName(nodes, i + 1) === 'data') {
|
|
112
113
|
// `if|unless data <$nbtPath$>`
|
|
113
114
|
nbtPath(nodes, i + 2, ctx);
|
|
114
115
|
i += 2;
|
|
@@ -123,7 +124,7 @@ const rootCommand = (nodes, index, ctx) => {
|
|
|
123
124
|
summonNbt(nodes, index + 1, ctx);
|
|
124
125
|
}
|
|
125
126
|
};
|
|
126
|
-
|
|
127
|
+
// #region Checkers for argument nodes
|
|
127
128
|
const block = (node, ctx) => {
|
|
128
129
|
if (!node.nbt) {
|
|
129
130
|
return;
|
|
@@ -131,7 +132,7 @@ const block = (node, ctx) => {
|
|
|
131
132
|
nbt.checker.index('block', core.ResourceLocationNode.toString(node.id, 'full'))(node.nbt, ctx);
|
|
132
133
|
};
|
|
133
134
|
const entity = (node, ctx) => {
|
|
134
|
-
const nbtPair = node.selector?.arguments?.children.find(pair => pair.key?.value === 'nbt');
|
|
135
|
+
const nbtPair = node.selector?.arguments?.children.find((pair) => pair.key?.value === 'nbt');
|
|
135
136
|
if (!nbtPair) {
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
@@ -148,8 +149,8 @@ const item = (node, ctx) => {
|
|
|
148
149
|
const particle = (node, ctx) => {
|
|
149
150
|
core.checker.dispatchSync(node, ctx);
|
|
150
151
|
};
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
// #endregion
|
|
153
|
+
// #region Checkers for command argument structure.
|
|
153
154
|
/**
|
|
154
155
|
* - `block <targetPos: block_pos> <nbt: nbt_compound_tag>`
|
|
155
156
|
* - `entity <target: entity> <nbt: nbt_compound_tag>`
|
|
@@ -177,7 +178,8 @@ const dataMergeTarget = (nodes, index, ctx) => {
|
|
|
177
178
|
case 'storage': {
|
|
178
179
|
const idNode = getNode(nodes, index + 1);
|
|
179
180
|
const nbtNode = getNode(nodes, index + 2);
|
|
180
|
-
if (core.ResourceLocationNode.is(idNode) &&
|
|
181
|
+
if (core.ResourceLocationNode.is(idNode) &&
|
|
182
|
+
nbt.NbtCompoundNode.is(nbtNode)) {
|
|
181
183
|
nbt.checker.index('storage', core.ResourceLocationNode.toString(idNode, 'full'))(nbtNode, ctx);
|
|
182
184
|
}
|
|
183
185
|
break;
|
|
@@ -224,11 +226,12 @@ const nbtPath = (nodes, index, ctx) => {
|
|
|
224
226
|
const summonNbt = (nodes, index, ctx) => {
|
|
225
227
|
const typeNode = getNode(nodes, index);
|
|
226
228
|
const nbtNode = getNode(nodes, index + 2);
|
|
227
|
-
if (core.ResourceLocationNode.is(typeNode) &&
|
|
229
|
+
if (core.ResourceLocationNode.is(typeNode) &&
|
|
230
|
+
nbt.NbtCompoundNode.is(nbtNode)) {
|
|
228
231
|
nbt.checker.index('entity_type', core.ResourceLocationNode.toString(typeNode, 'full'))(nbtNode, ctx);
|
|
229
232
|
}
|
|
230
233
|
};
|
|
231
|
-
|
|
234
|
+
// #endregion
|
|
232
235
|
export const getTypesFromEntity = (entity, ctx) => {
|
|
233
236
|
if (entity.playerName !== undefined || entity.selector?.playersOnly) {
|
|
234
237
|
return ['minecraft:player'];
|
|
@@ -247,10 +250,10 @@ export const getTypesFromEntity = (entity, ctx) => {
|
|
|
247
250
|
if (!valueNode || valueNode.inverted) {
|
|
248
251
|
continue;
|
|
249
252
|
}
|
|
250
|
-
const value = core.ResourceLocationNode.toString(valueNode.value, 'full');
|
|
253
|
+
const value = core.ResourceLocationNode.toString(valueNode.value, 'full', true);
|
|
251
254
|
if (value.startsWith(core.ResourceLocation.TagPrefix)) {
|
|
252
255
|
const tagValues = getTagValues('tag/entity_type', value.slice(1), ctx);
|
|
253
|
-
types = types.filter(t => tagValues.includes(t));
|
|
256
|
+
types = types.filter((t) => tagValues.includes(t));
|
|
254
257
|
}
|
|
255
258
|
else {
|
|
256
259
|
types = [value];
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as core from '@spyglassmc/core';
|
|
2
|
-
export const objectiveCriterion = node => [
|
|
3
|
-
|
|
4
|
-
];
|
|
5
|
-
export const vector = node => {
|
|
2
|
+
export const objectiveCriterion = (node) => [core.ColorToken.create(node, 'type')];
|
|
3
|
+
export const vector = (node) => {
|
|
6
4
|
return [core.ColorToken.create(node, 'vector')];
|
|
7
5
|
};
|
|
8
6
|
export function register(meta) {
|
|
@@ -2,24 +2,55 @@ import * as core from '@spyglassmc/core';
|
|
|
2
2
|
export const ColorArgumentValues = [...core.Color.ColorNames, 'reset'];
|
|
3
3
|
export const EntityAnchorArgumentValues = ['feet', 'eyes'];
|
|
4
4
|
export const ItemSlotArgumentValues = [
|
|
5
|
-
...[...Array(54).keys()].map(n => `container.${n}`),
|
|
6
|
-
...[...Array(27).keys()].map(n => `enderchest.${n}`),
|
|
7
|
-
...[...Array(15).keys()].map(n => `horse.${n}`),
|
|
8
|
-
...[...Array(9).keys()].map(n => `hotbar.${n}`),
|
|
9
|
-
...[...Array(27).keys()].map(n => `inventory.${n}`),
|
|
10
|
-
...[...Array(8).keys()].map(n => `villager.${n}`),
|
|
11
|
-
'armor.chest',
|
|
12
|
-
'
|
|
13
|
-
'
|
|
5
|
+
...[...Array(54).keys()].map((n) => `container.${n}`),
|
|
6
|
+
...[...Array(27).keys()].map((n) => `enderchest.${n}`),
|
|
7
|
+
...[...Array(15).keys()].map((n) => `horse.${n}`),
|
|
8
|
+
...[...Array(9).keys()].map((n) => `hotbar.${n}`),
|
|
9
|
+
...[...Array(27).keys()].map((n) => `inventory.${n}`),
|
|
10
|
+
...[...Array(8).keys()].map((n) => `villager.${n}`),
|
|
11
|
+
'armor.chest',
|
|
12
|
+
'armor.feet',
|
|
13
|
+
'armor.head',
|
|
14
|
+
'armor.legs',
|
|
15
|
+
'horse.armor',
|
|
16
|
+
'horse.chest',
|
|
17
|
+
'horse.saddle',
|
|
18
|
+
'weapon',
|
|
19
|
+
'weapon.mainhand',
|
|
20
|
+
'weapon.offhand',
|
|
21
|
+
];
|
|
22
|
+
export const OperationArgumentValues = [
|
|
23
|
+
'=',
|
|
24
|
+
'+=',
|
|
25
|
+
'-=',
|
|
26
|
+
'*=',
|
|
27
|
+
'/=',
|
|
28
|
+
'%=',
|
|
29
|
+
'<',
|
|
30
|
+
'>',
|
|
31
|
+
'><',
|
|
14
32
|
];
|
|
15
|
-
export const OperationArgumentValues = ['=', '+=', '-=', '*=', '/=', '%=', '<', '>', '><'];
|
|
16
33
|
export const ScoreboardSlotArgumentValues = [
|
|
17
|
-
'belowName',
|
|
18
|
-
|
|
34
|
+
'belowName',
|
|
35
|
+
'list',
|
|
36
|
+
'sidebar',
|
|
37
|
+
...core.Color.ColorNames.map((n) => `sidebar.team.${n}`),
|
|
19
38
|
];
|
|
20
39
|
export const SwizzleArgumentValues = [
|
|
21
|
-
'x',
|
|
22
|
-
'
|
|
23
|
-
'
|
|
40
|
+
'x',
|
|
41
|
+
'xy',
|
|
42
|
+
'xz',
|
|
43
|
+
'xyz',
|
|
44
|
+
'xzy',
|
|
45
|
+
'y',
|
|
46
|
+
'yx',
|
|
47
|
+
'yz',
|
|
48
|
+
'yxz',
|
|
49
|
+
'yzx',
|
|
50
|
+
'z',
|
|
51
|
+
'zx',
|
|
52
|
+
'zy',
|
|
53
|
+
'zxy',
|
|
54
|
+
'zyx',
|
|
24
55
|
];
|
|
25
56
|
//# sourceMappingURL=index.js.map
|