@platformos/platformos-language-server-common 0.0.11 → 0.0.13
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/CHANGELOG.md +43 -0
- package/dist/PropertyShapeInference.d.ts +5 -0
- package/dist/PropertyShapeInference.js +28 -0
- package/dist/PropertyShapeInference.js.map +1 -1
- package/dist/TypeSystem.js +117 -60
- package/dist/TypeSystem.js.map +1 -1
- package/dist/VariableShapeExtractor.js +2 -4
- package/dist/VariableShapeExtractor.js.map +1 -1
- package/dist/codeActions/CodeActionsProvider.d.ts +1 -1
- package/dist/codeActions/providers/GenerateDocBlockProvider.d.ts +10 -0
- package/dist/codeActions/providers/GenerateDocBlockProvider.js +39 -0
- package/dist/codeActions/providers/GenerateDocBlockProvider.js.map +1 -0
- package/dist/commands/providers/GenerateDocBlockCommandProvider.d.ts +19 -0
- package/dist/commands/providers/GenerateDocBlockCommandProvider.js +64 -0
- package/dist/commands/providers/GenerateDocBlockCommandProvider.js.map +1 -0
- package/dist/completions/CompletionsProvider.d.ts +1 -0
- package/dist/completions/CompletionsProvider.js +6 -0
- package/dist/completions/CompletionsProvider.js.map +1 -1
- package/dist/completions/params/LiquidCompletionParams.js +7 -2
- package/dist/completions/params/LiquidCompletionParams.js.map +1 -1
- package/dist/completions/providers/GraphQLFieldCompletionProvider.d.ts +12 -0
- package/dist/completions/providers/GraphQLFieldCompletionProvider.js +75 -0
- package/dist/completions/providers/GraphQLFieldCompletionProvider.js.map +1 -0
- package/dist/definitions/DefinitionProvider.d.ts +19 -1
- package/dist/definitions/DefinitionProvider.js +33 -1
- package/dist/definitions/DefinitionProvider.js.map +1 -1
- package/dist/definitions/providers/PageRouteDefinitionProvider.d.ts +51 -0
- package/dist/definitions/providers/PageRouteDefinitionProvider.js +204 -0
- package/dist/definitions/providers/PageRouteDefinitionProvider.js.map +1 -0
- package/dist/definitions/providers/RenderPartialDefinitionProvider.d.ts +14 -0
- package/dist/definitions/providers/RenderPartialDefinitionProvider.js +50 -0
- package/dist/definitions/providers/RenderPartialDefinitionProvider.js.map +1 -0
- package/dist/diagnostics/runChecks.d.ts +3 -1
- package/dist/diagnostics/runChecks.js +2 -1
- package/dist/diagnostics/runChecks.js.map +1 -1
- package/dist/documentLinks/DocumentLinksProvider.d.ts +3 -1
- package/dist/documentLinks/DocumentLinksProvider.js +16 -20
- package/dist/documentLinks/DocumentLinksProvider.js.map +1 -1
- package/dist/documents/DocumentManager.js +0 -4
- package/dist/documents/DocumentManager.js.map +1 -1
- package/dist/documents/types.d.ts +1 -20
- package/dist/documents/types.js.map +1 -1
- package/dist/hover/HoverProvider.d.ts +1 -0
- package/dist/hover/HoverProvider.js +6 -0
- package/dist/hover/HoverProvider.js.map +1 -1
- package/dist/hover/providers/GraphQLFieldHoverProvider.d.ts +12 -0
- package/dist/hover/providers/GraphQLFieldHoverProvider.js +85 -0
- package/dist/hover/providers/GraphQLFieldHoverProvider.js.map +1 -0
- package/dist/json/completions/providers/BlockTypeCompletionProvider.d.ts +4 -3
- package/dist/json/completions/providers/BlockTypeCompletionProvider.js +5 -10
- package/dist/json/completions/providers/BlockTypeCompletionProvider.js.map +1 -1
- package/dist/json/hover/providers/BlockSettingsHoverProvider.js +5 -10
- package/dist/json/hover/providers/BlockSettingsHoverProvider.js.map +1 -1
- package/dist/json/schemaSettings.d.ts +3 -3
- package/dist/json/schemaSettings.js.map +1 -1
- package/dist/renamed/handlers/BlockRenameHandler.d.ts +3 -3
- package/dist/renamed/handlers/BlockRenameHandler.js +86 -15
- package/dist/renamed/handlers/BlockRenameHandler.js.map +1 -1
- package/dist/renamed/handlers/SectionRenameHandler.d.ts +3 -3
- package/dist/renamed/handlers/SectionRenameHandler.js +3 -3
- package/dist/renamed/handlers/SectionRenameHandler.js.map +1 -1
- package/dist/server/AppGraphManager.js +3 -4
- package/dist/server/AppGraphManager.js.map +1 -1
- package/dist/server/CachedFileSystem.js +7 -2
- package/dist/server/CachedFileSystem.js.map +1 -1
- package/dist/server/startServer.js +71 -5
- package/dist/server/startServer.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/searchPaths.d.ts +21 -0
- package/dist/utils/searchPaths.js +34 -0
- package/dist/utils/searchPaths.js.map +1 -0
- package/package.json +6 -4
- package/src/PropertyShapeInference.spec.ts +44 -0
- package/src/PropertyShapeInference.ts +27 -0
- package/src/TypeSystem.spec.ts +59 -0
- package/src/TypeSystem.ts +132 -63
- package/src/VariableShapeExtractor.ts +2 -4
- package/src/completions/CompletionsProvider.ts +11 -0
- package/src/completions/params/LiquidCompletionParams.ts +7 -2
- package/src/completions/providers/GraphQLFieldCompletionProvider.ts +78 -0
- package/src/definitions/DefinitionProvider.ts +52 -0
- package/src/definitions/providers/PageRouteDefinitionProvider.spec.ts +753 -0
- package/src/definitions/providers/PageRouteDefinitionProvider.ts +250 -0
- package/src/definitions/providers/RenderPartialDefinitionProvider.spec.ts +191 -0
- package/src/definitions/providers/RenderPartialDefinitionProvider.ts +70 -0
- package/src/diagnostics/runChecks.ts +4 -0
- package/src/documentLinks/DocumentLinksProvider.spec.ts +131 -10
- package/src/documentLinks/DocumentLinksProvider.ts +23 -32
- package/src/documents/DocumentManager.ts +0 -4
- package/src/documents/types.ts +1 -21
- package/src/hover/HoverProvider.ts +11 -0
- package/src/hover/providers/GraphQLFieldHoverProvider.spec.ts +124 -0
- package/src/hover/providers/GraphQLFieldHoverProvider.ts +90 -0
- package/src/server/AppGraphManager.ts +3 -5
- package/src/server/CachedFileSystem.ts +11 -2
- package/src/server/startServer.ts +85 -5
- package/src/utils/searchPaths.spec.ts +101 -0
- package/src/utils/searchPaths.ts +32 -0
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
SourceCodeType,
|
|
11
11
|
UriString,
|
|
12
12
|
} from '@platformos/platformos-check-common';
|
|
13
|
-
import { TranslationProvider } from '@platformos/platformos-common';
|
|
13
|
+
import { TranslationProvider, isPage } from '@platformos/platformos-common';
|
|
14
14
|
import {
|
|
15
15
|
Connection,
|
|
16
16
|
FileChangeType,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
AppGraphRootRequest,
|
|
45
45
|
} from '../types';
|
|
46
46
|
import { debounce } from '../utils';
|
|
47
|
+
import { SearchPathsLoader } from '../utils/searchPaths';
|
|
47
48
|
import { VERSION } from '../version';
|
|
48
49
|
import { CachedFileSystem } from './CachedFileSystem';
|
|
49
50
|
import { Configuration, INCLUDE_FILES_FROM_DISK } from './Configuration';
|
|
@@ -55,6 +56,13 @@ import { URI } from 'vscode-uri';
|
|
|
55
56
|
|
|
56
57
|
const defaultLogger = () => {};
|
|
57
58
|
|
|
59
|
+
/**
|
|
60
|
+
* When a file-watcher batch contains this many page-file changes, we
|
|
61
|
+
* assume a bulk operation (git checkout, branch switch, stash pop) and
|
|
62
|
+
* fully rebuild the route table instead of applying incremental updates.
|
|
63
|
+
*/
|
|
64
|
+
const BULK_PAGE_CHANGE_THRESHOLD = 10;
|
|
65
|
+
|
|
58
66
|
/**
|
|
59
67
|
* The `git:` VFS does not support the `fs.readDirectory` call and makes most things break.
|
|
60
68
|
* `git` URIs are the ones you'd encounter when doing a git diff in VS Code. They're not
|
|
@@ -108,11 +116,13 @@ export function startServer(
|
|
|
108
116
|
const diagnosticsManager = new DiagnosticsManager(connection);
|
|
109
117
|
const documentsLocator = new DocumentsLocator(fs);
|
|
110
118
|
const translationProvider = new TranslationProvider(fs);
|
|
119
|
+
const searchPathsCache = new SearchPathsLoader(fs);
|
|
111
120
|
const documentLinksProvider = new DocumentLinksProvider(
|
|
112
121
|
documentManager,
|
|
113
122
|
findAppRootURI,
|
|
114
123
|
documentsLocator,
|
|
115
124
|
translationProvider,
|
|
125
|
+
searchPathsCache,
|
|
116
126
|
);
|
|
117
127
|
const codeActionsProvider = new CodeActionsProvider(documentManager, diagnosticsManager);
|
|
118
128
|
const onTypeFormattingProvider = new OnTypeFormattingProvider(
|
|
@@ -161,6 +171,7 @@ export function startServer(
|
|
|
161
171
|
jsonValidationSet,
|
|
162
172
|
appGraphManager,
|
|
163
173
|
includeFilesFromDisk: () => configuration[INCLUDE_FILES_FROM_DISK],
|
|
174
|
+
getRouteTable: () => definitionsProvider.getRouteTable(),
|
|
164
175
|
}),
|
|
165
176
|
100,
|
|
166
177
|
);
|
|
@@ -215,7 +226,14 @@ export function startServer(
|
|
|
215
226
|
return (documentManager.get(defaultLocaleFileUri) as AugmentedJsonSourceCode) ?? null;
|
|
216
227
|
}
|
|
217
228
|
|
|
218
|
-
const definitionsProvider = new DefinitionProvider(
|
|
229
|
+
const definitionsProvider = new DefinitionProvider(
|
|
230
|
+
documentManager,
|
|
231
|
+
getDefaultLocaleSourceCode,
|
|
232
|
+
fs,
|
|
233
|
+
findAppRootURI,
|
|
234
|
+
documentsLocator,
|
|
235
|
+
searchPathsCache,
|
|
236
|
+
);
|
|
219
237
|
const jsonLanguageService = new JSONLanguageService(documentManager, jsonValidationSet);
|
|
220
238
|
const cssLanguageService = new CSSLanguageService(documentManager);
|
|
221
239
|
const completionsProvider = new CompletionsProvider({
|
|
@@ -342,6 +360,9 @@ export function startServer(
|
|
|
342
360
|
{
|
|
343
361
|
globPattern: '**/*.css',
|
|
344
362
|
},
|
|
363
|
+
{
|
|
364
|
+
globPattern: '**/app/config.yml',
|
|
365
|
+
},
|
|
345
366
|
],
|
|
346
367
|
});
|
|
347
368
|
});
|
|
@@ -388,7 +409,11 @@ export function startServer(
|
|
|
388
409
|
cssLanguageService.change(uri, params.contentChanges[0].text, version);
|
|
389
410
|
return;
|
|
390
411
|
}
|
|
391
|
-
|
|
412
|
+
const text = params.contentChanges[0].text;
|
|
413
|
+
documentManager.change(uri, text, version);
|
|
414
|
+
if (isPage(uri)) {
|
|
415
|
+
definitionsProvider.onPageFileChanged(uri, text);
|
|
416
|
+
}
|
|
392
417
|
if (await configuration.shouldCheckOnChange()) {
|
|
393
418
|
runChecks([uri]);
|
|
394
419
|
} else {
|
|
@@ -400,6 +425,15 @@ export function startServer(
|
|
|
400
425
|
connection.onDidSaveTextDocument(async (params) => {
|
|
401
426
|
if (hasUnsupportedDocument(params)) return;
|
|
402
427
|
const { uri } = params.textDocument;
|
|
428
|
+
|
|
429
|
+
// onDidChangeWatchedFiles also fires for in-editor saves, but it arrives after
|
|
430
|
+
// onDidSaveTextDocument. Invalidate the search-paths cache here immediately so
|
|
431
|
+
// that go-to-definition requests triggered by the same save don't see stale data
|
|
432
|
+
// while waiting for the file-watcher notification.
|
|
433
|
+
if (uri.endsWith('/app/config.yml')) {
|
|
434
|
+
searchPathsCache.invalidate();
|
|
435
|
+
}
|
|
436
|
+
|
|
403
437
|
if (await configuration.shouldCheckOnSave()) {
|
|
404
438
|
runChecks([uri]);
|
|
405
439
|
}
|
|
@@ -534,6 +568,16 @@ export function startServer(
|
|
|
534
568
|
if (params.changes.length === 0) return;
|
|
535
569
|
|
|
536
570
|
const triggerUris = params.changes.map((change) => change.uri);
|
|
571
|
+
|
|
572
|
+
// When many page files change at once (e.g., git checkout, branch switch, stash pop),
|
|
573
|
+
// incremental updates aren't reliable — files not open in the editor won't get
|
|
574
|
+
// individual onDidChangeTextDocument events. VS Code reports branch-switch changes
|
|
575
|
+
// as FileChangeType.Changed, so we count all change types.
|
|
576
|
+
const bulkPageChanges = params.changes.filter((c) => isPage(c.uri));
|
|
577
|
+
if (bulkPageChanges.length >= BULK_PAGE_CHANGE_THRESHOLD) {
|
|
578
|
+
definitionsProvider.invalidateRouteTable();
|
|
579
|
+
}
|
|
580
|
+
|
|
537
581
|
const updates: Promise<any>[] = [];
|
|
538
582
|
for (const change of params.changes) {
|
|
539
583
|
// App Check config changes should clear the config cache
|
|
@@ -542,6 +586,21 @@ export function startServer(
|
|
|
542
586
|
continue;
|
|
543
587
|
}
|
|
544
588
|
|
|
589
|
+
// app/config.yml changes should clear expanded search paths cache
|
|
590
|
+
// and force re-check of all open documents.
|
|
591
|
+
// Note: readFile for config.yml bypasses the CachedFileSystem cache,
|
|
592
|
+
// so we don't need to invalidate it — reads are always fresh.
|
|
593
|
+
if (change.uri.endsWith('/app/config.yml')) {
|
|
594
|
+
documentsLocator.clearExpandedPathsCache();
|
|
595
|
+
searchPathsCache.invalidate();
|
|
596
|
+
|
|
597
|
+
// Ensure open liquid files are re-checked with the new search paths
|
|
598
|
+
for (const doc of documentManager.openDocuments) {
|
|
599
|
+
triggerUris.push(doc.uri);
|
|
600
|
+
}
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
|
|
545
604
|
// Rename cache invalidation is handled by onDidRenameFiles
|
|
546
605
|
if (documentManager.hasRecentRename(change.uri)) {
|
|
547
606
|
documentManager.clearRecentRename(change.uri);
|
|
@@ -556,7 +615,14 @@ export function startServer(
|
|
|
556
615
|
fs.stat.invalidate(change.uri);
|
|
557
616
|
appGraphManager.create(change.uri);
|
|
558
617
|
// If a file is created under out feet, we update its contents.
|
|
559
|
-
updates.push(
|
|
618
|
+
updates.push(
|
|
619
|
+
documentManager.changeFromDisk(change.uri).then(() => {
|
|
620
|
+
if (isPage(change.uri)) {
|
|
621
|
+
const doc = documentManager.get(change.uri);
|
|
622
|
+
if (doc) definitionsProvider.onPageFileChanged(change.uri, doc.source);
|
|
623
|
+
}
|
|
624
|
+
}),
|
|
625
|
+
);
|
|
560
626
|
break;
|
|
561
627
|
|
|
562
628
|
case FileChangeType.Changed:
|
|
@@ -568,7 +634,20 @@ export function startServer(
|
|
|
568
634
|
// If it is open, then we don't need to update it because the document manager
|
|
569
635
|
// will have the version from the editor.
|
|
570
636
|
if (documentManager.get(change.uri)?.version === undefined) {
|
|
571
|
-
updates.push(
|
|
637
|
+
updates.push(
|
|
638
|
+
documentManager.changeFromDisk(change.uri).then(() => {
|
|
639
|
+
if (isPage(change.uri)) {
|
|
640
|
+
const doc = documentManager.get(change.uri);
|
|
641
|
+
if (doc) definitionsProvider.onPageFileChanged(change.uri, doc.source);
|
|
642
|
+
}
|
|
643
|
+
}),
|
|
644
|
+
);
|
|
645
|
+
} else if (isPage(change.uri)) {
|
|
646
|
+
// File is open in editor but changed externally (e.g. git checkout).
|
|
647
|
+
// The doc manager already has the editor version, but the route table
|
|
648
|
+
// may be stale — update it from whatever the doc manager holds.
|
|
649
|
+
const doc = documentManager.get(change.uri);
|
|
650
|
+
if (doc) definitionsProvider.onPageFileChanged(change.uri, doc.source);
|
|
572
651
|
}
|
|
573
652
|
break;
|
|
574
653
|
|
|
@@ -578,6 +657,7 @@ export function startServer(
|
|
|
578
657
|
fs.readFile.invalidate(change.uri);
|
|
579
658
|
fs.stat.invalidate(change.uri);
|
|
580
659
|
appGraphManager.delete(change.uri);
|
|
660
|
+
if (isPage(change.uri)) definitionsProvider.onPageFileDeleted(change.uri);
|
|
581
661
|
// If a file is deleted, it's removed from the document manager
|
|
582
662
|
documentManager.delete(change.uri);
|
|
583
663
|
break;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { URI } from 'vscode-uri';
|
|
3
|
+
import { SearchPathsLoader } from './searchPaths';
|
|
4
|
+
|
|
5
|
+
const rootUri = URI.parse('file:///project');
|
|
6
|
+
const configUri = 'file:///project/app/config.yml';
|
|
7
|
+
|
|
8
|
+
function createMockFs(configContent: string | null) {
|
|
9
|
+
return {
|
|
10
|
+
readFile: vi.fn(async (uri: string) => {
|
|
11
|
+
if (uri === configUri && configContent !== null) return configContent;
|
|
12
|
+
throw new Error(`File not found: ${uri}`);
|
|
13
|
+
}),
|
|
14
|
+
readDirectory: vi.fn(async () => []),
|
|
15
|
+
stat: vi.fn(async () => ({ type: 1, size: 0 })),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('SearchPathsLoader', () => {
|
|
20
|
+
it('should cache results across calls for the same root', async () => {
|
|
21
|
+
const fs = createMockFs('theme_search_paths:\n - theme/dress');
|
|
22
|
+
const loader = new SearchPathsLoader(fs);
|
|
23
|
+
|
|
24
|
+
const result1 = await loader.get(rootUri);
|
|
25
|
+
expect(result1).toEqual(['theme/dress']);
|
|
26
|
+
|
|
27
|
+
const result2 = await loader.get(rootUri);
|
|
28
|
+
expect(result2).toEqual(['theme/dress']);
|
|
29
|
+
|
|
30
|
+
// readFile should only be called once — second call served from cache
|
|
31
|
+
expect(fs.readFile).toHaveBeenCalledTimes(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return fresh results after invalidate()', async () => {
|
|
35
|
+
let configContent = 'theme_search_paths:\n - theme/dress';
|
|
36
|
+
const fs = {
|
|
37
|
+
readFile: vi.fn(async (uri: string) => {
|
|
38
|
+
if (uri === configUri) return configContent;
|
|
39
|
+
throw new Error(`File not found: ${uri}`);
|
|
40
|
+
}),
|
|
41
|
+
readDirectory: vi.fn(async () => []),
|
|
42
|
+
stat: vi.fn(async () => ({ type: 1, size: 0 })),
|
|
43
|
+
};
|
|
44
|
+
const loader = new SearchPathsLoader(fs);
|
|
45
|
+
|
|
46
|
+
const result1 = await loader.get(rootUri);
|
|
47
|
+
expect(result1).toEqual(['theme/dress']);
|
|
48
|
+
|
|
49
|
+
// Config changes externally
|
|
50
|
+
configContent = 'theme_search_paths:\n - theme/simple';
|
|
51
|
+
|
|
52
|
+
// Without invalidation, still returns cached result
|
|
53
|
+
const result2 = await loader.get(rootUri);
|
|
54
|
+
expect(result2).toEqual(['theme/dress']);
|
|
55
|
+
|
|
56
|
+
// After invalidation, reads fresh
|
|
57
|
+
loader.invalidate();
|
|
58
|
+
const result3 = await loader.get(rootUri);
|
|
59
|
+
expect(result3).toEqual(['theme/simple']);
|
|
60
|
+
|
|
61
|
+
expect(fs.readFile).toHaveBeenCalledTimes(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should return null when config has no search paths', async () => {
|
|
65
|
+
const fs = createMockFs('some_other_key: value');
|
|
66
|
+
const loader = new SearchPathsLoader(fs);
|
|
67
|
+
|
|
68
|
+
const result = await loader.get(rootUri);
|
|
69
|
+
expect(result).toBeNull();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should return null when config.yml does not exist', async () => {
|
|
73
|
+
const fs = createMockFs(null);
|
|
74
|
+
const loader = new SearchPathsLoader(fs);
|
|
75
|
+
|
|
76
|
+
const result = await loader.get(rootUri);
|
|
77
|
+
expect(result).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should cache per root URI independently', async () => {
|
|
81
|
+
const root2 = URI.parse('file:///other-project');
|
|
82
|
+
const config2Uri = 'file:///other-project/app/config.yml';
|
|
83
|
+
const fs = {
|
|
84
|
+
readFile: vi.fn(async (uri: string) => {
|
|
85
|
+
if (uri === configUri) return 'theme_search_paths:\n - theme/a';
|
|
86
|
+
if (uri === config2Uri) return 'theme_search_paths:\n - theme/b';
|
|
87
|
+
throw new Error(`File not found: ${uri}`);
|
|
88
|
+
}),
|
|
89
|
+
readDirectory: vi.fn(async () => []),
|
|
90
|
+
stat: vi.fn(async () => ({ type: 1, size: 0 })),
|
|
91
|
+
};
|
|
92
|
+
const loader = new SearchPathsLoader(fs);
|
|
93
|
+
|
|
94
|
+
const result1 = await loader.get(rootUri);
|
|
95
|
+
const result2 = await loader.get(root2);
|
|
96
|
+
|
|
97
|
+
expect(result1).toEqual(['theme/a']);
|
|
98
|
+
expect(result2).toEqual(['theme/b']);
|
|
99
|
+
expect(fs.readFile).toHaveBeenCalledTimes(2);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AbstractFileSystem, loadSearchPaths } from '@platformos/platformos-common';
|
|
2
|
+
import { URI } from 'vscode-uri';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cached loader for theme_search_paths from app/config.yml.
|
|
6
|
+
*
|
|
7
|
+
* Caches per root URI so that repeated calls (document links, definitions,
|
|
8
|
+
* checks) within the same editor session don't re-read and re-parse the
|
|
9
|
+
* config file on every invocation.
|
|
10
|
+
*
|
|
11
|
+
* Call `invalidate()` when app/config.yml changes on disk — the file watcher
|
|
12
|
+
* in startServer.ts handles this. This is the only reliable invalidation
|
|
13
|
+
* point because config.yml changes may come from external tools (vim, CLI)
|
|
14
|
+
* that don't trigger editor-level change events.
|
|
15
|
+
*/
|
|
16
|
+
export class SearchPathsLoader {
|
|
17
|
+
private cache = new Map<string, Promise<string[] | null>>();
|
|
18
|
+
|
|
19
|
+
constructor(private fs: AbstractFileSystem) {}
|
|
20
|
+
|
|
21
|
+
get(rootUri: URI): Promise<string[] | null> {
|
|
22
|
+
const key = rootUri.toString();
|
|
23
|
+
if (!this.cache.has(key)) {
|
|
24
|
+
this.cache.set(key, loadSearchPaths(this.fs, rootUri));
|
|
25
|
+
}
|
|
26
|
+
return this.cache.get(key)!;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
invalidate(): void {
|
|
30
|
+
this.cache.clear();
|
|
31
|
+
}
|
|
32
|
+
}
|