@spyglassmc/json 0.3.7 → 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.
@@ -0,0 +1,10 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import * as mcdoc from '@spyglassmc/mcdoc';
3
+ import type { JsonNode, TypedJsonNode } from '../node/index.js';
4
+ export declare const typed: core.SyncChecker<TypedJsonNode>;
5
+ export declare function register(meta: core.MetaRegistry): void;
6
+ export interface JsonCheckerOptions {
7
+ discardDuplicateKeyErrors?: true;
8
+ }
9
+ export declare function index(type: mcdoc.McdocType, options?: JsonCheckerOptions): core.SyncChecker<JsonNode>;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,109 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import * as mcdoc from '@spyglassmc/mcdoc';
3
+ import { JsonPairNode, JsonStringNode } from '../node/index.js';
4
+ export const typed = (node, ctx) => {
5
+ index(node.targetType)(node.children[0], ctx);
6
+ };
7
+ export function register(meta) {
8
+ meta.registerChecker('json:typed', typed);
9
+ }
10
+ export function index(type, options) {
11
+ return (node, ctx) => {
12
+ mcdoc.runtime.checker.typeDefinition([{ originalNode: node, inferredType: inferType(node) }], type, mcdoc.runtime.checker.McdocCheckerContext.create(ctx, {
13
+ isEquivalent: (inferred, def) => {
14
+ switch (inferred.kind) {
15
+ case 'list':
16
+ return ['list', 'byte_array', 'int_array', 'long_array', 'tuple'].includes(def.kind);
17
+ case 'struct':
18
+ return def.kind === 'struct';
19
+ case 'byte':
20
+ case 'short':
21
+ case 'int':
22
+ case 'long':
23
+ return ['byte', 'short', 'int', 'long', 'float', 'double'].includes(def.kind);
24
+ case 'float':
25
+ case 'double':
26
+ return ['float', 'double'].includes(def.kind);
27
+ default:
28
+ return false;
29
+ }
30
+ },
31
+ getChildren: node => {
32
+ if (node.type === 'json:array') {
33
+ return node.children.filter(n => n.value).map(n => [{ originalNode: n.value, inferredType: inferType(n.value) }]);
34
+ }
35
+ if (node.type === 'json:object') {
36
+ return node.children.filter(kvp => kvp.key).map(kvp => ({
37
+ key: { originalNode: kvp.key, inferredType: inferType(kvp.key) },
38
+ possibleValues: kvp.value
39
+ ? [{ originalNode: kvp.value, inferredType: inferType(kvp.value) }]
40
+ : [],
41
+ }));
42
+ }
43
+ return [];
44
+ },
45
+ reportError: err => {
46
+ if (err.kind === 'duplicate_key' && options?.discardDuplicateKeyErrors) {
47
+ return;
48
+ }
49
+ mcdoc.runtime.checker.getDefaultErrorReporter(ctx, (mcdoc.runtime.checker.getDefaultErrorRange))(err);
50
+ },
51
+ attachTypeInfo: (node, definition, desc = '') => {
52
+ node.typeDef = definition;
53
+ // TODO: improve hover info
54
+ // TODO some sort of shared default implementaion between JSON and SNBT (DRY)
55
+ if (node.parent && JsonPairNode?.is(node.parent)) {
56
+ if (node.parent.key?.typeDef && node.parent.value?.typeDef) {
57
+ const valueString = mcdoc.McdocType.toString(node.parent.value.typeDef);
58
+ let keyString = mcdoc.McdocType.toString(node.parent.key.typeDef);
59
+ if (node.parent.key.typeDef.kind !== 'literal') {
60
+ keyString = `[${keyString}]`;
61
+ }
62
+ const hover = `\`\`\`typescript\n${keyString}: ${valueString}\n\`\`\`\n${desc}`;
63
+ node.parent.key.hover = hover;
64
+ if (node.parent.value.type !== 'json:array'
65
+ && node.parent.value.type !== 'json:object') {
66
+ node.parent.value.hover =
67
+ `\`\`\`typescript\n${valueString}\n\`\`\`\n${desc}`;
68
+ }
69
+ }
70
+ }
71
+ else if (node.type !== 'json:array' && node.type !== 'json:object') {
72
+ node.hover = `\`\`\`typescript\n${mcdoc.McdocType.toString(definition)}\n\`\`\`\n${desc}`;
73
+ }
74
+ },
75
+ stringAttacher: (node, attacher) => {
76
+ if (!JsonStringNode.is(node)) {
77
+ return;
78
+ }
79
+ attacher(node);
80
+ if (node.children) {
81
+ core.AstNode.setParents(node);
82
+ // Because the runtime checker happens after binding, we need to manually call this
83
+ core.binder.fallbackSync(node, ctx);
84
+ core.checker.fallbackSync(node, ctx);
85
+ }
86
+ },
87
+ }));
88
+ };
89
+ }
90
+ function inferType(node) {
91
+ switch (node.type) {
92
+ case 'json:boolean':
93
+ return { kind: 'literal', value: { kind: 'boolean', value: node.value } };
94
+ case 'json:number':
95
+ return {
96
+ kind: 'literal',
97
+ value: { kind: node.value.type, value: Number(node.value.value) },
98
+ };
99
+ case 'json:null':
100
+ return { kind: 'any' }; // null is always invalid?
101
+ case 'json:string':
102
+ return { kind: 'literal', value: { kind: 'string', value: node.value } };
103
+ case 'json:array':
104
+ return { kind: 'list', item: { kind: 'any' } };
105
+ case 'json:object':
106
+ return { kind: 'struct', fields: [] };
107
+ }
108
+ }
109
+ //# sourceMappingURL=index.js.map
@@ -1,7 +1,8 @@
1
1
  import type { Colorizer, MetaRegistry } from '@spyglassmc/core';
2
- import type { JsonBooleanNode, JsonNullNode, JsonObjectNode } from '../node/index.js';
2
+ import type { JsonBooleanNode, JsonNullNode, JsonObjectNode, JsonStringNode } from '../node/index.js';
3
3
  export declare const boolean: Colorizer<JsonBooleanNode>;
4
4
  export declare const null_: Colorizer<JsonNullNode>;
5
5
  export declare const object: Colorizer<JsonObjectNode>;
6
+ export declare const string: Colorizer<JsonStringNode>;
6
7
  export declare function register(meta: MetaRegistry): void;
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -19,11 +19,19 @@ export const object = (node, ctx) => {
19
19
  }
20
20
  return ans;
21
21
  };
22
+ export const string = (node, ctx) => {
23
+ if (node.children && node.children?.length > 0) {
24
+ const child = node.children[0];
25
+ const colorizer = ctx.meta.getColorizer(child.type);
26
+ return colorizer(child, ctx);
27
+ }
28
+ return core.colorizer.string(node, ctx);
29
+ };
22
30
  export function register(meta) {
23
31
  meta.registerColorizer('json:boolean', boolean);
24
32
  meta.registerColorizer('json:null', null_);
25
33
  meta.registerColorizer('json:number', core.colorizer.number);
26
34
  meta.registerColorizer('json:object', object);
27
- meta.registerColorizer('json:string', core.colorizer.string);
35
+ meta.registerColorizer('json:string', string);
28
36
  }
29
37
  //# sourceMappingURL=index.js.map
@@ -1,9 +1,3 @@
1
- import type { Completer, MetaRegistry } from '@spyglassmc/core';
2
- import type { JsonArrayNode, JsonBooleanNode, JsonNode, JsonObjectNode } from '../node/index.js';
3
- export declare const JsonTriggerCharacters: string[];
4
- export declare const entry: Completer<JsonNode>;
5
- export declare const object: Completer<JsonObjectNode>;
6
- export declare const array: Completer<JsonArrayNode>;
7
- export declare const boolean: Completer<JsonBooleanNode>;
8
- export declare function register(meta: MetaRegistry): void;
1
+ import * as core from '@spyglassmc/core';
2
+ export declare function register(meta: core.MetaRegistry): void;
9
3
  //# sourceMappingURL=index.d.ts.map
@@ -1,146 +1,84 @@
1
1
  import * as core from '@spyglassmc/core';
2
- import { CompletionItem, Range } from '@spyglassmc/core';
3
- import { JsonExpectation } from '../node/index.js';
4
- export const JsonTriggerCharacters = ['\n', ':', '"'];
5
- const SIMPLE_SNIPPETS = {
6
- 'json:object': '{$1}',
7
- 'json:array': '[$1]',
8
- 'json:string': '"$1"',
9
- 'json:boolean': '${1|false,true|}',
10
- 'json:number': '${1:0}',
11
- };
12
- export const entry = (node, ctx) => {
13
- return core.completer.dispatch(node, ctx);
2
+ import * as mcdoc from '@spyglassmc/mcdoc';
3
+ const array = (node, ctx) => {
4
+ const index = core.binarySearch(node.children, ctx.offset, (n, o) => {
5
+ return core.Range.compareOffset(n.range, o, true);
6
+ });
7
+ const item = index >= 0 ? node.children[index] : undefined;
8
+ if (item?.value) {
9
+ return ctx.meta.getCompleter(item.value.type)(item.value, ctx);
10
+ }
11
+ if (node.typeDef?.kind === 'list') {
12
+ const completions = getValues(node.typeDef.item, ctx.offset, ctx);
13
+ if (ctx.offset < node.children[node.children.length - 1]?.range.start ?? 0) {
14
+ return completions.map(c => ({ ...c, insertText: c.insertText + ',' }));
15
+ }
16
+ return completions;
17
+ }
18
+ return [];
14
19
  };
15
- export const object = core.completer.record({
16
- key: (record, pair, ctx, range, insertValue, insertComma) => {
17
- if (record.expectation) {
18
- return unique(record.expectation
19
- .filter(JsonExpectation.isObject)
20
- .flatMap((e) => objectCompletion(range, record, e, ctx, insertValue, insertComma, pair?.key?.value)));
20
+ const object = core.completer.record({
21
+ key: (record, pair, ctx, range, iv, ipe, exitingKeys) => {
22
+ if (!record.typeDef) {
23
+ return [];
21
24
  }
22
- return [];
25
+ const keySet = new Set(exitingKeys.map(n => n.value));
26
+ return mcdoc.runtime.completer
27
+ .getFields(record.typeDef, ctx)
28
+ .filter(({ key }) => !keySet.has(key))
29
+ .map(({ key, field }) => core.CompletionItem.create(key, pair?.key ?? range, {
30
+ kind: 5 /* core.CompletionKind.Field */,
31
+ detail: mcdoc.McdocType.toString(field.type),
32
+ deprecated: field.deprecated,
33
+ sortText: field.optional ? '$b' : '$a', // sort above hardcoded $schema
34
+ filterText: `"${key}"`,
35
+ insertText: `"${key}"${iv ? ': ' : ''}${ipe ? '$1,' : ''}`,
36
+ }));
23
37
  },
24
- value: (record, pair, ctx) => {
25
- if (pair.value && !Range.isEmpty(pair.value)) {
26
- return core.completer.dispatch(pair.value, ctx);
38
+ value: (record, pair, ctx, range) => {
39
+ if (pair.value) {
40
+ return ctx.meta.getCompleter(pair.value.type)(pair.value, ctx);
27
41
  }
28
- if (record.expectation) {
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)));
42
+ if (pair.key && record.typeDef) {
43
+ const pairKey = pair.key.value;
44
+ const field = mcdoc.runtime.completer.getFields(record.typeDef, ctx)
45
+ .find(({ key }) => key === pairKey)
46
+ ?.field.type;
47
+ if (field) {
48
+ return getValues(field, range, ctx);
49
+ }
34
50
  }
35
51
  return [];
36
52
  },
37
53
  });
38
- export const array = (node, ctx) => {
39
- const index = core.binarySearch(node.children, ctx.offset, (n, o) => n.sep
40
- ? Range.compareOffset(Range.translate(n, 0, -1), o, true)
41
- : Range.compareOffset(n.range, o, true));
42
- const item = index >= 0 ? node.children[index] : undefined;
43
- if (item?.value) {
44
- return core.completer.dispatch(item.value, ctx);
45
- }
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)));
52
- }
53
- return [];
54
- };
55
- export const boolean = (node) => {
56
- return ['false', 'true'].map((v) => simpleCompletion(node, v));
57
- };
58
- const string = (node, ctx) => {
59
- if (node.children?.length) {
60
- return core.completer.string(node, ctx);
54
+ const primitive = (node, ctx) => {
55
+ const insideRange = core.Range.contains(node, ctx.offset, true);
56
+ if (node.type === 'json:string' && node.children?.length && insideRange) {
57
+ const childItems = core.completer.string(node, ctx);
58
+ if (childItems.length > 0) {
59
+ return childItems;
60
+ }
61
61
  }
62
- if (node.expectation) {
63
- return unique(node.expectation
64
- .filter(JsonExpectation.isString)
65
- .flatMap((e) => stringCompletion(node, e, ctx)));
62
+ if (!node.typeDef) {
63
+ return [];
66
64
  }
67
- return [];
65
+ return getValues(node.typeDef, insideRange ? node : ctx.offset, ctx);
68
66
  };
69
- function objectCompletion(range, node, expectation, ctx, insertValue, insertComma, selectedKey) {
70
- if (expectation.fields) {
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));
75
- }
76
- else if (expectation.keys) {
77
- return expectation.keys.flatMap((e) => stringCompletion(range, e, ctx).map((c) => ({
78
- ...c,
79
- ...(insertValue
80
- ? { insertText: `${c.insertText}: ${insertComma ? ',' : ''}` }
81
- : {}),
82
- })));
83
- }
84
- return [];
85
- }
86
- function fieldCompletion(range, field, insertValue, insertComma) {
87
- const value = field.value?.[0] ? SIMPLE_SNIPPETS[field.value[0].type] : '';
88
- return CompletionItem.create(field.key, range, {
89
- kind: 10 /* CompletionKind.Property */,
90
- detail: field.value?.map((e) => e.typedoc).join(' | '),
91
- sortText: `${field.deprecated ? 2 : field.opt ? 1 : 0}${field.key}`,
92
- deprecated: field.deprecated,
93
- filterText: `"${field.key}"`,
94
- insertText: `"${field.key}"${insertValue ? `: ${value}` : ''}${insertComma ? ',' : ''}`,
95
- });
96
- }
97
- function valueCompletion(range, expectation, ctx) {
98
- return unique(expectation.flatMap((e) => {
99
- switch (e.type) {
100
- case 'json:object':
101
- case 'json:array':
102
- return [simpleCompletion(range, SIMPLE_SNIPPETS[e.type])];
103
- case 'json:string':
104
- return stringCompletion(ctx.offset, e, ctx);
105
- case 'json:boolean':
106
- return ['false', 'true'].map((v) => simpleCompletion(range, v));
107
- case 'json:number':
108
- return [simpleCompletion(range, '0')];
109
- }
67
+ function getValues(typeDef, range, ctx) {
68
+ return mcdoc.runtime.completer.getValues(typeDef, ctx)
69
+ .map(({ value, detail, kind, completionKind, insertText }) => core.CompletionItem.create(value, range, {
70
+ kind: completionKind ?? 12 /* core.CompletionKind.Value */,
71
+ detail,
72
+ filterText: kind === 'string' ? `"${value}"` : value,
73
+ insertText: kind === 'string' ? `"${insertText ?? value}"` : insertText ?? value,
110
74
  }));
111
75
  }
112
- function stringCompletion(range, expectation, ctx) {
113
- if (Array.isArray(expectation.pool)) {
114
- return expectation.pool.map((v) => CompletionItem.create(v, range, {
115
- kind: 12 /* CompletionKind.Value */,
116
- filterText: `"${v}"`,
117
- insertText: `"${v}"`,
118
- }));
119
- }
120
- return [simpleCompletion(range, SIMPLE_SNIPPETS[expectation.type])];
121
- }
122
- function simpleCompletion(range, value) {
123
- return CompletionItem.create(value.replace('$1', ''), range, {
124
- kind: 12 /* CompletionKind.Value */,
125
- insertText: value,
126
- });
127
- }
128
- function unique(completions) {
129
- const ans = [];
130
- const labels = new Set();
131
- completions.forEach((c) => {
132
- if (!labels.has(c.label)) {
133
- labels.add(c.label);
134
- ans.push(c);
135
- }
136
- });
137
- return ans;
138
- }
139
76
  export function register(meta) {
140
- meta.registerCompleter('json:entry', entry);
141
77
  meta.registerCompleter('json:array', array);
142
- meta.registerCompleter('json:boolean', boolean);
78
+ meta.registerCompleter('json:boolean', primitive);
79
+ meta.registerCompleter('json:number', primitive);
80
+ meta.registerCompleter('json:null', primitive);
143
81
  meta.registerCompleter('json:object', object);
144
- meta.registerCompleter('json:string', string);
82
+ meta.registerCompleter('json:string', primitive);
145
83
  }
146
84
  //# sourceMappingURL=index.js.map
@@ -1,22 +1,24 @@
1
1
  import * as core from '@spyglassmc/core';
2
2
  import { indentFormatter } from '@spyglassmc/core';
3
3
  const array = (node, ctx) => {
4
- if (node.children.length === 0)
4
+ if (node.children.length === 0) {
5
5
  return '[]';
6
+ }
6
7
  const values = node.children.map((child) => {
7
- const value = child.value &&
8
- ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
8
+ const value = child.value
9
+ && ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
9
10
  return `${ctx.indent(1)}${value ?? ''}`;
10
11
  });
11
12
  return `[\n${values.join(',\n')}\n${ctx.indent()}]`;
12
13
  };
13
14
  const object = (node, ctx) => {
14
- if (node.children.length === 0)
15
+ if (node.children.length === 0) {
15
16
  return '{}';
17
+ }
16
18
  const fields = node.children.map((child) => {
17
19
  const key = child.key && core.formatter.string(child.key, ctx);
18
- const value = child.value &&
19
- ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
20
+ const value = child.value
21
+ && ctx.meta.getFormatter(child.value.type)(child.value, indentFormatter(ctx));
20
22
  return `${ctx.indent(1)}${key ?? ''}: ${value ?? ''}`;
21
23
  });
22
24
  return `{\n${fields.join(',\n')}\n${ctx.indent()}}`;
package/lib/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import * as core from '@spyglassmc/core';
1
+ import type * as core from '@spyglassmc/core';
2
+ export * as checker from './checker/index.js';
2
3
  export * as colorizer from './colorizer/index.js';
3
4
  export * as completer from './completer/index.js';
4
5
  export * as formatter from './formatter/index.js';
package/lib/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  /* istanbul ignore file */
2
- import * as core from '@spyglassmc/core';
2
+ import * as checker from './checker/index.js';
3
3
  import * as colorizer from './colorizer/index.js';
4
4
  import * as completer from './completer/index.js';
5
5
  import * as formatter from './formatter/index.js';
6
6
  import * as parser from './parser/index.js';
7
+ export * as checker from './checker/index.js';
7
8
  export * as colorizer from './colorizer/index.js';
8
9
  export * as completer from './completer/index.js';
9
10
  export * as formatter from './formatter/index.js';
@@ -11,11 +12,17 @@ export * from './node/index.js';
11
12
  export * as parser from './parser/index.js';
12
13
  export const initialize = ({ meta }) => {
13
14
  meta.registerLanguage('json', {
14
- extensions: ['.json', '.mcmeta'],
15
- triggerCharacters: completer.JsonTriggerCharacters,
16
- parser: core.dumpErrors(parser.entry),
15
+ extensions: ['.json'],
16
+ triggerCharacters: ['\n', ':', '"'],
17
+ parser: parser.file,
18
+ });
19
+ meta.registerLanguage('mcmeta', {
20
+ extensions: ['.mcmeta'],
21
+ triggerCharacters: ['\n', ':', '"'],
22
+ parser: parser.file,
17
23
  });
18
24
  meta.registerParser('json:entry', parser.entry);
25
+ checker.register(meta);
19
26
  colorizer.register(meta);
20
27
  completer.register(meta);
21
28
  formatter.register(meta);
@@ -1,2 +1,72 @@
1
- export * from './JsonAstNode.js';
1
+ import * as core from '@spyglassmc/core';
2
+ import type * as mcdoc from '@spyglassmc/mcdoc';
3
+ export interface JsonFileNode extends core.AstNode {
4
+ readonly type: 'json:file';
5
+ readonly children: [JsonNode];
6
+ }
7
+ export declare namespace JsonFileNode {
8
+ function is(obj: object | undefined): obj is JsonFileNode;
9
+ }
10
+ interface JsonBaseNode {
11
+ typeDef?: mcdoc.runtime.checker.SimplifiedMcdocType;
12
+ }
13
+ export type JsonNode = JsonObjectNode | JsonArrayNode | JsonPrimitiveNode;
14
+ export declare namespace JsonNode {
15
+ function is(node: core.AstNode): node is JsonNode;
16
+ }
17
+ export interface JsonObjectNode extends core.RecordBaseNode<JsonStringNode, JsonNode>, JsonBaseNode {
18
+ readonly type: 'json:object';
19
+ }
20
+ export declare namespace JsonObjectNode {
21
+ function is(obj: object | undefined): obj is JsonObjectNode;
22
+ function mock(range: core.RangeLike): JsonObjectNode;
23
+ }
24
+ export type JsonPairNode = core.PairNode<JsonStringNode, JsonNode>;
25
+ export declare namespace JsonPairNode {
26
+ function is(obj: object): obj is JsonPairNode;
27
+ }
28
+ export interface JsonArrayNode extends core.ListNode<JsonNode>, JsonBaseNode {
29
+ readonly type: 'json:array';
30
+ }
31
+ export declare namespace JsonArrayNode {
32
+ function is(obj: object | undefined): obj is JsonArrayNode;
33
+ function mock(range: core.RangeLike): JsonArrayNode;
34
+ }
35
+ export type JsonPrimitiveNode = JsonStringNode | JsonNumberNode | JsonBooleanNode | JsonNullNode;
36
+ export interface JsonStringNode extends core.StringBaseNode, JsonBaseNode {
37
+ readonly type: 'json:string';
38
+ }
39
+ export declare namespace JsonStringNode {
40
+ function is(obj: object | undefined): obj is JsonStringNode;
41
+ function mock(range: core.RangeLike): JsonStringNode;
42
+ }
43
+ export interface JsonNumberNode extends core.AstNode, JsonBaseNode {
44
+ readonly type: 'json:number';
45
+ readonly children: [core.LongNode | core.FloatNode];
46
+ readonly value: core.LongNode | core.FloatNode;
47
+ }
48
+ export declare namespace JsonNumberNode {
49
+ function is(obj: object): obj is JsonNumberNode;
50
+ }
51
+ export interface JsonBooleanNode extends core.BooleanBaseNode, JsonBaseNode {
52
+ readonly type: 'json:boolean';
53
+ }
54
+ export declare namespace JsonBooleanNode {
55
+ function is(obj: object): obj is JsonBooleanNode;
56
+ }
57
+ export interface JsonNullNode extends core.AstNode, JsonBaseNode {
58
+ readonly type: 'json:null';
59
+ }
60
+ export declare namespace JsonNullNode {
61
+ function is(obj: object): obj is JsonNullNode;
62
+ }
63
+ export interface TypedJsonNode extends core.AstNode {
64
+ type: 'json:typed';
65
+ children: [JsonNode];
66
+ targetType: mcdoc.McdocType;
67
+ }
68
+ export declare namespace TypedJsonNode {
69
+ function is(obj: object): obj is TypedJsonNode;
70
+ }
71
+ export {};
2
72
  //# sourceMappingURL=index.d.ts.map
package/lib/node/index.js CHANGED
@@ -1,2 +1,98 @@
1
- export * from './JsonAstNode.js';
1
+ import * as core from '@spyglassmc/core';
2
+ import { JsonStringOptions } from '../parser/index.js';
3
+ export var JsonFileNode;
4
+ (function (JsonFileNode) {
5
+ /* istanbul ignore next */
6
+ function is(obj) {
7
+ return obj?.type === 'json:file';
8
+ }
9
+ JsonFileNode.is = is;
10
+ })(JsonFileNode || (JsonFileNode = {}));
11
+ export var JsonNode;
12
+ (function (JsonNode) {
13
+ function is(node) {
14
+ return (JsonObjectNode.is(node)
15
+ || JsonArrayNode.is(node)
16
+ || JsonStringNode.is(node)
17
+ || JsonNumberNode.is(node)
18
+ || JsonBooleanNode.is(node)
19
+ || JsonNullNode.is(node));
20
+ }
21
+ JsonNode.is = is;
22
+ })(JsonNode || (JsonNode = {}));
23
+ export var JsonObjectNode;
24
+ (function (JsonObjectNode) {
25
+ /* istanbul ignore next */
26
+ function is(obj) {
27
+ return obj?.type === 'json:object';
28
+ }
29
+ JsonObjectNode.is = is;
30
+ function mock(range) {
31
+ return { type: 'json:object', range: core.Range.get(range), children: [] };
32
+ }
33
+ JsonObjectNode.mock = mock;
34
+ })(JsonObjectNode || (JsonObjectNode = {}));
35
+ export var JsonPairNode;
36
+ (function (JsonPairNode) {
37
+ /* istanbul ignore next */
38
+ function is(obj) {
39
+ return obj.type === 'pair';
40
+ }
41
+ JsonPairNode.is = is;
42
+ })(JsonPairNode || (JsonPairNode = {}));
43
+ export var JsonArrayNode;
44
+ (function (JsonArrayNode) {
45
+ function is(obj) {
46
+ return obj?.type === 'json:array';
47
+ }
48
+ JsonArrayNode.is = is;
49
+ function mock(range) {
50
+ return { type: 'json:array', range: core.Range.get(range), children: [] };
51
+ }
52
+ JsonArrayNode.mock = mock;
53
+ })(JsonArrayNode || (JsonArrayNode = {}));
54
+ export var JsonStringNode;
55
+ (function (JsonStringNode) {
56
+ /* istanbul ignore next */
57
+ function is(obj) {
58
+ return obj?.type === 'json:string';
59
+ }
60
+ JsonStringNode.is = is;
61
+ function mock(range) {
62
+ return { ...core.StringNode.mock(range, JsonStringOptions), type: 'json:string' };
63
+ }
64
+ JsonStringNode.mock = mock;
65
+ })(JsonStringNode || (JsonStringNode = {}));
66
+ export var JsonNumberNode;
67
+ (function (JsonNumberNode) {
68
+ /* istanbul ignore next */
69
+ function is(obj) {
70
+ return obj.type === 'json:number';
71
+ }
72
+ JsonNumberNode.is = is;
73
+ })(JsonNumberNode || (JsonNumberNode = {}));
74
+ export var JsonBooleanNode;
75
+ (function (JsonBooleanNode) {
76
+ /* istanbul ignore next */
77
+ function is(obj) {
78
+ return obj.type === 'json:boolean';
79
+ }
80
+ JsonBooleanNode.is = is;
81
+ })(JsonBooleanNode || (JsonBooleanNode = {}));
82
+ export var JsonNullNode;
83
+ (function (JsonNullNode) {
84
+ /* istanbul ignore next */
85
+ function is(obj) {
86
+ return obj.type === 'json:null';
87
+ }
88
+ JsonNullNode.is = is;
89
+ })(JsonNullNode || (JsonNullNode = {}));
90
+ export var TypedJsonNode;
91
+ (function (TypedJsonNode) {
92
+ /* istanbul ignore next */
93
+ function is(obj) {
94
+ return obj.type === 'json:typed';
95
+ }
96
+ TypedJsonNode.is = is;
97
+ })(TypedJsonNode || (TypedJsonNode = {}));
2
98
  //# sourceMappingURL=index.js.map
@@ -1,10 +1,4 @@
1
1
  import * as core from '@spyglassmc/core';
2
2
  import { entry } from './entry.js';
3
- export const array = (ctx, src) => core.setType('json:array', core.list({
4
- start: '[',
5
- value: entry,
6
- sep: ',',
7
- trailingSep: false,
8
- end: ']',
9
- }))(ctx, src);
3
+ export const array = (ctx, src) => core.setType('json:array', core.list({ start: '[', value: entry, sep: ',', trailingSep: false, end: ']' }))(ctx, src);
10
4
  //# sourceMappingURL=array.js.map
@@ -3,18 +3,10 @@ import { Range } from '@spyglassmc/core';
3
3
  export const boolean = (src, _ctx) => {
4
4
  const start = src.cursor;
5
5
  if (src.trySkip('false')) {
6
- return {
7
- type: 'json:boolean',
8
- range: Range.create(start, src),
9
- value: false,
10
- };
6
+ return { type: 'json:boolean', range: Range.create(start, src), value: false };
11
7
  }
12
8
  if (src.trySkip('true')) {
13
- return {
14
- type: 'json:boolean',
15
- range: Range.create(start, src),
16
- value: true,
17
- };
9
+ return { type: 'json:boolean', range: Range.create(start, src), value: true };
18
10
  }
19
11
  return core.Failure;
20
12
  };
@@ -5,31 +5,16 @@ 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([
9
- '0',
10
- '1',
11
- '2',
12
- '3',
13
- '4',
14
- '5',
15
- '6',
16
- '7',
17
- '8',
18
- '9',
19
- '-',
20
- ]);
8
+ const LegalNumberStart = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-']);
21
9
  export const entry = (src, ctx) => core.select([
22
10
  { predicate: (src) => src.tryPeek('['), parser: array },
23
- {
24
- predicate: (src) => src.tryPeek('false') || src.tryPeek('true'),
25
- parser: boolean,
26
- },
11
+ { predicate: (src) => src.tryPeek('false') || src.tryPeek('true'), parser: boolean },
27
12
  { predicate: (src) => src.tryPeek('null'), parser: null_ },
13
+ { predicate: (src) => LegalNumberStart.has(src.peek()), parser: number },
28
14
  {
29
- predicate: (src) => LegalNumberStart.has(src.peek()),
30
- parser: number,
15
+ predicate: (src) => src.tryPeek('{'),
16
+ parser: object,
31
17
  },
32
- { predicate: (src) => src.tryPeek('{'), parser: object },
33
18
  { parser: string },
34
19
  ])(src, ctx);
35
20
  //# sourceMappingURL=entry.js.map
@@ -0,0 +1,4 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import type { JsonFileNode } from '../node/index.js';
3
+ export declare const file: core.Parser<JsonFileNode>;
4
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1,4 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import { entry } from './entry.js';
3
+ export const file = core.map(core.dumpErrors(entry), (res) => ({ type: 'json:file', range: res.range, children: [res] }));
4
+ //# sourceMappingURL=file.js.map
@@ -1,5 +1,8 @@
1
1
  export * from './array.js';
2
+ export * from './boolean.js';
2
3
  export * from './entry.js';
4
+ export * from './file.js';
5
+ export * from './null.js';
3
6
  export * from './number.js';
4
7
  export * from './object.js';
5
8
  export * from './string.js';
@@ -1,5 +1,8 @@
1
1
  export * from './array.js';
2
+ export * from './boolean.js';
2
3
  export * from './entry.js';
4
+ export * from './file.js';
5
+ export * from './null.js';
3
6
  export * from './number.js';
4
7
  export * from './object.js';
5
8
  export * from './string.js';
@@ -3,10 +3,7 @@ import { Range } from '@spyglassmc/core';
3
3
  export const null_ = (src, ctx) => {
4
4
  const start = src.cursor;
5
5
  if (src.trySkip('null')) {
6
- return {
7
- type: 'json:null',
8
- range: Range.create(start, src),
9
- };
6
+ return { type: 'json:null', range: Range.create(start, src) };
10
7
  }
11
8
  return core.Failure;
12
9
  };
@@ -1,24 +1,14 @@
1
1
  import * as core from '@spyglassmc/core';
2
2
  export const number = (src, ctx) => {
3
- const value = core.select([
4
- {
3
+ const value = core.select([{
5
4
  regex: /^-?(?:0|[1-9]\d*)(?!\d|[.eE])/,
6
- parser: core.long({
7
- pattern: /^-?(?:0|[1-9]\d*)$/,
8
- }),
9
- },
10
- {
5
+ parser: core.long({ pattern: /^-?(?:0|[1-9]\d*)$/ }),
6
+ }, {
11
7
  parser: core.float({
12
8
  // Regex form of the chart from https://www.json.org.
13
9
  pattern: /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][-+]?\d+)?$/,
14
10
  }),
15
- },
16
- ])(src, ctx);
17
- return {
18
- type: 'json:number',
19
- children: [value],
20
- value: value,
21
- range: value.range,
22
- };
11
+ }])(src, ctx);
12
+ return { type: 'json:number', children: [value], value, range: value.range };
23
13
  };
24
14
  //# sourceMappingURL=number.js.map
@@ -3,13 +3,7 @@ import { entry } from './entry.js';
3
3
  import { string } from './string.js';
4
4
  export const object = (src, ctx) => core.setType('json:object', core.record({
5
5
  start: '{',
6
- pair: {
7
- key: string,
8
- sep: ':',
9
- value: entry,
10
- end: ',',
11
- trailingEnd: false,
12
- },
6
+ pair: { key: string, sep: ':', value: entry, end: ',', trailingEnd: false },
13
7
  end: '}',
14
8
  }))(src, ctx);
15
9
  //# sourceMappingURL=object.js.map
@@ -1,9 +1,6 @@
1
1
  import * as core from '@spyglassmc/core';
2
2
  export const JsonStringOptions = {
3
- escapable: {
4
- characters: ['b', 'f', 'n', 'r', 't'],
5
- unicode: true,
6
- },
3
+ escapable: { characters: ['b', 'f', 'n', 'r', 't'], unicode: true },
7
4
  quotes: ['"'],
8
5
  };
9
6
  export const string = (src, ctx) => core.setType('json:string', core.string(JsonStringOptions))(src, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spyglassmc/json",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "type": "module",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -25,7 +25,8 @@
25
25
  "url": "https://github.com/SpyglassMC/Spyglass/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@spyglassmc/core": "0.4.5",
29
- "@spyglassmc/locales": "0.3.5"
28
+ "@spyglassmc/core": "0.4.7",
29
+ "@spyglassmc/locales": "0.3.7",
30
+ "@spyglassmc/mcdoc": "0.3.10"
30
31
  }
31
32
  }
@@ -1,98 +0,0 @@
1
- import type { DeepReadonly, ItemNode, PairNode } from '@spyglassmc/core';
2
- import * as core from '@spyglassmc/core';
3
- export type JsonNode = JsonObjectNode | JsonArrayNode | JsonStringNode | JsonNumberNode | JsonBooleanNode | JsonNullNode;
4
- export type JsonRelatedNode = JsonNode | JsonPairNode | JsonItemNode;
5
- export declare namespace JsonNode {
6
- function is(node: core.AstNode): node is JsonNode;
7
- function isRelated(node: core.AstNode): node is JsonRelatedNode;
8
- }
9
- interface JsonBaseAstNode {
10
- expectation?: JsonExpectation[];
11
- }
12
- export type JsonExpectation = JsonObjectExpectation | JsonArrayExpectation | JsonStringExpectation | JsonNumberExpectation | JsonBooleanExpectation;
13
- export declare namespace JsonExpectation {
14
- function isArray(e: DeepReadonly<JsonExpectation>): e is DeepReadonly<JsonArrayExpectation>;
15
- function isObject(e: DeepReadonly<JsonExpectation>): e is DeepReadonly<JsonObjectExpectation>;
16
- function isString(e: DeepReadonly<JsonExpectation>): e is DeepReadonly<JsonStringExpectation>;
17
- }
18
- interface JsonBaseExpectation {
19
- typedoc: string;
20
- }
21
- export interface JsonObjectExpectation extends JsonBaseExpectation {
22
- readonly type: 'json:object';
23
- fields?: {
24
- key: string;
25
- value?: JsonExpectation[];
26
- opt?: boolean;
27
- deprecated?: boolean;
28
- }[];
29
- keys?: JsonStringExpectation[];
30
- }
31
- export interface JsonObjectNode extends core.RecordBaseNode<JsonStringNode, JsonNode>, JsonBaseAstNode {
32
- readonly type: 'json:object';
33
- }
34
- export declare namespace JsonObjectNode {
35
- function is(obj: object | undefined): obj is JsonObjectNode;
36
- function mock(range: core.RangeLike): JsonObjectNode;
37
- }
38
- export type JsonPairNode = PairNode<JsonStringNode, JsonNode>;
39
- export declare namespace JsonPairNode {
40
- function is(obj: object): obj is JsonPairNode;
41
- }
42
- export interface JsonArrayExpectation extends JsonBaseExpectation {
43
- readonly type: 'json:array';
44
- items?: JsonExpectation[];
45
- }
46
- export interface JsonArrayNode extends core.ListNode<JsonNode>, JsonBaseAstNode {
47
- readonly type: 'json:array';
48
- }
49
- export declare namespace JsonArrayNode {
50
- function is(obj: object | undefined): obj is JsonArrayNode;
51
- function mock(range: core.RangeLike): JsonArrayNode;
52
- }
53
- export type JsonItemNode = ItemNode<JsonNode>;
54
- export declare namespace JsonItemNode {
55
- function is(obj: object): obj is JsonItemNode;
56
- }
57
- export interface JsonStringExpectation extends JsonBaseExpectation {
58
- readonly type: 'json:string';
59
- pool?: string[];
60
- }
61
- export declare namespace JsonStringExpectation {
62
- function is(obj: object): obj is JsonStringExpectation;
63
- }
64
- export interface JsonStringNode extends core.StringBaseNode, JsonBaseAstNode {
65
- readonly type: 'json:string';
66
- }
67
- export declare namespace JsonStringNode {
68
- function is(obj: object | undefined): obj is JsonStringNode;
69
- function mock(range: core.RangeLike): JsonStringNode;
70
- }
71
- export interface JsonNumberExpectation extends JsonBaseExpectation {
72
- readonly type: 'json:number';
73
- }
74
- export interface JsonNumberNode extends JsonBaseAstNode, core.AstNode {
75
- readonly type: 'json:number';
76
- readonly children: [core.LongNode | core.FloatNode];
77
- readonly value: core.LongNode | core.FloatNode;
78
- }
79
- export declare namespace JsonNumberNode {
80
- function is(obj: object): obj is JsonNumberNode;
81
- }
82
- export interface JsonBooleanExpectation extends JsonBaseExpectation {
83
- readonly type: 'json:boolean';
84
- }
85
- export interface JsonBooleanNode extends core.BooleanBaseNode, JsonBaseAstNode {
86
- readonly type: 'json:boolean';
87
- }
88
- export declare namespace JsonBooleanNode {
89
- function is(obj: object): obj is JsonBooleanNode;
90
- }
91
- export interface JsonNullNode extends core.AstNode, JsonBaseAstNode {
92
- readonly type: 'json:null';
93
- }
94
- export declare namespace JsonNullNode {
95
- function is(obj: object): obj is JsonNullNode;
96
- }
97
- export {};
98
- //# sourceMappingURL=JsonAstNode.d.ts.map
@@ -1,128 +0,0 @@
1
- import * as core from '@spyglassmc/core';
2
- import { JsonStringOptions } from '../parser/index.js';
3
- export var JsonNode;
4
- (function (JsonNode) {
5
- function is(node) {
6
- return (JsonObjectNode.is(node) ||
7
- JsonArrayNode.is(node) ||
8
- JsonStringNode.is(node) ||
9
- JsonNumberNode.is(node) ||
10
- JsonBooleanNode.is(node) ||
11
- JsonNullNode.is(node));
12
- }
13
- JsonNode.is = is;
14
- function isRelated(node) {
15
- return JsonNode.is(node) || JsonPairNode.is(node) || JsonItemNode.is(node);
16
- }
17
- JsonNode.isRelated = isRelated;
18
- })(JsonNode || (JsonNode = {}));
19
- export var JsonExpectation;
20
- (function (JsonExpectation) {
21
- function isArray(e) {
22
- return e.type === 'json:array';
23
- }
24
- JsonExpectation.isArray = isArray;
25
- function isObject(e) {
26
- return e.type === 'json:object';
27
- }
28
- JsonExpectation.isObject = isObject;
29
- function isString(e) {
30
- return e.type === 'json:string';
31
- }
32
- JsonExpectation.isString = isString;
33
- })(JsonExpectation || (JsonExpectation = {}));
34
- export var JsonObjectNode;
35
- (function (JsonObjectNode) {
36
- /* istanbul ignore next */
37
- function is(obj) {
38
- return obj?.type === 'json:object';
39
- }
40
- JsonObjectNode.is = is;
41
- function mock(range) {
42
- return {
43
- type: 'json:object',
44
- range: core.Range.get(range),
45
- children: [],
46
- };
47
- }
48
- JsonObjectNode.mock = mock;
49
- })(JsonObjectNode || (JsonObjectNode = {}));
50
- export var JsonPairNode;
51
- (function (JsonPairNode) {
52
- /* istanbul ignore next */
53
- function is(obj) {
54
- return obj.type === 'pair';
55
- }
56
- JsonPairNode.is = is;
57
- })(JsonPairNode || (JsonPairNode = {}));
58
- export var JsonArrayNode;
59
- (function (JsonArrayNode) {
60
- function is(obj) {
61
- return obj?.type === 'json:array';
62
- }
63
- JsonArrayNode.is = is;
64
- function mock(range) {
65
- return {
66
- type: 'json:array',
67
- range: core.Range.get(range),
68
- children: [],
69
- };
70
- }
71
- JsonArrayNode.mock = mock;
72
- })(JsonArrayNode || (JsonArrayNode = {}));
73
- export var JsonItemNode;
74
- (function (JsonItemNode) {
75
- /* istanbul ignore next */
76
- function is(obj) {
77
- return obj.type === 'item';
78
- }
79
- JsonItemNode.is = is;
80
- })(JsonItemNode || (JsonItemNode = {}));
81
- export var JsonStringExpectation;
82
- (function (JsonStringExpectation) {
83
- /* istanbul ignore next */
84
- function is(obj) {
85
- return obj.type === 'json:string';
86
- }
87
- JsonStringExpectation.is = is;
88
- })(JsonStringExpectation || (JsonStringExpectation = {}));
89
- export var JsonStringNode;
90
- (function (JsonStringNode) {
91
- /* istanbul ignore next */
92
- function is(obj) {
93
- return obj?.type === 'json:string';
94
- }
95
- JsonStringNode.is = is;
96
- function mock(range) {
97
- return {
98
- ...core.StringNode.mock(range, JsonStringOptions),
99
- type: 'json:string',
100
- };
101
- }
102
- JsonStringNode.mock = mock;
103
- })(JsonStringNode || (JsonStringNode = {}));
104
- export var JsonNumberNode;
105
- (function (JsonNumberNode) {
106
- /* istanbul ignore next */
107
- function is(obj) {
108
- return obj.type === 'json:number';
109
- }
110
- JsonNumberNode.is = is;
111
- })(JsonNumberNode || (JsonNumberNode = {}));
112
- export var JsonBooleanNode;
113
- (function (JsonBooleanNode) {
114
- /* istanbul ignore next */
115
- function is(obj) {
116
- return obj.type === 'json:boolean';
117
- }
118
- JsonBooleanNode.is = is;
119
- })(JsonBooleanNode || (JsonBooleanNode = {}));
120
- export var JsonNullNode;
121
- (function (JsonNullNode) {
122
- /* istanbul ignore next */
123
- function is(obj) {
124
- return obj.type === 'json:null';
125
- }
126
- JsonNullNode.is = is;
127
- })(JsonNullNode || (JsonNullNode = {}));
128
- //# sourceMappingURL=JsonAstNode.js.map