@spyglassmc/core 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/lib/common/Dev.js +2 -5
  2. package/lib/common/ReadonlyProxy.js +1 -3
  3. package/lib/common/StateProxy.js +2 -8
  4. package/lib/common/externals/BrowserExternals.js +7 -12
  5. package/lib/common/externals/NodeJsExternals.js +12 -8
  6. package/lib/common/externals/index.d.ts +8 -1
  7. package/lib/common/util.js +3 -10
  8. package/lib/node/AstNode.js +7 -9
  9. package/lib/node/BooleanNode.js +1 -4
  10. package/lib/node/FloatNode.js +1 -5
  11. package/lib/node/IntegerNode.js +1 -5
  12. package/lib/node/ListNode.d.ts +1 -1
  13. package/lib/node/LiteralNode.js +1 -6
  14. package/lib/node/LongNode.js +1 -5
  15. package/lib/node/PrefixedNode.d.ts +13 -0
  16. package/lib/node/PrefixedNode.js +22 -0
  17. package/lib/node/ResourceLocationNode.d.ts +1 -1
  18. package/lib/node/ResourceLocationNode.js +2 -8
  19. package/lib/node/StringNode.d.ts +2 -1
  20. package/lib/node/StringNode.js +1 -4
  21. package/lib/node/SymbolNode.js +1 -6
  22. package/lib/node/index.d.ts +1 -0
  23. package/lib/node/index.js +1 -0
  24. package/lib/parser/comment.d.ts +1 -1
  25. package/lib/parser/comment.js +2 -6
  26. package/lib/parser/error.js +1 -4
  27. package/lib/parser/file.d.ts +2 -2
  28. package/lib/parser/file.js +1 -2
  29. package/lib/parser/float.js +2 -7
  30. package/lib/parser/index.d.ts +1 -0
  31. package/lib/parser/index.js +1 -0
  32. package/lib/parser/integer.js +3 -7
  33. package/lib/parser/list.d.ts +1 -1
  34. package/lib/parser/list.js +2 -6
  35. package/lib/parser/literal.js +2 -9
  36. package/lib/parser/long.js +2 -7
  37. package/lib/parser/prefixed.d.ts +8 -0
  38. package/lib/parser/prefixed.js +23 -0
  39. package/lib/parser/record.d.ts +1 -1
  40. package/lib/parser/record.js +11 -17
  41. package/lib/parser/resourceLocation.d.ts +1 -0
  42. package/lib/parser/resourceLocation.js +6 -4
  43. package/lib/parser/string.js +6 -9
  44. package/lib/parser/util.d.ts +14 -3
  45. package/lib/parser/util.js +48 -26
  46. package/lib/processor/ColorInfoProvider.js +8 -25
  47. package/lib/processor/binder/builtin.d.ts +1 -0
  48. package/lib/processor/binder/builtin.js +20 -30
  49. package/lib/processor/checker/builtin.d.ts +1 -0
  50. package/lib/processor/checker/builtin.js +13 -7
  51. package/lib/processor/colorizer/Colorizer.d.ts +1 -1
  52. package/lib/processor/colorizer/Colorizer.js +4 -7
  53. package/lib/processor/colorizer/builtin.js +2 -2
  54. package/lib/processor/completer/Completer.js +1 -3
  55. package/lib/processor/completer/builtin.d.ts +3 -2
  56. package/lib/processor/completer/builtin.js +67 -23
  57. package/lib/processor/formatter/Formatter.js +1 -3
  58. package/lib/processor/formatter/builtin.js +2 -4
  59. package/lib/processor/linter/builtin/undeclaredSymbol.js +27 -40
  60. package/lib/service/CacheService.d.ts +1 -1
  61. package/lib/service/CacheService.js +12 -13
  62. package/lib/service/Config.d.ts +36 -0
  63. package/lib/service/Config.js +28 -45
  64. package/lib/service/Context.d.ts +2 -0
  65. package/lib/service/Context.js +4 -12
  66. package/lib/service/Downloader.d.ts +3 -0
  67. package/lib/service/Downloader.js +9 -3
  68. package/lib/service/ErrorReporter.js +3 -0
  69. package/lib/service/FileService.js +10 -29
  70. package/lib/service/Hover.js +1 -4
  71. package/lib/service/MetaRegistry.d.ts +4 -2
  72. package/lib/service/MetaRegistry.js +16 -8
  73. package/lib/service/Project.d.ts +9 -3
  74. package/lib/service/Project.js +71 -48
  75. package/lib/service/Service.d.ts +1 -1
  76. package/lib/service/Service.js +11 -36
  77. package/lib/service/SymbolLocations.js +1 -4
  78. package/lib/service/fileUtil.d.ts +7 -0
  79. package/lib/service/fileUtil.js +29 -4
  80. package/lib/source/IndexMap.js +1 -4
  81. package/lib/source/Location.js +3 -9
  82. package/lib/source/Position.js +1 -2
  83. package/lib/source/PositionRange.js +2 -2
  84. package/lib/source/Range.js +9 -21
  85. package/lib/source/Source.d.ts +11 -1
  86. package/lib/source/Source.js +31 -5
  87. package/lib/symbol/Symbol.d.ts +14 -9
  88. package/lib/symbol/Symbol.js +80 -61
  89. package/lib/symbol/SymbolUtil.d.ts +3 -3
  90. package/lib/symbol/SymbolUtil.js +48 -72
  91. package/package.json +3 -2
@@ -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;
@@ -125,8 +129,7 @@ export class Project {
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,30 @@ 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].filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
159
+ const filteredFiles = this.ignore.filter(supportedFiles);
160
+ return filteredFiles;
156
161
  }
157
- constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
162
+ constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], isDebugging = false, logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
158
163
  this.#cacheRoot = cacheRoot;
159
164
  this.#eventEmitter = new externals.event.EventEmitter();
160
165
  this.externals = externals;
161
166
  this.fs = fs;
162
167
  this.#initializers = initializers;
168
+ this.isDebugging = isDebugging;
163
169
  this.logger = logger;
164
170
  this.profilers = profilers;
165
171
  this.projectRoot = projectRoot;
166
172
  this.cacheService = new CacheService(cacheRoot, this);
167
173
  this.#configService = new ConfigService(this, defaultConfig);
168
- this.downloader = downloader ??
169
- new Downloader(cacheRoot, externals, logger);
174
+ this.downloader = downloader ?? new Downloader(cacheRoot, externals, logger);
170
175
  this.symbols = new SymbolUtil({}, externals.event.EventEmitter);
171
176
  this.#ctx = {};
172
177
  this.logger.info(`[Project] [init] cacheRoot = “${cacheRoot}”`);
173
- this.#configService
174
- .on('changed', ({ config }) => {
178
+ this.#configService.on('changed', ({ config }) => {
175
179
  this.config = config;
176
180
  this.logger.info('[Project] [Config] Changed');
177
- })
178
- .on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading “${uri}”`, error));
181
+ }).on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading “${uri}”`, error));
179
182
  this.setInitPromise();
180
183
  this.setReadyPromise();
181
184
  this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
@@ -188,32 +191,27 @@ export class Project {
188
191
  uri: doc.uri,
189
192
  version: doc.version,
190
193
  });
191
- })
192
- .on('documentRemoved', ({ uri }) => {
194
+ }).on('documentRemoved', ({ uri }) => {
193
195
  this.emit('documentErrored', { errors: [], uri });
194
- })
195
- .on('fileCreated', async ({ uri }) => {
196
+ }).on('fileCreated', async ({ uri }) => {
196
197
  if (uri.endsWith(Project.RootSuffix)) {
197
198
  this.updateRoots();
198
199
  }
199
200
  this.bindUri(uri);
200
201
  return this.ensureBindingStarted(uri);
201
- })
202
- .on('fileModified', async ({ uri }) => {
202
+ }).on('fileModified', async ({ uri }) => {
203
203
  this.#symbolUpToDateUris.delete(uri);
204
204
  if (this.isOnlyWatched(uri)) {
205
205
  await this.ensureBindingStarted(uri);
206
206
  }
207
- })
208
- .on('fileDeleted', ({ uri }) => {
207
+ }).on('fileDeleted', ({ uri }) => {
209
208
  if (uri.endsWith(Project.RootSuffix)) {
210
209
  this.updateRoots();
211
210
  }
212
211
  this.#symbolUpToDateUris.delete(uri);
213
212
  this.symbols.clear({ uri });
214
213
  this.tryClearingCache(uri);
215
- })
216
- .on('ready', () => {
214
+ }).on('ready', () => {
217
215
  this.#isReady = true;
218
216
  // // Recheck client managed files after the READY process, as they may have incomplete results and are user-facing.
219
217
  // const promises: Promise<unknown>[] = []
@@ -226,6 +224,18 @@ export class Project {
226
224
  setInitPromise() {
227
225
  const loadConfig = async () => {
228
226
  this.config = await this.#configService.load();
227
+ this.ignore = ignore();
228
+ for (const pattern of this.config.env.exclude) {
229
+ if (pattern === '@gitignore') {
230
+ const gitignore = await this.readGitignore();
231
+ if (gitignore) {
232
+ this.ignore.add(gitignore);
233
+ }
234
+ }
235
+ else {
236
+ this.ignore.add(pattern);
237
+ }
238
+ }
229
239
  };
230
240
  const callIntializers = async () => {
231
241
  const initCtx = {
@@ -233,6 +243,7 @@ export class Project {
233
243
  config: this.config,
234
244
  downloader: this.downloader,
235
245
  externals: this.externals,
246
+ isDebugging: this.isDebugging,
236
247
  logger: this.logger,
237
248
  meta: this.meta,
238
249
  projectRoot: this.projectRoot,
@@ -262,6 +273,19 @@ export class Project {
262
273
  };
263
274
  this.#initPromise = init();
264
275
  }
276
+ async readGitignore() {
277
+ try {
278
+ const uri = this.projectRoot + Project.GitIgnore;
279
+ const contents = await this.externals.fs.readFile(uri);
280
+ return bufferToString(contents);
281
+ }
282
+ catch (e) {
283
+ if (!this.externals.error.isKind(e, 'ENOENT')) {
284
+ this.logger.error(`[Project] [readGitignore]`, e);
285
+ }
286
+ }
287
+ return undefined;
288
+ }
265
289
  setReadyPromise() {
266
290
  const getDependencies = async () => {
267
291
  const ans = [];
@@ -297,30 +321,24 @@ export class Project {
297
321
  const listProjectFiles = () => new Promise((resolve) => {
298
322
  this.#watchedFiles.clear();
299
323
  this.#watcherReady = false;
300
- this.#watcher = this.externals.fs
301
- .watch(this.projectRoot)
302
- .once('ready', () => {
324
+ this.#watcher = this.externals.fs.watch(this.projectRoot).once('ready', () => {
303
325
  this.#watcherReady = true;
304
326
  resolve();
305
- })
306
- .on('add', (uri) => {
327
+ }).on('add', (uri) => {
307
328
  this.#watchedFiles.add(uri);
308
329
  if (this.#watcherReady) {
309
330
  this.emit('fileCreated', { uri });
310
331
  }
311
- })
312
- .on('change', (uri) => {
332
+ }).on('change', (uri) => {
313
333
  if (this.#watcherReady) {
314
334
  this.emit('fileModified', { uri });
315
335
  }
316
- })
317
- .on('unlink', (uri) => {
336
+ }).on('unlink', (uri) => {
318
337
  this.#watchedFiles.delete(uri);
319
338
  if (this.#watcherReady) {
320
339
  this.emit('fileDeleted', { uri });
321
340
  }
322
- })
323
- .on('error', (e) => {
341
+ }).on('error', (e) => {
324
342
  this.logger.error('[Project] [chokidar]', e);
325
343
  });
326
344
  });
@@ -350,9 +368,7 @@ export class Project {
350
368
  this.emit('documentErrored', { errors: values, uri });
351
369
  }
352
370
  __profiler.task('Pop Errors');
353
- const { addedFiles, changedFiles, removedFiles } = await this
354
- .cacheService
355
- .validate();
371
+ const { addedFiles, changedFiles, removedFiles } = await this.cacheService.validate();
356
372
  for (const uri of removedFiles) {
357
373
  this.emit('fileDeleted', { uri });
358
374
  }
@@ -506,9 +522,18 @@ export class Project {
506
522
  }
507
523
  parse(doc) {
508
524
  const ctx = ParserContext.create(this, { doc });
525
+ const parser = ctx.meta.getParserForLanguageId(ctx.doc.languageId);
526
+ if (!parser) {
527
+ return {
528
+ type: 'file',
529
+ range: Range.create(0),
530
+ children: [],
531
+ locals: Object.create(null),
532
+ parserErrors: [],
533
+ };
534
+ }
509
535
  const src = new Source(doc.getText());
510
- const node = file()(src, ctx);
511
- return node;
536
+ return file(parser)(src, ctx);
512
537
  }
513
538
  async bind(doc, node) {
514
539
  if (node.binderErrors) {
@@ -562,8 +587,7 @@ export class Project {
562
587
  continue;
563
588
  }
564
589
  const { ruleSeverity, ruleValue } = result;
565
- const { configValidator, linter, nodePredicate } = this.meta
566
- .getLinter(ruleName);
590
+ const { configValidator, linter, nodePredicate } = this.meta.getLinter(ruleName);
567
591
  if (!configValidator(ruleName, ruleValue, this.logger)) {
568
592
  // Config value is invalid.
569
593
  continue;
@@ -590,8 +614,7 @@ export class Project {
590
614
  // @SingletonPromise()
591
615
  async ensureBindingStarted(uri) {
592
616
  uri = this.normalizeUri(uri);
593
- if (this.#symbolUpToDateUris.has(uri) ||
594
- this.#bindingInProgressUris.has(uri)) {
617
+ if (this.#symbolUpToDateUris.has(uri) || this.#bindingInProgressUris.has(uri)) {
595
618
  return;
596
619
  }
597
620
  this.#bindingInProgressUris.add(uri);
@@ -702,14 +725,14 @@ export class Project {
702
725
  }
703
726
  }
704
727
  shouldRemove(uri) {
705
- return (!this.#clientManagedUris.has(uri) &&
706
- !this.#dependencyFiles.has(uri) &&
707
- !this.#watchedFiles.has(uri));
728
+ return (!this.#clientManagedUris.has(uri)
729
+ && !this.#dependencyFiles.has(uri)
730
+ && !this.#watchedFiles.has(uri));
708
731
  }
709
732
  isOnlyWatched(uri) {
710
- return (this.#watchedFiles.has(uri) &&
711
- !this.#clientManagedUris.has(uri) &&
712
- !this.#dependencyFiles.has(uri));
733
+ return (this.#watchedFiles.has(uri)
734
+ && !this.#clientManagedUris.has(uri)
735
+ && !this.#dependencyFiles.has(uri));
713
736
  }
714
737
  }
715
738
  __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[];
@@ -1,5 +1,5 @@
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
5
  import { ColorizerContext, CompleterContext, FormatterContext, ProcessorContext, SignatureHelpProviderContext, } from './Context.js';
@@ -14,15 +14,11 @@ export class Service {
14
14
  logger;
15
15
  profilers;
16
16
  project;
17
- constructor({ isDebugging = false, logger, profilers = ProfilerFactory.noop(), project, }) {
17
+ constructor({ isDebugging = false, logger, profilers = ProfilerFactory.noop(), project }) {
18
18
  this.isDebugging = isDebugging;
19
19
  this.logger = logger;
20
20
  this.profilers = profilers;
21
- this.project = new Project({
22
- logger,
23
- profilers,
24
- ...project,
25
- });
21
+ this.project = new Project({ isDebugging, logger, profilers, ...project });
26
22
  }
27
23
  debug(message) {
28
24
  if (this.isDebugging) {
@@ -45,12 +41,8 @@ export class Service {
45
41
  this.debug(`Getting color info for '${doc.uri}' # ${doc.version}`);
46
42
  const ans = [];
47
43
  traversePreOrder(node, (_) => true, (node) => node.color, (node) => ans.push({
48
- color: Array.isArray(node.color)
49
- ? node.color
50
- : node.color.value,
51
- range: Array.isArray(node.color)
52
- ? node.range
53
- : node.color.range ?? node.range,
44
+ color: Array.isArray(node.color) ? node.color : node.color.value,
45
+ range: Array.isArray(node.color) ? node.range : node.color.range ?? node.range,
54
46
  }));
55
47
  return ans;
56
48
  }
@@ -62,10 +54,7 @@ export class Service {
62
54
  getColorPresentation(file, doc, range, color) {
63
55
  try {
64
56
  this.debug(`Getting color presentation for '${doc.uri}' # ${doc.version} @ ${Range.toString(range)}`);
65
- let node = AstNode.findDeepestChild({
66
- node: file,
67
- needle: range.start,
68
- });
57
+ let node = AstNode.findDeepestChild({ node: file, needle: range.start });
69
58
  while (node) {
70
59
  const nodeColor = node.color;
71
60
  if (nodeColor && !Array.isArray(nodeColor)) {
@@ -85,11 +74,7 @@ export class Service {
85
74
  this.debug(`Getting completion for '${doc.uri}' # ${doc.version} @ ${offset}`);
86
75
  const shouldComplete = this.project.meta.shouldComplete(doc.languageId, triggerCharacter);
87
76
  if (shouldComplete) {
88
- return completer.file(node, CompleterContext.create(this.project, {
89
- doc,
90
- offset,
91
- triggerCharacter,
92
- }));
77
+ return completer.file(node, CompleterContext.create(this.project, { doc, offset, triggerCharacter }));
93
78
  }
94
79
  }
95
80
  catch (e) {
@@ -110,19 +95,13 @@ export class Service {
110
95
  // Punctuation should not be treated differently from any other characters, per example:
111
96
  // Hata &ack Sub
112
97
  // —— Skylinerw, 2022 https://discord.com/channels/154777837382008833/734106483104415856/955521761351454741
113
- return [...initialism]
114
- .map((c, i) => `${c.toUpperCase()}${secrets[i % secrets.length]}`)
115
- .join(' ');
98
+ return [...initialism].map((c, i) => `${c.toUpperCase()}${secrets[i % secrets.length]}`).join(' ');
116
99
  }
117
100
  format(node, doc, tabSize, insertSpaces) {
118
101
  try {
119
102
  this.debug(`Formatting '${doc.uri}' # ${doc.version}`);
120
103
  const formatter = this.project.meta.getFormatter(node.type);
121
- return formatter(node, FormatterContext.create(this.project, {
122
- doc,
123
- tabSize,
124
- insertSpaces,
125
- }));
104
+ return formatter(node, FormatterContext.create(this.project, { doc, tabSize, insertSpaces }));
126
105
  }
127
106
  catch (e) {
128
107
  this.logger.error(`[Service] [format] Failed for “${doc.uri}” #${doc.version}`, e);
@@ -136,8 +115,7 @@ export class Service {
136
115
  while (node) {
137
116
  const symbol = this.project.symbols.resolveAlias(node.symbol);
138
117
  if (symbol) {
139
- const hover = `\`\`\`typescript\n(${symbol.category}${symbol.subcategory ? `/${symbol.subcategory}` : ''}) ${symbol.identifier}\n\`\`\`` +
140
- (symbol.desc ? `\n******\n${symbol.desc}` : '');
118
+ const hover = `\`\`\`typescript\n(${symbol.category}${symbol.subcategory ? `/${symbol.subcategory}` : ''}) ${symbol.identifier}\n\`\`\`` + (symbol.desc ? `\n******\n${symbol.desc}` : '');
141
119
  return Hover.create(node.range, hover);
142
120
  }
143
121
  if (node.hover) {
@@ -170,10 +148,7 @@ export class Service {
170
148
  getSignatureHelp(node, doc, offset) {
171
149
  try {
172
150
  this.debug(`Getting signature help for '${doc.uri}' # ${doc.version} @ ${offset}`);
173
- const ctx = SignatureHelpProviderContext.create(this.project, {
174
- doc,
175
- offset,
176
- });
151
+ const ctx = SignatureHelpProviderContext.create(this.project, { doc, offset });
177
152
  for (const provider of this.project.meta.signatureHelpProviders) {
178
153
  const result = provider(node, ctx);
179
154
  if (result) {
@@ -3,10 +3,7 @@ export var SymbolLocations;
3
3
  (function (SymbolLocations) {
4
4
  /* istanbul ignore next */
5
5
  function create(range, locations) {
6
- return {
7
- range: Range.get(range),
8
- locations,
9
- };
6
+ return { range: Range.get(range), locations };
10
7
  }
11
8
  SymbolLocations.create = create;
12
9
  })(SymbolLocations || (SymbolLocations = {}));