@spyglassmc/java-edition 0.3.8 → 0.3.10
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 +11 -9
- package/lib/binder/index.js +149 -150
- package/lib/common/index.js +6 -9
- package/lib/dependency/common.d.ts +5 -0
- package/lib/dependency/common.js +8 -0
- package/lib/dependency/index.js +7 -17
- package/lib/dependency/mcmeta.d.ts +6 -12
- package/lib/dependency/mcmeta.js +21 -38
- package/lib/index.d.ts +1 -0
- package/lib/index.js +74 -32
- package/lib/json/checker/index.d.ts +3 -10
- package/lib/json/checker/index.js +36 -244
- package/lib/json/index.d.ts +0 -1
- package/lib/json/index.js +0 -3
- package/lib/mcfunction/checker/index.d.ts +0 -2
- package/lib/mcfunction/checker/index.js +254 -183
- package/lib/mcfunction/common/index.d.ts +4 -2
- package/lib/mcfunction/common/index.js +56 -52
- package/lib/mcfunction/completer/argument.js +112 -57
- package/lib/mcfunction/index.d.ts +3 -2
- package/lib/mcfunction/index.js +18 -19
- package/lib/mcfunction/inlayHintProvider.js +2 -3
- package/lib/mcfunction/mcdocAttributes.d.ts +4 -0
- package/lib/mcfunction/mcdocAttributes.js +74 -0
- package/lib/mcfunction/node/argument.d.ts +115 -12
- package/lib/mcfunction/node/argument.js +131 -63
- package/lib/mcfunction/parser/argument.d.ts +14 -4
- package/lib/mcfunction/parser/argument.js +380 -212
- package/lib/mcfunction/signatureHelpProvider.d.ts +2 -1
- package/lib/mcfunction/signatureHelpProvider.js +10 -18
- package/lib/mcfunction/tree/argument.d.ts +68 -1
- package/lib/mcfunction/tree/patch.js +279 -77
- package/lib/mcfunction/tree/patchValidator.d.ts +7 -0
- package/lib/mcfunction/tree/patchValidator.js +25 -0
- package/package.json +8 -9
package/lib/dependency/mcmeta.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
165
|
-
|
|
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
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
|
|
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
|
-
|
|
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
|
|
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
|
|
37
|
-
const
|
|
38
|
-
|
|
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
|
-
|
|
66
|
-
(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
3
|
-
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
'
|
|
21
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
package/lib/json/index.d.ts
CHANGED
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
|