@spyglassmc/java-edition 0.3.8 → 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.
Files changed (35) hide show
  1. package/lib/binder/index.d.ts +11 -9
  2. package/lib/binder/index.js +149 -150
  3. package/lib/common/index.js +6 -9
  4. package/lib/dependency/common.d.ts +5 -0
  5. package/lib/dependency/common.js +8 -0
  6. package/lib/dependency/index.js +7 -17
  7. package/lib/dependency/mcmeta.d.ts +6 -12
  8. package/lib/dependency/mcmeta.js +21 -38
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.js +74 -32
  11. package/lib/json/checker/index.d.ts +3 -10
  12. package/lib/json/checker/index.js +36 -244
  13. package/lib/json/index.d.ts +0 -1
  14. package/lib/json/index.js +0 -3
  15. package/lib/mcfunction/checker/index.d.ts +0 -2
  16. package/lib/mcfunction/checker/index.js +254 -183
  17. package/lib/mcfunction/common/index.d.ts +4 -2
  18. package/lib/mcfunction/common/index.js +56 -52
  19. package/lib/mcfunction/completer/argument.js +112 -57
  20. package/lib/mcfunction/index.d.ts +3 -2
  21. package/lib/mcfunction/index.js +18 -19
  22. package/lib/mcfunction/inlayHintProvider.js +2 -3
  23. package/lib/mcfunction/mcdocAttributes.d.ts +4 -0
  24. package/lib/mcfunction/mcdocAttributes.js +71 -0
  25. package/lib/mcfunction/node/argument.d.ts +115 -12
  26. package/lib/mcfunction/node/argument.js +131 -63
  27. package/lib/mcfunction/parser/argument.d.ts +14 -4
  28. package/lib/mcfunction/parser/argument.js +380 -212
  29. package/lib/mcfunction/signatureHelpProvider.d.ts +2 -1
  30. package/lib/mcfunction/signatureHelpProvider.js +10 -18
  31. package/lib/mcfunction/tree/argument.d.ts +68 -1
  32. package/lib/mcfunction/tree/patch.js +279 -77
  33. package/lib/mcfunction/tree/patchValidator.d.ts +7 -0
  34. package/lib/mcfunction/tree/patchValidator.js +25 -0
  35. package/package.json +8 -9
@@ -3,236 +3,300 @@ import * as json from '@spyglassmc/json';
3
3
  import { localize } from '@spyglassmc/locales';
4
4
  import * as mcf from '@spyglassmc/mcfunction';
5
5
  import * as nbt from '@spyglassmc/nbt';
6
+ import { dissectUri, reportDissectError } from '../../binder/index.js';
6
7
  import { getTagValues } from '../../common/index.js';
7
- import { BlockNode, EntityNode, ItemNode, ParticleNode } from '../node/index.js';
8
+ import { ReleaseVersion } from '../../dependency/common.js';
9
+ import { BlockNode, ComponentTestExactNode, ComponentTestExistsNode, ComponentTestSubpredicateNode, EntityNode, ItemPredicateNode, ItemStackNode, NbtNode, NbtPathNode, NbtResourceNode, ParticleNode, } from '../node/index.js';
10
+ const entry = (node, ctx) => {
11
+ const parts = dissectUri(ctx.doc.uri, ctx);
12
+ if (parts?.ok === false) {
13
+ reportDissectError(parts.path, parts.expected, ctx);
14
+ }
15
+ core.checker.dispatchSync(node, ctx);
16
+ };
8
17
  export const command = (node, ctx) => {
9
18
  if (node.slash && node.parent && mcf.McfunctionNode.is(node.parent)) {
10
19
  ctx.err.report(localize('unexpected-leading-slash'), node.slash);
11
20
  }
12
21
  rootCommand(node.children, 0, ctx);
13
22
  };
14
- const getName = (nodes, index) => {
15
- return nodes[index]?.path[nodes[index].path.length - 1];
16
- };
17
- const getNode = (nodes, index) => {
18
- return nodes[index]?.children[0];
19
- };
23
+ function getEarlierNode(nodes, before, name) {
24
+ if (name === undefined) {
25
+ return undefined;
26
+ }
27
+ for (let i = before - 1; i > 0; i -= 1) {
28
+ if (nodes[i].path[nodes[i].path.length - 1] === name) {
29
+ return nodes[i].children[0];
30
+ }
31
+ }
32
+ return undefined;
33
+ }
20
34
  const rootCommand = (nodes, index, ctx) => {
21
- for (const { children: [node], } of nodes) {
35
+ for (let i = 0; i < nodes.length; i += 1) {
36
+ const node = nodes[i].children[0];
22
37
  if (BlockNode.is(node)) {
23
38
  block(node, ctx);
24
39
  }
25
40
  else if (EntityNode.is(node)) {
26
41
  entity(node, ctx);
27
42
  }
28
- else if (ItemNode.is(node)) {
29
- item(node, ctx);
43
+ else if (ItemPredicateNode.is(node)) {
44
+ itemPredicate(node, ctx);
45
+ }
46
+ else if (ItemStackNode.is(node)) {
47
+ itemStack(node, ctx);
30
48
  }
31
49
  else if (ParticleNode.is(node)) {
32
50
  particle(node, ctx);
33
51
  }
34
- else if (json.JsonNode.is(node)) {
35
- // TODO v4.0: check text component
36
- }
37
- }
38
- if (getName(nodes, index) === 'data') {
39
- if (getName(nodes, index + 1) === 'get') {
40
- nbtPath(nodes, index + 2, ctx);
41
- }
42
- else if (getName(nodes, index + 1) === 'merge') {
43
- dataMergeTarget(nodes, index + 2, ctx);
52
+ else if (NbtResourceNode.is(node)) {
53
+ nbtResource(node, ctx);
44
54
  }
45
- else if (getName(nodes, index + 1) === 'modify') {
46
- nbtPath(nodes, index + 2, ctx);
47
- const targetPath = getNode(nodes, index + 4);
48
- // if (nbt.NbtPathNode.is(targetPath)) {
49
- // const operationNode = getNode(nodes, index + 5)
50
- // const operation = getName(nodes, index + 5) as 'append' | 'insert' | 'merge' | 'prepend' | 'set' | undefined
51
- // const sourceTypeIndex = operation === 'insert' ? index + 7 : index + 6
52
- // let targetMcdocType: mcdoc.McdocType | undefined = targetPath.targetType ? mcdoc.simplifyType(targetPath.targetType) : undefined
53
- // const isType = (type: mcdoc.McdocType['kind']) => !targetMcdocType || targetMcdocType.kind === type || (targetMcdocType.type === 'union' && targetMcdocType.members.some(m => m.type === type))
54
- // if (operation === 'merge') {
55
- // if (!(isType('compound') || isType('index'))) {
56
- // ctx.err.report(
57
- // localize('mcfunction.checker.command.data-modify-unapplicable-operation', localeQuote(operation), localize('nbt.node.compound'), localeQuote(mcdoc.McdocType.toString(targetMcdocType))),
58
- // core.Range.span(targetPath, operationNode!),
59
- // core.ErrorSeverity.Warning
60
- // )
61
- // targetMcdocType = undefined
62
- // }
63
- // } else if (operation === 'append' || operation === 'insert' || operation === 'prepend') {
64
- // if (isType('list') || isType('byte_array') || isType('int_array') || isType('long_array')) {
65
- // if (targetMcdocType?.type === 'list') {
66
- // targetMcdocType = targetMcdocType.item
67
- // } else if (targetMcdocType?.type === 'byte_array') {
68
- // targetMcdocType = { type: 'byte', valueRange: targetMcdocType.valueRange }
69
- // } else if (targetMcdocType?.type === 'int_array') {
70
- // targetMcdocType = { type: 'int', valueRange: targetMcdocType.valueRange }
71
- // } else if (targetMcdocType?.type === 'long_array') {
72
- // targetMcdocType = { type: 'long', valueRange: targetMcdocType.valueRange }
73
- // }
74
- // } else {
75
- // ctx.err.report(
76
- // localize('mcfunction.checker.command.data-modify-unapplicable-operation', localeQuote(operation), localize('nbt.node.list'), localeQuote(mcdoc.McdocType.toString(targetMcdocType))),
77
- // core.Range.span(targetPath, operationNode!),
78
- // core.ErrorSeverity.Warning
79
- // )
80
- // targetMcdocType = undefined
81
- // }
82
- // }
83
- // if (targetMcdocType) {
84
- // if (getName(nodes, sourceTypeIndex) === 'from') {
85
- // // `from <$nbtPath$>`
86
- // nbtPath(nodes, sourceTypeIndex + 1, ctx)
87
- // const sourcePath = getNode(nodes, sourceTypeIndex + 3)
88
- // if (nbt.NbtPathNode.is(sourcePath)) {
89
- // const { errorMessage } = mcdoc.checkAssignability({ source: sourcePath.targetType, target: targetMcdocType })
90
- // if (errorMessage) {
91
- // ctx.err.report(errorMessage, core.Range.span(targetPath, sourcePath), core.ErrorSeverity.Warning)
92
- // }
93
- // }
94
- // } else if (getName(nodes, sourceTypeIndex) === 'value') {
95
- // // `value <value: nbt_tag>`
96
- // const valueNode = getNode(nodes, sourceTypeIndex + 1)
97
- // if (nbt.NbtNode.is(valueNode)) {
98
- // nbt.checker.fieldValue(targetMcdocType, { allowUnknownKey: true })(valueNode, ctx)
99
- // }
100
- // }
101
- // }
102
- // }
55
+ else if (json.TypedJsonNode.is(node)) {
56
+ json.checker.typed(node, ctx);
103
57
  }
104
- else if (getName(nodes, index + 1) === 'remove') {
105
- nbtPath(nodes, index + 2, ctx);
58
+ else if (NbtNode.is(node) && node.properties) {
59
+ const dispatchedBy = getEarlierNode(nodes, i, node.properties.dispatchedBy);
60
+ const indexedBy = getEarlierNode(nodes, i, node.properties.indexedBy);
61
+ nbtChecker(dispatchedBy, indexedBy)(node, ctx);
106
62
  }
107
- }
108
- else if (getName(nodes, index) === 'execute') {
109
- for (let i = index + 1; i < nodes.length; i++) {
110
- if ((getName(nodes, i) === 'if' || getName(nodes, i) === 'unless') &&
111
- getName(nodes, i + 1) === 'data') {
112
- // `if|unless data <$nbtPath$>`
113
- nbtPath(nodes, i + 2, ctx);
114
- i += 2;
115
- }
116
- else if (getName(nodes, i) === 'run') {
117
- rootCommand(nodes, i + 1, ctx);
118
- break;
119
- }
63
+ else if (NbtPathNode.is(node) && node.properties) {
64
+ const dispatchedBy = getEarlierNode(nodes, i, node.properties.dispatchedBy);
65
+ nbtPathChecker(dispatchedBy)(node, ctx);
120
66
  }
121
67
  }
122
- else if (getName(nodes, index) === 'summon') {
123
- summonNbt(nodes, index + 1, ctx);
124
- }
125
68
  };
126
69
  // #region Checkers for argument nodes
127
70
  const block = (node, ctx) => {
128
71
  if (!node.nbt) {
129
72
  return;
130
73
  }
131
- nbt.checker.index('block', core.ResourceLocationNode.toString(node.id, 'full'))(node.nbt, ctx);
74
+ const type = core.ResourceLocationNode.toString(node.id, 'full');
75
+ nbt.checker.index('minecraft:block', type, { isPredicate: node.isPredicate })(node.nbt, ctx);
132
76
  };
133
77
  const entity = (node, ctx) => {
134
- const nbtPair = node.selector?.arguments?.children.find((pair) => pair.key?.value === 'nbt');
135
- if (!nbtPair) {
136
- return;
78
+ for (const pair of node.selector?.arguments?.children ?? []) {
79
+ if (pair.key?.value !== 'nbt' || !pair.value) {
80
+ continue;
81
+ }
82
+ const types = getTypesFromEntity(node, ctx);
83
+ if (!nbt.NbtCompoundNode.is(pair.value.value)) {
84
+ continue;
85
+ }
86
+ nbt.checker.index('minecraft:entity', types, { isPredicate: true })(pair.value.value, ctx);
137
87
  }
138
- const types = getTypesFromEntity(node, ctx);
139
- const nbtValue = nbtPair.value;
140
- nbt.checker.index('entity_type', types)(nbtValue, ctx);
141
88
  };
142
- const item = (node, ctx) => {
143
- if (!node.nbt) {
89
+ const itemPredicate = (node, ctx) => {
90
+ if (node.nbt) {
91
+ const type = core.ResourceLocationNode.toString(node.id, 'full');
92
+ nbt.checker.index('minecraft:item', type, { isPredicate: true })(node.nbt, ctx);
93
+ }
94
+ if (!node.tests?.children) {
144
95
  return;
145
96
  }
146
- nbt.checker.index('item', core.ResourceLocationNode.toString(node.id, 'full'))(node.nbt, ctx);
147
- };
148
- const particle = (node, ctx) => {
149
- core.checker.dispatchSync(node, ctx);
150
- };
151
- // #endregion
152
- // #region Checkers for command argument structure.
153
- /**
154
- * - `block <targetPos: block_pos> <nbt: nbt_compound_tag>`
155
- * - `entity <target: entity> <nbt: nbt_compound_tag>`
156
- * - `storage <target: resource_location> <nbt: nbt_compound_tag>`
157
- */
158
- const dataMergeTarget = (nodes, index, ctx) => {
159
- const registry = getName(nodes, index);
160
- switch (registry) {
161
- case 'block': {
162
- const nbtNode = getNode(nodes, index + 2);
163
- if (nbt.NbtCompoundNode.is(nbtNode)) {
164
- nbt.checker.index('block', undefined)(nbtNode, ctx);
97
+ const anyOfTest = node.tests.children[0];
98
+ for (const allOfTest of anyOfTest.children) {
99
+ for (const test of allOfTest.children) {
100
+ const key = core.ResourceLocationNode.toString(test.key, 'full');
101
+ // count is a special case that's only valid in item predicate arguments, not json
102
+ // note: basically all errors checked here are otherwise accepted by vanilla, but it's good to report them
103
+ if (key === 'minecraft:count' && !ComponentTestExistsNode.is(test) && test.value) {
104
+ const validInt = { kind: 'int', valueRange: { kind: 0b00, min: 0 } };
105
+ const type = {
106
+ kind: 'union',
107
+ members: [
108
+ validInt,
109
+ {
110
+ kind: 'struct',
111
+ fields: [
112
+ { kind: 'pair', key: 'min', optional: true, type: validInt },
113
+ { kind: 'pair', key: 'max', optional: true, type: validInt },
114
+ ],
115
+ },
116
+ ],
117
+ };
118
+ nbt.checker.typeDefinition(type)(test.value, ctx);
165
119
  }
166
- break;
167
- }
168
- case 'entity': {
169
- const entityNode = getNode(nodes, index + 1);
170
- const nbtNode = getNode(nodes, index + 2);
171
- if (EntityNode.is(entityNode) && nbt.NbtCompoundNode.is(nbtNode)) {
172
- const types = getTypesFromEntity(entityNode, ctx);
173
- nbt.checker.index('entity_type', types)(nbtNode, ctx);
120
+ else if (ComponentTestExactNode.is(test) && test.value) {
121
+ nbt.checker.index('minecraft:data_component', key)(test.value, ctx);
174
122
  }
175
- break;
176
- }
177
- case 'storage': {
178
- const idNode = getNode(nodes, index + 1);
179
- const nbtNode = getNode(nodes, index + 2);
180
- if (core.ResourceLocationNode.is(idNode) &&
181
- nbt.NbtCompoundNode.is(nbtNode)) {
182
- nbt.checker.index('storage', core.ResourceLocationNode.toString(idNode, 'full'))(nbtNode, ctx);
123
+ else if (ComponentTestSubpredicateNode.is(test) && test.value) {
124
+ nbt.checker.index('minecraft:item_sub_predicate', key)(test.value, ctx);
183
125
  }
184
- break;
185
126
  }
186
127
  }
187
128
  };
188
- /**
189
- * - `block <block_pos> <nbt_path>`
190
- * - `entity <entity> <nbt_path>`
191
- * - `storage <resource_location> <nbt_path>`
192
- */
193
- const nbtPath = (nodes, index, ctx) => {
194
- const registry = getName(nodes, index);
195
- switch (registry) {
196
- case 'block': {
197
- const nbtNode = getNode(nodes, index + 2);
198
- if (nbt.NbtPathNode.is(nbtNode)) {
199
- nbt.checker.path('block', undefined)(nbtNode, ctx);
129
+ const itemStack = (node, ctx) => {
130
+ const itemId = core.ResourceLocationNode.toString(node.id, 'full');
131
+ if (node.nbt) {
132
+ nbt.checker.index('minecraft:item', itemId)(node.nbt, ctx);
133
+ }
134
+ if (!node.components) {
135
+ return;
136
+ }
137
+ const groupedComponents = new Map();
138
+ for (const pair of node.components.children) {
139
+ if (!pair.key) {
140
+ continue;
141
+ }
142
+ const componentId = core.ResourceLocationNode.toString(pair.key, 'full');
143
+ if (!groupedComponents.has(componentId)) {
144
+ groupedComponents.set(componentId, []);
145
+ }
146
+ groupedComponents.get(componentId).push(pair.key);
147
+ if (pair.value) {
148
+ nbt.checker.index('minecraft:data_component', componentId)(pair.value, ctx);
149
+ }
150
+ }
151
+ for (const [_, group] of groupedComponents) {
152
+ if (group.length > 1) {
153
+ for (const node of group) {
154
+ ctx.err.report(localize('mcfunction.parser.duplicate-components'), node.range, 2 /* core.ErrorSeverity.Warning */);
200
155
  }
201
- break;
202
156
  }
203
- case 'entity': {
204
- const entityNode = getNode(nodes, index + 1);
205
- const nbtNode = getNode(nodes, index + 2);
206
- if (EntityNode.is(entityNode) && nbt.NbtPathNode.is(nbtNode)) {
207
- const types = getTypesFromEntity(entityNode, ctx);
208
- nbt.checker.path('entity_type', types)(nbtNode, ctx);
157
+ }
158
+ };
159
+ const nbtResource = (node, ctx) => {
160
+ const type = {
161
+ kind: 'dispatcher',
162
+ registry: 'minecraft:resource',
163
+ parallelIndices: [{ kind: 'static', value: core.ResourceLocation.lengthen(node.category) }],
164
+ };
165
+ nbt.checker.typeDefinition(type)(node.children[0], ctx);
166
+ };
167
+ function nbtChecker(dispatchedBy, indexedBy) {
168
+ return (node, ctx) => {
169
+ if (!node.properties) {
170
+ return;
171
+ }
172
+ const tag = node.children[0];
173
+ if (indexedBy) {
174
+ if (NbtPathNode.is(indexedBy)) {
175
+ const indexedByTypedef = indexedBy.children[0].endTypeDef;
176
+ const typeDef = indexedByTypedef && node.properties.isListIndex
177
+ ? getListLikeChild(indexedByTypedef)
178
+ : indexedByTypedef;
179
+ if (typeDef) {
180
+ nbt.checker.typeDefinition(typeDef, node.properties)(tag, ctx);
181
+ }
209
182
  }
210
- break;
183
+ return;
211
184
  }
212
- case 'storage': {
213
- const idNode = getNode(nodes, index + 1);
214
- const nbtNode = getNode(nodes, index + 2);
215
- if (core.ResourceLocationNode.is(idNode) && nbt.NbtPathNode.is(nbtNode)) {
216
- nbt.checker.path('storage', core.ResourceLocationNode.toString(idNode, 'full'))(nbtNode, ctx);
185
+ switch (node.properties.dispatcher) {
186
+ case 'minecraft:entity':
187
+ if (nbt.NbtCompoundNode.is(tag)) {
188
+ const types = (EntityNode.is(dispatchedBy) || core.ResourceLocationNode.is(dispatchedBy))
189
+ ? getTypesFromEntity(dispatchedBy, ctx)
190
+ : undefined;
191
+ nbt.checker.index('minecraft:entity', types, {
192
+ isPredicate: node.properties.isPredicate,
193
+ isMerge: node.properties.isMerge,
194
+ })(tag, ctx);
195
+ }
196
+ break;
197
+ case 'minecraft:block':
198
+ if (nbt.NbtCompoundNode.is(tag)) {
199
+ nbt.checker.index('minecraft:block', undefined, {
200
+ isPredicate: node.properties.isPredicate,
201
+ isMerge: node.properties.isMerge,
202
+ })(tag, ctx);
203
+ }
204
+ break;
205
+ case 'minecraft:storage':
206
+ if (nbt.NbtCompoundNode.is(tag)) {
207
+ const storage = core.ResourceLocationNode.is(dispatchedBy)
208
+ ? core.ResourceLocationNode.toString(dispatchedBy)
209
+ : undefined;
210
+ nbt.checker.index('minecraft:storage', storage, {
211
+ isPredicate: node.properties.isPredicate,
212
+ isMerge: node.properties.isMerge,
213
+ })(tag, ctx);
214
+ }
215
+ break;
216
+ }
217
+ };
218
+ }
219
+ function getListLikeChild(typeDef) {
220
+ switch (typeDef.kind) {
221
+ case 'list':
222
+ return typeDef.item;
223
+ case 'byte_array':
224
+ return { kind: 'byte' };
225
+ case 'int_array':
226
+ return { kind: 'int' };
227
+ case 'long_array':
228
+ return { kind: 'long' };
229
+ case 'union':
230
+ const members = typeDef.members
231
+ .map(m => getListLikeChild(m))
232
+ .filter((m) => m !== undefined);
233
+ if (members.length === 0) {
234
+ return undefined;
217
235
  }
218
- break;
236
+ if (members.length === 1) {
237
+ return members[0];
238
+ }
239
+ return { kind: 'union', members };
240
+ default:
241
+ return undefined;
242
+ }
243
+ }
244
+ function nbtPathChecker(dispatchedBy) {
245
+ return (node, ctx) => {
246
+ if (!node.properties) {
247
+ return;
219
248
  }
249
+ const path = node.children[0];
250
+ switch (node.properties.dispatcher) {
251
+ case 'minecraft:entity':
252
+ const types = (EntityNode.is(dispatchedBy) || core.ResourceLocationNode.is(dispatchedBy))
253
+ ? getTypesFromEntity(dispatchedBy, ctx)
254
+ : undefined;
255
+ nbt.checker.path('minecraft:entity', types)(path, ctx);
256
+ break;
257
+ case 'minecraft:block':
258
+ nbt.checker.path('minecraft:block', undefined)(path, ctx);
259
+ break;
260
+ case 'minecraft:storage':
261
+ const storage = core.ResourceLocationNode.is(dispatchedBy)
262
+ ? core.ResourceLocationNode.toString(dispatchedBy)
263
+ : undefined;
264
+ nbt.checker.path('minecraft:storage', storage)(path, ctx);
265
+ break;
266
+ }
267
+ };
268
+ }
269
+ const particle = (node, ctx) => {
270
+ const id = core.ResourceLocationNode.toString(node.id, 'short');
271
+ const release = ctx.project['loadedVersion'];
272
+ if (release && ReleaseVersion.cmp(release, '1.20.5') < 0) {
273
+ return;
220
274
  }
221
- };
222
- /**
223
- * - `<entity: entity_summon> [<pos: vec3>] [<nbt: nbt_compound_tag>]`
224
- */
225
- const summonNbt = (nodes, index, ctx) => {
226
- const typeNode = getNode(nodes, index);
227
- const nbtNode = getNode(nodes, index + 2);
228
- if (core.ResourceLocationNode.is(typeNode) &&
229
- nbt.NbtCompoundNode.is(nbtNode)) {
230
- nbt.checker.index('entity_type', core.ResourceLocationNode.toString(typeNode, 'full'))(nbtNode, ctx);
275
+ const options = node.children?.find(nbt.NbtCompoundNode.is);
276
+ if (ParticleNode.requiresOptions(id)) {
277
+ if (options) {
278
+ nbt.checker.index('minecraft:particle', core.ResourceLocation.lengthen(id))(options, ctx);
279
+ }
280
+ else {
281
+ ctx.err.report(localize('expected', localize('nbt.node.compound')), core.Range.create(node.id.range.end, node.id.range.end + 1));
282
+ }
283
+ }
284
+ else if (options) {
285
+ ctx.err.report(localize('expected', localize('nothing')), options);
231
286
  }
232
287
  };
233
288
  // #endregion
234
- export const getTypesFromEntity = (entity, ctx) => {
235
- if (entity.playerName !== undefined || entity.selector?.playersOnly) {
289
+ function getTypesFromEntity(entity, ctx) {
290
+ if (core.ResourceLocationNode.is(entity)) {
291
+ const value = core.ResourceLocationNode.toString(entity, 'full', true);
292
+ if (value.startsWith(core.ResourceLocation.TagPrefix)) {
293
+ return getTagValues('tag/entity_type', value.slice(1), ctx);
294
+ }
295
+ else {
296
+ return [value];
297
+ }
298
+ }
299
+ else if (entity.playerName !== undefined || entity.selector?.playersOnly) {
236
300
  return ['minecraft:player'];
237
301
  }
238
302
  else if (entity.selector) {
@@ -240,7 +304,7 @@ export const getTypesFromEntity = (entity, ctx) => {
240
304
  if (!argumentsNode) {
241
305
  return undefined;
242
306
  }
243
- let types = [];
307
+ let types = undefined;
244
308
  for (const pairNode of argumentsNode.children) {
245
309
  if (pairNode.key?.value !== 'type') {
246
310
  continue;
@@ -252,7 +316,12 @@ export const getTypesFromEntity = (entity, ctx) => {
252
316
  const value = core.ResourceLocationNode.toString(valueNode.value, 'full', true);
253
317
  if (value.startsWith(core.ResourceLocation.TagPrefix)) {
254
318
  const tagValues = getTagValues('tag/entity_type', value.slice(1), ctx);
255
- types = types.filter((t) => tagValues.includes(t));
319
+ if (types === undefined) {
320
+ types = tagValues.map(core.ResourceLocation.lengthen);
321
+ }
322
+ else {
323
+ types = types.filter((t) => tagValues.includes(t));
324
+ }
256
325
  }
257
326
  else {
258
327
  types = [value];
@@ -261,12 +330,14 @@ export const getTypesFromEntity = (entity, ctx) => {
261
330
  return types;
262
331
  }
263
332
  return undefined;
264
- };
333
+ }
265
334
  export function register(meta) {
335
+ meta.registerChecker('mcfunction:entry', entry);
266
336
  meta.registerChecker('mcfunction:command', command);
267
337
  meta.registerChecker('mcfunction:block', block);
268
338
  meta.registerChecker('mcfunction:entity', entity);
269
- meta.registerChecker('mcfunction:item', item);
339
+ meta.registerChecker('mcfunction:item_stack', itemStack);
340
+ meta.registerChecker('mcfunction:item_predicate', itemPredicate);
270
341
  meta.registerChecker('mcfunction:particle', particle);
271
342
  }
272
343
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,11 @@
1
+ import * as core from '@spyglassmc/core';
1
2
  export declare const ColorArgumentValues: string[];
2
3
  export declare const EntityAnchorArgumentValues: string[];
3
4
  export declare const GamemodeArgumentValues: string[];
4
- export declare const ItemSlotArgumentValues: string[];
5
+ export declare function getItemSlotArgumentValues(ctx: core.ContextBase): string[];
6
+ export declare function getItemSlotsArgumentValues(ctx: core.ContextBase): string[];
5
7
  export declare const OperationArgumentValues: string[];
6
- export declare const ScoreboardSlotArgumentValues: string[];
8
+ export declare function getScoreboardSlotArgumentValues(ctx: core.ContextBase): string[];
7
9
  export declare const SwizzleArgumentValues: string[];
8
10
  export declare const HeightmapValues: string[];
9
11
  export declare const RotationValues: string[];
@@ -1,47 +1,60 @@
1
1
  import * as core from '@spyglassmc/core';
2
+ import { ReleaseVersion } from '../../dependency/index.js';
2
3
  export const ColorArgumentValues = [...core.Color.ColorNames, 'reset'];
3
4
  export const EntityAnchorArgumentValues = ['feet', 'eyes'];
4
- export const GamemodeArgumentValues = [
5
- 'adventure',
6
- 'survival',
7
- 'creative',
8
- 'spectator',
9
- ];
10
- export const ItemSlotArgumentValues = [
11
- ...[...Array(54).keys()].map((n) => `container.${n}`),
12
- ...[...Array(27).keys()].map((n) => `enderchest.${n}`),
13
- ...[...Array(15).keys()].map((n) => `horse.${n}`),
14
- ...[...Array(9).keys()].map((n) => `hotbar.${n}`),
15
- ...[...Array(27).keys()].map((n) => `inventory.${n}`),
16
- ...[...Array(8).keys()].map((n) => `villager.${n}`),
17
- 'armor.chest',
18
- 'armor.feet',
19
- 'armor.head',
20
- 'armor.legs',
21
- 'horse.armor',
22
- 'horse.chest',
23
- 'horse.saddle',
24
- 'weapon',
25
- 'weapon.mainhand',
26
- 'weapon.offhand',
27
- ];
28
- export const OperationArgumentValues = [
29
- '=',
30
- '+=',
31
- '-=',
32
- '*=',
33
- '/=',
34
- '%=',
35
- '<',
36
- '>',
37
- '><',
38
- ];
39
- export const ScoreboardSlotArgumentValues = [
40
- 'belowName',
41
- 'list',
42
- 'sidebar',
43
- ...core.Color.ColorNames.map((n) => `sidebar.team.${n}`),
44
- ];
5
+ export const GamemodeArgumentValues = ['adventure', 'survival', 'creative', 'spectator'];
6
+ export function getItemSlotArgumentValues(ctx) {
7
+ const release = ctx.project['loadedVersion'];
8
+ const output = [
9
+ ...[...Array(54).keys()].map((n) => `container.${n}`),
10
+ ...[...Array(27).keys()].map((n) => `enderchest.${n}`),
11
+ ...[...Array(15).keys()].map((n) => `horse.${n}`),
12
+ ...[...Array(9).keys()].map((n) => `hotbar.${n}`),
13
+ ...[...Array(27).keys()].map((n) => `inventory.${n}`),
14
+ ...[...Array(8).keys()].map((n) => `villager.${n}`),
15
+ 'armor.chest',
16
+ 'armor.feet',
17
+ 'armor.head',
18
+ 'armor.legs',
19
+ 'horse.chest',
20
+ 'horse.saddle',
21
+ 'weapon',
22
+ 'weapon.mainhand',
23
+ 'weapon.offhand',
24
+ ];
25
+ if (ReleaseVersion.cmp(release, '1.20.5') >= 0) {
26
+ output.push(...[...Array(4).keys()].map((n) => `player.crafting.${n}`), 'armor.body', 'contents', 'player.cursor');
27
+ }
28
+ else {
29
+ output.push('horse.armor');
30
+ }
31
+ return output;
32
+ }
33
+ // Only exists since 1.20.5
34
+ export function getItemSlotsArgumentValues(ctx) {
35
+ return [
36
+ ...getItemSlotArgumentValues(ctx),
37
+ 'armor.*',
38
+ 'container.*',
39
+ 'enderchest.*',
40
+ 'horse.*',
41
+ 'hotbar.*',
42
+ 'inventory.*',
43
+ 'player.crafting.*',
44
+ 'villager.*',
45
+ 'weapon.*',
46
+ ];
47
+ }
48
+ export const OperationArgumentValues = ['=', '+=', '-=', '*=', '/=', '%=', '<', '>', '><'];
49
+ export function getScoreboardSlotArgumentValues(ctx) {
50
+ const release = ctx.project['loadedVersion'];
51
+ return [
52
+ ReleaseVersion.cmp(release, '1.20.2') < 0 ? 'belowName' : 'below_name',
53
+ 'list',
54
+ 'sidebar',
55
+ ...core.Color.ColorNames.map((n) => `sidebar.team.${n}`),
56
+ ];
57
+ }
45
58
  export const SwizzleArgumentValues = [
46
59
  'x',
47
60
  'xy',
@@ -67,15 +80,6 @@ export const HeightmapValues = [
67
80
  'world_surface',
68
81
  'world_surface_wg',
69
82
  ];
70
- export const RotationValues = [
71
- 'none',
72
- 'clockwise_90',
73
- '180',
74
- 'counterclockwise_90',
75
- ];
76
- export const MirrorValues = [
77
- 'none',
78
- 'left_right',
79
- 'front_back',
80
- ];
83
+ export const RotationValues = ['none', 'clockwise_90', '180', 'counterclockwise_90'];
84
+ export const MirrorValues = ['none', 'left_right', 'front_back'];
81
85
  //# sourceMappingURL=index.js.map