@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
@@ -2,7 +2,7 @@ import * as core from '@spyglassmc/core';
2
2
  /**
3
3
  * @param inputVersion {@link core.Config.env.gameVersion}
4
4
  */
5
- export function resolveConfiguredVersion(inputVersion, { packMcmeta, versions, }) {
5
+ export async function resolveConfiguredVersion(inputVersion, versions, getPackMcmeta) {
6
6
  function findReleaseTarget(version) {
7
7
  if (version.release_target) {
8
8
  return version.release_target;
@@ -35,6 +35,7 @@ export function resolveConfiguredVersion(inputVersion, { packMcmeta, versions, }
35
35
  versions = versions.sort((a, b) => b.data_version - a.data_version);
36
36
  const latestRelease = versions.find((v) => v.type === 'release');
37
37
  if (inputVersion === 'auto') {
38
+ const packMcmeta = await getPackMcmeta();
38
39
  if (packMcmeta && latestRelease) {
39
40
  // If the pack format is larger than the latest release, use the latest snapshot
40
41
  if (packMcmeta.pack.pack_format > latestRelease.data_pack_version) {
@@ -66,8 +67,7 @@ export function resolveConfiguredVersion(inputVersion, { packMcmeta, versions, }
66
67
  else if (inputVersion === 'latest snapshot') {
67
68
  return toVersionInfo(versions[0]);
68
69
  }
69
- return toVersionInfo(versions.find((v) => inputVersion === v.id.toLowerCase() ||
70
- inputVersion === v.name.toLowerCase()));
70
+ return toVersionInfo(versions.find((v) => inputVersion === v.id.toLowerCase() || inputVersion === v.name.toLowerCase()));
71
71
  }
72
72
  const DataSources = {
73
73
  fastly: 'https://fastly.jsdelivr.net/gh/${user}/${repo}@${tag}/${path}',
@@ -78,11 +78,7 @@ export function getMcmetaSummaryUris(version, isLatest, source) {
78
78
  const tag = isLatest ? 'summary' : `${version}-summary`;
79
79
  function getUri(path) {
80
80
  const template = DataSources[source.toLowerCase()] ?? source;
81
- const ans = template
82
- .replace(/\${user}/g, 'misode')
83
- .replace(/\${repo}/g, 'mcmeta')
84
- .replace(/\${tag}/g, tag)
85
- .replace(/\${path}/g, path);
81
+ const ans = template.replace(/\${user}/g, 'misode').replace(/\${repo}/g, 'mcmeta').replace(/\${tag}/g, tag).replace(/\${path}/g, path);
86
82
  if (!core.RemoteUriString.is(ans)) {
87
83
  throw new Error(`Expected a remote URI from data source template but got ${ans}`);
88
84
  }
@@ -103,17 +99,13 @@ export function symbolRegistrar(summary) {
103
99
  const capitalizedCategory = `${category[0].toUpperCase()}${category.slice(1)}`;
104
100
  for (const [id, [properties, defaults]] of Object.entries(states)) {
105
101
  const uri = McmetaSummaryUri;
106
- symbols
107
- .query(uri, category, core.ResourceLocation.lengthen(id))
108
- .onEach(Object.entries(properties), ([state, values], blockQuery) => {
102
+ symbols.query(uri, category, core.ResourceLocation.lengthen(id)).onEach(Object.entries(properties), ([state, values], blockQuery) => {
109
103
  const defaultValue = defaults[state];
110
104
  blockQuery.member(`${uri}#${capitalizedCategory}_states`, state, (stateQuery) => {
111
- stateQuery
112
- .enter({
105
+ stateQuery.enter({
113
106
  data: { subcategory: 'state' },
114
107
  usage: { type: 'declaration' },
115
- })
116
- .onEach(values, (value) => {
108
+ }).onEach(values, (value) => {
117
109
  stateQuery.member(value, (valueQuery) => {
118
110
  valueQuery.enter({
119
111
  data: { subcategory: 'state_value' },
@@ -121,14 +113,7 @@ export function symbolRegistrar(summary) {
121
113
  });
122
114
  if (value === defaultValue) {
123
115
  stateQuery.amend({
124
- data: {
125
- relations: {
126
- default: {
127
- category,
128
- path: valueQuery.path,
129
- },
130
- },
131
- },
116
+ data: { relations: { default: { category, path: valueQuery.path } } },
132
117
  });
133
118
  }
134
119
  });
@@ -139,38 +124,36 @@ export function symbolRegistrar(summary) {
139
124
  }
140
125
  function addRegistriesSymbols(registries, symbols) {
141
126
  function isCategory(str) {
142
- return (core.FileCategories.includes(str) ||
143
- core.RegistryCategories.includes(str));
127
+ return (core.FileCategories.includes(str)
128
+ || core.RegistryCategories.includes(str));
144
129
  }
145
130
  for (const [registryId, registry] of Object.entries(registries)) {
146
131
  if (isCategory(registryId)) {
147
132
  for (const entryId of registry) {
148
- symbols
149
- .query(McmetaSummaryUri, registryId, core.ResourceLocation.lengthen(entryId))
133
+ symbols.query(McmetaSummaryUri, registryId, core.ResourceLocation.lengthen(entryId))
150
134
  .enter({ usage: { type: 'declaration' } });
151
135
  }
152
136
  }
153
137
  }
154
138
  }
139
+ function addBuiltinSymbols(symbols) {
140
+ symbols.query(McmetaSummaryUri, 'loot_table', 'minecraft:empty')
141
+ .enter({ usage: { type: 'declaration' } });
142
+ }
155
143
  return (symbols) => {
156
144
  addRegistriesSymbols(summary.registries, symbols);
157
145
  addStatesSymbols('block', summary.blocks, symbols);
158
146
  addStatesSymbols('fluid', summary.fluids, symbols);
147
+ addBuiltinSymbols(symbols);
159
148
  };
160
149
  }
161
150
  export const Fluids = {
162
- flowing_lava: [
163
- {
164
- falling: ['false', 'true'],
165
- level: ['1', '2', '3', '4', '5', '6', '7', '8'],
166
- },
167
- { falling: 'false', level: '1' },
168
- ],
151
+ flowing_lava: [{ falling: ['false', 'true'], level: ['1', '2', '3', '4', '5', '6', '7', '8'] }, {
152
+ falling: 'false',
153
+ level: '1',
154
+ }],
169
155
  flowing_water: [
170
- {
171
- falling: ['false', 'true'],
172
- level: ['1', '2', '3', '4', '5', '6', '7', '8'],
173
- },
156
+ { falling: ['false', 'true'], level: ['1', '2', '3', '4', '5', '6', '7', '8'] },
174
157
  { falling: 'false', level: '1' },
175
158
  ],
176
159
  lava: [{ falling: ['false', 'true'] }, { falling: 'false' }],
package/lib/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as core from '@spyglassmc/core';
2
+ export * as binder from './binder/index.js';
2
3
  export * as dependency from './dependency/index.js';
3
4
  export * as json from './json/index.js';
4
5
  export * as mcf from './mcfunction/index.js';
package/lib/index.js CHANGED
@@ -1,23 +1,22 @@
1
1
  import * as core from '@spyglassmc/core';
2
+ import * as json from '@spyglassmc/json';
2
3
  import * as mcdoc from '@spyglassmc/mcdoc';
3
4
  import * as nbt from '@spyglassmc/nbt';
4
5
  import { uriBinder } from './binder/index.js';
5
- import { getVanillaDatapack } from './dependency/index.js';
6
- import { getMcmetaSummary, getVanillaMcdoc, getVersions, PackMcmeta, resolveConfiguredVersion, symbolRegistrar, } from './dependency/index.js';
6
+ import { getMcmetaSummary, getVanillaDatapack, getVanillaMcdoc, getVersions, PackMcmeta, ReleaseVersion, resolveConfiguredVersion, symbolRegistrar, } from './dependency/index.js';
7
7
  import * as jeJson from './json/index.js';
8
8
  import * as jeMcf from './mcfunction/index.js';
9
+ export * as binder from './binder/index.js';
9
10
  export * as dependency from './dependency/index.js';
10
11
  export * as json from './json/index.js';
11
12
  export * as mcf from './mcfunction/index.js';
12
13
  export const initialize = async (ctx) => {
13
14
  const { config, downloader, externals, logger, meta, projectRoot } = ctx;
14
- async function getPackMcmeta() {
15
- let ans;
16
- const uri = `${projectRoot}pack.mcmeta`;
15
+ async function readPackMcmeta(uri) {
17
16
  try {
18
17
  const data = await core.fileUtil.readJson(externals, uri);
19
18
  PackMcmeta.assert(data);
20
- ans = data;
19
+ return data;
21
20
  }
22
21
  catch (e) {
23
22
  if (!externals.error.isKind(e, 'ENOENT')) {
@@ -25,7 +24,26 @@ export const initialize = async (ctx) => {
25
24
  logger.error(`[je.initialize] Failed loading pack.mcmeta “${uri}”`, e);
26
25
  }
27
26
  }
28
- return ans;
27
+ return undefined;
28
+ }
29
+ async function findPackMcmeta() {
30
+ const searched = new Set();
31
+ for (let depth = 0; depth <= 2; depth += 1) {
32
+ const files = await externals.fs.getAllFiles(projectRoot, depth + 1);
33
+ for (const uri of files.filter(uri => uri.endsWith('/pack.mcmeta'))) {
34
+ if (searched.has(uri)) {
35
+ continue;
36
+ }
37
+ searched.add(uri);
38
+ const data = await readPackMcmeta(uri);
39
+ if (data) {
40
+ logger.info(`[je.initialize] Found a valid pack.mcmeta “${uri}” with pack_format “${data.pack.pack_format}”`);
41
+ return data;
42
+ }
43
+ }
44
+ }
45
+ logger.warn('[je.initialize] Failed finding a valid pack.mcmeta');
46
+ return undefined;
29
47
  }
30
48
  meta.registerUriBinder(uriBinder);
31
49
  const versions = await getVersions(ctx.externals, ctx.downloader);
@@ -33,18 +51,12 @@ export const initialize = async (ctx) => {
33
51
  ctx.logger.error('[je-initialize] Failed loading game version list. Expect everything to be broken.');
34
52
  return;
35
53
  }
36
- const packMcmeta = await getPackMcmeta();
37
- const { release, id: version, isLatest, } = resolveConfiguredVersion(config.env.gameVersion, {
38
- packMcmeta,
39
- versions,
40
- });
41
- meta.registerDependencyProvider('@vanilla-datapack', () => getVanillaDatapack(downloader, version, isLatest));
54
+ const version = await resolveConfiguredVersion(config.env.gameVersion, versions, findPackMcmeta);
55
+ const release = version.release;
56
+ meta.registerDependencyProvider('@vanilla-datapack', () => getVanillaDatapack(downloader, version.id, version.isLatest));
42
57
  meta.registerDependencyProvider('@vanilla-mcdoc', () => getVanillaMcdoc(downloader));
43
- const summary = await getMcmetaSummary(ctx.externals, downloader, logger, version, isLatest, config.env.dataSource, config.env.mcmetaSummaryOverrides);
44
- if (!summary.blocks ||
45
- !summary.commands ||
46
- !summary.fluids ||
47
- !summary.registries) {
58
+ const summary = await getMcmetaSummary(ctx.externals, downloader, logger, version.id, version.isLatest, config.env.dataSource, config.env.mcmetaSummaryOverrides);
59
+ if (!summary.blocks || !summary.commands || !summary.fluids || !summary.registries) {
48
60
  ctx.logger.error('[je-initialize] Failed loading mcmeta summaries. Expect everything to be broken.');
49
61
  return;
50
62
  }
@@ -57,23 +69,53 @@ export const initialize = async (ctx) => {
57
69
  linter: core.linter.nameConvention('value'),
58
70
  nodePredicate: (n) =>
59
71
  // nbt compound keys without mcdoc definition.
60
- (!n.symbol &&
61
- n.parent?.parent?.type === 'nbt:compound' &&
62
- core.PairNode.is(n.parent) &&
63
- n.type === 'string' &&
64
- n.parent.key === n) ||
65
- // nbt path keys without mcdoc definition.
66
- (!n.symbol && n.parent?.type === 'nbt:path' && n.type === 'string') ||
67
- // mcdoc compound key definition outside of `::minecraft` modules.
68
- (mcdoc.StructFieldNode.is(n.parent) &&
69
- mcdoc.StructKeyNode.is(n) &&
70
- !n.symbol?.path[0]?.startsWith('::minecraft')),
72
+ (!n.symbol
73
+ && n.parent?.parent?.type === 'nbt:compound'
74
+ && core.PairNode.is(n.parent)
75
+ && n.type === 'string'
76
+ && n.parent.key === n) // nbt path keys without mcdoc definition.
77
+ || (!n.symbol && n.parent?.type === 'nbt:path' && n.type === 'string') // mcdoc compound key definition outside of `::minecraft` modules.
78
+ || (mcdoc.StructFieldNode.is(n.parent)
79
+ && mcdoc.StructKeyNode.is(n)
80
+ && !n.symbol?.path[0]?.startsWith('::minecraft')),
81
+ });
82
+ mcdoc.runtime.registerAttribute(meta, 'since', mcdoc.runtime.attribute.validator.string, {
83
+ filterElement: (config, ctx) => {
84
+ if (!config.startsWith('1.')) {
85
+ ctx.logger.warn(`Invalid mcdoc attribute for "since": ${config}`);
86
+ return true;
87
+ }
88
+ return ReleaseVersion.cmp(release, config) >= 0;
89
+ },
90
+ });
91
+ mcdoc.runtime.registerAttribute(meta, 'until', mcdoc.runtime.attribute.validator.string, {
92
+ filterElement: (config, ctx) => {
93
+ if (!config.startsWith('1.')) {
94
+ ctx.logger.warn(`Invalid mcdoc attribute for "until": ${config}`);
95
+ return true;
96
+ }
97
+ return ReleaseVersion.cmp(release, config) < 0;
98
+ },
99
+ });
100
+ mcdoc.runtime.registerAttribute(meta, 'deprecated', mcdoc.runtime.attribute.validator.optional(mcdoc.runtime.attribute.validator.string), {
101
+ mapField: (config, field, ctx) => {
102
+ if (config === undefined) {
103
+ return { ...field, deprecated: true };
104
+ }
105
+ if (!config.startsWith('1.')) {
106
+ ctx.logger.warn(`Invalid mcdoc attribute for "deprecated": ${config}`);
107
+ return field;
108
+ }
109
+ if (ReleaseVersion.cmp(release, config) >= 0) {
110
+ return { ...field, deprecated: true };
111
+ }
112
+ return field;
113
+ },
71
114
  });
115
+ json.initialize(ctx);
72
116
  jeJson.initialize(ctx);
73
117
  jeMcf.initialize(ctx, summary.commands, release);
74
118
  nbt.initialize(ctx);
75
- return {
76
- loadedVersion: release,
77
- };
119
+ return { loadedVersion: release };
78
120
  };
79
121
  //# sourceMappingURL=index.js.map
@@ -1,12 +1,5 @@
1
- import * as core from '@spyglassmc/core';
2
- import type { JsonNode } from '@spyglassmc/json';
3
- import * as mcdoc from '@spyglassmc/mcdoc';
4
- export declare const entry: core.Checker<JsonNode>;
1
+ import type * as core from '@spyglassmc/core';
2
+ import * as json from '@spyglassmc/json';
3
+ export declare const file: core.Checker<json.JsonFileNode>;
5
4
  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>;
12
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,251 +1,43 @@
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';
5
- import { dissectUri } from '../../binder/index.js';
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
- ]);
49
- export const entry = (node, ctx) => {
50
- const parts = dissectUri(ctx.doc.uri, ctx);
51
- if (parts && Checkers.has(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
1
+ import * as json from '@spyglassmc/json';
2
+ import { dissectUri, reportDissectError } from '../../binder/index.js';
3
+ function createTagDefinition(registry) {
4
+ const id = {
5
+ kind: 'tree',
6
+ values: {
7
+ registry: { kind: 'literal', value: { kind: 'string', value: registry } },
8
+ tags: { kind: 'literal', value: { kind: 'string', value: 'allowed' } },
9
+ },
10
+ };
11
+ return {
12
+ kind: 'concrete',
13
+ child: { kind: 'reference', path: '::java::data::tag::Tag' },
14
+ typeArgs: [{ kind: 'string', attributes: [{ name: 'id', value: id }] }],
15
+ };
16
+ }
17
+ export const file = (node, ctx) => {
18
+ const child = node.children[0];
19
+ if (ctx.doc.uri.endsWith('/pack.mcmeta')) {
20
+ const type = { kind: 'reference', path: '::java::pack::Pack' };
21
+ return json.checker.index(type)(child, ctx);
57
22
  }
58
- else if (ctx.doc.uri.endsWith('/pack.mcmeta')) {
59
- return definition('::java::Pack')(node, ctx);
23
+ const parts = dissectUri(ctx.doc.uri, ctx);
24
+ if (parts?.ok) {
25
+ if (parts?.category.startsWith('tag/')) {
26
+ const type = createTagDefinition(parts.category.slice(4));
27
+ return json.checker.index(type)(child, ctx);
28
+ }
29
+ const type = {
30
+ kind: 'dispatcher',
31
+ registry: 'minecraft:resource',
32
+ parallelIndices: [{ kind: 'static', value: parts.category }],
33
+ };
34
+ return json.checker.index(type, { discardDuplicateKeyErrors: true })(child, ctx);
60
35
  }
61
- else {
62
- return;
36
+ else if (parts?.ok === false) {
37
+ reportDissectError(parts.path, parts.expected, ctx);
63
38
  }
64
39
  };
65
40
  export function register(meta) {
66
- meta.registerChecker('json:array', entry);
67
- meta.registerChecker('json:boolean', entry);
68
- meta.registerChecker('json:null', entry);
69
- meta.registerChecker('json:number', entry);
70
- meta.registerChecker('json:object', entry);
71
- meta.registerChecker('json:string', entry);
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;
41
+ meta.registerChecker('json:file', file);
250
42
  }
251
43
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,3 @@
1
1
  import type * as core from '@spyglassmc/core';
2
- export * as checker from './checker/index.js';
3
2
  export declare const initialize: (ctx: core.ProjectInitializerContext) => void;
4
3
  //# sourceMappingURL=index.d.ts.map
package/lib/json/index.js CHANGED
@@ -1,9 +1,6 @@
1
1
  /* istanbul ignore file */
2
- import * as json from '@spyglassmc/json';
3
2
  import * as checker from './checker/index.js';
4
- export * as checker from './checker/index.js';
5
3
  export const initialize = (ctx) => {
6
- json.initialize(ctx);
7
4
  checker.register(ctx.meta);
8
5
  };
9
6
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,5 @@
1
1
  import * as core from '@spyglassmc/core';
2
2
  import * as mcf from '@spyglassmc/mcfunction';
3
- import { EntityNode } from '../node/index.js';
4
3
  export declare const command: core.Checker<mcf.CommandNode>;
5
- export declare const getTypesFromEntity: (entity: EntityNode, ctx: core.CheckerContext) => core.FullResourceLocation[] | undefined;
6
4
  export declare function register(meta: core.MetaRegistry): void;
7
5
  //# sourceMappingURL=index.d.ts.map