@spyglassmc/core 0.3.0 → 0.4.1

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 (64) hide show
  1. package/lib/common/Dev.js +5 -2
  2. package/lib/common/Operations.js +7 -3
  3. package/lib/common/ReadonlyProxy.js +3 -1
  4. package/lib/common/StateProxy.js +18 -7
  5. package/lib/common/externals/BrowserExternals.js +2 -9
  6. package/lib/common/externals/NodeJsExternals.js +7 -17
  7. package/lib/common/externals/index.d.ts +0 -3
  8. package/lib/common/util.d.ts +1 -0
  9. package/lib/common/util.js +14 -10
  10. package/lib/node/AstNode.js +6 -4
  11. package/lib/node/FileNode.js +6 -1
  12. package/lib/node/ResourceLocationNode.d.ts +2 -2
  13. package/lib/node/ResourceLocationNode.js +11 -5
  14. package/lib/parser/boolean.js +1 -1
  15. package/lib/parser/comment.d.ts +1 -1
  16. package/lib/parser/comment.js +1 -1
  17. package/lib/parser/float.js +2 -1
  18. package/lib/parser/integer.js +2 -1
  19. package/lib/parser/list.d.ts +1 -1
  20. package/lib/parser/list.js +3 -3
  21. package/lib/parser/long.js +2 -1
  22. package/lib/parser/record.d.ts +1 -1
  23. package/lib/parser/record.js +18 -8
  24. package/lib/parser/resourceLocation.js +61 -8
  25. package/lib/parser/string.js +75 -7
  26. package/lib/parser/util.d.ts +1 -0
  27. package/lib/parser/util.js +8 -4
  28. package/lib/processor/ColorInfoProvider.js +20 -7
  29. package/lib/processor/binder/builtin.js +27 -17
  30. package/lib/processor/checker/builtin.d.ts +1 -2
  31. package/lib/processor/checker/builtin.js +10 -12
  32. package/lib/processor/colorizer/builtin.js +10 -8
  33. package/lib/processor/completer/Completer.js +4 -2
  34. package/lib/processor/completer/builtin.js +26 -23
  35. package/lib/processor/formatter/builtin.js +14 -12
  36. package/lib/processor/linter/builtin/undeclaredSymbol.js +47 -24
  37. package/lib/processor/linter/builtin.js +7 -8
  38. package/lib/service/CacheService.d.ts +5 -2
  39. package/lib/service/CacheService.js +21 -9
  40. package/lib/service/Config.d.ts +2 -2
  41. package/lib/service/Config.js +23 -19
  42. package/lib/service/Downloader.js +12 -7
  43. package/lib/service/FileService.js +22 -8
  44. package/lib/service/MetaRegistry.d.ts +5 -0
  45. package/lib/service/MetaRegistry.js +7 -6
  46. package/lib/service/Profiler.js +10 -5
  47. package/lib/service/Project.d.ts +9 -7
  48. package/lib/service/Project.js +62 -36
  49. package/lib/service/Service.js +19 -9
  50. package/lib/service/fileUtil.js +2 -1
  51. package/lib/source/IndexMap.js +1 -1
  52. package/lib/source/LanguageError.d.ts +18 -4
  53. package/lib/source/LanguageError.js +16 -6
  54. package/lib/source/Location.js +4 -1
  55. package/lib/source/PositionRange.d.ts +1 -1
  56. package/lib/source/PositionRange.js +4 -4
  57. package/lib/source/Range.js +6 -3
  58. package/lib/source/Source.d.ts +2 -0
  59. package/lib/source/Source.js +9 -1
  60. package/lib/symbol/Symbol.d.ts +7 -7
  61. package/lib/symbol/Symbol.js +22 -9
  62. package/lib/symbol/SymbolUtil.d.ts +2 -2
  63. package/lib/symbol/SymbolUtil.js +74 -43
  64. package/package.json +2 -2
@@ -1,24 +1,37 @@
1
- import { localeQuote, localize } from '@spyglassmc/locales';
2
1
  import { Arrayable, ResourceLocation } from '../../../common/index.js';
3
- import { LinterSeverity, SymbolLinterConfig as Config } from '../../../service/index.js';
4
- import { SymbolUtil } from '../../../symbol/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'
5
12
  export const undeclaredSymbol = (node, ctx) => {
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
12
- .query({ doc: ctx.doc, node }, node.symbol.category, ...node.symbol.path)
13
- .amend({
14
- data: { visibility: getVisibility(action.declare) },
15
- usage: { type: 'declaration', node },
16
- });
17
- }
18
- if (Config.Action.isReport(action)) {
19
- const severityOverride = action.report === 'inherit' ? undefined : LinterSeverity.toErrorSeverity(action.report);
20
- ctx.err.lint(localize('linter.undeclared-symbol.message', node.symbol.category, localeQuote(node.symbol.identifier)), node, undefined, severityOverride);
21
- }
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
+ // }
22
35
  };
23
36
  function getAction(config, symbol, ctx) {
24
37
  if (Config.Action.is(config)) {
@@ -28,11 +41,21 @@ function getAction(config, symbol, ctx) {
28
41
  function testSingleCondition(condition) {
29
42
  const resourceLocation = ResourceLocation.lengthen(symbol.identifier);
30
43
  const namespace = resourceLocation.slice(0, resourceLocation.indexOf(ResourceLocation.NamespacePathSep));
31
- return ((condition.category ? Arrayable.toArray(condition.category).includes(symbol.category) : true) &&
32
- (condition.namespace ? Arrayable.toArray(condition.namespace).includes(namespace) : true) &&
33
- (condition.excludeNamespace ? !Arrayable.toArray(condition.excludeNamespace).includes(namespace) : true) &&
34
- (condition.pattern ? Arrayable.toArray(condition.pattern).some(p => new RegExp(p).test(symbol.identifier)) : true) &&
35
- (condition.excludePattern ? !Arrayable.toArray(condition.excludePattern).some(p => new RegExp(p).test(symbol.identifier)) : true));
44
+ return ((condition.category
45
+ ? Arrayable.toArray(condition.category).includes(symbol.category)
46
+ : true) &&
47
+ (condition.namespace
48
+ ? Arrayable.toArray(condition.namespace).includes(namespace)
49
+ : true) &&
50
+ (condition.excludeNamespace
51
+ ? !Arrayable.toArray(condition.excludeNamespace).includes(namespace)
52
+ : true) &&
53
+ (condition.pattern
54
+ ? Arrayable.toArray(condition.pattern).some((p) => new RegExp(p).test(symbol.identifier))
55
+ : true) &&
56
+ (condition.excludePattern
57
+ ? !Arrayable.toArray(condition.excludePattern).some((p) => new RegExp(p).test(symbol.identifier))
58
+ : true));
36
59
  }
37
60
  try {
38
61
  return Arrayable.toArray(conditions).some(testSingleCondition);
@@ -28,7 +28,7 @@ export function nameConvention(key) {
28
28
  export const quote = (node, ctx) => {
29
29
  const config = ctx.ruleValue;
30
30
  const mustValueBeQuoted = node.options.unquotable
31
- ? [...node.value].some(c => !isAllowedCharacter(c, node.options.unquotable))
31
+ ? [...node.value].some((c) => !isAllowedCharacter(c, node.options.unquotable))
32
32
  : true;
33
33
  const isQuoteRequired = config.always || mustValueBeQuoted;
34
34
  const isQuoteProhibited = config.always === false && !mustValueBeQuoted;
@@ -66,8 +66,7 @@ export var configValidator;
66
66
  new RegExp(val);
67
67
  }
68
68
  catch (e) {
69
- logger.error(wrapError(name, localize('') // FIXME
70
- ), e);
69
+ logger.error(wrapError(name, localize('')), e);
71
70
  return false;
72
71
  }
73
72
  return true;
@@ -82,27 +81,27 @@ export function registerLinters(meta) {
82
81
  meta.registerLinter('nameOfObjective', {
83
82
  configValidator: configValidator.nameConvention,
84
83
  linter: nameConvention('value'),
85
- nodePredicate: n => n.symbol && n.symbol.category === 'objective',
84
+ nodePredicate: (n) => n.symbol && n.symbol.category === 'objective',
86
85
  });
87
86
  meta.registerLinter('nameOfScoreHolder', {
88
87
  configValidator: configValidator.nameConvention,
89
88
  linter: nameConvention('value'),
90
- nodePredicate: n => n.symbol && n.symbol.category === 'score_holder',
89
+ nodePredicate: (n) => n.symbol && n.symbol.category === 'score_holder',
91
90
  });
92
91
  meta.registerLinter('nameOfTag', {
93
92
  configValidator: configValidator.nameConvention,
94
93
  linter: nameConvention('value'),
95
- nodePredicate: n => n.symbol && n.symbol.category === 'tag',
94
+ nodePredicate: (n) => n.symbol && n.symbol.category === 'tag',
96
95
  });
97
96
  meta.registerLinter('nameOfTeam', {
98
97
  configValidator: configValidator.nameConvention,
99
98
  linter: nameConvention('value'),
100
- nodePredicate: n => n.symbol && n.symbol.category === 'team',
99
+ nodePredicate: (n) => n.symbol && n.symbol.category === 'team',
101
100
  });
102
101
  meta.registerLinter('undeclaredSymbol', {
103
102
  configValidator: configValidator.symbolLinterConfig,
104
103
  linter: undeclaredSymbol,
105
- nodePredicate: n => n.symbol && !McdocCategories.includes(n.symbol.category),
104
+ nodePredicate: (n) => n.symbol && !McdocCategories.includes(n.symbol.category),
106
105
  });
107
106
  }
108
107
  //# sourceMappingURL=builtin.js.map
@@ -1,4 +1,5 @@
1
1
  import type { TextDocument } from 'vscode-languageserver-textdocument';
2
+ import type { PosRangeLanguageError } from '../source/index.js';
2
3
  import { SymbolTable } from '../symbol/index.js';
3
4
  import type { RootUriString } from './fileUtil.js';
4
5
  import type { Project } from './Project.js';
@@ -6,7 +7,7 @@ import type { Project } from './Project.js';
6
7
  * The format version of the cache. Should be increased when any changes that
7
8
  * could invalidate the cache are introduced to the Spyglass codebase.
8
9
  */
9
- export declare const LatestCacheVersion = 1;
10
+ export declare const LatestCacheVersion = 2;
10
11
  /**
11
12
  * Checksums of cached files or roots.
12
13
  */
@@ -18,6 +19,7 @@ interface Checksums {
18
19
  declare namespace Checksums {
19
20
  function create(): Checksums;
20
21
  }
22
+ declare type ErrorCache = Record<string, readonly PosRangeLanguageError[]>;
21
23
  interface LoadResult {
22
24
  symbols: SymbolTable;
23
25
  }
@@ -32,6 +34,7 @@ export declare class CacheService {
32
34
  private readonly cacheRoot;
33
35
  private readonly project;
34
36
  checksums: Checksums;
37
+ errors: ErrorCache;
35
38
  /**
36
39
  * @param cacheRoot File path to the directory where cache files by Spyglass should be stored.
37
40
  * @param project
@@ -50,7 +53,7 @@ export declare class CacheService {
50
53
  */
51
54
  save(): Promise<boolean>;
52
55
  hasFileChangedSinceCache(doc: TextDocument): Promise<boolean>;
53
- reset(): void;
56
+ reset(): LoadResult;
54
57
  }
55
58
  export {};
56
59
  //# sourceMappingURL=CacheService.d.ts.map
@@ -5,7 +5,7 @@ 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 = 1;
8
+ export const LatestCacheVersion = 2;
9
9
  var Checksums;
10
10
  (function (Checksums) {
11
11
  function create() {
@@ -21,6 +21,7 @@ export class CacheService {
21
21
  cacheRoot;
22
22
  project;
23
23
  checksums = Checksums.create();
24
+ errors = {};
24
25
  #hasValidatedFiles = false;
25
26
  /**
26
27
  * @param cacheRoot File path to the directory where cache files by Spyglass should be stored.
@@ -35,7 +36,8 @@ export class CacheService {
35
36
  }
36
37
  try {
37
38
  // TODO: Don't update this for every single change.
38
- this.checksums.files[doc.uri] = await this.project.externals.crypto.getSha1(doc.getText());
39
+ this.checksums.files[doc.uri] =
40
+ await this.project.externals.crypto.getSha1(doc.getText());
39
41
  }
40
42
  catch (e) {
41
43
  if (!this.project.externals.error.isKind(e, 'EISDIR')) {
@@ -63,6 +65,9 @@ export class CacheService {
63
65
  this.checksums.symbolRegistrars[id] = checksum;
64
66
  }
65
67
  });
68
+ this.project.on('documentErrored', ({ uri, errors }) => {
69
+ this.errors[uri] = errors;
70
+ });
66
71
  }
67
72
  #cacheFilePath;
68
73
  /**
@@ -71,7 +76,7 @@ export class CacheService {
71
76
  * @returns `${cacheRoot}symbols/${sha1(projectRoot)}.json`
72
77
  */
73
78
  async getCacheFileUri() {
74
- return this.#cacheFilePath ??= new Uri(`symbols/${await this.project.externals.crypto.getSha1(this.project.projectRoot)}.json.gz`, this.cacheRoot).toString();
79
+ return (this.#cacheFilePath ??= new Uri(`symbols/${await this.project.externals.crypto.getSha1(this.project.projectRoot)}.json.gz`, this.cacheRoot).toString());
75
80
  }
76
81
  async load() {
77
82
  const __profiler = this.project.profilers.get('cache#load');
@@ -80,10 +85,11 @@ export class CacheService {
80
85
  try {
81
86
  filePath = await this.getCacheFileUri();
82
87
  this.project.logger.info(`[CacheService#load] symbolCachePath = “${filePath}”`);
83
- const cache = await fileUtil.readGzippedJson(this.project.externals, filePath);
88
+ const cache = (await fileUtil.readGzippedJson(this.project.externals, filePath));
84
89
  __profiler.task('Read File');
85
90
  if (cache.version === LatestCacheVersion) {
86
91
  this.checksums = cache.checksums;
92
+ this.errors = cache.errors;
87
93
  ans.symbols = SymbolTable.link(cache.symbols);
88
94
  __profiler.task('Link Symbols');
89
95
  }
@@ -122,7 +128,7 @@ export class CacheService {
122
128
  }
123
129
  }
124
130
  for (const [uri, checksum] of Object.entries(this.checksums.files)) {
125
- if (unchangedRoots.some(root => uri.startsWith(root))) {
131
+ if (unchangedRoots.some((root) => uri.startsWith(root))) {
126
132
  ans.unchangedFiles.push(uri);
127
133
  continue;
128
134
  }
@@ -136,7 +142,8 @@ export class CacheService {
136
142
  }
137
143
  }
138
144
  catch (e) {
139
- if (this.project.externals.error.isKind(e, 'ENOENT') || this.project.externals.error.isKind(e, 'EISDIR')) {
145
+ if (this.project.externals.error.isKind(e, 'ENOENT') ||
146
+ this.project.externals.error.isKind(e, 'EISDIR')) {
140
147
  ans.removedFiles.push(uri);
141
148
  }
142
149
  else {
@@ -163,10 +170,11 @@ export class CacheService {
163
170
  try {
164
171
  filePath = await this.getCacheFileUri();
165
172
  const cache = {
166
- checksums: this.checksums,
173
+ version: LatestCacheVersion,
167
174
  projectRoot: this.project.projectRoot,
175
+ checksums: this.checksums,
168
176
  symbols: SymbolTable.unlink(this.project.symbols.global),
169
- version: LatestCacheVersion,
177
+ errors: this.errors,
170
178
  };
171
179
  __profiler.task('Unlink Symbols');
172
180
  await fileUtil.writeGzippedJson(this.project.externals, filePath, cache);
@@ -179,10 +187,14 @@ export class CacheService {
179
187
  return false;
180
188
  }
181
189
  async hasFileChangedSinceCache(doc) {
182
- return this.checksums.files[doc.uri] !== await this.project.externals.crypto.getSha1(doc.getText());
190
+ return (this.checksums.files[doc.uri] !==
191
+ (await this.project.externals.crypto.getSha1(doc.getText())));
183
192
  }
184
193
  reset() {
194
+ this.#hasValidatedFiles = false;
185
195
  this.checksums = Checksums.create();
196
+ this.errors = {};
197
+ return { symbols: {} };
186
198
  }
187
199
  }
188
200
  //# sourceMappingURL=CacheService.js.map
@@ -189,8 +189,8 @@ export declare namespace SymbolLinterConfig {
189
189
  }
190
190
  }
191
191
  /**
192
- * Config which simulates the default vanilla command system.
193
- */
192
+ * Config which simulates the default vanilla command system.
193
+ */
194
194
  export declare const VanillaConfig: Config;
195
195
  declare type ConfigEvent = {
196
196
  config: Config;
@@ -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' ||
7
+ return (value === 'hint' ||
8
8
  value === 'information' ||
9
9
  value === 'warning' ||
10
- value === 'error';
10
+ value === 'error');
11
11
  }
12
12
  LinterSeverity.is = is;
13
13
  function toErrorSeverity(value) {
@@ -64,7 +64,8 @@ export var SymbolLinterConfig;
64
64
  const value = v;
65
65
  return ((value.if === undefined || Arrayable.is(value.if, Condition.is)) &&
66
66
  (value.then === undefined || Action.is(value.then)) &&
67
- (value.override === undefined || Arrayable.is(value.override, Complex.is)));
67
+ (value.override === undefined ||
68
+ Arrayable.is(value.override, Complex.is)));
68
69
  }
69
70
  Complex.is = is;
70
71
  })(Complex = SymbolLinterConfig.Complex || (SymbolLinterConfig.Complex = {}));
@@ -75,22 +76,29 @@ export var SymbolLinterConfig;
75
76
  return false;
76
77
  }
77
78
  const value = v;
78
- return ((value.category === undefined || Arrayable.is(value.category, TypePredicates.isString)) &&
79
- (value.pattern === undefined || Arrayable.is(value.pattern, TypePredicates.isString)) &&
80
- (value.excludePattern === undefined || Arrayable.is(value.excludePattern, TypePredicates.isString)) &&
81
- (value.namespace === undefined || Arrayable.is(value.namespace, TypePredicates.isString)) &&
82
- (value.excludeNamespace === undefined || Arrayable.is(value.excludeNamespace, TypePredicates.isString)));
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)));
83
89
  }
84
90
  Condition.is = is;
85
91
  })(Condition = SymbolLinterConfig.Condition || (SymbolLinterConfig.Condition = {}));
86
92
  let Action;
87
93
  (function (Action) {
88
94
  function isDeclare(value) {
89
- return value !== undefined && ['block', 'file', 'public'].includes(value.declare);
95
+ return (value !== undefined &&
96
+ ['block', 'file', 'public'].includes(value.declare));
90
97
  }
91
98
  Action.isDeclare = isDeclare;
92
99
  function isReport(value) {
93
- return value !== undefined && ['inherit', 'hint', 'information', 'warning', 'error'].includes(value.report);
100
+ return (value !== undefined &&
101
+ ['inherit', 'hint', 'information', 'warning', 'error'].includes(value.report));
94
102
  }
95
103
  Action.isReport = isReport;
96
104
  function is(v) {
@@ -104,14 +112,12 @@ export var SymbolLinterConfig;
104
112
  })(Action = SymbolLinterConfig.Action || (SymbolLinterConfig.Action = {}));
105
113
  })(SymbolLinterConfig || (SymbolLinterConfig = {}));
106
114
  /**
107
- * Config which simulates the default vanilla command system.
108
- */
115
+ * Config which simulates the default vanilla command system.
116
+ */
109
117
  export const VanillaConfig = {
110
118
  env: {
111
119
  dataSource: 'GitHub',
112
- dependencies: [
113
- '@vanilla-mcdoc',
114
- ],
120
+ dependencies: ['@vanilla-mcdoc'],
115
121
  feature: {
116
122
  codeActions: true,
117
123
  colors: true,
@@ -122,9 +128,7 @@ export const VanillaConfig = {
122
128
  formatting: true,
123
129
  hover: true,
124
130
  inlayHint: {
125
- enabledNodes: [
126
- 'mcfunction:command_child/unknown',
127
- ],
131
+ enabledNodes: ['mcfunction:command_child/unknown'],
128
132
  },
129
133
  semanticColoring: true,
130
134
  selectionRanges: true,
@@ -253,7 +257,7 @@ export class ConfigService {
253
257
  return ConfigService.merge(this.defaultConfig, ans);
254
258
  }
255
259
  static isConfigFile(uri) {
256
- return ConfigService.ConfigFileNames.some(n => uri.endsWith(`/${n}`));
260
+ return ConfigService.ConfigFileNames.some((n) => uri.endsWith(`/${n}`));
257
261
  }
258
262
  static merge(base, ...overrides) {
259
263
  // FIXME
@@ -30,17 +30,22 @@ export class Downloader {
30
30
  out.cacheUri = cacheUri = new Uri(`downloader/${id}`, this.cacheRoot).toString();
31
31
  cacheChecksumUri = new Uri(`downloader/${id}${checksumExtension}`, this.cacheRoot).toString();
32
32
  try {
33
- out.checksum = checksum = await this.download({ ...checksumJob, id: id + checksumExtension });
33
+ out.checksum = checksum = await this.download({
34
+ ...checksumJob,
35
+ id: id + checksumExtension,
36
+ });
34
37
  try {
35
- const cacheChecksum = bufferToString(await fileUtil.readFile(this.externals, cacheChecksumUri))
36
- .slice(0, -1); // Remove ending newline
38
+ const cacheChecksum = bufferToString(await fileUtil.readFile(this.externals, cacheChecksumUri)).slice(0, -1); // Remove ending newline
37
39
  if (checksum === cacheChecksum) {
38
40
  try {
39
41
  const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
40
42
  if (ttl) {
41
- this.#memoryCache.set(uri, { buffer: cachedBuffer, time: performance.now() });
43
+ this.#memoryCache.set(uri, {
44
+ buffer: cachedBuffer,
45
+ time: performance.now(),
46
+ });
42
47
  }
43
- const deserializer = cache.deserializer ?? (b => b);
48
+ const deserializer = cache.deserializer ?? ((b) => b);
44
49
  const ans = await transformer(deserializer(cachedBuffer));
45
50
  this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum}`);
46
51
  return ans;
@@ -85,7 +90,7 @@ export class Downloader {
85
90
  }
86
91
  }
87
92
  try {
88
- const serializer = cache.serializer ?? (b => b);
93
+ const serializer = cache.serializer ?? ((b) => b);
89
94
  await fileUtil.writeFile(this.externals, cacheUri, serializer(buffer));
90
95
  }
91
96
  catch (e) {
@@ -100,7 +105,7 @@ export class Downloader {
100
105
  if (cache && cacheUri) {
101
106
  try {
102
107
  const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
103
- const deserializer = cache.deserializer ?? (b => b);
108
+ const deserializer = cache.deserializer ?? ((b) => b);
104
109
  const ans = await transformer(deserializer(cachedBuffer));
105
110
  this.logger.warn(`[Downloader] [${id}] Fell back to cached file “${cacheUri}”`);
106
111
  return ans;
@@ -128,7 +128,8 @@ export class FileUriSupporter {
128
128
  const files = new Map();
129
129
  for (let { uri } of dependencies) {
130
130
  try {
131
- if (fileUtil.isFileUri(uri) && (await externals.fs.stat(uri)).isDirectory()) {
131
+ if (fileUtil.isFileUri(uri) &&
132
+ (await externals.fs.stat(uri)).isDirectory()) {
132
133
  uri = fileUtil.ensureEndingSlash(uri);
133
134
  roots.push(uri);
134
135
  files.set(uri, await externals.fs.getAllFiles(uri));
@@ -150,7 +151,12 @@ export class ArchiveUriSupporter {
150
151
  externals;
151
152
  entries;
152
153
  static Protocol = 'archive:';
153
- static SupportedArchiveExtnames = ['.tar', '.tar.bz2', '.tar.gz', '.zip'];
154
+ static SupportedArchiveExtnames = [
155
+ '.tar',
156
+ '.tar.bz2',
157
+ '.tar.gz',
158
+ '.zip',
159
+ ];
154
160
  protocol = ArchiveUriSupporter.Protocol;
155
161
  /**
156
162
  * @param entries A map from archive URIs to unzipped entries.
@@ -204,7 +210,7 @@ export class ArchiveUriSupporter {
204
210
  }
205
211
  }
206
212
  static getUri(archiveUri, pathInArchive = '') {
207
- return `${ArchiveUriSupporter.Protocol}//${encodeURIComponent(archiveUri)}/${pathInArchive.replace(/\\/g, '/')}`;
213
+ return `${ArchiveUriSupporter.Protocol}${encodeURIComponent(archiveUri)}?path=${encodeURIComponent(pathInArchive.replace(/\\/g, '/'))}`;
208
214
  }
209
215
  /**
210
216
  * @throws When `uri` has the wrong protocol or hostname.
@@ -213,16 +219,22 @@ export class ArchiveUriSupporter {
213
219
  if (uri.protocol !== ArchiveUriSupporter.Protocol) {
214
220
  throw new Error(`Expected protocol “${ArchiveUriSupporter.Protocol}” in “${uri}”`);
215
221
  }
222
+ const path = uri.searchParams.get('path');
223
+ if (!path) {
224
+ throw new Error(`Missing path in archive uri “${uri.toString()}”`);
225
+ }
216
226
  return {
217
- archiveUri: decodeURIComponent(uri.hostname),
218
- pathInArchive: uri.pathname.charAt(0) === '/' ? uri.pathname.slice(1) : uri.pathname,
227
+ archiveUri: decodeURIComponent(uri.pathname),
228
+ pathInArchive: path.charAt(0) === '/' ? path.slice(1) : path,
219
229
  };
220
230
  }
221
231
  static async create(dependencies, externals, logger, checksums) {
222
232
  const entries = new Map();
223
233
  for (const { uri, info } of dependencies) {
224
234
  try {
225
- if (uri.startsWith('file:') && ArchiveUriSupporter.SupportedArchiveExtnames.some(ext => uri.endsWith(ext)) && (await externals.fs.stat(uri)).isFile()) {
235
+ if (uri.startsWith('file:') &&
236
+ ArchiveUriSupporter.SupportedArchiveExtnames.some((ext) => uri.endsWith(ext)) &&
237
+ (await externals.fs.stat(uri)).isFile()) {
226
238
  const rootUri = ArchiveUriSupporter.getUri(uri);
227
239
  const cachedChecksum = checksums[rootUri];
228
240
  if (cachedChecksum !== undefined) {
@@ -233,8 +245,10 @@ export class ArchiveUriSupporter {
233
245
  continue;
234
246
  }
235
247
  }
236
- const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), { stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0 });
237
- entries.set(uri, new Map(files.map(f => [f.path.replace(/\\/g, '/'), f])));
248
+ const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), {
249
+ stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0,
250
+ });
251
+ entries.set(uri, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
238
252
  }
239
253
  }
240
254
  catch (e) {
@@ -26,6 +26,11 @@ interface LinterRegistration {
26
26
  }
27
27
  interface SymbolRegistrarRegistration {
28
28
  registrar: SymbolRegistrar;
29
+ /**
30
+ * A checksum associated with this symbol registrar.
31
+ * If the cached checksum is equal to this provided checksum,
32
+ * the symbol registrar is not executed.
33
+ */
29
34
  checksum: string | undefined;
30
35
  }
31
36
  /**
@@ -1,5 +1,5 @@
1
1
  import { Lazy } from '../common/index.js';
2
- import { binder, checker, colorizer, completer, formatter, linter } from '../processor/index.js';
2
+ import { binder, checker, colorizer, completer, formatter, linter, } from '../processor/index.js';
3
3
  /* istanbul ignore next */
4
4
  /**
5
5
  * The meta registry of Spyglass. You can register new parsers, processors, and languages here.
@@ -51,13 +51,13 @@ export class MetaRegistry {
51
51
  * An array of file extensions (including the leading dot (`.`)) that are supported.
52
52
  */
53
53
  getSupportedFileExtensions() {
54
- return [...this.#languages.values()].flatMap(v => v.extensions);
54
+ return [...this.#languages.values()].flatMap((v) => v.extensions);
55
55
  }
56
56
  /**
57
57
  * An array of characters that trigger a completion request.
58
58
  */
59
59
  getTriggerCharacters() {
60
- return Array.from(this.#languages.values()).flatMap(v => v.triggerCharacters ?? []);
60
+ return Array.from(this.#languages.values()).flatMap((v) => v.triggerCharacters ?? []);
61
61
  }
62
62
  /**
63
63
  * @param fileExtension The file extension including the leading dot. e.g. `".mcfunction"`.
@@ -109,7 +109,8 @@ export class MetaRegistry {
109
109
  }
110
110
  shouldComplete(languageID, triggerCharacter) {
111
111
  const language = this.#languages.get(languageID);
112
- return !triggerCharacter || !!language?.triggerCharacters?.includes(triggerCharacter);
112
+ return (!triggerCharacter ||
113
+ !!language?.triggerCharacters?.includes(triggerCharacter));
113
114
  }
114
115
  getCompleterForLanguageID(languageID) {
115
116
  return this.#languages.get(languageID)?.completer ?? completer.fallback;
@@ -136,11 +137,11 @@ export class MetaRegistry {
136
137
  return this.#inlayHintProviders;
137
138
  }
138
139
  getLinter(ruleName) {
139
- return this.#linters.get(ruleName) ?? {
140
+ return (this.#linters.get(ruleName) ?? {
140
141
  configValidator: () => false,
141
142
  linter: linter.noop,
142
143
  nodePredicate: () => false,
143
- };
144
+ });
144
145
  }
145
146
  registerLinter(ruleName, options) {
146
147
  this.#linters.set(ruleName, options);
@@ -42,7 +42,7 @@ class TopNImpl {
42
42
  this.logger.info(`[Profiler: ${this.id}] Min/Avg/Max: ${this.#minTime} / ${totalDuration / this.#taskCount} / ${this.#maxTime} ms`);
43
43
  this.logger.info(`[Profiler: ${this.id}] Top ${Math.min(this.n, this.#topTasks.length)} task(s):`);
44
44
  for (const [name, time] of this.#topTasks) {
45
- this.logger.info(`[Profiler: ${this.id}] ${name}${' '.repeat(longestTaskNameLength - name.length)} - ${time} ms (${time / totalDuration * 100}%)`);
45
+ this.logger.info(`[Profiler: ${this.id}] ${name}${' '.repeat(longestTaskNameLength - name.length)} - ${time} ms (${(time / totalDuration) * 100}%)`);
46
46
  }
47
47
  }
48
48
  }
@@ -83,7 +83,9 @@ class TotalImpl {
83
83
  }
84
84
  }
85
85
  class NoopImpl {
86
- task() { return this; }
86
+ task() {
87
+ return this;
88
+ }
87
89
  finalize() { }
88
90
  }
89
91
  export class ProfilerFactory {
@@ -96,9 +98,12 @@ export class ProfilerFactory {
96
98
  get(id, style = 'total', n) {
97
99
  if (this.#enabledProfilers.has(id)) {
98
100
  switch (style) {
99
- case 'top-n': return new TopNImpl(id, this.logger, n);
100
- case 'total': return new TotalImpl(id, this.logger);
101
- default: return Dev.assertNever(style);
101
+ case 'top-n':
102
+ return new TopNImpl(id, this.logger, n);
103
+ case 'total':
104
+ return new TotalImpl(id, this.logger);
105
+ default:
106
+ return Dev.assertNever(style);
102
107
  }
103
108
  }
104
109
  else {