@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.
- package/lib/service/CacheService.js +2 -2
- package/lib/service/Config.d.ts +1 -1
- package/lib/service/Config.js +1 -1
- package/lib/service/FileService.d.ts +1 -0
- package/lib/service/FileService.js +7 -14
- package/lib/service/Project.d.ts +1 -4
- package/lib/service/Project.js +42 -37
- package/package.json +4 -3
|
@@ -130,8 +130,8 @@ export class CacheService {
|
|
|
130
130
|
ans.unchangedFiles.push(uri);
|
|
131
131
|
continue;
|
|
132
132
|
}
|
|
133
|
-
if (this.project.
|
|
134
|
-
ans.
|
|
133
|
+
if (this.project.shouldExclude(uri)) {
|
|
134
|
+
ans.removedFiles.push(uri);
|
|
135
135
|
continue;
|
|
136
136
|
}
|
|
137
137
|
try {
|
package/lib/service/Config.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface EnvConfig {
|
|
|
59
59
|
*/
|
|
60
60
|
dependencies: string[];
|
|
61
61
|
/**
|
|
62
|
-
* A list of file patterns to exclude.
|
|
62
|
+
* A list of file patterns to exclude.
|
|
63
63
|
*/
|
|
64
64
|
exclude: string[];
|
|
65
65
|
/**
|
package/lib/service/Config.js
CHANGED
|
@@ -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: ['
|
|
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
|
|
245
|
-
|
|
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
|
-
|
|
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) {
|
package/lib/service/Project.d.ts
CHANGED
|
@@ -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;
|
package/lib/service/Project.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
161
|
-
return
|
|
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
|
|
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.
|
|
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
|
-
"
|
|
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.
|
|
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
|
},
|