@spyglassmc/core 0.4.18 → 0.4.20

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.
@@ -130,8 +130,8 @@ export class CacheService {
130
130
  ans.unchangedFiles.push(uri);
131
131
  continue;
132
132
  }
133
- if (this.project.ignore.ignores(uri)) {
134
- ans.unchangedFiles.push(uri);
133
+ if (this.project.shouldExclude(uri)) {
134
+ ans.removedFiles.push(uri);
135
135
  continue;
136
136
  }
137
137
  try {
@@ -59,7 +59,7 @@ export interface EnvConfig {
59
59
  */
60
60
  dependencies: string[];
61
61
  /**
62
- * A list of file patterns to exclude. Each value in this array can either be a glob pattern or the special string `@gitignore`.
62
+ * A list of file patterns to exclude.
63
63
  */
64
64
  exclude: string[];
65
65
  /**
@@ -107,7 +107,7 @@ export const VanillaConfig = {
107
107
  env: {
108
108
  dataSource: 'GitHub',
109
109
  dependencies: ['@vanilla-datapack', '@vanilla-resourcepack', '@vanilla-mcdoc'],
110
- exclude: ['@gitignore', '.vscode/', '.github/'],
110
+ exclude: ['.*/**'],
111
111
  customResources: {},
112
112
  feature: {
113
113
  codeActions: true,
@@ -95,6 +95,7 @@ export declare class FileUriSupporter implements UriProtocolSupporter {
95
95
  }
96
96
  export declare class ArchiveUriSupporter implements UriProtocolSupporter {
97
97
  private readonly externals;
98
+ private readonly logger;
98
99
  private readonly entries;
99
100
  static readonly Protocol = "archive:";
100
101
  private static readonly SupportedArchiveExtnames;
@@ -154,6 +154,7 @@ export class FileUriSupporter {
154
154
  }
155
155
  export class ArchiveUriSupporter {
156
156
  externals;
157
+ logger;
157
158
  entries;
158
159
  static Protocol = 'archive:';
159
160
  static SupportedArchiveExtnames = ['.tar', '.tar.bz2', '.tar.gz', '.zip'];
@@ -161,8 +162,9 @@ export class ArchiveUriSupporter {
161
162
  /**
162
163
  * @param entries A map from archive names to unzipped entries.
163
164
  */
164
- constructor(externals, entries) {
165
+ constructor(externals, logger, entries) {
165
166
  this.externals = externals;
167
+ this.logger = logger;
166
168
  this.entries = entries;
167
169
  }
168
170
  async hash(uri) {
@@ -199,6 +201,7 @@ export class ArchiveUriSupporter {
199
201
  }
200
202
  *listFiles() {
201
203
  for (const [archiveName, files] of this.entries.entries()) {
204
+ this.logger.info(`[ArchiveUriSupporter#listFiles] Listing ${files.size} files from ${archiveName}`);
202
205
  for (const file of files.values()) {
203
206
  yield ArchiveUriSupporter.getUri(archiveName, file.path);
204
207
  }
@@ -236,27 +239,17 @@ export class ArchiveUriSupporter {
236
239
  if (entries.has(archiveName)) {
237
240
  throw new Error(`A different URI with ${archiveName} already exists`);
238
241
  }
239
- /// Debug message for #1609
240
- logger.info(`[ArchiveUriSupporter#create] Extracting archive ${archiveName} from ${uri}`);
241
242
  const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), { stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0 });
242
- const newEntries = new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f]));
243
243
  /// Debug message for #1609
244
- logger.info(`[ArchiveUriSupporter#create] Extracted ${files.length} files, adding ${newEntries.size} entries`);
245
- for (const [path, entry] of [...newEntries.entries()].slice(0, 20)) {
246
- logger.info(`[ArchiveUriSupporter#create] ${path} (${entry.data.length} bytes)`);
247
- }
248
- entries.set(archiveName, newEntries);
244
+ logger.info(`[ArchiveUriSupporter#create] Extracted ${files.length} files from ${archiveName}`);
245
+ entries.set(archiveName, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
249
246
  }
250
247
  }
251
248
  catch (e) {
252
249
  logger.error(`[ArchiveUriSupporter#create] Bad dependency ${uri}`, e);
253
250
  }
254
251
  }
255
- /// Debug message for #1609
256
- logger.info(`[ArchiveUriSupporter#create] Finalizing with ${entries.size} archives: ${[
257
- ...entries.keys(),
258
- ]}`);
259
- return new ArchiveUriSupporter(externals, entries);
252
+ return new ArchiveUriSupporter(externals, logger, entries);
260
253
  }
261
254
  }
262
255
  async function hashFile(externals, uri) {
@@ -1,4 +1,3 @@
1
- import type { Ignore } from 'ignore';
2
1
  import type { TextDocumentContentChangeEvent } from 'vscode-languageserver-textdocument';
3
2
  import { TextDocument } from 'vscode-languageserver-textdocument';
4
3
  import type { ExternalEventEmitter, Externals } from '../common/index.js';
@@ -98,11 +97,9 @@ export type ProjectData = Pick<Project, 'cacheRoot' | 'config' | 'downloader' |
98
97
  export declare class Project implements ExternalEventEmitter {
99
98
  #private;
100
99
  private static readonly RootSuffix;
101
- private static readonly GitIgnore;
102
100
  readonly cacheService: CacheService;
103
101
  get isReady(): boolean;
104
102
  config: Config;
105
- ignore: Ignore;
106
103
  readonly downloader: Downloader;
107
104
  readonly externals: Externals;
108
105
  readonly fs: FileService;
@@ -161,7 +158,6 @@ export declare class Project implements ExternalEventEmitter {
161
158
  getTrackedFiles(): string[];
162
159
  constructor({ cacheRoot, defaultConfig, downloader, externals, fs, initializers, isDebugging, logger, profilers, projectRoots, }: ProjectOptions);
163
160
  private setInitPromise;
164
- private readGitignore;
165
161
  private setReadyPromise;
166
162
  /**
167
163
  * Load the config file and initialize parsers and processors.
@@ -203,6 +199,7 @@ export declare class Project implements ExternalEventEmitter {
203
199
  ensureClientManagedChecked(uri: string): Promise<DocAndNode | undefined>;
204
200
  getClientManaged(uri: string): DocAndNode | undefined;
205
201
  showCacheRoot(): Promise<void>;
202
+ shouldExclude(uri: string): boolean;
206
203
  private tryClearingCache;
207
204
  private shouldRemove;
208
205
  private isOnlyWatched;
@@ -4,7 +4,7 @@ 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
+ import * as micromatch from 'micromatch';
8
8
  import { TextDocument } from 'vscode-languageserver-textdocument';
9
9
  import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, } from '../common/index.js';
10
10
  import { FileNode } from '../node/index.js';
@@ -63,7 +63,6 @@ const CacheAutoSaveInterval = 600_000; // 10 Minutes.
63
63
  */
64
64
  export class Project {
65
65
  static RootSuffix = '/pack.mcmeta';
66
- static GitIgnore = '.gitignore';
67
66
  /** Prevent circular binding. */
68
67
  #bindingInProgressUris = new Set();
69
68
  #cacheSaverIntervalId;
@@ -85,7 +84,6 @@ export class Project {
85
84
  return this.#isReady;
86
85
  }
87
86
  config;
88
- ignore = ignore();
89
87
  downloader;
90
88
  externals;
91
89
  fs;
@@ -155,10 +153,11 @@ export class Project {
155
153
  */
156
154
  getTrackedFiles() {
157
155
  const extensions = this.meta.getSupportedFileExtensions();
156
+ this.logger.info(`[Project#getTrackedFiles] Supported file extensions: ${extensions}`);
158
157
  const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles]
159
158
  .filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
160
- const filteredFiles = this.ignore.filter(supportedFiles);
161
- return filteredFiles;
159
+ this.logger.info(`[Project#getTrackedFiles] Listed ${supportedFiles.length} supported files`);
160
+ return supportedFiles;
162
161
  }
163
162
  constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], isDebugging = false, logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoots, }) {
164
163
  this.#cacheRoot = cacheRoot;
@@ -224,21 +223,6 @@ export class Project {
224
223
  });
225
224
  }
226
225
  setInitPromise() {
227
- const loadConfig = async () => {
228
- this.config = await this.#configService.load();
229
- this.ignore = ignore();
230
- for (const pattern of this.config.env.exclude) {
231
- if (pattern === '@gitignore') {
232
- const gitignore = await this.readGitignore();
233
- if (gitignore) {
234
- this.ignore.add(gitignore);
235
- }
236
- }
237
- else {
238
- this.ignore.add(pattern);
239
- }
240
- }
241
- };
242
226
  const callIntializers = async () => {
243
227
  const initCtx = {
244
228
  cacheRoot: this.cacheRoot,
@@ -268,29 +252,13 @@ export class Project {
268
252
  this.symbols = new SymbolUtil(symbols, this.externals.event.EventEmitter);
269
253
  this.symbols.buildCache();
270
254
  __profiler.task('Load Cache');
271
- await loadConfig();
255
+ this.config = await this.#configService.load();
272
256
  __profiler.task('Load Config');
273
257
  await callIntializers();
274
258
  __profiler.task('Initialize').finalize();
275
259
  };
276
260
  this.#initPromise = init();
277
261
  }
278
- async readGitignore() {
279
- if (this.projectRoots.length === 0) {
280
- return undefined;
281
- }
282
- try {
283
- const uri = this.projectRoots[0] + Project.GitIgnore;
284
- const contents = await this.externals.fs.readFile(uri);
285
- return bufferToString(contents);
286
- }
287
- catch (e) {
288
- if (!this.externals.error.isKind(e, 'ENOENT')) {
289
- this.logger.error(`[Project] [readGitignore]`, e);
290
- }
291
- }
292
- return undefined;
293
- }
294
262
  setReadyPromise() {
295
263
  const getDependencies = async () => {
296
264
  const ans = [];
@@ -336,15 +304,24 @@ export class Project {
336
304
  this.#watcherReady = true;
337
305
  resolve();
338
306
  }).on('add', (uri) => {
307
+ if (this.shouldExclude(uri)) {
308
+ return;
309
+ }
339
310
  this.#watchedFiles.add(uri);
340
311
  if (this.#watcherReady) {
341
312
  this.emit('fileCreated', { uri });
342
313
  }
343
314
  }).on('change', (uri) => {
315
+ if (this.shouldExclude(uri)) {
316
+ return;
317
+ }
344
318
  if (this.#watcherReady) {
345
319
  this.emit('fileModified', { uri });
346
320
  }
347
321
  }).on('unlink', (uri) => {
322
+ if (this.shouldExclude(uri)) {
323
+ return;
324
+ }
348
325
  this.#watchedFiles.delete(uri);
349
326
  if (this.#watcherReady) {
350
327
  this.emit('fileDeleted', { uri });
@@ -390,6 +367,17 @@ export class Project {
390
367
  __profiler.task('Bind URIs');
391
368
  const files = [...addedFiles, ...changedFiles].sort(this.meta.uriSorter);
392
369
  __profiler.task('Sort URIs');
370
+ const fileCountByExtension = new Map();
371
+ for (const file of files) {
372
+ const ext = fileUtil.extname(file)?.replace(/^\./, '');
373
+ if (ext) {
374
+ fileCountByExtension.set(ext, (fileCountByExtension.get(ext) ?? 0) + 1);
375
+ }
376
+ }
377
+ this.logger.info(`[Project#ready] == Files to bind ==`);
378
+ for (const [ext, count] of fileCountByExtension.entries()) {
379
+ this.logger.info(`[Project#ready] File extension ${ext}: ${count}`);
380
+ }
393
381
  const __bindProfiler = this.profilers.get('project#ready#bind', 'top-n', 50);
394
382
  for (const uri of files) {
395
383
  await this.ensureBindingStarted(uri);
@@ -657,6 +645,9 @@ export class Project {
657
645
  if (!fileUtil.isFileUri(uri)) {
658
646
  return; // We only accept `file:` scheme for client-managed URIs.
659
647
  }
648
+ if (this.shouldExclude(uri)) {
649
+ return;
650
+ }
660
651
  const doc = TextDocument.create(uri, languageID, version, content);
661
652
  const node = this.parse(doc);
662
653
  this.#clientManagedUris.add(uri);
@@ -676,6 +667,9 @@ export class Project {
676
667
  if (!fileUtil.isFileUri(uri)) {
677
668
  return; // We only accept `file:` scheme for client-managed URIs.
678
669
  }
670
+ if (this.shouldExclude(uri)) {
671
+ return;
672
+ }
679
673
  const doc = this.#clientManagedDocAndNodes.get(uri)?.doc;
680
674
  if (!doc) {
681
675
  throw new Error(`TextDocument for ${uri} is not cached. This should not happen. Did the language client send a didChange notification without sending a didOpen one, or is there a logic error on our side resulting the 'read' function overriding the 'TextDocument' created in the 'didOpen' notification handler?`);
@@ -730,6 +724,17 @@ export class Project {
730
724
  this.logger.error('[Service#showCacheRoot]', e);
731
725
  }
732
726
  }
727
+ shouldExclude(uri) {
728
+ if (this.config.env.exclude.length === 0) {
729
+ return false;
730
+ }
731
+ for (const rel of fileUtil.getRels(uri, this.projectRoots)) {
732
+ if (micromatch.any(rel, this.config.env.exclude)) {
733
+ return true;
734
+ }
735
+ }
736
+ return false;
737
+ }
733
738
  tryClearingCache(uri) {
734
739
  if (this.shouldRemove(uri)) {
735
740
  this.removeCachedTextDocument(uri);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spyglassmc/core",
3
- "version": "0.4.18",
3
+ "version": "0.4.20",
4
4
  "type": "module",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -19,16 +19,17 @@
19
19
  "chokidar": "^3.5.2",
20
20
  "decompress": "^4.2.1",
21
21
  "follow-redirects": "^1.14.8",
22
- "ignore": "^5.3.1",
22
+ "micromatch": "^4.0.8",
23
23
  "pako": "^2.0.4",
24
24
  "rfdc": "^1.3.0",
25
25
  "vscode-languageserver-textdocument": "^1.0.4",
26
26
  "whatwg-url": "^14.0.0",
27
- "@spyglassmc/locales": "0.3.10"
27
+ "@spyglassmc/locales": "0.3.11"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/decompress": "^4.2.3",
31
31
  "@types/follow-redirects": "^1.14.1",
32
+ "@types/micromatch": "^4.0.9",
32
33
  "@types/pako": "^2.0.0",
33
34
  "@types/whatwg-url": "^11.0.4"
34
35
  },