@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.
Files changed (91) hide show
  1. package/lib/common/Dev.js +2 -5
  2. package/lib/common/ReadonlyProxy.js +1 -3
  3. package/lib/common/StateProxy.js +2 -8
  4. package/lib/common/externals/BrowserExternals.js +7 -12
  5. package/lib/common/externals/NodeJsExternals.js +12 -8
  6. package/lib/common/externals/index.d.ts +8 -1
  7. package/lib/common/util.js +3 -10
  8. package/lib/node/AstNode.js +7 -9
  9. package/lib/node/BooleanNode.js +1 -4
  10. package/lib/node/FloatNode.js +1 -5
  11. package/lib/node/IntegerNode.js +1 -5
  12. package/lib/node/ListNode.d.ts +1 -1
  13. package/lib/node/LiteralNode.js +1 -6
  14. package/lib/node/LongNode.js +1 -5
  15. package/lib/node/PrefixedNode.d.ts +13 -0
  16. package/lib/node/PrefixedNode.js +22 -0
  17. package/lib/node/ResourceLocationNode.d.ts +1 -1
  18. package/lib/node/ResourceLocationNode.js +2 -8
  19. package/lib/node/StringNode.d.ts +2 -1
  20. package/lib/node/StringNode.js +1 -4
  21. package/lib/node/SymbolNode.js +1 -6
  22. package/lib/node/index.d.ts +1 -0
  23. package/lib/node/index.js +1 -0
  24. package/lib/parser/comment.d.ts +1 -1
  25. package/lib/parser/comment.js +2 -6
  26. package/lib/parser/error.js +1 -4
  27. package/lib/parser/file.d.ts +2 -2
  28. package/lib/parser/file.js +1 -2
  29. package/lib/parser/float.js +2 -7
  30. package/lib/parser/index.d.ts +1 -0
  31. package/lib/parser/index.js +1 -0
  32. package/lib/parser/integer.js +3 -7
  33. package/lib/parser/list.d.ts +1 -1
  34. package/lib/parser/list.js +2 -6
  35. package/lib/parser/literal.js +2 -9
  36. package/lib/parser/long.js +2 -7
  37. package/lib/parser/prefixed.d.ts +8 -0
  38. package/lib/parser/prefixed.js +23 -0
  39. package/lib/parser/record.d.ts +1 -1
  40. package/lib/parser/record.js +11 -17
  41. package/lib/parser/resourceLocation.d.ts +1 -0
  42. package/lib/parser/resourceLocation.js +6 -4
  43. package/lib/parser/string.js +6 -9
  44. package/lib/parser/util.d.ts +14 -3
  45. package/lib/parser/util.js +48 -26
  46. package/lib/processor/ColorInfoProvider.js +8 -25
  47. package/lib/processor/binder/builtin.d.ts +1 -0
  48. package/lib/processor/binder/builtin.js +20 -30
  49. package/lib/processor/checker/builtin.d.ts +1 -0
  50. package/lib/processor/checker/builtin.js +13 -7
  51. package/lib/processor/colorizer/Colorizer.d.ts +1 -1
  52. package/lib/processor/colorizer/Colorizer.js +4 -7
  53. package/lib/processor/colorizer/builtin.js +2 -2
  54. package/lib/processor/completer/Completer.js +1 -3
  55. package/lib/processor/completer/builtin.d.ts +3 -2
  56. package/lib/processor/completer/builtin.js +67 -23
  57. package/lib/processor/formatter/Formatter.js +1 -3
  58. package/lib/processor/formatter/builtin.js +2 -4
  59. package/lib/processor/linter/builtin/undeclaredSymbol.js +27 -40
  60. package/lib/service/CacheService.d.ts +1 -1
  61. package/lib/service/CacheService.js +12 -13
  62. package/lib/service/Config.d.ts +36 -0
  63. package/lib/service/Config.js +28 -45
  64. package/lib/service/Context.d.ts +2 -0
  65. package/lib/service/Context.js +4 -12
  66. package/lib/service/Downloader.d.ts +3 -0
  67. package/lib/service/Downloader.js +9 -3
  68. package/lib/service/ErrorReporter.js +3 -0
  69. package/lib/service/FileService.js +10 -29
  70. package/lib/service/Hover.js +1 -4
  71. package/lib/service/MetaRegistry.d.ts +4 -2
  72. package/lib/service/MetaRegistry.js +16 -8
  73. package/lib/service/Project.d.ts +9 -3
  74. package/lib/service/Project.js +71 -48
  75. package/lib/service/Service.d.ts +1 -1
  76. package/lib/service/Service.js +11 -36
  77. package/lib/service/SymbolLocations.js +1 -4
  78. package/lib/service/fileUtil.d.ts +7 -0
  79. package/lib/service/fileUtil.js +29 -4
  80. package/lib/source/IndexMap.js +1 -4
  81. package/lib/source/Location.js +3 -9
  82. package/lib/source/Position.js +1 -2
  83. package/lib/source/PositionRange.js +2 -2
  84. package/lib/source/Range.js +9 -21
  85. package/lib/source/Source.d.ts +11 -1
  86. package/lib/source/Source.js +31 -5
  87. package/lib/symbol/Symbol.d.ts +14 -9
  88. package/lib/symbol/Symbol.js +80 -61
  89. package/lib/symbol/SymbolUtil.d.ts +3 -3
  90. package/lib/symbol/SymbolUtil.js +48 -72
  91. package/package.json +3 -2
@@ -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
@@ -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, }: Options<K, V>): InfallibleParser<RecordNode<K, V>>;
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
@@ -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, } = attempt(pair.key, src, ctx);
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, } = attempt(valueParser, src, ctx);
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 LegalCharacters = new Set([
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) => !LegalCharacters.has(c)),
92
- ...[...rawPath].filter((c) => c !== '/' && !LegalCharacters.has(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.isPredicate) {
103
+ if (!ans.namespace && options.requireCanonical) {
102
104
  ctx.err.report(localize('parser.resource-location.namespace-expected'), ans);
103
105
  }
104
106
  }
@@ -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 */
@@ -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, Source } from '../source/index.js';
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>, ...teminators: (string | readonly string[])[]): InfallibleParser<N>;
145
- export declare function stopBefore<N extends Returnable>(parser: Parser<N>, ...teminators: (string | readonly string[])[]): 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
  */
@@ -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, ...teminators) {
202
- const flatTerminators = teminators.flat();
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
- ((color[1] * 255) << 16) +
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
- color[2] * 255)
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)))).sort(attemptSorter);
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
- .query(ctx.doc, node.isTag
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", "operator", "property", "string", "struct", "type", "type", "variable", "error", "literal", "operator", "resourceLocation", "vector"];
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;