@spyglassmc/core 0.4.42 → 0.4.44
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/common/UriStore.d.ts +43 -0
- package/lib/common/UriStore.js +166 -0
- package/lib/common/externals/BrowserExternals.js +9 -19
- package/lib/common/externals/NodeJsExternals.d.ts +10 -15
- package/lib/common/externals/NodeJsExternals.js +12 -39
- package/lib/common/externals/index.d.ts +17 -26
- package/lib/common/index.d.ts +1 -0
- package/lib/common/index.js +1 -0
- package/lib/common/util.d.ts +12 -2
- package/lib/common/util.js +31 -12
- package/lib/service/Config.d.ts +15 -25
- package/lib/service/Config.js +88 -4
- package/lib/service/FileWatcher.d.ts +21 -0
- package/lib/service/FileWatcher.js +2 -0
- package/lib/service/Project.d.ts +16 -8
- package/lib/service/Project.js +122 -129
- package/lib/service/Service.d.ts +1 -1
- package/lib/service/fileUtil.d.ts +3 -1
- package/lib/service/fileUtil.js +8 -4
- package/lib/service/index.d.ts +1 -0
- package/lib/service/index.js +1 -0
- package/lib/symbol/Symbol.d.ts +8 -8
- package/lib/symbol/Symbol.js +1 -0
- package/package.json +6 -6
package/lib/service/Project.js
CHANGED
|
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import picomatch from 'picomatch';
|
|
8
8
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
9
|
-
import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, } from '../common/index.js';
|
|
9
|
+
import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, UriStore, } from '../common/index.js';
|
|
10
10
|
import { FileNode } from '../node/index.js';
|
|
11
11
|
import { file } from '../parser/index.js';
|
|
12
12
|
import { traversePreOrder } from '../processor/index.js';
|
|
@@ -73,11 +73,13 @@ export class Project {
|
|
|
73
73
|
#symbolUpToDateUris = new Set();
|
|
74
74
|
#eventEmitter;
|
|
75
75
|
#initializers;
|
|
76
|
+
#watcher;
|
|
77
|
+
get watchedFiles() {
|
|
78
|
+
return this.#watcher?.watchedFiles ?? new UriStore();
|
|
79
|
+
}
|
|
76
80
|
#initPromise;
|
|
77
81
|
#readyPromise;
|
|
78
|
-
#
|
|
79
|
-
#watcher;
|
|
80
|
-
#watcherReady = false;
|
|
82
|
+
#isInitialized = false;
|
|
81
83
|
#isReady = false;
|
|
82
84
|
get isReady() {
|
|
83
85
|
return this.#isReady;
|
|
@@ -150,7 +152,7 @@ export class Project {
|
|
|
150
152
|
* are not loaded into the memory.
|
|
151
153
|
*/
|
|
152
154
|
getTrackedFiles() {
|
|
153
|
-
const supportedFiles = [...this.#dependencyFiles ?? [], ...this
|
|
155
|
+
const supportedFiles = [...this.#dependencyFiles ?? [], ...this.watchedFiles];
|
|
154
156
|
this.logger.info(`[Project#getTrackedFiles] Listed ${supportedFiles.length} supported files`);
|
|
155
157
|
return supportedFiles;
|
|
156
158
|
}
|
|
@@ -171,12 +173,11 @@ export class Project {
|
|
|
171
173
|
this.logger.info(`[Project] [init] cacheRoot = ${cacheRoot}`);
|
|
172
174
|
this.logger.info(`[Project] [init] projectRoots = ${projectRoots.join(' ')}`);
|
|
173
175
|
this.#configService.on('changed', ({ config }) => {
|
|
176
|
+
const oldConfig = this.config;
|
|
174
177
|
this.config = config;
|
|
175
178
|
this.logger.info('[Project] [Config] Changed');
|
|
176
|
-
this.emit('configChanged', config);
|
|
179
|
+
this.emit('configChanged', { oldConfig, newConfig: config });
|
|
177
180
|
}).on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading ${uri}`, error));
|
|
178
|
-
this.setInitPromise();
|
|
179
|
-
this.setReadyPromise();
|
|
180
181
|
this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
|
|
181
182
|
this.on('documentUpdated', ({ doc, node }) => {
|
|
182
183
|
// if (!this.#isReady) {
|
|
@@ -212,12 +213,19 @@ export class Project {
|
|
|
212
213
|
// Recheck client managed files after the READY process, as they may have incomplete results and are user-facing.
|
|
213
214
|
const promises = [];
|
|
214
215
|
for (const { doc, node } of this.#clientManagedDocAndNodes.values()) {
|
|
215
|
-
promises.push(this.check(doc, node));
|
|
216
|
+
promises.push(this.bind(doc, node).then(() => this.check(doc, node)));
|
|
216
217
|
}
|
|
217
218
|
Promise.all(promises).catch(e => this.logger.error('[Project#ready] Error occurred when rechecking client managed files after READY', e));
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Load the config file and initialize parsers and processors.
|
|
223
|
+
*/
|
|
224
|
+
async init() {
|
|
225
|
+
return (this.#initPromise ??= this.#init());
|
|
226
|
+
}
|
|
227
|
+
async #init() {
|
|
228
|
+
this.#isInitialized = false;
|
|
221
229
|
const callIntializers = async () => {
|
|
222
230
|
const initCtx = {
|
|
223
231
|
cacheRoot: this.cacheRoot,
|
|
@@ -240,20 +248,30 @@ export class Project {
|
|
|
240
248
|
});
|
|
241
249
|
this.#ctx = ctx;
|
|
242
250
|
};
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
const __profiler = this.profilers.get('project#init');
|
|
252
|
+
const { symbols } = await this.cacheService.load();
|
|
253
|
+
this.symbols = new SymbolUtil(symbols, this.externals.event.EventEmitter);
|
|
254
|
+
this.symbols.buildCache();
|
|
255
|
+
__profiler.task('Load Cache');
|
|
256
|
+
this.config = await this.#configService.load();
|
|
257
|
+
__profiler.task('Load Config');
|
|
258
|
+
await callIntializers();
|
|
259
|
+
__profiler.task('Initialize').finalize();
|
|
260
|
+
this.#isInitialized = true;
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Finish the initial run of parsing, binding, and checking the entire project.
|
|
265
|
+
*/
|
|
266
|
+
async ready(options = {}) {
|
|
267
|
+
return (this.#readyPromise ??= this.#ready(options));
|
|
255
268
|
}
|
|
256
|
-
|
|
269
|
+
async #ready({ projectRootsWatcher } = {}) {
|
|
270
|
+
if (!this.#isInitialized) {
|
|
271
|
+
throw new Error('Project.ready() must be called after Project.init() resolves');
|
|
272
|
+
}
|
|
273
|
+
this.#isReady = false;
|
|
274
|
+
this.#watcher = projectRootsWatcher;
|
|
257
275
|
const getDependencies = async () => {
|
|
258
276
|
const dependencies = [];
|
|
259
277
|
for (const input of this.config.env.dependencies) {
|
|
@@ -292,119 +310,92 @@ export class Project {
|
|
|
292
310
|
this.fs.register('file:', fileUriSupporter, true);
|
|
293
311
|
this.fs.register(ArchiveUriSupporter.Protocol, archiveUriSupporter, true);
|
|
294
312
|
};
|
|
295
|
-
const listProjectFiles =
|
|
296
|
-
if (this
|
|
297
|
-
resolve();
|
|
313
|
+
const listProjectFiles = async () => {
|
|
314
|
+
if (!this.#watcher) {
|
|
298
315
|
return;
|
|
299
316
|
}
|
|
300
|
-
this.#
|
|
301
|
-
|
|
302
|
-
this.#watcher = this.externals.fs.watch(this.projectRoots, {
|
|
303
|
-
usePolling: this.config.env.useFilePolling,
|
|
304
|
-
}).once('ready', () => {
|
|
305
|
-
this.#watcherReady = true;
|
|
306
|
-
resolve();
|
|
307
|
-
}).on('add', (uri) => {
|
|
308
|
-
if (this.shouldExclude(uri)) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
this.#watchedFiles.add(uri);
|
|
312
|
-
if (this.#watcherReady) {
|
|
313
|
-
this.emit('fileCreated', { uri });
|
|
314
|
-
}
|
|
315
|
-
}).on('change', (uri) => {
|
|
317
|
+
this.#watcher
|
|
318
|
+
.on('add', (uri) => {
|
|
316
319
|
if (this.shouldExclude(uri)) {
|
|
317
320
|
return;
|
|
318
321
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}).on('unlink', (uri) => {
|
|
322
|
+
this.emit('fileCreated', { uri });
|
|
323
|
+
})
|
|
324
|
+
.on('change', (uri) => {
|
|
323
325
|
if (this.shouldExclude(uri)) {
|
|
324
326
|
return;
|
|
325
327
|
}
|
|
326
|
-
this
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
const ready = async () => {
|
|
335
|
-
await this.init();
|
|
336
|
-
const __profiler = this.profilers.get('project#ready');
|
|
337
|
-
await Promise.all([listDependencyFiles(), listProjectFiles()]);
|
|
338
|
-
this.#dependencyFiles = new Set([...this.fs.listFiles()]
|
|
339
|
-
.filter((uri) => !this.shouldExclude(uri)));
|
|
340
|
-
this.#dependencyRoots = new Set(this.fs.listRoots());
|
|
341
|
-
this.updateRoots();
|
|
342
|
-
__profiler.task('List URIs');
|
|
343
|
-
for (const [id, { checksum, registrar }] of this.meta.symbolRegistrars) {
|
|
344
|
-
const cacheChecksum = this.cacheService.checksums.symbolRegistrars[id];
|
|
345
|
-
if (cacheChecksum === undefined || checksum !== cacheChecksum) {
|
|
346
|
-
this.symbols.clear({ contributor: `symbol_registrar/${id}` });
|
|
347
|
-
this.symbols.contributeAs(`symbol_registrar/${id}`, () => {
|
|
348
|
-
registrar(this.symbols, { logger: this.logger });
|
|
349
|
-
});
|
|
350
|
-
this.emit('symbolRegistrarExecuted', { id, checksum });
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
this.logger.info(`[SymbolRegistrar] Skipped “${id}” thanks to cache ${checksum}`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
__profiler.task('Register Symbols');
|
|
357
|
-
for (const [uri, values] of Object.entries(this.cacheService.errors)) {
|
|
358
|
-
this.emit('documentErrored', { errors: values, uri });
|
|
359
|
-
}
|
|
360
|
-
__profiler.task('Pop Errors');
|
|
361
|
-
const { addedFiles, changedFiles, removedFiles } = await this.cacheService.validate();
|
|
362
|
-
for (const uri of removedFiles) {
|
|
328
|
+
this.emit('fileModified', { uri });
|
|
329
|
+
})
|
|
330
|
+
.on('unlink', (uri) => {
|
|
331
|
+
// No `this.shouldExclude(uri)` check here as `unlink` events may be sent for
|
|
332
|
+
// hot-reload file exclusions. We want to be able to clean up the symbols for these
|
|
333
|
+
// excluded files.
|
|
363
334
|
this.emit('fileDeleted', { uri });
|
|
335
|
+
})
|
|
336
|
+
.on('error', (e) => {
|
|
337
|
+
this.logger.error('[Project#watcher]', e);
|
|
338
|
+
});
|
|
339
|
+
await this.#watcher.ready();
|
|
340
|
+
};
|
|
341
|
+
const __profiler = this.profilers.get('project#ready');
|
|
342
|
+
await Promise.all([listDependencyFiles(), listProjectFiles()]);
|
|
343
|
+
this.#dependencyFiles = new Set([...this.fs.listFiles()]
|
|
344
|
+
.filter((uri) => !this.shouldExclude(uri)));
|
|
345
|
+
this.#dependencyRoots = new Set(this.fs.listRoots());
|
|
346
|
+
this.updateRoots();
|
|
347
|
+
__profiler.task('List URIs');
|
|
348
|
+
for (const [id, { checksum, registrar }] of this.meta.symbolRegistrars) {
|
|
349
|
+
const cacheChecksum = this.cacheService.checksums.symbolRegistrars[id];
|
|
350
|
+
if (cacheChecksum === undefined || checksum !== cacheChecksum) {
|
|
351
|
+
this.symbols.clear({ contributor: `symbol_registrar/${id}` });
|
|
352
|
+
this.symbols.contributeAs(`symbol_registrar/${id}`, () => {
|
|
353
|
+
registrar(this.symbols, { logger: this.logger });
|
|
354
|
+
});
|
|
355
|
+
this.emit('symbolRegistrarExecuted', { id, checksum });
|
|
364
356
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
this.bindUri(addedFiles);
|
|
368
|
-
}
|
|
369
|
-
__profiler.task('Bind URIs');
|
|
370
|
-
const files = [...addedFiles, ...changedFiles].sort(this.meta.uriSorter);
|
|
371
|
-
__profiler.task('Sort URIs');
|
|
372
|
-
const fileCountByExtension = new Map();
|
|
373
|
-
for (const file of files) {
|
|
374
|
-
const ext = fileUtil.extname(file)?.replace(/^\./, '');
|
|
375
|
-
if (ext) {
|
|
376
|
-
fileCountByExtension.set(ext, (fileCountByExtension.get(ext) ?? 0) + 1);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
this.logger.info(`[Project#ready] == Files to bind ==`);
|
|
380
|
-
for (const [ext, count] of fileCountByExtension.entries()) {
|
|
381
|
-
this.logger.info(`[Project#ready] File extension ${ext}: ${count}`);
|
|
357
|
+
else {
|
|
358
|
+
this.logger.info(`[SymbolRegistrar] Skipped “${id}” thanks to cache ${checksum}`);
|
|
382
359
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
360
|
+
}
|
|
361
|
+
__profiler.task('Register Symbols');
|
|
362
|
+
for (const [uri, values] of Object.entries(this.cacheService.errors)) {
|
|
363
|
+
this.emit('documentErrored', { errors: values, uri });
|
|
364
|
+
}
|
|
365
|
+
__profiler.task('Pop Errors');
|
|
366
|
+
const { addedFiles, changedFiles, removedFiles } = await this.cacheService.validate();
|
|
367
|
+
this.logger.info(`[Project#ready] Files added/changed/removed: ${addedFiles.length}/${changedFiles.length}/${removedFiles.length}`);
|
|
368
|
+
for (const uri of removedFiles) {
|
|
369
|
+
this.emit('fileDeleted', { uri });
|
|
370
|
+
}
|
|
371
|
+
__profiler.task('Validate Cache');
|
|
372
|
+
if (addedFiles.length > 0) {
|
|
373
|
+
this.bindUri(addedFiles);
|
|
374
|
+
}
|
|
375
|
+
__profiler.task('Bind URIs');
|
|
376
|
+
const files = [...addedFiles, ...changedFiles].sort(this.meta.uriSorter);
|
|
377
|
+
__profiler.task('Sort URIs');
|
|
378
|
+
const fileCountByExtension = new Map();
|
|
379
|
+
for (const file of files) {
|
|
380
|
+
const ext = fileUtil.extname(file)?.replace(/^\./, '');
|
|
381
|
+
if (ext) {
|
|
382
|
+
fileCountByExtension.set(ext, (fileCountByExtension.get(ext) ?? 0) + 1);
|
|
387
383
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Finish the initial run of parsing, binding, and checking the entire project.
|
|
405
|
-
*/
|
|
406
|
-
async ready() {
|
|
407
|
-
await this.#readyPromise;
|
|
384
|
+
}
|
|
385
|
+
this.logger.info(`[Project#ready] == Files to bind ==`);
|
|
386
|
+
for (const [ext, count] of fileCountByExtension.entries()) {
|
|
387
|
+
this.logger.info(`[Project#ready] File extension ${ext}: ${count}`);
|
|
388
|
+
}
|
|
389
|
+
const __bindProfiler = this.profilers.get('project#ready#bind', 'top-n', 50);
|
|
390
|
+
for (const uri of files) {
|
|
391
|
+
await this.ensureBindingStarted(uri);
|
|
392
|
+
__bindProfiler.task(uri);
|
|
393
|
+
}
|
|
394
|
+
__bindProfiler.finalize();
|
|
395
|
+
__profiler.task('Bind Files');
|
|
396
|
+
__profiler.finalize();
|
|
397
|
+
this.emit('ready', {});
|
|
398
|
+
this.#isReady = true;
|
|
408
399
|
return this;
|
|
409
400
|
}
|
|
410
401
|
/**
|
|
@@ -412,15 +403,14 @@ export class Project {
|
|
|
412
403
|
*/
|
|
413
404
|
async close() {
|
|
414
405
|
clearInterval(this.#cacheSaverIntervalId);
|
|
415
|
-
await this.#watcher
|
|
406
|
+
await this.#watcher?.close();
|
|
416
407
|
await this.cacheService.save();
|
|
417
408
|
}
|
|
418
409
|
async restart() {
|
|
419
410
|
try {
|
|
420
|
-
await this.#watcher.close();
|
|
421
411
|
this.#bindingInProgressUris.clear();
|
|
422
412
|
this.#symbolUpToDateUris.clear();
|
|
423
|
-
this
|
|
413
|
+
this.#readyPromise = undefined;
|
|
424
414
|
await this.ready();
|
|
425
415
|
}
|
|
426
416
|
catch (e) {
|
|
@@ -770,13 +760,16 @@ export class Project {
|
|
|
770
760
|
shouldRemove(uri) {
|
|
771
761
|
return (!this.#clientManagedUris.has(uri)
|
|
772
762
|
&& !this.#dependencyFiles?.has(uri)
|
|
773
|
-
&& !this
|
|
763
|
+
&& !this.watchedFiles.has(uri));
|
|
774
764
|
}
|
|
775
765
|
isOnlyWatched(uri) {
|
|
776
|
-
return (this
|
|
766
|
+
return (this.watchedFiles.has(uri)
|
|
777
767
|
&& !this.#clientManagedUris.has(uri)
|
|
778
768
|
&& !this.#dependencyFiles?.has(uri));
|
|
779
769
|
}
|
|
770
|
+
async onEditorConfigurationUpdate(editorConfiguration) {
|
|
771
|
+
await this.#configService.onEditorConfigurationUpdate(editorConfiguration);
|
|
772
|
+
}
|
|
780
773
|
}
|
|
781
774
|
__decorate([
|
|
782
775
|
SingletonPromise()
|
package/lib/service/Service.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare class Service {
|
|
|
28
28
|
getCodeActions(node: FileNode<AstNode>, doc: TextDocument, range: Range): readonly CodeAction[];
|
|
29
29
|
getColorInfo(node: FileNode<AstNode>, doc: TextDocument): ColorInfo[];
|
|
30
30
|
getColorPresentation(file: FileNode<AstNode>, doc: TextDocument, range: Range, color: Color): ColorPresentation[];
|
|
31
|
-
complete(node: FileNode<AstNode>, doc: TextDocument, offset: number, triggerCharacter?: string): import("../index.js").CompletionItem[];
|
|
31
|
+
complete(node: FileNode<AstNode>, doc: TextDocument, offset: number, triggerCharacter?: string): import("../processor/index.js").CompletionItem[];
|
|
32
32
|
dataHackPubify(initialism: string): string;
|
|
33
33
|
format(node: FileNode<AstNode>, doc: TextDocument, tabSize: number, insertSpaces: boolean): string;
|
|
34
34
|
getHover(file: FileNode<AstNode>, doc: TextDocument, offset: number): Hover | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Externals, FsLocation } from '../common/index.js';
|
|
2
|
+
import { Uri } from '../common/index.js';
|
|
2
3
|
export type RootUriString = `${string}/`;
|
|
3
4
|
export type FileExtension = `.${string}`;
|
|
4
5
|
export declare namespace fileUtil {
|
|
@@ -35,6 +36,7 @@ export declare namespace fileUtil {
|
|
|
35
36
|
function getRoot(uri: string, rootUris: readonly RootUriString[]): string | undefined;
|
|
36
37
|
function isRootUri(uri: string): uri is RootUriString;
|
|
37
38
|
function ensureEndingSlash(uri: string): RootUriString;
|
|
39
|
+
function trimEndingSlash(uri: string): string;
|
|
38
40
|
function join(fromUri: string, toUri: string): string;
|
|
39
41
|
function isFileUri(uri: string): boolean;
|
|
40
42
|
/**
|
|
@@ -49,7 +51,7 @@ export declare namespace fileUtil {
|
|
|
49
51
|
* @returns The part from the beginning of the URI to the last `/`.
|
|
50
52
|
*/
|
|
51
53
|
function dirname(uri: string): string;
|
|
52
|
-
function
|
|
54
|
+
function getParentOfUri(uri: FsLocation): Uri;
|
|
53
55
|
/**
|
|
54
56
|
* @throws
|
|
55
57
|
*
|
package/lib/service/fileUtil.js
CHANGED
|
@@ -82,6 +82,10 @@ export var fileUtil;
|
|
|
82
82
|
return isRootUri(uri) ? uri : `${uri}/`;
|
|
83
83
|
}
|
|
84
84
|
fileUtil.ensureEndingSlash = ensureEndingSlash;
|
|
85
|
+
function trimEndingSlash(uri) {
|
|
86
|
+
return isRootUri(uri) ? uri.slice(0, -1) : uri;
|
|
87
|
+
}
|
|
88
|
+
fileUtil.trimEndingSlash = trimEndingSlash;
|
|
85
89
|
function join(fromUri, toUri) {
|
|
86
90
|
return (ensureEndingSlash(fromUri) + (toUri.startsWith('/') ? toUri.slice(1) : toUri));
|
|
87
91
|
}
|
|
@@ -115,10 +119,10 @@ export var fileUtil;
|
|
|
115
119
|
}
|
|
116
120
|
fileUtil.dirname = dirname;
|
|
117
121
|
/* istanbul ignore next */
|
|
118
|
-
function
|
|
119
|
-
return new Uri('.',
|
|
122
|
+
function getParentOfUri(uri) {
|
|
123
|
+
return new Uri('.', trimEndingSlash(uri.toString()));
|
|
120
124
|
}
|
|
121
|
-
fileUtil.
|
|
125
|
+
fileUtil.getParentOfUri = getParentOfUri;
|
|
122
126
|
/* istanbul ignore next */
|
|
123
127
|
/**
|
|
124
128
|
* @throws
|
|
@@ -145,7 +149,7 @@ export var fileUtil;
|
|
|
145
149
|
* @param mode Default to `0o777` (`rwxrwxrwx`)
|
|
146
150
|
*/
|
|
147
151
|
async function ensureParentOfFile(externals, path, mode = 0o777) {
|
|
148
|
-
return ensureDir(externals,
|
|
152
|
+
return ensureDir(externals, getParentOfUri(path), mode);
|
|
149
153
|
}
|
|
150
154
|
fileUtil.ensureParentOfFile = ensureParentOfFile;
|
|
151
155
|
async function chmod(externals, path, mode) {
|
package/lib/service/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './ErrorReporter.js';
|
|
|
6
6
|
export * from './fetcher.js';
|
|
7
7
|
export { FileService, UriProtocolSupporter } from './FileService.js';
|
|
8
8
|
export * from './fileUtil.js';
|
|
9
|
+
export * from './FileWatcher.js';
|
|
9
10
|
export * from './Hover.js';
|
|
10
11
|
export * from './MetaRegistry.js';
|
|
11
12
|
export * from './Profiler.js';
|
package/lib/service/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './ErrorReporter.js';
|
|
|
7
7
|
export * from './fetcher.js';
|
|
8
8
|
export { FileService } from './FileService.js';
|
|
9
9
|
export * from './fileUtil.js';
|
|
10
|
+
export * from './FileWatcher.js';
|
|
10
11
|
export * from './Hover.js';
|
|
11
12
|
export * from './MetaRegistry.js';
|
|
12
13
|
export * from './Profiler.js';
|