@spyglassmc/core 0.4.5 → 0.4.7

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 +4 -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 +9 -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 +70 -24
  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 +73 -49
  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
@@ -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;
@@ -1,6 +1,6 @@
1
1
  import type { DeepReadonly } from '../../common/index.js';
2
2
  import type { BooleanBaseNode } from '../../node/BooleanNode.js';
3
- import type { FileNode, LiteralBaseNode, PairNode, RecordBaseNode, ResourceLocationNode, StringBaseNode, SymbolBaseNode } from '../../node/index.js';
3
+ import type { FileNode, LiteralBaseNode, PairNode, Quote, RecordBaseNode, ResourceLocationNode, StringBaseNode, SymbolBaseNode } from '../../node/index.js';
4
4
  import { AstNode } from '../../node/index.js';
5
5
  import type { CompleterContext, MetaRegistry } from '../../service/index.js';
6
6
  import type { RangeLike } from '../../source/index.js';
@@ -20,11 +20,12 @@ export declare const literal: Completer<LiteralBaseNode>;
20
20
  export declare const noop: Completer<any>;
21
21
  interface RecordOptions<K extends AstNode, V extends AstNode, N extends RecordBaseNode<K, V>> {
22
22
  key: (record: DeepReadonly<N>, pair: DeepReadonly<PairNode<K, V>> | undefined, ctx: CompleterContext, range: RangeLike, insertValue: boolean, insertPairEnd: boolean, existingKeys: DeepReadonly<K>[]) => CompletionItem[];
23
- value: (record: DeepReadonly<N>, pair: DeepReadonly<PairNode<K, V>>, ctx: CompleterContext) => CompletionItem[];
23
+ value: (record: DeepReadonly<N>, pair: DeepReadonly<PairNode<K, V>>, ctx: CompleterContext, range: RangeLike) => CompletionItem[];
24
24
  }
25
25
  export declare function record<K extends AstNode, V extends AstNode, N extends RecordBaseNode<K, V>>(o: RecordOptions<K, V, N>): Completer<N>;
26
26
  export declare const resourceLocation: Completer<ResourceLocationNode>;
27
27
  export declare const string: Completer<StringBaseNode>;
28
+ export declare function escapeString(value: string, quote?: Quote): string;
28
29
  export declare const symbol: Completer<SymbolBaseNode>;
29
30
  export declare function registerCompleters(meta: MetaRegistry): void;
30
31
  export {};
@@ -3,6 +3,7 @@ import { ResourceLocation } from '../../common/index.js';
3
3
  import { AstNode } from '../../node/index.js';
4
4
  import { LinterConfigValue } from '../../service/index.js';
5
5
  import { Range } from '../../source/index.js';
6
+ import { SymbolUtil } from '../../symbol/index.js';
6
7
  import { CompletionItem } from './Completer.js';
7
8
  /**
8
9
  * Uses the shallowest selected node that has its own completer to provide the completion items.
@@ -43,10 +44,22 @@ export const literal = (node) => {
43
44
  ['resourceLocation', 17 /* CompletionKind.File */],
44
45
  ['variable', 6 /* CompletionKind.Variable */],
45
46
  ]).get(node.options.colorTokenType ?? 'keyword') ?? 14 /* CompletionKind.Keyword */;
46
- return (node.options.pool.map((v) => CompletionItem.create(v, node, { kind })) ??
47
- []);
47
+ return (node.options.pool.map((v) => CompletionItem.create(v, node, { kind })) ?? []);
48
48
  };
49
49
  export const noop = () => [];
50
+ const prefixed = (node, ctx) => {
51
+ const child = node.children.find(c => c.type !== 'literal');
52
+ if (!child) {
53
+ return [CompletionItem.create('!', node)];
54
+ }
55
+ const childItems = dispatch(child, ctx);
56
+ return childItems.map(item => ({
57
+ ...item,
58
+ label: node.prefix + item.label,
59
+ filterText: node.prefix + (item.filterText ?? item.label),
60
+ insertText: node.prefix + (item.insertText ?? item.label),
61
+ }));
62
+ };
50
63
  export function record(o) {
51
64
  return (node, ctx) => {
52
65
  if (!Range.contains(Range.translate(node, 1, -1), ctx.offset, true)) {
@@ -54,9 +67,7 @@ export function record(o) {
54
67
  }
55
68
  const completeKeys = (pair) => o.key(node, pair, ctx, pair?.key ?? ctx.offset, false, false, existingKeys);
56
69
  const completePairs = (pair) => o.key(node, pair, ctx, pair ?? ctx.offset, true, hasNextPair || !!pair?.end, existingKeys);
57
- const existingKeys = node.children
58
- .filter((n) => !!n.key)
59
- .map((n) => n.key);
70
+ const existingKeys = node.children.filter((n) => !!n.key).map((n) => n.key);
60
71
  const index = binarySearch(node.children, ctx.offset, (n, o) => n.end
61
72
  ? Range.compareOffset(Range.translate(n, 0, -1), o, true)
62
73
  : Range.compareOffset(n.range, o, true));
@@ -69,33 +80,35 @@ export function record(o) {
69
80
  if (!key && !sep && !value) {
70
81
  return completePairs(undefined);
71
82
  }
72
- if ((key && Range.contains(key, ctx.offset, true)) ||
73
- (sep && ctx.offset <= sep.start) ||
74
- (value && ctx.offset < value.range.start)) {
83
+ if ((key && Range.contains(key, ctx.offset, true)) || (sep && ctx.offset <= sep.start)) {
75
84
  // Selected key.
76
85
  if (!value || Range.isEmpty(value.range)) {
77
86
  return completePairs(pair);
78
87
  }
79
88
  return completeKeys(pair);
80
89
  }
81
- if ((value && Range.contains(value, ctx.offset, true)) ||
82
- (sep && ctx.offset >= sep.end) ||
83
- (key && ctx.offset > key.range.end)) {
90
+ if (value && ctx.offset < value.range.start) {
91
+ return o.value(node, pair, ctx, ctx.offset);
92
+ }
93
+ if ((value && Range.contains(value, ctx.offset, true))
94
+ || (sep && ctx.offset >= sep.end)
95
+ || (key && ctx.offset > key.range.end)) {
84
96
  // Selected value.
85
- return o.value(node, pair, ctx);
97
+ return o.value(node, pair, ctx, value ?? ctx.offset);
86
98
  }
87
99
  return [];
88
100
  };
89
101
  }
90
102
  export const resourceLocation = (node, ctx) => {
91
103
  const config = LinterConfigValue.destruct(ctx.config.lint.idOmitDefaultNamespace);
92
- const includeEmptyNamespace = !node.options.isPredicate &&
93
- node.namespace === '';
94
- const includeDefaultNamespace = node.options.isPredicate ||
95
- config?.ruleValue !== true;
96
- const excludeDefaultNamespace = !node.options.isPredicate &&
97
- config?.ruleValue !== false;
98
- const getPool = (category) => optimizePool(Object.keys(ctx.symbols.getVisibleSymbols(category, ctx.doc.uri)));
104
+ const includeEmptyNamespace = !node.options.requireCanonical && node.namespace === '';
105
+ const includeDefaultNamespace = node.options.requireCanonical || config?.ruleValue !== true;
106
+ const excludeDefaultNamespace = !node.options.requireCanonical && config?.ruleValue !== false;
107
+ const getPool = (category) => {
108
+ const symbols = ctx.symbols.getVisibleSymbols(category, ctx.doc.uri);
109
+ const declarations = Object.entries(symbols).flatMap(([key, symbol]) => SymbolUtil.isDeclared(symbol) ? [key] : []);
110
+ return optimizePool(declarations);
111
+ };
99
112
  const optimizePool = (pool) => {
100
113
  const defaultNsPrefix = `${ResourceLocation.DefaultNamespace}${ResourceLocation.NamespacePathSep}`;
101
114
  const defaultNsIds = [];
@@ -126,17 +139,39 @@ export const resourceLocation = (node, ctx) => {
126
139
  const pool = node.options.pool
127
140
  ? optimizePool(node.options.pool)
128
141
  : [
129
- ...getPool(node.options.category),
142
+ ...(!node.options.requireTag
143
+ ? getPool(node.options.category)
144
+ : []),
130
145
  ...(node.options.allowTag
131
146
  ? getPool(`tag/${node.options.category}`).map((v) => `${ResourceLocation.TagPrefix}${v}`)
132
147
  : []),
133
148
  ];
134
- return pool.map((v) => CompletionItem.create(v, node, { kind: 3 /* CompletionKind.Function */ }));
149
+ const items = pool.map((v) => CompletionItem.create(v, node, { kind: 3 /* CompletionKind.Function */ }));
150
+ if (node.options.category) {
151
+ const symbols = ctx.symbols.getVisibleSymbols(node.options.category, ctx.doc.uri);
152
+ const thisKey = Object.entries(symbols).flatMap(([key, symbol]) => {
153
+ if ((symbol.declaration?.[0] ?? symbol.definition?.[0])?.uri == ctx.doc.uri) {
154
+ return [key];
155
+ }
156
+ return [];
157
+ });
158
+ if (thisKey.length > 0) {
159
+ items.push(CompletionItem.create('THIS', node, {
160
+ kind: 15 /* CompletionKind.Snippet */,
161
+ insertText: thisKey[0],
162
+ detail: thisKey[0],
163
+ }));
164
+ }
165
+ }
166
+ return items;
135
167
  };
136
168
  export const string = (node, ctx) => {
137
169
  if (node.children?.length) {
138
- // FIXME: Escape quotes/slashes in the result. Note that `\`, `$`, and `}` have to be escaped due to TextMate syntax.
139
- return dispatch(node.children[0], ctx);
170
+ return dispatch(node.children[0], ctx).map(item => ({
171
+ ...item,
172
+ filterText: escapeString(item.filterText ?? item.label, node.quote),
173
+ insertText: escapeString(item.insertText ?? item.label, node.quote),
174
+ }));
140
175
  }
141
176
  if (node.options.quotes && node.value === '') {
142
177
  return node.options.quotes.map((q) => CompletionItem.create(`${q}${q}`, node, {
@@ -146,8 +181,18 @@ export const string = (node, ctx) => {
146
181
  }
147
182
  return [];
148
183
  };
184
+ export function escapeString(value, quote) {
185
+ if (!quote) {
186
+ return value;
187
+ }
188
+ return value.replaceAll('\\', '\\\\').replaceAll(quote, '\\"');
189
+ }
149
190
  export const symbol = (node, ctx) => {
150
- return Object.keys(ctx.symbols.query(ctx.doc, node.options.category, ...(node.options.parentPath ?? [])).visibleMembers).map((v) => CompletionItem.create(v, node, { kind: 6 /* CompletionKind.Variable */ }));
191
+ const path = node.options.parentPath ?? [];
192
+ const symbols = ctx.symbols.query(ctx.doc, node.options.category, ...path).visibleMembers;
193
+ return Object.entries(symbols)
194
+ .filter(([k, v]) => SymbolUtil.isDeclared(v))
195
+ .map(([k, v]) => CompletionItem.create(k, node, { kind: 6 /* CompletionKind.Variable */ }));
151
196
  };
152
197
  export function registerCompleters(meta) {
153
198
  meta.registerCompleter('boolean', boolean);
@@ -156,6 +201,7 @@ export function registerCompleters(meta) {
156
201
  meta.registerCompleter('integer', noop);
157
202
  meta.registerCompleter('long', noop);
158
203
  meta.registerCompleter('literal', literal);
204
+ meta.registerCompleter('prefixed', prefixed);
159
205
  meta.registerCompleter('resource_location', resourceLocation);
160
206
  meta.registerCompleter('string', string);
161
207
  meta.registerCompleter('symbol', symbol);
@@ -1,8 +1,6 @@
1
1
  export function formatterContextIndentation(ctx, additionalLevels = 0) {
2
2
  const total = ctx.indentLevel + additionalLevels;
3
- return ctx.insertSpaces
4
- ? ' '.repeat(total * ctx.tabSize)
5
- : '\t'.repeat(total);
3
+ return ctx.insertSpaces ? ' '.repeat(total * ctx.tabSize) : '\t'.repeat(total);
6
4
  }
7
5
  export function indentFormatter(ctx, additionalLevels = 1) {
8
6
  return {
@@ -3,11 +3,9 @@ export const fallback = (node) => {
3
3
  throw new Error(`No formatter registered for type ${node.type}`);
4
4
  };
5
5
  export const file = (node, ctx) => {
6
- return node.children
7
- .map((child) => {
6
+ return node.children.map((child) => {
8
7
  return ctx.meta.getFormatter(child.type)(child, ctx);
9
- })
10
- .join('');
8
+ }).join('');
11
9
  };
12
10
  export const boolean = (node) => {
13
11
  return node.value ? 'true' : 'false';
@@ -1,37 +1,24 @@
1
+ import { localeQuote, localize } from '@spyglassmc/locales';
1
2
  import { Arrayable, ResourceLocation } from '../../../common/index.js';
2
- import { SymbolLinterConfig as Config } from '../../../service/index.js';
3
- // import { localeQuote, localize } from '@spyglassmc/locales'
4
- // import type { DeepReadonly } from '../../../common/index.js'
5
- // import { Arrayable, ResourceLocation } from '../../../common/index.js'
6
- // import type { AstNode } from '../../../node/index.js'
7
- // import type { LinterContext } from '../../../service/index.js'
8
- // import { LinterSeverity, SymbolLinterConfig as Config } from '../../../service/index.js'
9
- // import type { Symbol } from '../../../symbol/index.js'
10
- // import { SymbolUtil, SymbolVisibility } from '../../../symbol/index.js'
11
- // import type { Linter } from '../Linter.js'
3
+ import { LinterSeverity, SymbolLinterConfig as Config } from '../../../service/index.js';
4
+ import { SymbolUtil } from '../../../symbol/index.js';
12
5
  export const undeclaredSymbol = (node, ctx) => {
13
- // if (!node.symbol || SymbolUtil.isDeclared(node.symbol)) {
14
- // return
15
- // }
16
- // const action = getAction(ctx.ruleValue as Config, node.symbol, ctx)
17
- // if (Config.Action.isDeclare(action)) {
18
- // ctx.symbols
19
- // .query({ doc: ctx.doc, node }, node.symbol.category, ...node.symbol.path)
20
- // .amend({
21
- // data: { visibility: getVisibility(action.declare) },
22
- // usage: { type: 'declaration', node },
23
- // })
24
- // }
25
- // if (Config.Action.isReport(action)) {
26
- // const severityOverride = action.report === 'inherit' ? undefined : LinterSeverity.toErrorSeverity(action.report)
27
- // ctx.err.lint(
28
- // localize('linter.undeclared-symbol.message',
29
- // node.symbol.category,
30
- // localeQuote(node.symbol.identifier)
31
- // ),
32
- // node, undefined, severityOverride
33
- // )
34
- // }
6
+ if (!node.symbol || SymbolUtil.isDeclared(node.symbol)) {
7
+ return;
8
+ }
9
+ const action = getAction(ctx.ruleValue, node.symbol, ctx);
10
+ if (Config.Action.isDeclare(action)) {
11
+ ctx.symbols.query({ doc: ctx.doc, node }, node.symbol.category, ...node.symbol.path).amend({
12
+ data: { visibility: getVisibility(action.declare) },
13
+ usage: { type: 'declaration', node },
14
+ });
15
+ }
16
+ if (Config.Action.isReport(action)) {
17
+ const severityOverride = action.report === 'inherit'
18
+ ? undefined
19
+ : LinterSeverity.toErrorSeverity(action.report);
20
+ ctx.err.lint(localize('linter.undeclared-symbol.message', node.symbol.category, localeQuote(node.symbol.identifier)), node, undefined, severityOverride);
21
+ }
35
22
  };
36
23
  function getAction(config, symbol, ctx) {
37
24
  if (Config.Action.is(config)) {
@@ -43,17 +30,17 @@ function getAction(config, symbol, ctx) {
43
30
  const namespace = resourceLocation.slice(0, resourceLocation.indexOf(ResourceLocation.NamespacePathSep));
44
31
  return ((condition.category
45
32
  ? Arrayable.toArray(condition.category).includes(symbol.category)
46
- : true) &&
47
- (condition.namespace
33
+ : true)
34
+ && (condition.namespace
48
35
  ? Arrayable.toArray(condition.namespace).includes(namespace)
49
- : true) &&
50
- (condition.excludeNamespace
36
+ : true)
37
+ && (condition.excludeNamespace
51
38
  ? !Arrayable.toArray(condition.excludeNamespace).includes(namespace)
52
- : true) &&
53
- (condition.pattern
39
+ : true)
40
+ && (condition.pattern
54
41
  ? Arrayable.toArray(condition.pattern).some((p) => new RegExp(p).test(symbol.identifier))
55
- : true) &&
56
- (condition.excludePattern
42
+ : true)
43
+ && (condition.excludePattern
57
44
  ? !Arrayable.toArray(condition.excludePattern).some((p) => new RegExp(p).test(symbol.identifier))
58
45
  : true));
59
46
  }
@@ -7,7 +7,7 @@ import type { Project } from './Project.js';
7
7
  * The format version of the cache. Should be increased when any changes that
8
8
  * could invalidate the cache are introduced to the Spyglass codebase.
9
9
  */
10
- export declare const LatestCacheVersion = 2;
10
+ export declare const LatestCacheVersion = 3;
11
11
  /**
12
12
  * Checksums of cached files or roots.
13
13
  */
@@ -5,15 +5,11 @@ import { fileUtil } from './fileUtil.js';
5
5
  * The format version of the cache. Should be increased when any changes that
6
6
  * could invalidate the cache are introduced to the Spyglass codebase.
7
7
  */
8
- export const LatestCacheVersion = 2;
8
+ export const LatestCacheVersion = 3;
9
9
  var Checksums;
10
10
  (function (Checksums) {
11
11
  function create() {
12
- return {
13
- files: {},
14
- roots: {},
15
- symbolRegistrars: {},
16
- };
12
+ return { files: {}, roots: {}, symbolRegistrars: {} };
17
13
  }
18
14
  Checksums.create = create;
19
15
  })(Checksums || (Checksums = {}));
@@ -36,8 +32,7 @@ export class CacheService {
36
32
  }
37
33
  try {
38
34
  // TODO: Don't update this for every single change.
39
- this.checksums.files[doc.uri] = await this.project.externals.crypto
40
- .getSha1(doc.getText());
35
+ this.checksums.files[doc.uri] = await this.project.externals.crypto.getSha1(doc.getText());
41
36
  }
42
37
  catch (e) {
43
38
  if (!this.project.externals.error.isKind(e, 'EISDIR')) {
@@ -128,7 +123,11 @@ export class CacheService {
128
123
  }
129
124
  }
130
125
  for (const [uri, checksum] of Object.entries(this.checksums.files)) {
131
- if (unchangedRoots.some((root) => uri.startsWith(root))) {
126
+ if (unchangedRoots.some((root) => fileUtil.isSubUriOf(uri, root))) {
127
+ ans.unchangedFiles.push(uri);
128
+ continue;
129
+ }
130
+ if (this.project.ignore.ignores(uri)) {
132
131
  ans.unchangedFiles.push(uri);
133
132
  continue;
134
133
  }
@@ -142,8 +141,8 @@ export class CacheService {
142
141
  }
143
142
  }
144
143
  catch (e) {
145
- if (this.project.externals.error.isKind(e, 'ENOENT') ||
146
- this.project.externals.error.isKind(e, 'EISDIR')) {
144
+ if (this.project.externals.error.isKind(e, 'ENOENT')
145
+ || this.project.externals.error.isKind(e, 'EISDIR')) {
147
146
  ans.removedFiles.push(uri);
148
147
  }
149
148
  else {
@@ -187,8 +186,8 @@ export class CacheService {
187
186
  return false;
188
187
  }
189
188
  async hasFileChangedSinceCache(doc) {
190
- return (this.checksums.files[doc.uri] !==
191
- (await this.project.externals.crypto.getSha1(doc.getText())));
189
+ return (this.checksums.files[doc.uri]
190
+ !== (await this.project.externals.crypto.getSha1(doc.getText())));
192
191
  }
193
192
  reset() {
194
193
  this.#hasValidatedFiles = false;
@@ -21,6 +21,28 @@ export interface Config {
21
21
  */
22
22
  snippet: SnippetsConfig;
23
23
  }
24
+ export interface CustomResourceConfig {
25
+ /**
26
+ * The entry you have dispatched from mcdoc. (eg. `picoblaze:game_event`)
27
+ */
28
+ category: string;
29
+ /**
30
+ * The file extension name of the dispatched resource. Only `.json` is supported for now.
31
+ */
32
+ ext?: '.json';
33
+ /**
34
+ * The pack type of the dispatched resource. Only `data` is supported for now.
35
+ */
36
+ pack?: 'data';
37
+ /**
38
+ * The first minecraft version the dispatched resource is available in.
39
+ */
40
+ since?: `1.${number}`;
41
+ /**
42
+ * The first minecraft version the dispatched resource is no longer available in.
43
+ */
44
+ until?: `1.${number}`;
45
+ }
24
46
  export interface EnvConfig {
25
47
  /**
26
48
  * Where to download data like `mcmeta` or `vanilla-mcdoc` from (case-insensitive).
@@ -36,6 +58,20 @@ export interface EnvConfig {
36
58
  * to a data pack folder or data pack archive (e.g. `.zip` or `.tar.gz`), or a special string like `@vanilla-mcdoc`.
37
59
  */
38
60
  dependencies: string[];
61
+ /**
62
+ * A list of file patterns to exclude. Each value in this array can either be a glob pattern or the special string `@gitignore`.
63
+ */
64
+ exclude: string[];
65
+ /**
66
+ * **Experimental feature, breaking changes could occur.**
67
+ *
68
+ * Track changes at [issue #1254](https://github.com/SpyglassMC/Spyglass/issues/1254).
69
+ *
70
+ * Custom resources, currently only works for `minecraft:resource` JSON definitions dispatched from mcdoc.
71
+ */
72
+ customResources: {
73
+ [path: string]: CustomResourceConfig;
74
+ };
39
75
  feature: {
40
76
  codeActions: boolean;
41
77
  colors: boolean;
@@ -4,10 +4,10 @@ import { FileCategories, RegistryCategories } from '../symbol/index.js';
4
4
  export var LinterSeverity;
5
5
  (function (LinterSeverity) {
6
6
  function is(value) {
7
- return (value === 'hint' ||
8
- value === 'information' ||
9
- value === 'warning' ||
10
- value === 'error');
7
+ return (value === 'hint'
8
+ || value === 'information'
9
+ || value === 'warning'
10
+ || value === 'error');
11
11
  }
12
12
  LinterSeverity.is = is;
13
13
  function toErrorSeverity(value) {
@@ -31,21 +31,12 @@ export var LinterConfigValue;
31
31
  return undefined;
32
32
  }
33
33
  if (LinterSeverity.is(value)) {
34
- return {
35
- ruleSeverity: LinterSeverity.toErrorSeverity(value),
36
- ruleValue: true,
37
- };
34
+ return { ruleSeverity: LinterSeverity.toErrorSeverity(value), ruleValue: true };
38
35
  }
39
36
  if (Array.isArray(value) && LinterSeverity.is(value[0])) {
40
- return {
41
- ruleSeverity: LinterSeverity.toErrorSeverity(value[0]),
42
- ruleValue: value[1],
43
- };
37
+ return { ruleSeverity: LinterSeverity.toErrorSeverity(value[0]), ruleValue: value[1] };
44
38
  }
45
- return {
46
- ruleSeverity: 2 /* ErrorSeverity.Warning */,
47
- ruleValue: value,
48
- };
39
+ return { ruleSeverity: 2 /* ErrorSeverity.Warning */, ruleValue: value };
49
40
  }
50
41
  LinterConfigValue.destruct = destruct;
51
42
  })(LinterConfigValue || (LinterConfigValue = {}));
@@ -62,10 +53,9 @@ export var SymbolLinterConfig;
62
53
  return false;
63
54
  }
64
55
  const value = v;
65
- return ((value.if === undefined || Arrayable.is(value.if, Condition.is)) &&
66
- (value.then === undefined || Action.is(value.then)) &&
67
- (value.override === undefined ||
68
- Arrayable.is(value.override, Complex.is)));
56
+ return ((value.if === undefined || Arrayable.is(value.if, Condition.is))
57
+ && (value.then === undefined || Action.is(value.then))
58
+ && (value.override === undefined || Arrayable.is(value.override, Complex.is)));
69
59
  }
70
60
  Complex.is = is;
71
61
  })(Complex = SymbolLinterConfig.Complex || (SymbolLinterConfig.Complex = {}));
@@ -76,29 +66,28 @@ export var SymbolLinterConfig;
76
66
  return false;
77
67
  }
78
68
  const value = v;
79
- return ((value.category === undefined ||
80
- Arrayable.is(value.category, TypePredicates.isString)) &&
81
- (value.pattern === undefined ||
82
- Arrayable.is(value.pattern, TypePredicates.isString)) &&
83
- (value.excludePattern === undefined ||
84
- Arrayable.is(value.excludePattern, TypePredicates.isString)) &&
85
- (value.namespace === undefined ||
86
- Arrayable.is(value.namespace, TypePredicates.isString)) &&
87
- (value.excludeNamespace === undefined ||
88
- Arrayable.is(value.excludeNamespace, TypePredicates.isString)));
69
+ return ((value.category === undefined
70
+ || Arrayable.is(value.category, TypePredicates.isString))
71
+ && (value.pattern === undefined || Arrayable.is(value.pattern, TypePredicates.isString))
72
+ && (value.excludePattern === undefined
73
+ || Arrayable.is(value.excludePattern, TypePredicates.isString))
74
+ && (value.namespace === undefined
75
+ || Arrayable.is(value.namespace, TypePredicates.isString))
76
+ && (value.excludeNamespace === undefined
77
+ || Arrayable.is(value.excludeNamespace, TypePredicates.isString)));
89
78
  }
90
79
  Condition.is = is;
91
80
  })(Condition = SymbolLinterConfig.Condition || (SymbolLinterConfig.Condition = {}));
92
81
  let Action;
93
82
  (function (Action) {
94
83
  function isDeclare(value) {
95
- return (value !== undefined &&
96
- ['block', 'file', 'public'].includes(value.declare));
84
+ return (value !== undefined
85
+ && ['block', 'file', 'public'].includes(value.declare));
97
86
  }
98
87
  Action.isDeclare = isDeclare;
99
88
  function isReport(value) {
100
- return (value !== undefined &&
101
- ['inherit', 'hint', 'information', 'warning', 'error'].includes(value.report));
89
+ return (value !== undefined
90
+ && ['inherit', 'hint', 'information', 'warning', 'error'].includes(value.report));
102
91
  }
103
92
  Action.isReport = isReport;
104
93
  function is(v) {
@@ -117,10 +106,9 @@ export var SymbolLinterConfig;
117
106
  export const VanillaConfig = {
118
107
  env: {
119
108
  dataSource: 'GitHub',
120
- dependencies: [
121
- '@vanilla-datapack',
122
- '@vanilla-mcdoc',
123
- ],
109
+ dependencies: ['@vanilla-datapack', '@vanilla-mcdoc'],
110
+ exclude: ['@gitignore', '.vscode/', '.github/'],
111
+ customResources: {},
124
112
  feature: {
125
113
  codeActions: true,
126
114
  colors: true,
@@ -204,9 +192,7 @@ export const VanillaConfig = {
204
192
  {
205
193
  if: [
206
194
  { category: RegistryCategories, namespace: 'minecraft' },
207
- {
208
- category: [...FileCategories, 'bossbar', 'objective', 'team'],
209
- },
195
+ { category: [...FileCategories, 'bossbar', 'objective', 'team'] },
210
196
  ],
211
197
  then: { report: 'warning' },
212
198
  },
@@ -223,10 +209,7 @@ export const VanillaConfig = {
223
209
  export class ConfigService {
224
210
  project;
225
211
  defaultConfig;
226
- static ConfigFileNames = Object.freeze([
227
- 'spyglass.json',
228
- '.spyglassrc.json',
229
- ]);
212
+ static ConfigFileNames = Object.freeze(['spyglass.json', '.spyglassrc.json']);
230
213
  #eventEmitter;
231
214
  constructor(project, defaultConfig = VanillaConfig) {
232
215
  this.project = project;
@@ -13,6 +13,7 @@ import type { ProfilerFactory } from './Profiler.js';
13
13
  import type { ProjectData } from './Project.js';
14
14
  export interface ContextBase {
15
15
  fs: FileService;
16
+ isDebugging: boolean;
16
17
  logger: Logger;
17
18
  meta: MetaRegistry;
18
19
  profilers: ProfilerFactory;
@@ -137,6 +138,7 @@ export declare namespace SignatureHelpProviderContext {
137
138
  function create(project: ProjectData, opts: SignatureHelpProviderContextOptions): SignatureHelpProviderContext;
138
139
  }
139
140
  export interface UriBinderContext extends ContextBase {
141
+ config: Config;
140
142
  symbols: SymbolUtil;
141
143
  }
142
144
  export declare namespace UriBinderContext {
@@ -7,6 +7,7 @@ export var ContextBase;
7
7
  function create(project) {
8
8
  return {
9
9
  fs: project.fs,
10
+ isDebugging: project.isDebugging,
10
11
  logger: project.logger,
11
12
  meta: project.meta,
12
13
  profilers: project.profilers,
@@ -44,20 +45,14 @@ export var ProcessorContext;
44
45
  var ProcessorWithRangeContext;
45
46
  (function (ProcessorWithRangeContext) {
46
47
  function create(project, opts) {
47
- return {
48
- ...ProcessorContext.create(project, opts),
49
- range: opts.range,
50
- };
48
+ return { ...ProcessorContext.create(project, opts), range: opts.range };
51
49
  }
52
50
  ProcessorWithRangeContext.create = create;
53
51
  })(ProcessorWithRangeContext || (ProcessorWithRangeContext = {}));
54
52
  var ProcessorWithOffsetContext;
55
53
  (function (ProcessorWithOffsetContext) {
56
54
  function create(project, opts) {
57
- return {
58
- ...ProcessorContext.create(project, opts),
59
- offset: opts.offset,
60
- };
55
+ return { ...ProcessorContext.create(project, opts), offset: opts.offset };
61
56
  }
62
57
  ProcessorWithOffsetContext.create = create;
63
58
  })(ProcessorWithOffsetContext || (ProcessorWithOffsetContext = {}));
@@ -137,10 +132,7 @@ export var SignatureHelpProviderContext;
137
132
  export var UriBinderContext;
138
133
  (function (UriBinderContext) {
139
134
  function create(project) {
140
- return {
141
- ...ContextBase.create(project),
142
- symbols: project.symbols,
143
- };
135
+ return { ...ContextBase.create(project), config: project.config, symbols: project.symbols };
144
136
  }
145
137
  UriBinderContext.create = create;
146
138
  })(UriBinderContext || (UriBinderContext = {}));
@@ -31,6 +31,9 @@ interface Job<R> {
31
31
  };
32
32
  transformer: (data: Uint8Array) => PromiseLike<R> | R;
33
33
  options?: ExternalDownloaderOptions;
34
+ /**
35
+ * If set, caches the result in memory. Time in milliseconds.
36
+ */
34
37
  ttl?: number;
35
38
  }
36
39
  export {};