@spyglassmc/json 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/checker/primitives/list.js +10 -6
- package/lib/checker/primitives/number.js +9 -3
- package/lib/checker/primitives/object.js +50 -28
- package/lib/checker/primitives/string.js +7 -3
- package/lib/checker/primitives/util.js +12 -8
- package/lib/colorizer/index.js +2 -2
- package/lib/completer/index.js +31 -24
- package/lib/formatter/index.js +6 -4
- package/lib/node/JsonAstNode.js +1 -3
- package/lib/parser/entry.js +21 -6
- package/lib/parser/object.js +7 -1
- package/package.json +3 -3
|
@@ -5,26 +5,30 @@ export function listOf(checker) {
|
|
|
5
5
|
return (node, ctx) => {
|
|
6
6
|
node.expectation = [{ type: 'json:array', typedoc: 'Array' }];
|
|
7
7
|
if (!ctx.depth || ctx.depth <= 0) {
|
|
8
|
+
;
|
|
8
9
|
node.expectation[0].items = expectation(checker, ctx);
|
|
9
10
|
}
|
|
10
11
|
if (!JsonArrayNode.is(node)) {
|
|
11
12
|
ctx.err.report(localize('expected', localize('array')), node);
|
|
12
13
|
}
|
|
13
14
|
else {
|
|
14
|
-
node.children
|
|
15
|
-
.
|
|
15
|
+
node.children
|
|
16
|
+
.filter((e) => e.value)
|
|
17
|
+
.forEach((e) => checker(e.value, ctx));
|
|
16
18
|
}
|
|
17
19
|
};
|
|
18
20
|
}
|
|
19
21
|
export function uniqueListOf(checker, options = {}) {
|
|
20
|
-
const getItem =
|
|
21
|
-
|
|
22
|
+
const getItem = options.items ??
|
|
23
|
+
((node) => [JsonStringNode.is(node) ? node.value : undefined, node]);
|
|
24
|
+
const reporter = options.report ??
|
|
25
|
+
((node, ctx) => ctx.err.report(localize('json.checker.item.duplicate'), node, 2 /* ErrorSeverity.Warning */));
|
|
22
26
|
return (node, ctx) => {
|
|
23
27
|
listOf(checker)(node, ctx);
|
|
24
28
|
if (JsonArrayNode.is(node)) {
|
|
25
29
|
const items = new Map();
|
|
26
30
|
const duplicates = new Set();
|
|
27
|
-
node.children.forEach(c => {
|
|
31
|
+
node.children.forEach((c) => {
|
|
28
32
|
if (!c.value)
|
|
29
33
|
return;
|
|
30
34
|
const [value, item] = getItem(c.value);
|
|
@@ -37,7 +41,7 @@ export function uniqueListOf(checker, options = {}) {
|
|
|
37
41
|
}
|
|
38
42
|
items.set(value, item);
|
|
39
43
|
});
|
|
40
|
-
duplicates.forEach(node => reporter(node, ctx));
|
|
44
|
+
duplicates.forEach((node) => reporter(node, ctx));
|
|
41
45
|
}
|
|
42
46
|
};
|
|
43
47
|
}
|
|
@@ -2,12 +2,18 @@ import { localize } from '@spyglassmc/locales';
|
|
|
2
2
|
import { JsonNumberNode } from '../../node/index.js';
|
|
3
3
|
const number = (type) => (min, max) => {
|
|
4
4
|
return (node, ctx) => {
|
|
5
|
-
const typedoc = 'Number' +
|
|
5
|
+
const typedoc = 'Number' +
|
|
6
|
+
(min === undefined && max === undefined
|
|
7
|
+
? ''
|
|
8
|
+
: `(${min ?? '-∞'}, ${max ?? '+∞'})`);
|
|
6
9
|
node.expectation = [{ type: 'json:number', typedoc }];
|
|
7
|
-
if (!JsonNumberNode.is(node) ||
|
|
10
|
+
if (!JsonNumberNode.is(node) ||
|
|
11
|
+
(type === 'integer' && !Number.isInteger(node.value))) {
|
|
8
12
|
ctx.err.report(localize('expected', localize(type)), node);
|
|
9
13
|
}
|
|
10
|
-
else if (min !== undefined &&
|
|
14
|
+
else if (min !== undefined &&
|
|
15
|
+
max !== undefined &&
|
|
16
|
+
(node.value < min || node.value > max)) {
|
|
11
17
|
ctx.err.report(localize('expected', localize('number.between', min, max)), node);
|
|
12
18
|
}
|
|
13
19
|
else if (min !== undefined && node.value < min) {
|
|
@@ -10,36 +10,44 @@ export function object(keys, values, options = {}) {
|
|
|
10
10
|
node.expectation = [{ type: 'json:object', typedoc: 'Object' }];
|
|
11
11
|
if (!ctx.depth || ctx.depth <= 0) {
|
|
12
12
|
if (Array.isArray(keys) && values) {
|
|
13
|
-
const fields = keys
|
|
13
|
+
const fields = keys
|
|
14
|
+
.map((key) => [key, values(key, ctx)])
|
|
15
|
+
.filter(([_, v]) => v !== undefined);
|
|
14
16
|
node.expectation[0].fields = fields.map(([key, prop]) => {
|
|
15
17
|
return {
|
|
16
18
|
key,
|
|
17
19
|
value: expectation(isComplex(prop) ? prop.checker : prop, ctx),
|
|
18
|
-
...isComplex(prop) && (prop.opt || prop.deprecated)
|
|
19
|
-
|
|
20
|
+
...(isComplex(prop) && (prop.opt || prop.deprecated)
|
|
21
|
+
? { opt: true }
|
|
22
|
+
: {}),
|
|
23
|
+
...(isComplex(prop) && prop.deprecated
|
|
24
|
+
? { deprecated: true }
|
|
25
|
+
: {}),
|
|
20
26
|
};
|
|
21
27
|
});
|
|
22
28
|
}
|
|
23
29
|
else if (typeof keys === 'function' && values) {
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
;
|
|
31
|
+
node.expectation[0].keys = expectation(keys, ctx)?.filter(JsonStringExpectation.is);
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
34
|
if (!JsonObjectNode.is(node)) {
|
|
29
35
|
ctx.err.report(localize('expected', localize('object')), node);
|
|
30
36
|
}
|
|
31
37
|
else if (Array.isArray(keys) && values) {
|
|
32
|
-
const givenKeys = node.children.map(n => n.key?.value);
|
|
33
|
-
keys.forEach(k => {
|
|
38
|
+
const givenKeys = node.children.map((n) => n.key?.value);
|
|
39
|
+
keys.forEach((k) => {
|
|
34
40
|
const value = values(k, ctx);
|
|
35
|
-
if (!value || isComplex(value) && (value.opt || value.deprecated)) {
|
|
41
|
+
if (!value || (isComplex(value) && (value.opt || value.deprecated))) {
|
|
36
42
|
return;
|
|
37
43
|
}
|
|
38
44
|
if (!givenKeys.includes(k)) {
|
|
39
45
|
ctx.err.report(localize('json.checker.property.missing', localeQuote(k)), Range.create(node.range.start, node.range.start + 1));
|
|
40
46
|
}
|
|
41
47
|
});
|
|
42
|
-
node.children
|
|
48
|
+
node.children
|
|
49
|
+
.filter((p) => p.key)
|
|
50
|
+
.forEach((prop) => {
|
|
43
51
|
const key = prop.key.value;
|
|
44
52
|
const value = values(key, ctx);
|
|
45
53
|
if (!value || !keys.includes(key)) {
|
|
@@ -51,9 +59,12 @@ export function object(keys, values, options = {}) {
|
|
|
51
59
|
if (isComplex(value) && value.deprecated) {
|
|
52
60
|
ctx.err.report(localize('json.checker.property.deprecated', localeQuote(key)), prop.key, 0 /* ErrorSeverity.Hint */, { deprecated: true });
|
|
53
61
|
}
|
|
54
|
-
const context = ctx.context +
|
|
62
|
+
const context = ctx.context +
|
|
63
|
+
(isComplex(value) && value.context ? `.${value.context}` : '');
|
|
55
64
|
const doc = localize(`json.doc.${context}`);
|
|
56
|
-
const propNode = prop.value !== undefined
|
|
65
|
+
const propNode = prop.value !== undefined
|
|
66
|
+
? prop.value
|
|
67
|
+
: { type: 'json:null', range: Range.create(0) };
|
|
57
68
|
const checker = isComplex(value) ? value.checker : value;
|
|
58
69
|
try {
|
|
59
70
|
checker(propNode, { ...ctx, context: `${context}.${key}` });
|
|
@@ -63,12 +74,18 @@ export function object(keys, values, options = {}) {
|
|
|
63
74
|
ctx.logger.error(`Checking "${key}" at ${pos.line}:${pos.character} in "${ctx.doc.uri}"`, e);
|
|
64
75
|
}
|
|
65
76
|
const defaultValue = isComplex(value) ? value.def : undefined;
|
|
66
|
-
const typedoc = propNode.expectation
|
|
67
|
-
|
|
77
|
+
const typedoc = propNode.expectation
|
|
78
|
+
?.map((e) => e.typedoc)
|
|
79
|
+
.join(' | ');
|
|
80
|
+
prop.key.hover = `\`\`\`typescript\n${context}.${key}: ${typedoc}\n\`\`\`${doc || defaultValue !== undefined ? '\n******\n ' : ''}${doc}${defaultValue !== undefined
|
|
81
|
+
? `\n\`@default\` ${JSON.stringify(defaultValue)}`
|
|
82
|
+
: ''}`;
|
|
68
83
|
});
|
|
69
84
|
}
|
|
70
85
|
else if (typeof keys === 'function' && values) {
|
|
71
|
-
node.children
|
|
86
|
+
node.children
|
|
87
|
+
.filter((p) => p.key)
|
|
88
|
+
.forEach((prop) => {
|
|
72
89
|
keys(prop.key, ctx);
|
|
73
90
|
if (prop.value !== undefined) {
|
|
74
91
|
const value = values(prop.key.value, ctx);
|
|
@@ -104,12 +121,15 @@ export function dispatch(arg1, arg2) {
|
|
|
104
121
|
ctx.err.report(localize('expected', localize('object')), node);
|
|
105
122
|
}
|
|
106
123
|
else if (arg2) {
|
|
107
|
-
const dispatcherIndex = node.children.findIndex(p => p.key?.value === arg1);
|
|
124
|
+
const dispatcherIndex = node.children.findIndex((p) => p.key?.value === arg1);
|
|
108
125
|
const dispatcher = node.children[dispatcherIndex];
|
|
109
|
-
const value = dispatcher?.value?.type === 'json:string'
|
|
126
|
+
const value = dispatcher?.value?.type === 'json:string'
|
|
127
|
+
? dispatcher.value.value
|
|
128
|
+
: undefined;
|
|
110
129
|
arg2(value, node.children, ctx)(node, ctx);
|
|
111
130
|
}
|
|
112
131
|
else {
|
|
132
|
+
;
|
|
113
133
|
arg1(node.children, ctx)(node, ctx);
|
|
114
134
|
}
|
|
115
135
|
};
|
|
@@ -122,7 +142,7 @@ export function pick(value, cases) {
|
|
|
122
142
|
if (properties === undefined) {
|
|
123
143
|
return {};
|
|
124
144
|
}
|
|
125
|
-
Object.keys(properties).forEach(key => {
|
|
145
|
+
Object.keys(properties).forEach((key) => {
|
|
126
146
|
const p = properties[key];
|
|
127
147
|
if (p === undefined)
|
|
128
148
|
return;
|
|
@@ -145,30 +165,32 @@ export function when(value, values, properties, notProperties = {}) {
|
|
|
145
165
|
return properties;
|
|
146
166
|
}
|
|
147
167
|
export function extract(value, children) {
|
|
148
|
-
const node = children?.find(p => p.key?.value === value);
|
|
168
|
+
const node = children?.find((p) => p.key?.value === value);
|
|
149
169
|
return node?.value?.type === 'json:string' ? node.value.value : undefined;
|
|
150
170
|
}
|
|
151
171
|
export function extractNested(wrap, value, children) {
|
|
152
|
-
const wrapper = children?.find(p => p.key?.value === wrap);
|
|
172
|
+
const wrapper = children?.find((p) => p.key?.value === wrap);
|
|
153
173
|
if (wrapper?.value?.type !== 'json:object')
|
|
154
174
|
return undefined;
|
|
155
|
-
const node = wrapper.children?.find(p => p.key?.value === value);
|
|
175
|
+
const node = wrapper.children?.find((p) => p.key?.value === value);
|
|
156
176
|
return node?.type === 'json:string' ? node.value : undefined;
|
|
157
177
|
}
|
|
158
178
|
export function extractStringArray(value, children) {
|
|
159
|
-
const node = children?.find(p => p.key?.value === value);
|
|
160
|
-
return node?.value?.type === 'json:array' &&
|
|
161
|
-
|
|
179
|
+
const node = children?.find((p) => p.key?.value === value);
|
|
180
|
+
return node?.value?.type === 'json:array' &&
|
|
181
|
+
node.value.children?.every((n) => n.value?.type === 'json:string')
|
|
182
|
+
? node.value.children.map((n) => n.value.value)
|
|
162
183
|
: undefined;
|
|
163
184
|
}
|
|
164
185
|
export function having(node, ctx, cases) {
|
|
165
|
-
const givenKeys = new Set(JsonObjectNode.is(node)
|
|
166
|
-
|
|
167
|
-
const key = Object.keys(cases).find(c => givenKeys.has(c));
|
|
186
|
+
const givenKeys = new Set(JsonObjectNode.is(node) ? node.children.map((n) => n.key?.value) : []);
|
|
187
|
+
const key = Object.keys(cases).find((c) => givenKeys.has(c));
|
|
168
188
|
if (key === undefined) {
|
|
169
189
|
ctx.err.report(localize('json.checker.property.missing', Object.keys(cases)), Range.create(node.range.start, node.range.start + 1));
|
|
170
|
-
return Object.fromEntries(Object.entries(cases)
|
|
171
|
-
|
|
190
|
+
return Object.fromEntries(Object.entries(cases).map(([k, v]) => [
|
|
191
|
+
k,
|
|
192
|
+
opt(typeof v === 'function' ? any() : v[k] ?? any()),
|
|
193
|
+
]));
|
|
172
194
|
}
|
|
173
195
|
const c = cases[key];
|
|
174
196
|
return typeof c === 'function' ? c() : c;
|
|
@@ -14,7 +14,9 @@ export function literal(value) {
|
|
|
14
14
|
}
|
|
15
15
|
export function string(name, parser, checker, expectation) {
|
|
16
16
|
return (node, ctx) => {
|
|
17
|
-
node.expectation = [
|
|
17
|
+
node.expectation = [
|
|
18
|
+
{ type: 'json:string', typedoc: typedoc(name), ...expectation },
|
|
19
|
+
];
|
|
18
20
|
if (!JsonStringNode.is(node)) {
|
|
19
21
|
ctx.err.report(localize('expected', localize('string')), node);
|
|
20
22
|
}
|
|
@@ -40,8 +42,10 @@ function typedoc(id) {
|
|
|
40
42
|
if (typeof id === 'string') {
|
|
41
43
|
return `String("${id}")`;
|
|
42
44
|
}
|
|
43
|
-
return id
|
|
44
|
-
|
|
45
|
+
return (id
|
|
46
|
+
.slice(0, 10)
|
|
47
|
+
.map((e) => `"${e}"`)
|
|
48
|
+
.join(' | ') + (id.length > 10 ? ' | ...' : ''));
|
|
45
49
|
}
|
|
46
50
|
export const simpleString = string();
|
|
47
51
|
//# sourceMappingURL=string.js.map
|
|
@@ -21,11 +21,11 @@ export function attempt(checker, node, ctx) {
|
|
|
21
21
|
const tempExpectation = node.expectation;
|
|
22
22
|
StateProxy.undoChanges(node);
|
|
23
23
|
const totalErrorSpan = tempCtx.err.errors
|
|
24
|
-
.map(e => e.range.end - e.range.start)
|
|
24
|
+
.map((e) => e.range.end - e.range.start)
|
|
25
25
|
.reduce((a, b) => a + b, 0);
|
|
26
26
|
return {
|
|
27
27
|
totalErrorSpan,
|
|
28
|
-
maxSeverity: Math.max(...tempCtx.err.errors.map(e => e.severity)),
|
|
28
|
+
maxSeverity: Math.max(...tempCtx.err.errors.map((e) => e.severity)),
|
|
29
29
|
expectation: tempExpectation,
|
|
30
30
|
updateNodeAndCtx: () => {
|
|
31
31
|
ctx.err.absorb(tempCtx.err);
|
|
@@ -40,13 +40,14 @@ export function any(checkers = []) {
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
const attempts = checkers
|
|
43
|
-
.map(checker => attempt(checker, node, ctx))
|
|
43
|
+
.map((checker) => attempt(checker, node, ctx))
|
|
44
44
|
.sort((a, b) => a.maxSeverity - b.maxSeverity || a.totalErrorSpan - b.totalErrorSpan);
|
|
45
|
-
const sameTypeAttempts = attempts
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const sameTypeAttempts = attempts.filter((a) => a.expectation?.map((e) => e.type).includes(node.type));
|
|
46
|
+
const allExpectations = attempts
|
|
47
|
+
.filter((a) => a.expectation)
|
|
48
|
+
.flatMap((a) => a.expectation);
|
|
48
49
|
if (sameTypeAttempts.length === 0) {
|
|
49
|
-
const allowedTypes = allExpectations.map(e => localize(e.type.slice(5)));
|
|
50
|
+
const allowedTypes = allExpectations.map((e) => localize(e.type.slice(5)));
|
|
50
51
|
ctx.err.report(localize('expected', arrayToMessage(allowedTypes, false)), node);
|
|
51
52
|
}
|
|
52
53
|
else {
|
|
@@ -56,7 +57,10 @@ export function any(checkers = []) {
|
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
export function expectation(checker, ctx) {
|
|
59
|
-
const node = StateProxy.create({
|
|
60
|
+
const node = StateProxy.create({
|
|
61
|
+
type: 'json:null',
|
|
62
|
+
range: Range.create(0),
|
|
63
|
+
});
|
|
60
64
|
const tempCtx = {
|
|
61
65
|
...ctx,
|
|
62
66
|
err: new ErrorReporter(),
|
package/lib/colorizer/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as core from '@spyglassmc/core';
|
|
2
2
|
import { ColorToken } from '@spyglassmc/core';
|
|
3
|
-
export const boolean = node => {
|
|
3
|
+
export const boolean = (node) => {
|
|
4
4
|
return [ColorToken.create(node, 'literal')];
|
|
5
5
|
};
|
|
6
|
-
export const null_ = node => {
|
|
6
|
+
export const null_ = (node) => {
|
|
7
7
|
return [ColorToken.create(node, 'literal')];
|
|
8
8
|
};
|
|
9
9
|
export const object = (node, ctx) => {
|
package/lib/completer/index.js
CHANGED
|
@@ -15,8 +15,9 @@ export const entry = (node, ctx) => {
|
|
|
15
15
|
export const object = core.completer.record({
|
|
16
16
|
key: (record, pair, ctx, range, insertValue, insertComma) => {
|
|
17
17
|
if (record.expectation) {
|
|
18
|
-
return unique(record.expectation
|
|
19
|
-
.
|
|
18
|
+
return unique(record.expectation
|
|
19
|
+
.filter(JsonExpectation.isObject)
|
|
20
|
+
.flatMap((e) => objectCompletion(range, record, e, ctx, insertValue, insertComma, pair?.key?.value)));
|
|
20
21
|
}
|
|
21
22
|
return [];
|
|
22
23
|
},
|
|
@@ -25,10 +26,11 @@ export const object = core.completer.record({
|
|
|
25
26
|
return core.completer.dispatch(pair.value, ctx);
|
|
26
27
|
}
|
|
27
28
|
if (record.expectation) {
|
|
28
|
-
return unique(record.expectation
|
|
29
|
-
.filter(
|
|
30
|
-
.
|
|
31
|
-
.
|
|
29
|
+
return unique(record.expectation
|
|
30
|
+
.filter(JsonExpectation.isObject)
|
|
31
|
+
.filter((e) => e.fields)
|
|
32
|
+
.map((e) => e.fields.find((f) => f.key === pair.key?.value))
|
|
33
|
+
.flatMap((f) => valueCompletion(ctx.offset, f.value, ctx)));
|
|
32
34
|
}
|
|
33
35
|
return [];
|
|
34
36
|
},
|
|
@@ -41,37 +43,42 @@ export const array = (node, ctx) => {
|
|
|
41
43
|
if (item?.value) {
|
|
42
44
|
return core.completer.dispatch(item.value, ctx);
|
|
43
45
|
}
|
|
44
|
-
if (node.expectation &&
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.
|
|
46
|
+
if (node.expectation &&
|
|
47
|
+
Range.contains(Range.translate(node, 1, -1), ctx.offset, true)) {
|
|
48
|
+
return unique(node.expectation
|
|
49
|
+
.filter(JsonExpectation.isArray)
|
|
50
|
+
.filter((e) => e.items)
|
|
51
|
+
.flatMap((e) => valueCompletion(ctx.offset, e.items, ctx)));
|
|
48
52
|
}
|
|
49
53
|
return [];
|
|
50
54
|
};
|
|
51
55
|
export const boolean = (node) => {
|
|
52
|
-
return ['false', 'true'].map(v => simpleCompletion(node, v));
|
|
56
|
+
return ['false', 'true'].map((v) => simpleCompletion(node, v));
|
|
53
57
|
};
|
|
54
58
|
const string = (node, ctx) => {
|
|
55
59
|
if (node.children?.length) {
|
|
56
60
|
return core.completer.string(node, ctx);
|
|
57
61
|
}
|
|
58
62
|
if (node.expectation) {
|
|
59
|
-
return unique(node.expectation
|
|
60
|
-
.
|
|
63
|
+
return unique(node.expectation
|
|
64
|
+
.filter(JsonExpectation.isString)
|
|
65
|
+
.flatMap((e) => stringCompletion(node, e, ctx)));
|
|
61
66
|
}
|
|
62
67
|
return [];
|
|
63
68
|
};
|
|
64
69
|
function objectCompletion(range, node, expectation, ctx, insertValue, insertComma, selectedKey) {
|
|
65
70
|
if (expectation.fields) {
|
|
66
|
-
return expectation
|
|
67
|
-
.filter(f => f.key === selectedKey ||
|
|
68
|
-
.
|
|
71
|
+
return expectation
|
|
72
|
+
.fields.filter((f) => f.key === selectedKey ||
|
|
73
|
+
!node.children.find((p) => f.key === p.key?.value))
|
|
74
|
+
.map((f) => fieldCompletion(range, f, insertValue, insertComma));
|
|
69
75
|
}
|
|
70
76
|
else if (expectation.keys) {
|
|
71
|
-
return expectation.keys.flatMap(e => stringCompletion(range, e, ctx)
|
|
72
|
-
.map(c => ({
|
|
77
|
+
return expectation.keys.flatMap((e) => stringCompletion(range, e, ctx).map((c) => ({
|
|
73
78
|
...c,
|
|
74
|
-
...insertValue
|
|
79
|
+
...(insertValue
|
|
80
|
+
? { insertText: `${c.insertText}: ${insertComma ? ',' : ''}` }
|
|
81
|
+
: {}),
|
|
75
82
|
})));
|
|
76
83
|
}
|
|
77
84
|
return [];
|
|
@@ -80,7 +87,7 @@ function fieldCompletion(range, field, insertValue, insertComma) {
|
|
|
80
87
|
const value = field.value?.[0] ? SIMPLE_SNIPPETS[field.value[0].type] : '';
|
|
81
88
|
return CompletionItem.create(field.key, range, {
|
|
82
89
|
kind: 10 /* CompletionKind.Property */,
|
|
83
|
-
detail: field.value?.map(e => e.typedoc).join(' | '),
|
|
90
|
+
detail: field.value?.map((e) => e.typedoc).join(' | '),
|
|
84
91
|
sortText: `${field.deprecated ? 2 : field.opt ? 1 : 0}${field.key}`,
|
|
85
92
|
deprecated: field.deprecated,
|
|
86
93
|
filterText: `"${field.key}"`,
|
|
@@ -88,7 +95,7 @@ function fieldCompletion(range, field, insertValue, insertComma) {
|
|
|
88
95
|
});
|
|
89
96
|
}
|
|
90
97
|
function valueCompletion(range, expectation, ctx) {
|
|
91
|
-
return unique(expectation.flatMap(e => {
|
|
98
|
+
return unique(expectation.flatMap((e) => {
|
|
92
99
|
switch (e.type) {
|
|
93
100
|
case 'json:object':
|
|
94
101
|
case 'json:array':
|
|
@@ -96,7 +103,7 @@ function valueCompletion(range, expectation, ctx) {
|
|
|
96
103
|
case 'json:string':
|
|
97
104
|
return stringCompletion(ctx.offset, e, ctx);
|
|
98
105
|
case 'json:boolean':
|
|
99
|
-
return ['false', 'true'].map(v => simpleCompletion(range, v));
|
|
106
|
+
return ['false', 'true'].map((v) => simpleCompletion(range, v));
|
|
100
107
|
case 'json:number':
|
|
101
108
|
return [simpleCompletion(range, '0')];
|
|
102
109
|
}
|
|
@@ -104,7 +111,7 @@ function valueCompletion(range, expectation, ctx) {
|
|
|
104
111
|
}
|
|
105
112
|
function stringCompletion(range, expectation, ctx) {
|
|
106
113
|
if (Array.isArray(expectation.pool)) {
|
|
107
|
-
return expectation.pool.map(v => CompletionItem.create(v, range, {
|
|
114
|
+
return expectation.pool.map((v) => CompletionItem.create(v, range, {
|
|
108
115
|
kind: 12 /* CompletionKind.Value */,
|
|
109
116
|
filterText: `"${v}"`,
|
|
110
117
|
insertText: `"${v}"`,
|
|
@@ -121,7 +128,7 @@ function simpleCompletion(range, value) {
|
|
|
121
128
|
function unique(completions) {
|
|
122
129
|
const ans = [];
|
|
123
130
|
const labels = new Set();
|
|
124
|
-
completions.forEach(c => {
|
|
131
|
+
completions.forEach((c) => {
|
|
125
132
|
if (!labels.has(c.label)) {
|
|
126
133
|
labels.add(c.label);
|
|
127
134
|
ans.push(c);
|
package/lib/formatter/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import { indentFormatter } from '@spyglassmc/core';
|
|
|
3
3
|
const array = (node, ctx) => {
|
|
4
4
|
if (node.children.length === 0)
|
|
5
5
|
return '[]';
|
|
6
|
-
const values = node.children.map(child => {
|
|
7
|
-
const value = child.value &&
|
|
6
|
+
const values = node.children.map((child) => {
|
|
7
|
+
const value = child.value &&
|
|
8
|
+
ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
|
|
8
9
|
return `${ctx.indent(1)}${value ?? ''}`;
|
|
9
10
|
});
|
|
10
11
|
return `[\n${values.join(',\n')}\n${ctx.indent()}]`;
|
|
@@ -12,9 +13,10 @@ const array = (node, ctx) => {
|
|
|
12
13
|
const object = (node, ctx) => {
|
|
13
14
|
if (node.children.length === 0)
|
|
14
15
|
return '{}';
|
|
15
|
-
const fields = node.children.map(child => {
|
|
16
|
+
const fields = node.children.map((child) => {
|
|
16
17
|
const key = child.key && core.formatter.string(child.key, ctx);
|
|
17
|
-
const value = child.value &&
|
|
18
|
+
const value = child.value &&
|
|
19
|
+
ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
|
|
18
20
|
return `${ctx.indent(1)}${key ?? ''}: ${value ?? ''}`;
|
|
19
21
|
});
|
|
20
22
|
return `{\n${fields.join(',\n')}\n${ctx.indent()}}`;
|
package/lib/node/JsonAstNode.js
CHANGED
|
@@ -12,9 +12,7 @@ export var JsonNode;
|
|
|
12
12
|
}
|
|
13
13
|
JsonNode.is = is;
|
|
14
14
|
function isRelated(node) {
|
|
15
|
-
return
|
|
16
|
-
JsonPairNode.is(node) ||
|
|
17
|
-
JsonItemNode.is(node));
|
|
15
|
+
return JsonNode.is(node) || JsonPairNode.is(node) || JsonItemNode.is(node);
|
|
18
16
|
}
|
|
19
17
|
JsonNode.isRelated = isRelated;
|
|
20
18
|
})(JsonNode || (JsonNode = {}));
|
package/lib/parser/entry.js
CHANGED
|
@@ -5,15 +5,30 @@ import { null_ } from './null.js';
|
|
|
5
5
|
import { number } from './number.js';
|
|
6
6
|
import { object } from './object.js';
|
|
7
7
|
import { string } from './string.js';
|
|
8
|
-
const LegalNumberStart = new Set([
|
|
8
|
+
const LegalNumberStart = new Set([
|
|
9
|
+
'0',
|
|
10
|
+
'1',
|
|
11
|
+
'2',
|
|
12
|
+
'3',
|
|
13
|
+
'4',
|
|
14
|
+
'5',
|
|
15
|
+
'6',
|
|
16
|
+
'7',
|
|
17
|
+
'8',
|
|
18
|
+
'9',
|
|
19
|
+
'-',
|
|
20
|
+
]);
|
|
9
21
|
export function json(dumpErrors = false) {
|
|
10
22
|
return (src, ctx) => {
|
|
11
23
|
const result = core.select([
|
|
12
|
-
{ predicate: src => src.tryPeek('['), parser: array },
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
{ predicate: (src) => src.tryPeek('['), parser: array },
|
|
25
|
+
{
|
|
26
|
+
predicate: (src) => src.tryPeek('false') || src.tryPeek('true'),
|
|
27
|
+
parser: boolean,
|
|
28
|
+
},
|
|
29
|
+
{ predicate: (src) => src.tryPeek('null'), parser: null_ },
|
|
30
|
+
{ predicate: (src) => LegalNumberStart.has(src.peek()), parser: number },
|
|
31
|
+
{ predicate: (src) => src.tryPeek('{'), parser: object },
|
|
17
32
|
{ parser: string },
|
|
18
33
|
])(src, ctx);
|
|
19
34
|
if (dumpErrors) {
|
package/lib/parser/object.js
CHANGED
|
@@ -4,7 +4,13 @@ import { string } from './string.js';
|
|
|
4
4
|
export const object = (src, ctx) => {
|
|
5
5
|
return core.setType('json:object', core.record({
|
|
6
6
|
start: '{',
|
|
7
|
-
pair: {
|
|
7
|
+
pair: {
|
|
8
|
+
key: string,
|
|
9
|
+
sep: ':',
|
|
10
|
+
value: entry,
|
|
11
|
+
end: ',',
|
|
12
|
+
trailingEnd: false,
|
|
13
|
+
},
|
|
8
14
|
end: '}',
|
|
9
15
|
}))(src, ctx);
|
|
10
16
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spyglassmc/json",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"url": "https://github.com/SpyglassMC/Spyglass/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@spyglassmc/core": "0.
|
|
29
|
-
"@spyglassmc/locales": "0.3.
|
|
28
|
+
"@spyglassmc/core": "0.4.1",
|
|
29
|
+
"@spyglassmc/locales": "0.3.1"
|
|
30
30
|
}
|
|
31
31
|
}
|