@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
@@ -4,7 +4,7 @@ import type { ExternalEventEmitter, Externals } from '../common/index.js';
4
4
  import { Logger } from '../common/index.js';
5
5
  import type { AstNode } from '../node/index.js';
6
6
  import { FileNode } from '../node/index.js';
7
- import type { LanguageError } from '../source/index.js';
7
+ import type { PosRangeLanguageError } from '../source/index.js';
8
8
  import { SymbolUtil } from '../symbol/index.js';
9
9
  import { CacheService } from './CacheService.js';
10
10
  import type { Config } from './Config.js';
@@ -38,8 +38,10 @@ export interface DocAndNode {
38
38
  }
39
39
  interface DocumentEvent extends DocAndNode {
40
40
  }
41
- interface DocumentErrorEvent extends DocumentEvent {
42
- errors: LanguageError[];
41
+ interface DocumentErrorEvent {
42
+ errors: readonly PosRangeLanguageError[];
43
+ uri: string;
44
+ version?: number;
43
45
  }
44
46
  interface FileEvent {
45
47
  uri: string;
@@ -124,21 +126,21 @@ export declare class Project implements ExternalEventEmitter {
124
126
  */
125
127
  get cacheRoot(): RootUriString;
126
128
  private updateRoots;
127
- on(event: 'documentErrorred', callbackFn: (data: DocumentErrorEvent) => void): this;
129
+ on(event: 'documentErrored', callbackFn: (data: DocumentErrorEvent) => void): this;
128
130
  on(event: 'documentUpdated', callbackFn: (data: DocumentEvent) => void): this;
129
131
  on(event: 'documentRemoved', callbackFn: (data: FileEvent) => void): this;
130
132
  on(event: `file${'Created' | 'Modified' | 'Deleted'}`, callbackFn: (data: FileEvent) => void): this;
131
133
  on(event: 'ready', callbackFn: (data: EmptyEvent) => void): this;
132
134
  on(event: 'rootsUpdated', callbackFn: (data: RootsEvent) => void): this;
133
135
  on(event: 'symbolRegistrarExecuted', callbackFn: (data: SymbolRegistrarEvent) => void): this;
134
- once(event: 'documentErrorred', callbackFn: (data: DocumentErrorEvent) => void): this;
136
+ once(event: 'documentErrored', callbackFn: (data: DocumentErrorEvent) => void): this;
135
137
  once(event: 'documentUpdated', callbackFn: (data: DocumentEvent) => void): this;
136
138
  once(event: 'documentRemoved', callbackFn: (data: FileEvent) => void): this;
137
139
  once(event: `file${'Created' | 'Modified' | 'Deleted'}`, callbackFn: (data: FileEvent) => void): this;
138
140
  once(event: 'ready', callbackFn: (data: EmptyEvent) => void): this;
139
141
  once(event: 'rootsUpdated', callbackFn: (data: RootsEvent) => void): this;
140
142
  once(event: 'symbolRegistrarExecuted', callbackFn: (data: SymbolRegistrarEvent) => void): this;
141
- emit(event: 'documentErrorred', data: DocumentErrorEvent): boolean;
143
+ emit(event: 'documentErrored', data: DocumentErrorEvent): boolean;
142
144
  emit(event: 'documentUpdated', data: DocumentEvent): boolean;
143
145
  emit(event: 'documentRemoved', data: FileEvent): boolean;
144
146
  emit(event: `file${'Created' | 'Modified' | 'Deleted'}`, data: FileEvent): boolean;
@@ -168,7 +170,7 @@ export declare class Project implements ExternalEventEmitter {
168
170
  */
169
171
  close(): Promise<void>;
170
172
  restart(): Promise<void>;
171
- resetCache(): void;
173
+ resetCache(): Promise<void>;
172
174
  normalizeUri(uri: string): string;
173
175
  private static readonly TextDocumentCacheMaxLength;
174
176
  private removeCachedTextDocument;
@@ -5,19 +5,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { TextDocument } from 'vscode-languageserver-textdocument';
8
- import { bufferToString, Logger, SingletonPromise, StateProxy } from '../common/index.js';
8
+ import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, } from '../common/index.js';
9
9
  import { FileNode } from '../node/index.js';
10
10
  import { file } from '../parser/index.js';
11
11
  import { traversePreOrder } from '../processor/index.js';
12
- import { Source } from '../source/index.js';
12
+ import { LanguageError, Source } from '../source/index.js';
13
13
  import { SymbolUtil } from '../symbol/index.js';
14
14
  import { CacheService } from './CacheService.js';
15
15
  import { ConfigService, LinterConfigValue } from './Config.js';
16
- import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext } from './Context.js';
16
+ import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext, } from './Context.js';
17
17
  import { DependencyKey } from './Dependency.js';
18
18
  import { Downloader } from './Downloader.js';
19
19
  import { LinterErrorReporter } from './ErrorReporter.js';
20
- import { ArchiveUriSupporter, FileService, FileUriSupporter } from './FileService.js';
20
+ import { ArchiveUriSupporter, FileService, FileUriSupporter, } from './FileService.js';
21
21
  import { fileUtil } from './fileUtil.js';
22
22
  import { MetaRegistry } from './MetaRegistry.js';
23
23
  import { ProfilerFactory } from './Profiler.js';
@@ -125,7 +125,8 @@ export class Project {
125
125
  const ans = new Set(rawRoots);
126
126
  // Identify roots indicated by `pack.mcmeta`.
127
127
  for (const file of this.getTrackedFiles()) {
128
- if (file.endsWith(Project.RootSuffix) && rawRoots.some(r => file.startsWith(r))) {
128
+ if (file.endsWith(Project.RootSuffix) &&
129
+ rawRoots.some((r) => file.startsWith(r))) {
129
130
  ans.add(file.slice(0, 1 - Project.RootSuffix.length));
130
131
  }
131
132
  }
@@ -151,8 +152,7 @@ export class Project {
151
152
  */
152
153
  getTrackedFiles() {
153
154
  const extensions = this.meta.getSupportedFileExtensions();
154
- return [...this.#dependencyFiles, ...this.#watchedFiles]
155
- .filter(file => extensions.includes(fileUtil.extname(file) ?? ''));
155
+ return [...this.#dependencyFiles, ...this.#watchedFiles].filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
156
156
  }
157
157
  constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
158
158
  this.#cacheRoot = cacheRoot;
@@ -178,16 +178,18 @@ export class Project {
178
178
  this.setInitPromise();
179
179
  this.setReadyPromise();
180
180
  this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
181
- this
182
- .on('documentUpdated', ({ doc, node }) => {
181
+ this.on('documentUpdated', ({ doc, node }) => {
183
182
  // if (!this.#isReady) {
184
183
  // return
185
184
  // }
186
- this.emit('documentErrorred', {
187
- doc,
188
- errors: FileNode.getErrors(node),
189
- node,
185
+ this.emit('documentErrored', {
186
+ errors: FileNode.getErrors(node).map((e) => LanguageError.withPosRange(e, doc)),
187
+ uri: doc.uri,
188
+ version: doc.version,
190
189
  });
190
+ })
191
+ .on('documentRemoved', ({ uri }) => {
192
+ this.emit('documentErrored', { errors: [], uri });
191
193
  })
192
194
  .on('fileCreated', async ({ uri }) => {
193
195
  if (uri.endsWith(Project.RootSuffix)) {
@@ -234,7 +236,7 @@ export class Project {
234
236
  meta: this.meta,
235
237
  projectRoot: this.projectRoot,
236
238
  };
237
- const results = await Promise.allSettled(this.#initializers.map(init => init(initCtx)));
239
+ const results = await Promise.allSettled(this.#initializers.map((init) => init(initCtx)));
238
240
  let ctx = {};
239
241
  results.forEach(async (r, i) => {
240
242
  if (r.status === 'rejected') {
@@ -291,7 +293,8 @@ export class Project {
291
293
  this.fs.register('file:', fileUriSupporter, true);
292
294
  this.fs.register(ArchiveUriSupporter.Protocol, archiveUriSupporter, true);
293
295
  };
294
- const listProjectFiles = () => new Promise(resolve => {
296
+ const listProjectFiles = () => new Promise((resolve) => {
297
+ this.#watchedFiles.clear();
295
298
  this.#watcherReady = false;
296
299
  this.#watcher = this.externals.fs
297
300
  .watch(this.projectRoot)
@@ -299,34 +302,31 @@ export class Project {
299
302
  this.#watcherReady = true;
300
303
  resolve();
301
304
  })
302
- .on('add', uri => {
305
+ .on('add', (uri) => {
303
306
  this.#watchedFiles.add(uri);
304
307
  if (this.#watcherReady) {
305
308
  this.emit('fileCreated', { uri });
306
309
  }
307
310
  })
308
- .on('change', uri => {
311
+ .on('change', (uri) => {
309
312
  if (this.#watcherReady) {
310
313
  this.emit('fileModified', { uri });
311
314
  }
312
315
  })
313
- .on('unlink', uri => {
316
+ .on('unlink', (uri) => {
314
317
  this.#watchedFiles.delete(uri);
315
318
  if (this.#watcherReady) {
316
319
  this.emit('fileDeleted', { uri });
317
320
  }
318
321
  })
319
- .on('error', e => {
322
+ .on('error', (e) => {
320
323
  this.logger.error('[Project] [chokidar]', e);
321
324
  });
322
325
  });
323
326
  const ready = async () => {
324
327
  await this.init();
325
328
  const __profiler = this.profilers.get('project#ready');
326
- await Promise.all([
327
- listDependencyFiles(),
328
- listProjectFiles(),
329
- ]);
329
+ await Promise.all([listDependencyFiles(), listProjectFiles()]);
330
330
  this.#dependencyFiles = new Set(this.fs.listFiles());
331
331
  this.#dependencyRoots = new Set(this.fs.listRoots());
332
332
  this.updateRoots();
@@ -345,9 +345,13 @@ export class Project {
345
345
  }
346
346
  }
347
347
  __profiler.task('Register Symbols');
348
+ for (const [uri, values] of Object.entries(this.cacheService.errors)) {
349
+ this.emit('documentErrored', { errors: values, uri });
350
+ }
351
+ __profiler.task('Pop Errors');
348
352
  const { addedFiles, changedFiles, removedFiles } = await this.cacheService.validate();
349
353
  for (const uri of removedFiles) {
350
- this.symbols.clear({ uri });
354
+ this.emit('fileDeleted', { uri });
351
355
  }
352
356
  __profiler.task('Validate Cache');
353
357
  if (addedFiles.length > 0) {
@@ -366,6 +370,7 @@ export class Project {
366
370
  __profiler.finalize();
367
371
  this.emit('ready', {});
368
372
  };
373
+ this.#isReady = false;
369
374
  this.#readyPromise = ready();
370
375
  }
371
376
  /**
@@ -393,6 +398,8 @@ export class Project {
393
398
  async restart() {
394
399
  try {
395
400
  await this.#watcher.close();
401
+ this.#bindingInProgressUris.clear();
402
+ this.#symbolUpToDateUris.clear();
396
403
  this.setReadyPromise();
397
404
  await this.ready();
398
405
  }
@@ -401,10 +408,19 @@ export class Project {
401
408
  }
402
409
  }
403
410
  resetCache() {
404
- return this.cacheService.reset();
411
+ this.logger.info('[Project#resetCache] Initiated...');
412
+ // Clear existing errors.
413
+ for (const uri of Object.keys(this.cacheService.errors)) {
414
+ this.emit('documentErrored', { errors: [], uri });
415
+ }
416
+ // Reset cache.
417
+ const { symbols } = this.cacheService.reset();
418
+ this.symbols = new SymbolUtil(symbols, this.externals.event.EventEmitter);
419
+ this.symbols.buildCache();
420
+ return this.restart();
405
421
  }
406
422
  normalizeUri(uri) {
407
- return this.fs.mapFromDisk(this.externals.uri.normalize(uri));
423
+ return this.fs.mapFromDisk(normalizeUri(uri));
408
424
  }
409
425
  static TextDocumentCacheMaxLength = 268435456;
410
426
  #textDocumentCache = new Map();
@@ -554,7 +570,7 @@ export class Project {
554
570
  ruleName,
555
571
  ruleValue,
556
572
  });
557
- traversePreOrder(node, () => true, () => true, node => {
573
+ traversePreOrder(node, () => true, () => true, (node) => {
558
574
  if (nodePredicate(node)) {
559
575
  const proxy = StateProxy.create(node);
560
576
  linter(proxy, ctx);
@@ -569,7 +585,9 @@ export class Project {
569
585
  }
570
586
  // @SingletonPromise()
571
587
  async ensureBindingStarted(uri) {
572
- if (this.#symbolUpToDateUris.has(uri) || this.#bindingInProgressUris.has(uri)) {
588
+ uri = this.normalizeUri(uri);
589
+ if (this.#symbolUpToDateUris.has(uri) ||
590
+ this.#bindingInProgressUris.has(uri)) {
573
591
  return;
574
592
  }
575
593
  this.#bindingInProgressUris.add(uri);
@@ -615,8 +633,8 @@ export class Project {
615
633
  * @throws If there is no `TextDocument` corresponding to the URI.
616
634
  */
617
635
  async onDidChange(uri, changes, version) {
618
- this.#symbolUpToDateUris.delete(uri);
619
636
  uri = this.normalizeUri(uri);
637
+ this.#symbolUpToDateUris.delete(uri);
620
638
  if (!fileUtil.isFileUri(uri)) {
621
639
  return; // We only accept `file:` scheme for client-managed URIs.
622
640
  }
@@ -645,17 +663,21 @@ export class Project {
645
663
  this.tryClearingCache(uri);
646
664
  }
647
665
  async ensureClientManagedChecked(uri) {
666
+ uri = this.normalizeUri(uri);
648
667
  const result = this.#clientManagedDocAndNodes.get(uri);
649
- if (result && this.#isReady) {
668
+ if (result) {
650
669
  const { doc, node } = result;
651
- await this.bind(doc, node);
652
- await this.check(doc, node);
653
- this.emit('documentUpdated', { doc, node });
654
- return { doc, node };
670
+ if (this.#isReady) {
671
+ await this.bind(doc, node);
672
+ await this.check(doc, node);
673
+ this.emit('documentUpdated', result);
674
+ }
675
+ return result;
655
676
  }
656
677
  return undefined;
657
678
  }
658
679
  getClientManaged(uri) {
680
+ uri = this.normalizeUri(uri);
659
681
  return this.#clientManagedDocAndNodes.get(uri);
660
682
  }
661
683
  async showCacheRoot() {
@@ -676,10 +698,14 @@ export class Project {
676
698
  }
677
699
  }
678
700
  shouldRemove(uri) {
679
- return !this.#clientManagedUris.has(uri) && !this.#dependencyFiles.has(uri) && !this.#watchedFiles.has(uri);
701
+ return (!this.#clientManagedUris.has(uri) &&
702
+ !this.#dependencyFiles.has(uri) &&
703
+ !this.#watchedFiles.has(uri));
680
704
  }
681
705
  isOnlyWatched(uri) {
682
- return this.#watchedFiles.has(uri) && !this.#clientManagedUris.has(uri) && !this.#dependencyFiles.has(uri);
706
+ return (this.#watchedFiles.has(uri) &&
707
+ !this.#clientManagedUris.has(uri) &&
708
+ !this.#dependencyFiles.has(uri));
683
709
  }
684
710
  }
685
711
  __decorate([
@@ -1,8 +1,8 @@
1
1
  import { AstNode } from '../node/index.js';
2
- import { ColorPresentation, completer, traversePreOrder } from '../processor/index.js';
2
+ import { ColorPresentation, completer, traversePreOrder, } from '../processor/index.js';
3
3
  import { Range } from '../source/index.js';
4
4
  import { SymbolUsageTypes } from '../symbol/index.js';
5
- import { ColorizerContext, CompleterContext, FormatterContext, ProcessorContext, SignatureHelpProviderContext } from './Context.js';
5
+ import { ColorizerContext, CompleterContext, FormatterContext, ProcessorContext, SignatureHelpProviderContext, } from './Context.js';
6
6
  import { fileUtil } from './fileUtil.js';
7
7
  import { Hover } from './Hover.js';
8
8
  import { ProfilerFactory } from './Profiler.js';
@@ -44,9 +44,11 @@ export class Service {
44
44
  try {
45
45
  this.debug(`Getting color info for '${doc.uri}' # ${doc.version}`);
46
46
  const ans = [];
47
- traversePreOrder(node, _ => true, node => node.color, node => ans.push({
47
+ traversePreOrder(node, (_) => true, (node) => node.color, (node) => ans.push({
48
48
  color: Array.isArray(node.color) ? node.color : node.color.value,
49
- range: Array.isArray(node.color) ? node.range : (node.color.range ?? node.range),
49
+ range: Array.isArray(node.color)
50
+ ? node.range
51
+ : node.color.range ?? node.range,
50
52
  }));
51
53
  return ans;
52
54
  }
@@ -63,7 +65,7 @@ export class Service {
63
65
  const nodeColor = node.color;
64
66
  if (nodeColor && !Array.isArray(nodeColor)) {
65
67
  const colorRange = nodeColor.range ?? node.range;
66
- return nodeColor.format.map(format => ColorPresentation.fromColorFormat(format, color, colorRange));
68
+ return nodeColor.format.map((format) => ColorPresentation.fromColorFormat(format, color, colorRange));
67
69
  }
68
70
  node = node.parent;
69
71
  }
@@ -78,7 +80,11 @@ export class Service {
78
80
  this.debug(`Getting completion for '${doc.uri}' # ${doc.version} @ ${offset}`);
79
81
  const shouldComplete = this.project.meta.shouldComplete(doc.languageId, triggerCharacter);
80
82
  if (shouldComplete) {
81
- return completer.file(node, CompleterContext.create(this.project, { doc, offset, triggerCharacter }));
83
+ return completer.file(node, CompleterContext.create(this.project, {
84
+ doc,
85
+ offset,
86
+ triggerCharacter,
87
+ }));
82
88
  }
83
89
  }
84
90
  catch (e) {
@@ -121,7 +127,8 @@ export class Service {
121
127
  while (node) {
122
128
  const symbol = this.project.symbols.resolveAlias(node.symbol);
123
129
  if (symbol) {
124
- const hover = `\`\`\`typescript\n(${symbol.category}${symbol.subcategory ? `/${symbol.subcategory}` : ''}) ${symbol.identifier}\n\`\`\`` + (symbol.desc ? `\n******\n${symbol.desc}` : '');
130
+ const hover = `\`\`\`typescript\n(${symbol.category}${symbol.subcategory ? `/${symbol.subcategory}` : ''}) ${symbol.identifier}\n\`\`\`` +
131
+ (symbol.desc ? `\n******\n${symbol.desc}` : '');
125
132
  return Hover.create(node.range, hover);
126
133
  }
127
134
  if (node.hover) {
@@ -154,7 +161,10 @@ export class Service {
154
161
  getSignatureHelp(node, doc, offset) {
155
162
  try {
156
163
  this.debug(`Getting signature help for '${doc.uri}' # ${doc.version} @ ${offset}`);
157
- const ctx = SignatureHelpProviderContext.create(this.project, { doc, offset });
164
+ const ctx = SignatureHelpProviderContext.create(this.project, {
165
+ doc,
166
+ offset,
167
+ });
158
168
  for (const provider of this.project.meta.signatureHelpProviders) {
159
169
  const result = provider(node, ctx);
160
170
  if (result) {
@@ -184,7 +194,7 @@ export class Service {
184
194
  for (const usage of searchedUsages) {
185
195
  let locs = symbol[usage] ?? [];
186
196
  if (currentFileOnly) {
187
- locs = locs.filter(l => l.uri === doc.uri);
197
+ locs = locs.filter((l) => l.uri === doc.uri);
188
198
  }
189
199
  rawLocations.push(...locs);
190
200
  }
@@ -43,7 +43,8 @@ export var fileUtil;
43
43
  }
44
44
  fileUtil.ensureEndingSlash = ensureEndingSlash;
45
45
  function join(fromUri, toUri) {
46
- return ensureEndingSlash(fromUri) + (toUri.startsWith('/') ? toUri.slice(1) : toUri);
46
+ return (ensureEndingSlash(fromUri) +
47
+ (toUri.startsWith('/') ? toUri.slice(1) : toUri));
47
48
  }
48
49
  fileUtil.join = join;
49
50
  /**
@@ -33,7 +33,7 @@ export var IndexMap;
33
33
  }
34
34
  IndexMap.toOuterRange = toOuterRange;
35
35
  function merge(outerMap, innerMap) {
36
- return innerMap.map(p => ({
36
+ return innerMap.map((p) => ({
37
37
  inner: p.inner,
38
38
  outer: toOuterRange(outerMap, p.outer),
39
39
  }));
@@ -1,14 +1,28 @@
1
+ import type { TextDocument } from 'vscode-languageserver-textdocument';
1
2
  import type { Location } from './Location.js';
3
+ import { PositionRange } from './PositionRange.js';
2
4
  import type { Range } from './Range.js';
3
- export interface LanguageError {
5
+ export interface LanguageErrorData {
4
6
  message: string;
5
- range: Range;
6
7
  severity: ErrorSeverity;
7
8
  info?: LanguageErrorInfo;
8
9
  }
9
- export declare namespace LanguageError {
10
- function create(message: string, range: Range, severity?: ErrorSeverity, info?: LanguageErrorInfo): LanguageError;
10
+ export interface LanguageError extends LanguageErrorData {
11
+ range: Range;
12
+ }
13
+ /**
14
+ * A language error that uses {@link PositionRange} instead of {@link Range} to represent the span of the error.
15
+ */
16
+ export interface PosRangeLanguageError extends LanguageErrorData {
17
+ posRange: PositionRange;
11
18
  }
19
+ export declare const LanguageError: Readonly<{
20
+ create(message: string, range: Range, severity?: ErrorSeverity, info?: LanguageErrorInfo): LanguageError;
21
+ /**
22
+ * @returns A {@link PosRangeLanguageError}.
23
+ */
24
+ withPosRange(error: LanguageError, doc: TextDocument): PosRangeLanguageError;
25
+ }>;
12
26
  export declare const enum ErrorSeverity {
13
27
  Hint = 0,
14
28
  Information = 1,
@@ -1,12 +1,22 @@
1
- export var LanguageError;
2
- (function (LanguageError) {
3
- function create(message, range, severity = 3 /* ErrorSeverity.Error */, info) {
1
+ import { PositionRange } from './PositionRange.js';
2
+ export const LanguageError = Object.freeze({
3
+ create(message, range, severity = 3 /* ErrorSeverity.Error */, info) {
4
4
  const ans = { range, message, severity };
5
5
  if (info) {
6
6
  ans.info = info;
7
7
  }
8
8
  return ans;
9
- }
10
- LanguageError.create = create;
11
- })(LanguageError || (LanguageError = {}));
9
+ },
10
+ /**
11
+ * @returns A {@link PosRangeLanguageError}.
12
+ */
13
+ withPosRange(error, doc) {
14
+ return {
15
+ posRange: PositionRange.from(error.range, doc),
16
+ message: error.message,
17
+ severity: error.severity,
18
+ ...(error.info && { info: error.info }),
19
+ };
20
+ },
21
+ });
12
22
  //# sourceMappingURL=LanguageError.js.map
@@ -6,7 +6,10 @@ export var Location;
6
6
  return {
7
7
  uri: partial.uri ?? '',
8
8
  range: Range.get(partial.range ?? { start: 0, end: 0 }),
9
- posRange: partial.posRange ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
9
+ posRange: partial.posRange ?? {
10
+ start: { line: 0, character: 0 },
11
+ end: { line: 0, character: 0 },
12
+ },
10
13
  };
11
14
  }
12
15
  Location.get = get;
@@ -12,7 +12,7 @@ export declare namespace PositionRange {
12
12
  /**
13
13
  * @returns A `PositionRange` converted from a `RangeLike`.
14
14
  */
15
- function from(range: RangeLike, doc: TextDocument): PositionRange;
15
+ function from(rangeLike: RangeLike, doc: TextDocument): PositionRange;
16
16
  /**
17
17
  * ```typescript
18
18
  * {
@@ -27,11 +27,11 @@ export var PositionRange;
27
27
  /**
28
28
  * @returns A `PositionRange` converted from a `RangeLike`.
29
29
  */
30
- function from(range, doc) {
31
- const _range = Range.get(range);
30
+ function from(rangeLike, doc) {
31
+ const range = Range.get(rangeLike);
32
32
  const ans = {
33
- start: doc.positionAt(_range.start),
34
- end: doc.positionAt(_range.end),
33
+ start: doc.positionAt(range.start),
34
+ end: doc.positionAt(range.end),
35
35
  };
36
36
  return ans;
37
37
  }
@@ -42,7 +42,8 @@ export var Range;
42
42
  }
43
43
  Range.span = span;
44
44
  function is(obj) {
45
- return (!!obj && typeof obj === 'object' &&
45
+ return (!!obj &&
46
+ typeof obj === 'object' &&
46
47
  typeof obj.start === 'number' &&
47
48
  typeof obj.end === 'number');
48
49
  }
@@ -65,7 +66,8 @@ export var Range;
65
66
  Range.toString = toString;
66
67
  function contains(range, offset, endInclusive = false) {
67
68
  range = get(range);
68
- return range.start <= offset && (endInclusive ? offset <= range.end : offset < range.end);
69
+ return (range.start <= offset &&
70
+ (endInclusive ? offset <= range.end : offset < range.end));
69
71
  }
70
72
  Range.contains = contains;
71
73
  function containsRange(a, b, endInclusive = false) {
@@ -144,7 +146,8 @@ export var Range;
144
146
  export var RangeContainer;
145
147
  (function (RangeContainer) {
146
148
  function is(obj) {
147
- return (!!obj && typeof obj === 'object' &&
149
+ return (!!obj &&
150
+ typeof obj === 'object' &&
148
151
  Range.is(obj.range));
149
152
  }
150
153
  RangeContainer.is = is;
@@ -43,6 +43,8 @@ export declare class ReadonlySource {
43
43
  tryPeekAfterWhitespace(expectedValue: string): boolean;
44
44
  peekUntil(...terminators: string[]): string;
45
45
  peekLine(): string;
46
+ peekRemaining(): string;
47
+ matchPattern(regex: RegExp): boolean;
46
48
  hasNonSpaceAheadInLine(): boolean;
47
49
  slice(start: number, end?: number): string;
48
50
  slice(rangeLike: Range | RangeContainer): string;
@@ -70,6 +70,12 @@ export class ReadonlySource {
70
70
  peekLine() {
71
71
  return this.peekUntil(CR, LF);
72
72
  }
73
+ peekRemaining() {
74
+ return this.string.slice(this.innerCursor);
75
+ }
76
+ matchPattern(regex) {
77
+ return regex.test(this.peekRemaining());
78
+ }
73
79
  hasNonSpaceAheadInLine() {
74
80
  for (let cursor = this.innerCursor; cursor < this.string.length; cursor++) {
75
81
  const c = this.string.charAt(cursor);
@@ -85,7 +91,9 @@ export class ReadonlySource {
85
91
  slice(param0, end) {
86
92
  if (typeof param0 === 'number') {
87
93
  const innerStart = IndexMap.toInnerOffset(this.indexMap, param0);
88
- const innerEnd = end !== undefined ? IndexMap.toInnerOffset(this.indexMap, end) : undefined;
94
+ const innerEnd = end !== undefined
95
+ ? IndexMap.toInnerOffset(this.indexMap, end)
96
+ : undefined;
89
97
  return this.string.slice(innerStart, innerEnd);
90
98
  }
91
99
  const range = IndexMap.toInnerRange(this.indexMap, Range.get(param0));