@spyglassmc/core 0.4.5 → 0.4.6
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/common/Dev.js +2 -5
- package/lib/common/ReadonlyProxy.js +1 -3
- package/lib/common/StateProxy.js +2 -8
- package/lib/common/externals/BrowserExternals.js +7 -12
- package/lib/common/externals/NodeJsExternals.js +12 -8
- package/lib/common/externals/index.d.ts +8 -1
- package/lib/common/util.js +3 -10
- package/lib/node/AstNode.js +7 -9
- package/lib/node/BooleanNode.js +1 -4
- package/lib/node/FloatNode.js +1 -5
- package/lib/node/IntegerNode.js +1 -5
- package/lib/node/ListNode.d.ts +1 -1
- package/lib/node/LiteralNode.js +1 -6
- package/lib/node/LongNode.js +1 -5
- package/lib/node/PrefixedNode.d.ts +13 -0
- package/lib/node/PrefixedNode.js +22 -0
- package/lib/node/ResourceLocationNode.d.ts +1 -1
- package/lib/node/ResourceLocationNode.js +2 -8
- package/lib/node/StringNode.d.ts +2 -1
- package/lib/node/StringNode.js +1 -4
- package/lib/node/SymbolNode.js +1 -6
- package/lib/node/index.d.ts +1 -0
- package/lib/node/index.js +1 -0
- package/lib/parser/comment.d.ts +1 -1
- package/lib/parser/comment.js +2 -6
- package/lib/parser/error.js +1 -4
- package/lib/parser/file.d.ts +2 -2
- package/lib/parser/file.js +1 -2
- package/lib/parser/float.js +2 -7
- package/lib/parser/index.d.ts +1 -0
- package/lib/parser/index.js +1 -0
- package/lib/parser/integer.js +3 -7
- package/lib/parser/list.d.ts +1 -1
- package/lib/parser/list.js +2 -6
- package/lib/parser/literal.js +2 -9
- package/lib/parser/long.js +2 -7
- package/lib/parser/prefixed.d.ts +8 -0
- package/lib/parser/prefixed.js +23 -0
- package/lib/parser/record.d.ts +1 -1
- package/lib/parser/record.js +11 -17
- package/lib/parser/resourceLocation.d.ts +1 -0
- package/lib/parser/resourceLocation.js +6 -4
- package/lib/parser/string.js +6 -9
- package/lib/parser/util.d.ts +14 -3
- package/lib/parser/util.js +48 -26
- package/lib/processor/ColorInfoProvider.js +8 -25
- package/lib/processor/binder/builtin.d.ts +1 -0
- package/lib/processor/binder/builtin.js +20 -30
- package/lib/processor/checker/builtin.d.ts +1 -0
- package/lib/processor/checker/builtin.js +13 -7
- package/lib/processor/colorizer/Colorizer.d.ts +1 -1
- package/lib/processor/colorizer/Colorizer.js +4 -7
- package/lib/processor/colorizer/builtin.js +2 -2
- package/lib/processor/completer/Completer.js +1 -3
- package/lib/processor/completer/builtin.d.ts +3 -2
- package/lib/processor/completer/builtin.js +67 -23
- package/lib/processor/formatter/Formatter.js +1 -3
- package/lib/processor/formatter/builtin.js +2 -4
- package/lib/processor/linter/builtin/undeclaredSymbol.js +27 -40
- package/lib/service/CacheService.d.ts +1 -1
- package/lib/service/CacheService.js +12 -13
- package/lib/service/Config.d.ts +36 -0
- package/lib/service/Config.js +28 -45
- package/lib/service/Context.d.ts +2 -0
- package/lib/service/Context.js +4 -12
- package/lib/service/Downloader.d.ts +3 -0
- package/lib/service/Downloader.js +9 -3
- package/lib/service/ErrorReporter.js +3 -0
- package/lib/service/FileService.js +10 -29
- package/lib/service/Hover.js +1 -4
- package/lib/service/MetaRegistry.d.ts +4 -2
- package/lib/service/MetaRegistry.js +16 -8
- package/lib/service/Project.d.ts +9 -3
- package/lib/service/Project.js +71 -48
- package/lib/service/Service.d.ts +1 -1
- package/lib/service/Service.js +11 -36
- package/lib/service/SymbolLocations.js +1 -4
- package/lib/service/fileUtil.d.ts +7 -0
- package/lib/service/fileUtil.js +29 -4
- package/lib/source/IndexMap.js +1 -4
- package/lib/source/Location.js +3 -9
- package/lib/source/Position.js +1 -2
- package/lib/source/PositionRange.js +2 -2
- package/lib/source/Range.js +9 -21
- package/lib/source/Source.d.ts +11 -1
- package/lib/source/Source.js +31 -5
- package/lib/symbol/Symbol.d.ts +14 -9
- package/lib/symbol/Symbol.js +80 -61
- package/lib/symbol/SymbolUtil.d.ts +3 -3
- package/lib/symbol/SymbolUtil.js +48 -72
- package/package.json +3 -2
package/lib/parser/long.js
CHANGED
|
@@ -6,11 +6,7 @@ const fallbackOnOutOfRange = (ans, _src, ctx, options) => {
|
|
|
6
6
|
};
|
|
7
7
|
export function long(options) {
|
|
8
8
|
return (src, ctx) => {
|
|
9
|
-
const ans = {
|
|
10
|
-
type: 'long',
|
|
11
|
-
range: Range.create(src),
|
|
12
|
-
value: 0n,
|
|
13
|
-
};
|
|
9
|
+
const ans = { type: 'long', range: Range.create(src), value: 0n };
|
|
14
10
|
if (src.peek() === '-' || src.peek() === '+') {
|
|
15
11
|
src.skip();
|
|
16
12
|
}
|
|
@@ -36,8 +32,7 @@ export function long(options) {
|
|
|
36
32
|
else if (!options.pattern.test(raw) || isOnlySign) {
|
|
37
33
|
ctx.err.report(localize('parser.long.illegal', options.pattern), ans);
|
|
38
34
|
}
|
|
39
|
-
else if ((options.min && ans.value < options.min) ||
|
|
40
|
-
(options.max && ans.value > options.max)) {
|
|
35
|
+
else if ((options.min && ans.value < options.min) || (options.max && ans.value > options.max)) {
|
|
41
36
|
const onOutOfRange = options.onOutOfRange ?? fallbackOnOutOfRange;
|
|
42
37
|
onOutOfRange(ans, src, ctx, options);
|
|
43
38
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AstNode, PrefixedNode } from '../node/index.js';
|
|
2
|
+
import type { InfallibleParser, Parser } from './Parser.js';
|
|
3
|
+
export interface Options<C extends AstNode> {
|
|
4
|
+
prefix: string;
|
|
5
|
+
child: Parser<C>;
|
|
6
|
+
}
|
|
7
|
+
export declare function prefixed<C extends AstNode>(options: Options<C>): InfallibleParser<PrefixedNode<C>>;
|
|
8
|
+
//# sourceMappingURL=prefixed.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Range } from '../source/index.js';
|
|
2
|
+
import { literal } from './literal.js';
|
|
3
|
+
import { Failure } from './Parser.js';
|
|
4
|
+
export function prefixed(options) {
|
|
5
|
+
return (src, ctx) => {
|
|
6
|
+
const ans = {
|
|
7
|
+
type: 'prefixed',
|
|
8
|
+
range: Range.create(src),
|
|
9
|
+
prefix: options.prefix,
|
|
10
|
+
children: [],
|
|
11
|
+
};
|
|
12
|
+
const prefix = literal(options.prefix)(src, ctx);
|
|
13
|
+
ans.children.push(prefix);
|
|
14
|
+
ans.range.end = src.cursor;
|
|
15
|
+
const child = options.child(src, ctx);
|
|
16
|
+
if (child !== Failure) {
|
|
17
|
+
ans.children.push(child);
|
|
18
|
+
}
|
|
19
|
+
ans.range.end = src.cursor;
|
|
20
|
+
return ans;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=prefixed.js.map
|
package/lib/parser/record.d.ts
CHANGED
|
@@ -18,5 +18,5 @@ export interface Options<K extends AstNode, V extends AstNode> {
|
|
|
18
18
|
/**
|
|
19
19
|
* @returns A parser that parses something coming in a key-value pair form. e.g. SNBT objects, entity selector arguments.
|
|
20
20
|
*/
|
|
21
|
-
export declare function record<K extends AstNode, V extends AstNode>({ start, pair, end
|
|
21
|
+
export declare function record<K extends AstNode, V extends AstNode>({ start, pair, end }: Options<K, V>): InfallibleParser<RecordNode<K, V>>;
|
|
22
22
|
//# sourceMappingURL=record.d.ts.map
|
package/lib/parser/record.js
CHANGED
|
@@ -5,13 +5,9 @@ import { attempt } from './util.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* @returns A parser that parses something coming in a key-value pair form. e.g. SNBT objects, entity selector arguments.
|
|
7
7
|
*/
|
|
8
|
-
export function record({ start, pair, end
|
|
8
|
+
export function record({ start, pair, end }) {
|
|
9
9
|
return (src, ctx) => {
|
|
10
|
-
const ans = {
|
|
11
|
-
type: 'record',
|
|
12
|
-
range: Range.create(src),
|
|
13
|
-
children: [],
|
|
14
|
-
};
|
|
10
|
+
const ans = { type: 'record', range: Range.create(src), children: [] };
|
|
15
11
|
if (src.trySkip(start)) {
|
|
16
12
|
src.skipWhitespace();
|
|
17
13
|
let requiresPairEnd = false;
|
|
@@ -26,10 +22,10 @@ export function record({ start, pair, end, }) {
|
|
|
26
22
|
}
|
|
27
23
|
// Key.
|
|
28
24
|
const keyStart = src.cursor;
|
|
29
|
-
const { result: keyResult, updateSrcAndCtx: updateForKey, endCursor: keyEnd
|
|
30
|
-
if (keyResult === Failure
|
|
31
|
-
(keyEnd - keyStart === 0
|
|
32
|
-
![pair.sep, pair.end, end, '\r', '\n', '\t', ' '].includes(src.peek()))) {
|
|
25
|
+
const { result: keyResult, updateSrcAndCtx: updateForKey, endCursor: keyEnd } = attempt(pair.key, src, ctx);
|
|
26
|
+
if (keyResult === Failure
|
|
27
|
+
|| (keyEnd - keyStart === 0
|
|
28
|
+
&& ![pair.sep, pair.end, end, '\r', '\n', '\t', ' '].includes(src.peek()))) {
|
|
33
29
|
ctx.err.report(localize('expected', localize('parser.record.key')), Range.create(src, () => src.skipUntilOrEnd(pair.sep, pair.end, end, '\r', '\n')));
|
|
34
30
|
}
|
|
35
31
|
else {
|
|
@@ -51,10 +47,10 @@ export function record({ start, pair, end, }) {
|
|
|
51
47
|
? pair.value
|
|
52
48
|
: pair.value.get(ans, key);
|
|
53
49
|
const valueStart = src.cursor;
|
|
54
|
-
const { result: valueResult, updateSrcAndCtx: updateForValue, endCursor: valueEnd
|
|
55
|
-
if (valueResult === Failure
|
|
56
|
-
(valueEnd - valueStart === 0
|
|
57
|
-
![pair.sep, pair.end, end, '\r', '\n', '\t', ' '].includes(src.peek()))) {
|
|
50
|
+
const { result: valueResult, updateSrcAndCtx: updateForValue, endCursor: valueEnd } = attempt(valueParser, src, ctx);
|
|
51
|
+
if (valueResult === Failure
|
|
52
|
+
|| (valueEnd - valueStart === 0
|
|
53
|
+
&& ![pair.sep, pair.end, end, '\r', '\n', '\t', ' '].includes(src.peek()))) {
|
|
58
54
|
ctx.err.report(localize('expected', localize('parser.record.value')), Range.create(src, () => src.skipUntilOrEnd(pair.sep, pair.end, end, '\r', '\n')));
|
|
59
55
|
}
|
|
60
56
|
else {
|
|
@@ -73,9 +69,7 @@ export function record({ start, pair, end, }) {
|
|
|
73
69
|
type: 'pair',
|
|
74
70
|
range: Range.create(pairStart, src),
|
|
75
71
|
...(key || value
|
|
76
|
-
? {
|
|
77
|
-
children: [key, value].filter((v) => !!v),
|
|
78
|
-
}
|
|
72
|
+
? { children: [key, value].filter((v) => !!v) }
|
|
79
73
|
: {}),
|
|
80
74
|
key,
|
|
81
75
|
sep: sepCharRange,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ResourceLocationNode, ResourceLocationOptions } from '../node/index.js';
|
|
2
2
|
import type { InfallibleParser } from './Parser.js';
|
|
3
|
+
export declare const LegalResourceLocationCharacters: Set<string>;
|
|
3
4
|
export declare function resourceLocation(options: ResourceLocationOptions): InfallibleParser<ResourceLocationNode>;
|
|
4
5
|
//# sourceMappingURL=resourceLocation.d.ts.map
|
|
@@ -6,6 +6,7 @@ const Terminators = new Set([
|
|
|
6
6
|
'\r',
|
|
7
7
|
'\n',
|
|
8
8
|
'=',
|
|
9
|
+
'~',
|
|
9
10
|
',',
|
|
10
11
|
'"',
|
|
11
12
|
"'",
|
|
@@ -16,8 +17,9 @@ const Terminators = new Set([
|
|
|
16
17
|
'(',
|
|
17
18
|
')',
|
|
18
19
|
';',
|
|
20
|
+
'|',
|
|
19
21
|
]);
|
|
20
|
-
const
|
|
22
|
+
export const LegalResourceLocationCharacters = new Set([
|
|
21
23
|
'a',
|
|
22
24
|
'b',
|
|
23
25
|
'c',
|
|
@@ -88,8 +90,8 @@ export function resourceLocation(options) {
|
|
|
88
90
|
/* istanbul ignore next */
|
|
89
91
|
const illegalChars = [
|
|
90
92
|
...new Set([
|
|
91
|
-
...[...(ans.namespace ?? [])].filter((c) => !
|
|
92
|
-
...[...rawPath].filter((c) => c !== '/' && !
|
|
93
|
+
...[...(ans.namespace ?? [])].filter((c) => !LegalResourceLocationCharacters.has(c)),
|
|
94
|
+
...[...rawPath].filter((c) => c !== '/' && !LegalResourceLocationCharacters.has(c)),
|
|
93
95
|
]),
|
|
94
96
|
];
|
|
95
97
|
if (illegalChars.length) {
|
|
@@ -98,7 +100,7 @@ export function resourceLocation(options) {
|
|
|
98
100
|
if (ans.isTag && !options.allowTag) {
|
|
99
101
|
ctx.err.report(localize('parser.resource-location.tag-disallowed'), ans);
|
|
100
102
|
}
|
|
101
|
-
if (!ans.namespace && options.
|
|
103
|
+
if (!ans.namespace && options.requireCanonical) {
|
|
102
104
|
ctx.err.report(localize('parser.resource-location.namespace-expected'), ans);
|
|
103
105
|
}
|
|
104
106
|
}
|
package/lib/parser/string.js
CHANGED
|
@@ -15,6 +15,7 @@ export function string(options) {
|
|
|
15
15
|
let start = src.cursor;
|
|
16
16
|
if (options.quotes?.length && (src.peek() === '"' || src.peek() === "'")) {
|
|
17
17
|
const currentQuote = src.read();
|
|
18
|
+
ans.quote = currentQuote;
|
|
18
19
|
const contentStart = src.cursor;
|
|
19
20
|
while (src.canRead() && src.peek() !== currentQuote) {
|
|
20
21
|
const c = src.peek();
|
|
@@ -22,9 +23,9 @@ export function string(options) {
|
|
|
22
23
|
const cStart = src.cursor;
|
|
23
24
|
src.skip();
|
|
24
25
|
const c2 = src.read();
|
|
25
|
-
if (c2 === '\\'
|
|
26
|
-
c2 === currentQuote
|
|
27
|
-
EscapeChar.is(options.escapable.characters, c2)) {
|
|
26
|
+
if (c2 === '\\'
|
|
27
|
+
|| c2 === currentQuote
|
|
28
|
+
|| EscapeChar.is(options.escapable.characters, c2)) {
|
|
28
29
|
ans.valueMap.push({
|
|
29
30
|
inner: Range.create(ans.value.length, ans.value.length + 1),
|
|
30
31
|
outer: Range.create(cStart, src),
|
|
@@ -75,8 +76,7 @@ export function string(options) {
|
|
|
75
76
|
start = contentStart;
|
|
76
77
|
}
|
|
77
78
|
else if (options.unquotable) {
|
|
78
|
-
while (src.canRead() &&
|
|
79
|
-
isAllowedCharacter(src.peek(), options.unquotable)) {
|
|
79
|
+
while (src.canRead() && isAllowedCharacter(src.peek(), options.unquotable)) {
|
|
80
80
|
ans.value += src.read();
|
|
81
81
|
}
|
|
82
82
|
if (!ans.value && !options.unquotable.allowEmpty) {
|
|
@@ -86,10 +86,7 @@ export function string(options) {
|
|
|
86
86
|
else {
|
|
87
87
|
ctx.err.report(localize('expected', options.quotes), src);
|
|
88
88
|
}
|
|
89
|
-
ans.valueMap.unshift({
|
|
90
|
-
inner: Range.create(0),
|
|
91
|
-
outer: Range.create(start),
|
|
92
|
-
});
|
|
89
|
+
ans.valueMap.unshift({ inner: Range.create(0), outer: Range.create(start) });
|
|
93
90
|
if (options.value?.parser) {
|
|
94
91
|
const valueResult = parseStringValue(options.value.parser, ans.value, ans.valueMap, ctx);
|
|
95
92
|
/* istanbul ignore else */
|
package/lib/parser/util.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { AstNode } from '../node/index.js';
|
|
2
2
|
import { SequenceUtil } from '../node/index.js';
|
|
3
3
|
import type { ParserContext } from '../service/index.js';
|
|
4
|
-
import type { ErrorSeverity, ReadonlySource
|
|
4
|
+
import type { ErrorSeverity, ReadonlySource } from '../source/index.js';
|
|
5
|
+
import { Source } from '../source/index.js';
|
|
5
6
|
import type { InfallibleParser, Parser, Result, Returnable } from './Parser.js';
|
|
6
7
|
type ExtractNodeType<P extends Parser<Returnable>> = P extends Parser<infer V> ? V : never;
|
|
7
8
|
/**
|
|
@@ -141,8 +142,18 @@ export declare function validate<N extends AstNode>(parser: Parser<N>, validator
|
|
|
141
142
|
/**
|
|
142
143
|
* @returns A parser that is based on the passed-in `parser`, but will never read to any of the terminator strings.
|
|
143
144
|
*/
|
|
144
|
-
export declare function stopBefore<N extends Returnable>(parser: InfallibleParser<N>, ...
|
|
145
|
-
export declare function stopBefore<N extends Returnable>(parser: Parser<N>, ...
|
|
145
|
+
export declare function stopBefore<N extends Returnable>(parser: InfallibleParser<N>, ...terminators: (string | readonly string[])[]): InfallibleParser<N>;
|
|
146
|
+
export declare function stopBefore<N extends Returnable>(parser: Parser<N>, ...terminators: (string | readonly string[])[]): Parser<N>;
|
|
147
|
+
/**
|
|
148
|
+
* @returns A parser that is based on the passed-in `parser`, but concatenates lines
|
|
149
|
+
* together when we reach, in order:
|
|
150
|
+
* - a backslash
|
|
151
|
+
* - whitespace (optional)
|
|
152
|
+
* - a newline
|
|
153
|
+
* - whitespace (optional)
|
|
154
|
+
*/
|
|
155
|
+
export declare function concatOnTrailingBackslash<N extends Returnable>(parser: InfallibleParser<N>): InfallibleParser<N>;
|
|
156
|
+
export declare function concatOnTrailingBackslash<N extends Returnable>(parser: Parser<N>): Parser<N>;
|
|
146
157
|
/**
|
|
147
158
|
* @returns A parser that is based on the passed-in `parser`, but will only read the acceptable characters.
|
|
148
159
|
*/
|
package/lib/parser/util.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
import { localize } from '@spyglassmc/locales';
|
|
1
2
|
import { SequenceUtil, SequenceUtilDiscriminator } from '../node/index.js';
|
|
2
3
|
import { ErrorReporter } from '../service/index.js';
|
|
3
|
-
import { Range } from '../source/index.js';
|
|
4
|
+
import { IndexMap, Range, Source } from '../source/index.js';
|
|
4
5
|
import { Failure } from './Parser.js';
|
|
5
6
|
export function attempt(parser, src, ctx) {
|
|
6
7
|
const tmpSrc = src.clone();
|
|
7
|
-
const tmpCtx = {
|
|
8
|
-
...ctx,
|
|
9
|
-
err: new ErrorReporter(),
|
|
10
|
-
};
|
|
8
|
+
const tmpCtx = { ...ctx, err: new ErrorReporter() };
|
|
11
9
|
const result = parser(tmpSrc, tmpCtx);
|
|
12
10
|
return {
|
|
13
11
|
result,
|
|
@@ -81,14 +79,7 @@ export function repeat(parser, parseGap) {
|
|
|
81
79
|
}
|
|
82
80
|
export function any(parsers, out) {
|
|
83
81
|
return (src, ctx) => {
|
|
84
|
-
const results = parsers
|
|
85
|
-
.map((parser, i) => ({
|
|
86
|
-
attempt: attempt(parser, src, ctx),
|
|
87
|
-
index: i,
|
|
88
|
-
}))
|
|
89
|
-
.filter(({ attempt }) => attempt.result !== Failure)
|
|
90
|
-
.sort((a, b) => b.attempt.endCursor - a.attempt.endCursor ||
|
|
91
|
-
a.attempt.errorAmount - b.attempt.errorAmount);
|
|
82
|
+
const results = parsers.map((parser, i) => ({ attempt: attempt(parser, src, ctx), index: i })).filter(({ attempt }) => attempt.result !== Failure).sort((a, b) => b.attempt.endCursor - a.attempt.endCursor || a.attempt.errorAmount - b.attempt.errorAmount);
|
|
92
83
|
if (results.length === 0) {
|
|
93
84
|
if (out) {
|
|
94
85
|
out.index = -1;
|
|
@@ -155,13 +146,11 @@ export function recover(parser, defaultValue) {
|
|
|
155
146
|
export function select(cases) {
|
|
156
147
|
return (src, ctx) => {
|
|
157
148
|
for (const { predicate, prefix, parser, regex } of cases) {
|
|
158
|
-
if (predicate?.(src)
|
|
159
|
-
(prefix !== undefined ? src.tryPeek(prefix) : undefined)
|
|
160
|
-
(regex && src.matchPattern(regex))
|
|
161
|
-
true) {
|
|
162
|
-
const callableParser = typeof parser === 'object'
|
|
163
|
-
? parser.get()
|
|
164
|
-
: parser;
|
|
149
|
+
if (predicate?.(src)
|
|
150
|
+
?? (prefix !== undefined ? src.tryPeek(prefix) : undefined)
|
|
151
|
+
?? (regex && src.matchPattern(regex))
|
|
152
|
+
?? true) {
|
|
153
|
+
const callableParser = typeof parser === 'object' ? parser.get() : parser;
|
|
165
154
|
return callableParser(src, ctx);
|
|
166
155
|
}
|
|
167
156
|
}
|
|
@@ -181,10 +170,7 @@ export function map(parser, fn) {
|
|
|
181
170
|
export function setType(type, parser) {
|
|
182
171
|
return map(parser, (res) => {
|
|
183
172
|
const { type: _type, ...restResult } = res;
|
|
184
|
-
const ans = {
|
|
185
|
-
type,
|
|
186
|
-
...restResult,
|
|
187
|
-
};
|
|
173
|
+
const ans = { type, ...restResult };
|
|
188
174
|
delete ans[SequenceUtilDiscriminator];
|
|
189
175
|
return ans;
|
|
190
176
|
});
|
|
@@ -198,8 +184,8 @@ export function validate(parser, validator, message, severity) {
|
|
|
198
184
|
return res;
|
|
199
185
|
});
|
|
200
186
|
}
|
|
201
|
-
export function stopBefore(parser, ...
|
|
202
|
-
const flatTerminators =
|
|
187
|
+
export function stopBefore(parser, ...terminators) {
|
|
188
|
+
const flatTerminators = terminators.flat();
|
|
203
189
|
return (src, ctx) => {
|
|
204
190
|
const tmpSrc = src.clone();
|
|
205
191
|
// Cut tmpSrc.string before the nearest terminator.
|
|
@@ -212,6 +198,42 @@ export function stopBefore(parser, ...teminators) {
|
|
|
212
198
|
return ans;
|
|
213
199
|
};
|
|
214
200
|
}
|
|
201
|
+
export function concatOnTrailingBackslash(parser) {
|
|
202
|
+
return (src, ctx) => {
|
|
203
|
+
let wrappedStr = src.sliceToCursor(0);
|
|
204
|
+
const wrappedSrcCursor = wrappedStr.length;
|
|
205
|
+
const indexMap = [];
|
|
206
|
+
while (src.canRead()) {
|
|
207
|
+
wrappedStr += src.readUntil('\\');
|
|
208
|
+
if (!src.canRead()) {
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
// If we get here, then `src.cursor` is at a backslash
|
|
212
|
+
if (src.hasNonSpaceAheadInLine(1)) {
|
|
213
|
+
wrappedStr += src.read();
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Create an index map that skips from the trailing backslash to the
|
|
217
|
+
// next line's first non-whitespace character
|
|
218
|
+
const from = src.getCharRange();
|
|
219
|
+
src.nextLine();
|
|
220
|
+
// Minecraft raises a `Line continuation at end of file` if a backslash
|
|
221
|
+
// (+ optional whitespace to the next line) is right before the end of the file
|
|
222
|
+
if (!src.canRead()) {
|
|
223
|
+
const ans = { type: 'error', range: Range.span(from, src) };
|
|
224
|
+
ctx.err.report(localize('parser.line-continuation-end-of-file'), ans);
|
|
225
|
+
}
|
|
226
|
+
src.skipSpace();
|
|
227
|
+
const to = src.getCharRange(-1);
|
|
228
|
+
indexMap.push({ inner: Range.create(wrappedStr.length), outer: Range.span(from, to) });
|
|
229
|
+
}
|
|
230
|
+
const wrappedSrc = new Source(wrappedStr, IndexMap.merge(src.indexMap, indexMap));
|
|
231
|
+
wrappedSrc.innerCursor = wrappedSrcCursor;
|
|
232
|
+
const ans = parser(wrappedSrc, ctx);
|
|
233
|
+
src.cursor = wrappedSrc.cursor;
|
|
234
|
+
return ans;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
215
237
|
export function acceptOnly(parser, ...characters) {
|
|
216
238
|
const set = new Set(characters.flat());
|
|
217
239
|
return (src, ctx) => {
|
|
@@ -108,11 +108,7 @@ export var ColorPresentation;
|
|
|
108
108
|
(function (ColorPresentation) {
|
|
109
109
|
function fromColorFormat(format, color, range) {
|
|
110
110
|
const presentation = colorPresentation(format, color);
|
|
111
|
-
return {
|
|
112
|
-
label: presentation,
|
|
113
|
-
text: presentation,
|
|
114
|
-
range,
|
|
115
|
-
};
|
|
111
|
+
return { label: presentation, text: presentation, range };
|
|
116
112
|
}
|
|
117
113
|
ColorPresentation.fromColorFormat = fromColorFormat;
|
|
118
114
|
function colorPresentation(format, color) {
|
|
@@ -121,32 +117,19 @@ export var ColorPresentation;
|
|
|
121
117
|
case ColorFormat.DecRGBA:
|
|
122
118
|
return color.map((c) => round(c)).join(' ');
|
|
123
119
|
case ColorFormat.DecRGB:
|
|
124
|
-
return color
|
|
125
|
-
.slice(0, 3)
|
|
126
|
-
.map((c) => round(c))
|
|
127
|
-
.join(' ');
|
|
120
|
+
return color.slice(0, 3).map((c) => round(c)).join(' ');
|
|
128
121
|
case ColorFormat.IntRGBA:
|
|
129
122
|
return color.map((c) => Math.round(c * 255)).join(' ');
|
|
130
123
|
case ColorFormat.IntRGB:
|
|
131
|
-
return color
|
|
132
|
-
.slice(0, 3)
|
|
133
|
-
.map((c) => Math.round(c * 255))
|
|
134
|
-
.join(' ');
|
|
124
|
+
return color.slice(0, 3).map((c) => Math.round(c * 255)).join(' ');
|
|
135
125
|
case ColorFormat.HexRGBA:
|
|
136
|
-
return `#${Math.round((((color[0] * 255) << 24) +
|
|
137
|
-
(
|
|
138
|
-
color[2] * 255) <<
|
|
139
|
-
(8 + color[3] * 255))
|
|
140
|
-
.toString(16)
|
|
141
|
-
.padStart(8, '0')}`;
|
|
126
|
+
return `#${Math.round((((color[0] * 255) << 24) + ((color[1] * 255) << 16) + color[2] * 255)
|
|
127
|
+
<< (8 + color[3] * 255)).toString(16).padStart(8, '0')}`;
|
|
142
128
|
case ColorFormat.HexRGB:
|
|
143
|
-
return `#${Math.round(((color[0] * 255) << 16) + ((color[1] * 255) << 8) +
|
|
144
|
-
|
|
145
|
-
.toString(16)
|
|
146
|
-
.padStart(6, '0')}`;
|
|
129
|
+
return `#${Math.round(((color[0] * 255) << 16) + ((color[1] * 255) << 8) + color[2] * 255)
|
|
130
|
+
.toString(16).padStart(6, '0')}`;
|
|
147
131
|
case ColorFormat.CompositeInt:
|
|
148
|
-
return `${Math.round(((color[0] * 255) << 16) + ((color[1] * 255) << 8) +
|
|
149
|
-
color[2] * 255)}`;
|
|
132
|
+
return `${Math.round(((color[0] * 255) << 16) + ((color[1] * 255) << 8) + color[2] * 255)}`;
|
|
150
133
|
}
|
|
151
134
|
}
|
|
152
135
|
})(ColorPresentation || (ColorPresentation = {}));
|
|
@@ -19,6 +19,7 @@ export declare const noop: SyncBinder<AstNode>;
|
|
|
19
19
|
* Use the shallowest children that have their own binder to validate.
|
|
20
20
|
*/
|
|
21
21
|
export declare const fallback: AsyncBinder<AstNode>;
|
|
22
|
+
export declare const fallbackSync: SyncBinder<AstNode>;
|
|
22
23
|
export declare const dispatchSync: SyncBinder<AstNode>;
|
|
23
24
|
export declare const resourceLocation: SyncBinder<ResourceLocationNode>;
|
|
24
25
|
export declare const symbol: SyncBinder<SymbolBaseNode>;
|
|
@@ -5,16 +5,10 @@ import { ErrorReporter } from '../../service/index.js';
|
|
|
5
5
|
import { traversePreOrder } from '../util.js';
|
|
6
6
|
import { AsyncBinder, SyncBinder } from './Binder.js';
|
|
7
7
|
export function attempt(binder, node, ctx) {
|
|
8
|
-
const tempCtx = {
|
|
9
|
-
...ctx,
|
|
10
|
-
err: new ErrorReporter(),
|
|
11
|
-
symbols: ctx.symbols.clone(),
|
|
12
|
-
};
|
|
8
|
+
const tempCtx = { ...ctx, err: new ErrorReporter(), symbols: ctx.symbols.clone() };
|
|
13
9
|
const processAfterBinder = () => {
|
|
14
10
|
StateProxy.undoChanges(node);
|
|
15
|
-
const totalErrorSpan = tempCtx.err.errors
|
|
16
|
-
.map((e) => e.range.end - e.range.start)
|
|
17
|
-
.reduce((a, b) => a + b, 0);
|
|
11
|
+
const totalErrorSpan = tempCtx.err.errors.map((e) => e.range.end - e.range.start).reduce((a, b) => a + b, 0);
|
|
18
12
|
return {
|
|
19
13
|
errorAmount: tempCtx.err.errors.length,
|
|
20
14
|
totalErrorSpan,
|
|
@@ -43,15 +37,14 @@ export function any(binders) {
|
|
|
43
37
|
const attemptSorter = (a, b) => a.errorAmount - b.errorAmount || a.totalErrorSpan - b.totalErrorSpan;
|
|
44
38
|
if (binders.every(SyncBinder.is)) {
|
|
45
39
|
return SyncBinder.create((node, ctx) => {
|
|
46
|
-
const attempts = binders
|
|
47
|
-
.map((binder) => attempt(binder, node, ctx))
|
|
48
|
-
.sort(attemptSorter);
|
|
40
|
+
const attempts = binders.map((binder) => attempt(binder, node, ctx)).sort(attemptSorter);
|
|
49
41
|
attempts[0].updateNodeAndCtx();
|
|
50
42
|
});
|
|
51
43
|
}
|
|
52
44
|
else {
|
|
53
45
|
return AsyncBinder.create(async (node, ctx) => {
|
|
54
|
-
const attempts = (await Promise.all(binders.map((binder) => attempt(binder, node, ctx))))
|
|
46
|
+
const attempts = (await Promise.all(binders.map((binder) => attempt(binder, node, ctx))))
|
|
47
|
+
.sort(attemptSorter);
|
|
55
48
|
attempts[0].updateNodeAndCtx();
|
|
56
49
|
});
|
|
57
50
|
}
|
|
@@ -74,6 +67,17 @@ export const fallback = AsyncBinder.create(async (node, ctx) => {
|
|
|
74
67
|
});
|
|
75
68
|
await Promise.all(promises);
|
|
76
69
|
});
|
|
70
|
+
export const fallbackSync = SyncBinder.create((node, ctx) => {
|
|
71
|
+
traversePreOrder(node, (node) => !ctx.meta.hasBinder(node.type), (node) => ctx.meta.hasBinder(node.type), (node) => {
|
|
72
|
+
const binder = ctx.meta.getBinder(node.type);
|
|
73
|
+
if (SyncBinder.is(binder)) {
|
|
74
|
+
binder(node, ctx);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
ctx.logger.warn(`[fallbackSync] Trying to run async binder for "${node.type}"`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
77
81
|
export const dispatchSync = SyncBinder.create((node, ctx) => {
|
|
78
82
|
for (const child of node.children ?? []) {
|
|
79
83
|
if (ctx.meta.hasBinder(child.type)) {
|
|
@@ -88,16 +92,8 @@ export const resourceLocation = SyncBinder.create((node, ctx) => {
|
|
|
88
92
|
? raw.replace(/\./g, ResourceLocation.NamespacePathSep)
|
|
89
93
|
: raw);
|
|
90
94
|
if (node.options.category) {
|
|
91
|
-
ctx.symbols
|
|
92
|
-
.
|
|
93
|
-
? `tag/${node.options.category}`
|
|
94
|
-
: node.options.category, sanitizedRaw)
|
|
95
|
-
.enter({
|
|
96
|
-
usage: {
|
|
97
|
-
type: node.options.usageType,
|
|
98
|
-
node,
|
|
99
|
-
accessType: node.options.accessType,
|
|
100
|
-
},
|
|
95
|
+
ctx.symbols.query(ctx.doc, node.isTag ? `tag/${node.options.category}` : node.options.category, sanitizedRaw).enter({
|
|
96
|
+
usage: { type: node.options.usageType, node, accessType: node.options.accessType },
|
|
101
97
|
});
|
|
102
98
|
}
|
|
103
99
|
if (node.options.pool && !node.options.allowUnknown) {
|
|
@@ -109,15 +105,9 @@ export const resourceLocation = SyncBinder.create((node, ctx) => {
|
|
|
109
105
|
});
|
|
110
106
|
export const symbol = SyncBinder.create((node, ctx) => {
|
|
111
107
|
if (node.value) {
|
|
112
|
-
const path = node.options.parentPath
|
|
113
|
-
? [...node.options.parentPath, node.value]
|
|
114
|
-
: [node.value];
|
|
108
|
+
const path = node.options.parentPath ? [...node.options.parentPath, node.value] : [node.value];
|
|
115
109
|
ctx.symbols.query(ctx.doc, node.options.category, ...path).enter({
|
|
116
|
-
usage: {
|
|
117
|
-
type: node.options.usageType,
|
|
118
|
-
node: node,
|
|
119
|
-
accessType: node.options.accessType,
|
|
120
|
-
},
|
|
110
|
+
usage: { type: node.options.usageType, node, accessType: node.options.accessType },
|
|
121
111
|
});
|
|
122
112
|
}
|
|
123
113
|
});
|
|
@@ -16,6 +16,7 @@ export declare const noop: SyncChecker<AstNode>;
|
|
|
16
16
|
* Use the shallowest children that have their own checker to validate.
|
|
17
17
|
*/
|
|
18
18
|
export declare const fallback: Checker<AstNode>;
|
|
19
|
+
export declare const fallbackSync: SyncChecker<AstNode>;
|
|
19
20
|
export declare const dispatchSync: SyncChecker<AstNode>;
|
|
20
21
|
export declare const resourceLocation: Checker<ResourceLocationNode>;
|
|
21
22
|
export declare const symbol: Checker<SymbolBaseNode>;
|
|
@@ -10,9 +10,7 @@ export function attempt(checker, node, ctx) {
|
|
|
10
10
|
// FIXME: await
|
|
11
11
|
checker(node, tempCtx);
|
|
12
12
|
StateProxy.undoChanges(node);
|
|
13
|
-
const totalErrorSpan = tempCtx.err.errors
|
|
14
|
-
.map((e) => e.range.end - e.range.start)
|
|
15
|
-
.reduce((a, b) => a + b, 0);
|
|
13
|
+
const totalErrorSpan = tempCtx.err.errors.map((e) => e.range.end - e.range.start).reduce((a, b) => a + b, 0);
|
|
16
14
|
return {
|
|
17
15
|
errorAmount: tempCtx.err.errors.length,
|
|
18
16
|
totalErrorSpan,
|
|
@@ -28,10 +26,7 @@ export function any(checkers) {
|
|
|
28
26
|
throw new Error('Expected at least one checker');
|
|
29
27
|
}
|
|
30
28
|
return (node, ctx) => {
|
|
31
|
-
const attempts = checkers
|
|
32
|
-
.map((checker) => attempt(checker, node, ctx))
|
|
33
|
-
.sort((a, b) => a.errorAmount - b.errorAmount ||
|
|
34
|
-
a.totalErrorSpan - b.totalErrorSpan);
|
|
29
|
+
const attempts = checkers.map((checker) => attempt(checker, node, ctx)).sort((a, b) => a.errorAmount - b.errorAmount || a.totalErrorSpan - b.totalErrorSpan);
|
|
35
30
|
attempts[0].updateNodeAndCtx();
|
|
36
31
|
};
|
|
37
32
|
}
|
|
@@ -53,6 +48,17 @@ export const fallback = async (node, ctx) => {
|
|
|
53
48
|
});
|
|
54
49
|
await Promise.all(promises);
|
|
55
50
|
};
|
|
51
|
+
export const fallbackSync = async (node, ctx) => {
|
|
52
|
+
const promises = [];
|
|
53
|
+
traversePreOrder(node, (node) => !ctx.meta.hasChecker(node.type), (node) => ctx.meta.hasChecker(node.type), (node) => {
|
|
54
|
+
const checker = ctx.meta.getChecker(node.type);
|
|
55
|
+
const result = checker(node, ctx);
|
|
56
|
+
if (result instanceof Promise) {
|
|
57
|
+
ctx.logger.warn(`[fallbackSync] Trying to run async checker for "${node.type}"`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
await Promise.all(promises);
|
|
61
|
+
};
|
|
56
62
|
export const dispatchSync = (node, ctx) => {
|
|
57
63
|
for (const child of node.children ?? []) {
|
|
58
64
|
if (ctx.meta.hasChecker(child.type)) {
|
|
@@ -17,7 +17,7 @@ export declare namespace ColorToken {
|
|
|
17
17
|
*/
|
|
18
18
|
function fillGap(tokens: readonly ColorToken[], targetRange: Range, type: ColorTokenType, modifiers?: ColorTokenModifier[]): ColorToken[];
|
|
19
19
|
}
|
|
20
|
-
export declare const ColorTokenTypes: readonly ["comment", "enum", "enumMember", "function", "keyword", "modifier", "number", "
|
|
20
|
+
export declare const ColorTokenTypes: readonly ["comment", "enum", "enumMember", "function", "keyword", "modifier", "number", "property", "string", "struct", "type", "variable", "error", "literal", "operator", "resourceLocation", "vector"];
|
|
21
21
|
export type ColorTokenType = typeof ColorTokenTypes[number];
|
|
22
22
|
export declare const ColorTokenModifiers: readonly ["declaration", "defaultLibrary", "definition", "deprecated", "documentation", "modification", "readonly"];
|
|
23
23
|
export type ColorTokenModifier = typeof ColorTokenModifiers[number];
|
|
@@ -3,11 +3,7 @@ export var ColorToken;
|
|
|
3
3
|
(function (ColorToken) {
|
|
4
4
|
/* istanbul ignore next */
|
|
5
5
|
function create(range, type, modifiers) {
|
|
6
|
-
return {
|
|
7
|
-
range: Range.get(range),
|
|
8
|
-
type,
|
|
9
|
-
modifiers,
|
|
10
|
-
};
|
|
6
|
+
return { range: Range.get(range), type, modifiers };
|
|
11
7
|
}
|
|
12
8
|
ColorToken.create = create;
|
|
13
9
|
/**
|
|
@@ -32,6 +28,9 @@ export var ColorToken;
|
|
|
32
28
|
ColorToken.fillGap = fillGap;
|
|
33
29
|
})(ColorToken || (ColorToken = {}));
|
|
34
30
|
// Built-in LSP semantic tokens: https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocument_semanticTokens
|
|
31
|
+
/*
|
|
32
|
+
* Hint: during development, the `Developer: Inspect Editor Tokens and Scopes` command in VS Code helps a lot with deciding on the color for nodes.
|
|
33
|
+
*/
|
|
35
34
|
export const ColorTokenTypes = Object.freeze([
|
|
36
35
|
'comment',
|
|
37
36
|
'enum',
|
|
@@ -40,12 +39,10 @@ export const ColorTokenTypes = Object.freeze([
|
|
|
40
39
|
'keyword',
|
|
41
40
|
'modifier',
|
|
42
41
|
'number',
|
|
43
|
-
'operator',
|
|
44
42
|
'property',
|
|
45
43
|
'string',
|
|
46
44
|
'struct',
|
|
47
45
|
'type',
|
|
48
|
-
'type',
|
|
49
46
|
'variable',
|
|
50
47
|
// Below are custom types.
|
|
51
48
|
'error',
|
|
@@ -6,8 +6,8 @@ import { ColorToken } from './Colorizer.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export const fallback = (node, ctx) => {
|
|
8
8
|
const ans = [];
|
|
9
|
-
traversePreOrder(node, (node) => !ctx.meta.hasColorizer(node.type)
|
|
10
|
-
(!ctx.range || Range.intersects(node.range, ctx.range)), (node) => ctx.meta.hasColorizer(node.type), (node) => {
|
|
9
|
+
traversePreOrder(node, (node) => !ctx.meta.hasColorizer(node.type)
|
|
10
|
+
&& (!ctx.range || Range.intersects(node.range, ctx.range)), (node) => ctx.meta.hasColorizer(node.type), (node) => {
|
|
11
11
|
const colorizer = ctx.meta.getColorizer(node.type);
|
|
12
12
|
const result = colorizer(node, ctx);
|
|
13
13
|
ans.push(...result);
|
|
@@ -51,9 +51,7 @@ export class InsertTextBuilder {
|
|
|
51
51
|
this.#ans += `$\{${this.#nextPlaceholder}:${CompletionItem.escape(defaultValues[0])}}`;
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
this.#ans += `$\{${this.#nextPlaceholder}|${defaultValues
|
|
55
|
-
.map((v) => v.replace(/([\\$},|])/g, '\\$1'))
|
|
56
|
-
.join(',')}|}`;
|
|
54
|
+
this.#ans += `$\{${this.#nextPlaceholder}|${defaultValues.map((v) => v.replace(/([\\$},|])/g, '\\$1')).join(',')}|}`;
|
|
57
55
|
}
|
|
58
56
|
this.#nextPlaceholder += 1;
|
|
59
57
|
return this;
|