@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
@@ -13,9 +13,12 @@ export class Downloader {
13
13
  async download(job, out = {}) {
14
14
  const { id, cache, uri, options, transformer, ttl } = job;
15
15
  if (ttl && this.#memoryCache.has(uri)) {
16
- const { buffer, time } = this.#memoryCache.get(uri);
17
- if (time <= performance.now() + ttl) {
16
+ const memoryCacheEntry = this.#memoryCache.get(uri);
17
+ const { buffer, time, cacheUri, checksum } = memoryCacheEntry;
18
+ if (performance.now() <= time + ttl) {
18
19
  this.logger.info(`[Downloader] [${id}] Skipped thanks to valid cache in memory`);
20
+ out.cacheUri = cacheUri;
21
+ out.checksum = checksum;
19
22
  return await transformer(buffer);
20
23
  }
21
24
  else {
@@ -28,7 +31,8 @@ export class Downloader {
28
31
  if (cache) {
29
32
  const { checksumJob, checksumExtension } = cache;
30
33
  out.cacheUri = cacheUri = new Uri(`downloader/${id}`, this.cacheRoot).toString();
31
- cacheChecksumUri = new Uri(`downloader/${id}${checksumExtension}`, this.cacheRoot).toString();
34
+ cacheChecksumUri = new Uri(`downloader/${id}${checksumExtension}`, this.cacheRoot)
35
+ .toString();
32
36
  try {
33
37
  out.checksum = checksum = await this.download({
34
38
  ...checksumJob,
@@ -42,6 +46,8 @@ export class Downloader {
42
46
  if (ttl) {
43
47
  this.#memoryCache.set(uri, {
44
48
  buffer: cachedBuffer,
49
+ cacheUri,
50
+ checksum,
45
51
  time: performance.now(),
46
52
  });
47
53
  }
@@ -7,6 +7,9 @@ export class ErrorReporter {
7
7
  * Reports a new error.
8
8
  */
9
9
  report(message, range, severity = 3 /* ErrorSeverity.Error */, info) {
10
+ if (message.trim() === '') {
11
+ throw new Error('Tried to report an error with no message');
12
+ }
10
13
  this.errors.push(LanguageError.create(message, Range.get(range), severity, info));
11
14
  }
12
15
  /**
@@ -77,8 +77,7 @@ export class FileServiceImpl {
77
77
  try {
78
78
  let mappedUri = this.map.getKey(virtualUri);
79
79
  if (mappedUri === undefined) {
80
- mappedUri = `${this.virtualUrisRoot}${await this.externals.crypto
81
- .getSha1(virtualUri)}/${fileUtil.basename(virtualUri)}`;
80
+ mappedUri = `${this.virtualUrisRoot}${await this.externals.crypto.getSha1(virtualUri)}/${fileUtil.basename(virtualUri)}`;
82
81
  // Delete old mapped file if it exists. This makes sure the
83
82
  // readonly permission on the file is not removed by it being
84
83
  // overwritten.
@@ -140,8 +139,7 @@ export class FileUriSupporter {
140
139
  const files = new Map();
141
140
  for (let { uri } of dependencies) {
142
141
  try {
143
- if (fileUtil.isFileUri(uri) &&
144
- (await externals.fs.stat(uri)).isDirectory()) {
142
+ if (fileUtil.isFileUri(uri) && (await externals.fs.stat(uri)).isDirectory()) {
145
143
  uri = fileUtil.ensureEndingSlash(uri);
146
144
  roots.push(uri);
147
145
  files.set(uri, await externals.fs.getAllFiles(uri));
@@ -154,21 +152,11 @@ export class FileUriSupporter {
154
152
  return new FileUriSupporter(externals, roots, files);
155
153
  }
156
154
  }
157
- // namespace ArchiveUri {
158
- // export function is(uri: Uri): boolean {
159
- // return uri.protocol === Protocol && uri.hostname === Hostname
160
- // }
161
- // }
162
155
  export class ArchiveUriSupporter {
163
156
  externals;
164
157
  entries;
165
158
  static Protocol = 'archive:';
166
- static SupportedArchiveExtnames = [
167
- '.tar',
168
- '.tar.bz2',
169
- '.tar.gz',
170
- '.zip',
171
- ];
159
+ static SupportedArchiveExtnames = ['.tar', '.tar.bz2', '.tar.gz', '.zip'];
172
160
  protocol = ArchiveUriSupporter.Protocol;
173
161
  /**
174
162
  * @param entries A map from archive names to unzipped entries.
@@ -202,10 +190,10 @@ export class ArchiveUriSupporter {
202
190
  }
203
191
  const entry = entries.get(pathInArchive);
204
192
  if (!entry) {
205
- throw new Error(`Path “${pathInArchive}” does not exist in archive “${archiveName}”`);
193
+ throw this.externals.error.createKind('ENOENT', `Path “${pathInArchive}” does not exist in archive “${archiveName}”`);
206
194
  }
207
195
  if (entry.type !== 'file') {
208
- throw new Error(`Path “${pathInArchive}” in archive “${archiveName}” is not a file`);
196
+ throw this.externals.error.createKind('EISDIR', `Path “${pathInArchive}” in archive “${archiveName}” is not a file`);
209
197
  }
210
198
  return entry.data;
211
199
  }
@@ -235,27 +223,20 @@ export class ArchiveUriSupporter {
235
223
  if (!path) {
236
224
  throw new Error(`Missing path in archive uri “${uri.toString()}”`);
237
225
  }
238
- return {
239
- archiveName: uri.host,
240
- pathInArchive: path.charAt(0) === '/' ? path.slice(1) : path,
241
- };
226
+ return { archiveName: uri.host, pathInArchive: path.charAt(0) === '/' ? path.slice(1) : path };
242
227
  }
243
228
  static async create(dependencies, externals, logger) {
244
229
  const entries = new Map();
245
230
  for (const { uri, info } of dependencies) {
246
231
  try {
247
- if (uri.startsWith('file:') &&
248
- ArchiveUriSupporter.SupportedArchiveExtnames.some((ext) => uri.endsWith(ext)) &&
249
- (await externals.fs.stat(uri)).isFile()) {
232
+ if (uri.startsWith('file:')
233
+ && ArchiveUriSupporter.SupportedArchiveExtnames.some((ext) => uri.endsWith(ext))
234
+ && (await externals.fs.stat(uri)).isFile()) {
250
235
  const archiveName = fileUtil.basename(uri);
251
236
  if (entries.has(archiveName)) {
252
237
  throw new Error(`A different URI with ${archiveName} already exists`);
253
238
  }
254
- const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), {
255
- stripLevel: typeof info?.startDepth === 'number'
256
- ? info.startDepth
257
- : 0,
258
- });
239
+ const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), { stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0 });
259
240
  entries.set(archiveName, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
260
241
  }
261
242
  }
@@ -3,10 +3,7 @@ export var Hover;
3
3
  (function (Hover) {
4
4
  /* istanbul ignore next */
5
5
  function create(range, markdown) {
6
- return {
7
- range: Range.get(range),
8
- markdown,
9
- };
6
+ return { range: Range.get(range), markdown };
10
7
  }
11
8
  Hover.create = create;
12
9
  })(Hover || (Hover = {}));
@@ -16,7 +16,7 @@ export interface LanguageOptions {
16
16
  */
17
17
  extensions: FileExtension[];
18
18
  triggerCharacters?: string[];
19
- parser: Parser<AstNode>;
19
+ parser?: Parser<AstNode>;
20
20
  completer?: Completer<any>;
21
21
  }
22
22
  interface LinterRegistration {
@@ -102,11 +102,13 @@ export declare class MetaRegistry {
102
102
  * @returns The corresponding `Parser` for the language ID.
103
103
  * @throws If there's no such language in the registry.
104
104
  */
105
- getParserForLanguageId<N extends AstNode>(languageID: string): Parser<N>;
105
+ getParserForLanguageId<N extends AstNode>(languageID: string): Parser<N> | undefined;
106
106
  registerSignatureHelpProvider(provider: SignatureHelpProvider<any>): void;
107
107
  get signatureHelpProviders(): Set<SignatureHelpProvider<any>>;
108
108
  registerSymbolRegistrar(id: string, registrar: SymbolRegistrarRegistration): void;
109
109
  get symbolRegistrars(): Map<string, SymbolRegistrarRegistration>;
110
+ registerCustom<T>(group: string, id: string, object: T): void;
111
+ getCustom<T>(group: string): Map<string, T> | undefined;
110
112
  registerUriBinder(uriBinder: UriBinder): void;
111
113
  get uriBinders(): Set<UriBinder>;
112
114
  setUriSorter(uriSorter: UriSorterRegistration): void;
@@ -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.
@@ -20,6 +20,7 @@ export class MetaRegistry {
20
20
  #parsers = new Map();
21
21
  #signatureHelpProviders = new Set();
22
22
  #symbolRegistrars = new Map();
23
+ #custom = new Map();
23
24
  #uriBinders = new Set();
24
25
  #uriSorter = () => 0;
25
26
  constructor() {
@@ -109,8 +110,7 @@ export class MetaRegistry {
109
110
  }
110
111
  shouldComplete(languageID, triggerCharacter) {
111
112
  const language = this.#languages.get(languageID);
112
- return (!triggerCharacter ||
113
- !!language?.triggerCharacters?.includes(triggerCharacter));
113
+ return (!triggerCharacter || !!language?.triggerCharacters?.includes(triggerCharacter));
114
114
  }
115
115
  getCompleterForLanguageID(languageID) {
116
116
  return this.#languages.get(languageID)?.completer ?? completer.fallback;
@@ -137,11 +137,8 @@ export class MetaRegistry {
137
137
  return this.#inlayHintProviders;
138
138
  }
139
139
  getLinter(ruleName) {
140
- return (this.#linters.get(ruleName) ?? {
141
- configValidator: () => false,
142
- linter: linter.noop,
143
- nodePredicate: () => false,
144
- });
140
+ return (this.#linters.get(ruleName)
141
+ ?? { configValidator: () => false, linter: linter.noop, nodePredicate: () => false });
145
142
  }
146
143
  registerLinter(ruleName, options) {
147
144
  this.#linters.set(ruleName, options);
@@ -184,6 +181,17 @@ export class MetaRegistry {
184
181
  get symbolRegistrars() {
185
182
  return this.#symbolRegistrars;
186
183
  }
184
+ registerCustom(group, id, object) {
185
+ let groupRegistry = this.#custom.get(group);
186
+ if (!groupRegistry) {
187
+ groupRegistry = new Map();
188
+ this.#custom.set(group, groupRegistry);
189
+ }
190
+ groupRegistry.set(id, object);
191
+ }
192
+ getCustom(group) {
193
+ return this.#custom.get(group);
194
+ }
187
195
  registerUriBinder(uriBinder) {
188
196
  this.#uriBinders.add(uriBinder);
189
197
  }
@@ -1,3 +1,4 @@
1
+ import type { Ignore } from 'ignore';
1
2
  import type { TextDocumentContentChangeEvent } from 'vscode-languageserver-textdocument';
2
3
  import { TextDocument } from 'vscode-languageserver-textdocument';
3
4
  import type { ExternalEventEmitter, Externals } from '../common/index.js';
@@ -13,7 +14,7 @@ import { FileService } from './FileService.js';
13
14
  import type { RootUriString } from './fileUtil.js';
14
15
  import { MetaRegistry } from './MetaRegistry.js';
15
16
  import { ProfilerFactory } from './Profiler.js';
16
- export type ProjectInitializerContext = Pick<Project, 'cacheRoot' | 'config' | 'downloader' | 'externals' | 'logger' | 'meta' | 'projectRoot'>;
17
+ export type ProjectInitializerContext = Pick<Project, 'cacheRoot' | 'config' | 'downloader' | 'externals' | 'isDebugging' | 'logger' | 'meta' | 'projectRoot'>;
17
18
  export type SyncProjectInitializer = (this: void, ctx: ProjectInitializerContext) => Record<string, string> | void;
18
19
  export type AsyncProjectInitializer = (this: void, ctx: ProjectInitializerContext) => PromiseLike<Record<string, string> | void>;
19
20
  export type ProjectInitializer = SyncProjectInitializer | AsyncProjectInitializer;
@@ -24,6 +25,7 @@ export interface ProjectOptions {
24
25
  externals: Externals;
25
26
  fs?: FileService;
26
27
  initializers?: readonly ProjectInitializer[];
28
+ isDebugging?: boolean;
27
29
  logger?: Logger;
28
30
  profilers?: ProfilerFactory;
29
31
  /**
@@ -55,7 +57,7 @@ interface SymbolRegistrarEvent {
55
57
  id: string;
56
58
  checksum: string | undefined;
57
59
  }
58
- export type ProjectData = Pick<Project, 'cacheRoot' | 'config' | 'downloader' | 'ensureBindingStarted' | 'externals' | 'fs' | 'logger' | 'meta' | 'profilers' | 'projectRoot' | 'roots' | 'symbols' | 'ctx'>;
60
+ export type ProjectData = Pick<Project, 'cacheRoot' | 'config' | 'downloader' | 'ensureBindingStarted' | 'externals' | 'fs' | 'isDebugging' | 'logger' | 'meta' | 'profilers' | 'projectRoot' | 'roots' | 'symbols' | 'ctx'>;
59
61
  /**
60
62
  * Manage all tracked documents and errors.
61
63
  *
@@ -96,12 +98,15 @@ export type ProjectData = Pick<Project, 'cacheRoot' | 'config' | 'downloader' |
96
98
  export declare class Project implements ExternalEventEmitter {
97
99
  #private;
98
100
  private static readonly RootSuffix;
101
+ private static readonly GitIgnore;
99
102
  readonly cacheService: CacheService;
100
103
  get isReady(): boolean;
101
104
  config: Config;
105
+ ignore: Ignore;
102
106
  readonly downloader: Downloader;
103
107
  readonly externals: Externals;
104
108
  readonly fs: FileService;
109
+ readonly isDebugging: boolean;
105
110
  readonly logger: Logger;
106
111
  readonly meta: MetaRegistry;
107
112
  readonly profilers: ProfilerFactory;
@@ -154,8 +159,9 @@ export declare class Project implements ExternalEventEmitter {
154
159
  * are not loaded into the memory.
155
160
  */
156
161
  getTrackedFiles(): string[];
157
- constructor({ cacheRoot, defaultConfig, downloader, externals, fs, initializers, logger, profilers, projectRoot, }: ProjectOptions);
162
+ constructor({ cacheRoot, defaultConfig, downloader, externals, fs, initializers, isDebugging, logger, profilers, projectRoot, }: ProjectOptions);
158
163
  private setInitPromise;
164
+ private readGitignore;
159
165
  private setReadyPromise;
160
166
  /**
161
167
  * Load the config file and initialize parsers and processors.
@@ -4,12 +4,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
+ import ignore from 'ignore';
7
8
  import { TextDocument } from 'vscode-languageserver-textdocument';
8
9
  import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, } from '../common/index.js';
9
10
  import { FileNode } from '../node/index.js';
10
11
  import { file } from '../parser/index.js';
11
12
  import { traversePreOrder } from '../processor/index.js';
12
- import { LanguageError, Source } from '../source/index.js';
13
+ import { LanguageError, Range, Source } from '../source/index.js';
13
14
  import { SymbolUtil } from '../symbol/index.js';
14
15
  import { CacheService } from './CacheService.js';
15
16
  import { ConfigService, LinterConfigValue } from './Config.js';
@@ -17,7 +18,7 @@ import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderC
17
18
  import { DependencyKey } from './Dependency.js';
18
19
  import { Downloader } from './Downloader.js';
19
20
  import { LinterErrorReporter } from './ErrorReporter.js';
20
- import { ArchiveUriSupporter, FileService, FileUriSupporter, } from './FileService.js';
21
+ import { ArchiveUriSupporter, FileService, FileUriSupporter } from './FileService.js';
21
22
  import { fileUtil } from './fileUtil.js';
22
23
  import { MetaRegistry } from './MetaRegistry.js';
23
24
  import { ProfilerFactory } from './Profiler.js';
@@ -62,6 +63,7 @@ const CacheAutoSaveInterval = 600_000; // 10 Minutes.
62
63
  */
63
64
  export class Project {
64
65
  static RootSuffix = '/pack.mcmeta';
66
+ static GitIgnore = '.gitignore';
65
67
  /** Prevent circular binding. */
66
68
  #bindingInProgressUris = new Set();
67
69
  #cacheSaverIntervalId;
@@ -83,9 +85,11 @@ export class Project {
83
85
  return this.#isReady;
84
86
  }
85
87
  config;
88
+ ignore = ignore();
86
89
  downloader;
87
90
  externals;
88
91
  fs;
92
+ isDebugging;
89
93
  logger;
90
94
  meta = new MetaRegistry();
91
95
  profilers;
@@ -121,12 +125,11 @@ export class Project {
121
125
  return this.#cacheRoot;
122
126
  }
123
127
  updateRoots() {
124
- const rawRoots = [...this.#dependencyRoots, this.projectRoot];
128
+ const rawRoots = [...this.#dependencyRoots ?? [], this.projectRoot];
125
129
  const ans = new Set(rawRoots);
126
130
  // Identify roots indicated by `pack.mcmeta`.
127
131
  for (const file of this.getTrackedFiles()) {
128
- if (file.endsWith(Project.RootSuffix) &&
129
- rawRoots.some((r) => file.startsWith(r))) {
132
+ if (file.endsWith(Project.RootSuffix) && rawRoots.some((r) => file.startsWith(r))) {
130
133
  ans.add(file.slice(0, 1 - Project.RootSuffix.length));
131
134
  }
132
135
  }
@@ -152,30 +155,31 @@ export class Project {
152
155
  */
153
156
  getTrackedFiles() {
154
157
  const extensions = this.meta.getSupportedFileExtensions();
155
- return [...this.#dependencyFiles, ...this.#watchedFiles].filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
158
+ const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles]
159
+ .filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
160
+ const filteredFiles = this.ignore.filter(supportedFiles);
161
+ return filteredFiles;
156
162
  }
157
- constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
163
+ constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], isDebugging = false, logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
158
164
  this.#cacheRoot = cacheRoot;
159
165
  this.#eventEmitter = new externals.event.EventEmitter();
160
166
  this.externals = externals;
161
167
  this.fs = fs;
162
168
  this.#initializers = initializers;
169
+ this.isDebugging = isDebugging;
163
170
  this.logger = logger;
164
171
  this.profilers = profilers;
165
172
  this.projectRoot = projectRoot;
166
173
  this.cacheService = new CacheService(cacheRoot, this);
167
174
  this.#configService = new ConfigService(this, defaultConfig);
168
- this.downloader = downloader ??
169
- new Downloader(cacheRoot, externals, logger);
175
+ this.downloader = downloader ?? new Downloader(cacheRoot, externals, logger);
170
176
  this.symbols = new SymbolUtil({}, externals.event.EventEmitter);
171
177
  this.#ctx = {};
172
178
  this.logger.info(`[Project] [init] cacheRoot = “${cacheRoot}”`);
173
- this.#configService
174
- .on('changed', ({ config }) => {
179
+ this.#configService.on('changed', ({ config }) => {
175
180
  this.config = config;
176
181
  this.logger.info('[Project] [Config] Changed');
177
- })
178
- .on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading “${uri}”`, error));
182
+ }).on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading “${uri}”`, error));
179
183
  this.setInitPromise();
180
184
  this.setReadyPromise();
181
185
  this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
@@ -188,32 +192,27 @@ export class Project {
188
192
  uri: doc.uri,
189
193
  version: doc.version,
190
194
  });
191
- })
192
- .on('documentRemoved', ({ uri }) => {
195
+ }).on('documentRemoved', ({ uri }) => {
193
196
  this.emit('documentErrored', { errors: [], uri });
194
- })
195
- .on('fileCreated', async ({ uri }) => {
197
+ }).on('fileCreated', async ({ uri }) => {
196
198
  if (uri.endsWith(Project.RootSuffix)) {
197
199
  this.updateRoots();
198
200
  }
199
201
  this.bindUri(uri);
200
202
  return this.ensureBindingStarted(uri);
201
- })
202
- .on('fileModified', async ({ uri }) => {
203
+ }).on('fileModified', async ({ uri }) => {
203
204
  this.#symbolUpToDateUris.delete(uri);
204
205
  if (this.isOnlyWatched(uri)) {
205
206
  await this.ensureBindingStarted(uri);
206
207
  }
207
- })
208
- .on('fileDeleted', ({ uri }) => {
208
+ }).on('fileDeleted', ({ uri }) => {
209
209
  if (uri.endsWith(Project.RootSuffix)) {
210
210
  this.updateRoots();
211
211
  }
212
212
  this.#symbolUpToDateUris.delete(uri);
213
213
  this.symbols.clear({ uri });
214
214
  this.tryClearingCache(uri);
215
- })
216
- .on('ready', () => {
215
+ }).on('ready', () => {
217
216
  this.#isReady = true;
218
217
  // // Recheck client managed files after the READY process, as they may have incomplete results and are user-facing.
219
218
  // const promises: Promise<unknown>[] = []
@@ -226,6 +225,18 @@ export class Project {
226
225
  setInitPromise() {
227
226
  const loadConfig = async () => {
228
227
  this.config = await this.#configService.load();
228
+ this.ignore = ignore();
229
+ for (const pattern of this.config.env.exclude) {
230
+ if (pattern === '@gitignore') {
231
+ const gitignore = await this.readGitignore();
232
+ if (gitignore) {
233
+ this.ignore.add(gitignore);
234
+ }
235
+ }
236
+ else {
237
+ this.ignore.add(pattern);
238
+ }
239
+ }
229
240
  };
230
241
  const callIntializers = async () => {
231
242
  const initCtx = {
@@ -233,6 +244,7 @@ export class Project {
233
244
  config: this.config,
234
245
  downloader: this.downloader,
235
246
  externals: this.externals,
247
+ isDebugging: this.isDebugging,
236
248
  logger: this.logger,
237
249
  meta: this.meta,
238
250
  projectRoot: this.projectRoot,
@@ -262,6 +274,19 @@ export class Project {
262
274
  };
263
275
  this.#initPromise = init();
264
276
  }
277
+ async readGitignore() {
278
+ try {
279
+ const uri = this.projectRoot + Project.GitIgnore;
280
+ const contents = await this.externals.fs.readFile(uri);
281
+ return bufferToString(contents);
282
+ }
283
+ catch (e) {
284
+ if (!this.externals.error.isKind(e, 'ENOENT')) {
285
+ this.logger.error(`[Project] [readGitignore]`, e);
286
+ }
287
+ }
288
+ return undefined;
289
+ }
265
290
  setReadyPromise() {
266
291
  const getDependencies = async () => {
267
292
  const ans = [];
@@ -297,30 +322,24 @@ export class Project {
297
322
  const listProjectFiles = () => new Promise((resolve) => {
298
323
  this.#watchedFiles.clear();
299
324
  this.#watcherReady = false;
300
- this.#watcher = this.externals.fs
301
- .watch(this.projectRoot)
302
- .once('ready', () => {
325
+ this.#watcher = this.externals.fs.watch(this.projectRoot).once('ready', () => {
303
326
  this.#watcherReady = true;
304
327
  resolve();
305
- })
306
- .on('add', (uri) => {
328
+ }).on('add', (uri) => {
307
329
  this.#watchedFiles.add(uri);
308
330
  if (this.#watcherReady) {
309
331
  this.emit('fileCreated', { uri });
310
332
  }
311
- })
312
- .on('change', (uri) => {
333
+ }).on('change', (uri) => {
313
334
  if (this.#watcherReady) {
314
335
  this.emit('fileModified', { uri });
315
336
  }
316
- })
317
- .on('unlink', (uri) => {
337
+ }).on('unlink', (uri) => {
318
338
  this.#watchedFiles.delete(uri);
319
339
  if (this.#watcherReady) {
320
340
  this.emit('fileDeleted', { uri });
321
341
  }
322
- })
323
- .on('error', (e) => {
342
+ }).on('error', (e) => {
324
343
  this.logger.error('[Project] [chokidar]', e);
325
344
  });
326
345
  });
@@ -350,9 +369,7 @@ export class Project {
350
369
  this.emit('documentErrored', { errors: values, uri });
351
370
  }
352
371
  __profiler.task('Pop Errors');
353
- const { addedFiles, changedFiles, removedFiles } = await this
354
- .cacheService
355
- .validate();
372
+ const { addedFiles, changedFiles, removedFiles } = await this.cacheService.validate();
356
373
  for (const uri of removedFiles) {
357
374
  this.emit('fileDeleted', { uri });
358
375
  }
@@ -506,9 +523,18 @@ export class Project {
506
523
  }
507
524
  parse(doc) {
508
525
  const ctx = ParserContext.create(this, { doc });
526
+ const parser = ctx.meta.getParserForLanguageId(ctx.doc.languageId);
527
+ if (!parser) {
528
+ return {
529
+ type: 'file',
530
+ range: Range.create(0),
531
+ children: [],
532
+ locals: Object.create(null),
533
+ parserErrors: [],
534
+ };
535
+ }
509
536
  const src = new Source(doc.getText());
510
- const node = file()(src, ctx);
511
- return node;
537
+ return file(parser)(src, ctx);
512
538
  }
513
539
  async bind(doc, node) {
514
540
  if (node.binderErrors) {
@@ -562,8 +588,7 @@ export class Project {
562
588
  continue;
563
589
  }
564
590
  const { ruleSeverity, ruleValue } = result;
565
- const { configValidator, linter, nodePredicate } = this.meta
566
- .getLinter(ruleName);
591
+ const { configValidator, linter, nodePredicate } = this.meta.getLinter(ruleName);
567
592
  if (!configValidator(ruleName, ruleValue, this.logger)) {
568
593
  // Config value is invalid.
569
594
  continue;
@@ -590,8 +615,7 @@ export class Project {
590
615
  // @SingletonPromise()
591
616
  async ensureBindingStarted(uri) {
592
617
  uri = this.normalizeUri(uri);
593
- if (this.#symbolUpToDateUris.has(uri) ||
594
- this.#bindingInProgressUris.has(uri)) {
618
+ if (this.#symbolUpToDateUris.has(uri) || this.#bindingInProgressUris.has(uri)) {
595
619
  return;
596
620
  }
597
621
  this.#bindingInProgressUris.add(uri);
@@ -702,14 +726,14 @@ export class Project {
702
726
  }
703
727
  }
704
728
  shouldRemove(uri) {
705
- return (!this.#clientManagedUris.has(uri) &&
706
- !this.#dependencyFiles.has(uri) &&
707
- !this.#watchedFiles.has(uri));
729
+ return (!this.#clientManagedUris.has(uri)
730
+ && !this.#dependencyFiles?.has(uri)
731
+ && !this.#watchedFiles.has(uri));
708
732
  }
709
733
  isOnlyWatched(uri) {
710
- return (this.#watchedFiles.has(uri) &&
711
- !this.#clientManagedUris.has(uri) &&
712
- !this.#dependencyFiles.has(uri));
734
+ return (this.#watchedFiles.has(uri)
735
+ && !this.#clientManagedUris.has(uri)
736
+ && !this.#dependencyFiles?.has(uri));
713
737
  }
714
738
  }
715
739
  __decorate([
@@ -22,7 +22,7 @@ export declare class Service {
22
22
  readonly logger: Logger;
23
23
  readonly profilers: ProfilerFactory;
24
24
  readonly project: Project;
25
- constructor({ isDebugging, logger, profilers, project, }: Options);
25
+ constructor({ isDebugging, logger, profilers, project }: Options);
26
26
  private debug;
27
27
  colorize(node: FileNode<AstNode>, doc: TextDocument, range?: Range): readonly ColorToken[];
28
28
  getColorInfo(node: FileNode<AstNode>, doc: TextDocument): ColorInfo[];