Skip to content

Commit 9b012d3

Browse files
committed
handle delete file and new export
1 parent 527be3e commit 9b012d3

File tree

2 files changed

+71
-50
lines changed

2 files changed

+71
-50
lines changed

packages/language-server/src/plugins/typescript/service.ts

+34-50
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ async function createLanguageService(
248248
? svelteHtmlDeclaration
249249
: './svelte-jsx-v4.d.ts';
250250

251+
const changedFilesForExportCache = new Set<string>();
252+
251253
const svelteTsxFiles = (
252254
isSvelte3
253255
? ['./svelte-shims.d.ts', './svelte-jsx.d.ts', './svelte-native-jsx.d.ts']
@@ -341,7 +343,7 @@ async function createLanguageService(
341343
svelteModuleLoader.deleteFromModuleCache(filePath);
342344
svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath);
343345

344-
scheduleUpdate();
346+
scheduleUpdate(filePath);
345347
}
346348

347349
function updateSnapshot(documentOrFilePath: Document | string): DocumentSnapshot {
@@ -359,7 +361,6 @@ async function createLanguageService(
359361

360362
if (!prevSnapshot) {
361363
svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath);
362-
host.getCachedExportInfoMap?.()?.clear();
363364
}
364365

365366
const newSnapshot = DocumentSnapshot.fromDocument(document, transformationConfig);
@@ -375,15 +376,7 @@ async function createLanguageService(
375376
return prevSnapshot;
376377
}
377378

378-
svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath);
379-
const newSnapshot = DocumentSnapshot.fromFilePath(
380-
filePath,
381-
docContext.createDocument,
382-
transformationConfig,
383-
tsSystem
384-
);
385-
snapshotManager.set(filePath, newSnapshot);
386-
return newSnapshot;
379+
return createSnapshot(filePath);
387380
}
388381

389382
/**
@@ -404,8 +397,7 @@ async function createLanguageService(
404397
}
405398

406399
return createSnapshot(
407-
svelteModuleLoader.svelteFileExists(fileName) ? svelteFileName : fileName,
408-
doc
400+
svelteModuleLoader.svelteFileExists(fileName) ? svelteFileName : fileName
409401
);
410402
}
411403

@@ -417,12 +409,12 @@ async function createLanguageService(
417409
return doc;
418410
}
419411

420-
return createSnapshot(fileName, doc);
412+
return createSnapshot(fileName);
421413
}
422414

423-
function createSnapshot(fileName: string, doc: DocumentSnapshot | undefined) {
415+
function createSnapshot(fileName: string) {
424416
svelteModuleLoader.deleteUnresolvedResolutionsFromCache(fileName);
425-
doc = DocumentSnapshot.fromFilePath(
417+
const doc = DocumentSnapshot.fromFilePath(
426418
fileName,
427419
docContext.createDocument,
428420
transformationConfig,
@@ -433,21 +425,10 @@ async function createLanguageService(
433425
}
434426

435427
function updateProjectFiles(): void {
436-
projectVersion++;
437-
dirty = true;
438-
const projectFileBefore = snapshotManager.getProjectFileNames();
439-
const projectFileCountBefore = projectFileBefore.length;
428+
scheduleUpdate();
429+
const projectFileCountBefore = snapshotManager.getProjectFileNames().length;
440430
snapshotManager.updateProjectFiles();
441-
const projectFileAfter = snapshotManager.getProjectFileNames();
442-
const projectFileCountAfter = projectFileAfter.length;
443-
444-
const hasAddedOrRemoved =
445-
(!!project && projectFileCountAfter !== projectFileCountBefore) ||
446-
checkProjectFileUpdate(projectFileBefore, projectFileAfter);
447-
448-
if (hasAddedOrRemoved) {
449-
host.getCachedExportInfoMap?.()?.clear();
450-
}
431+
const projectFileCountAfter = snapshotManager.getProjectFileNames().length;
451432

452433
if (projectFileCountAfter <= projectFileCountBefore) {
453434
return;
@@ -456,25 +437,6 @@ async function createLanguageService(
456437
reduceLanguageServiceCapabilityIfFileSizeTooBig();
457438
}
458439

459-
function checkProjectFileUpdate(oldFiles: string[], newFiles: string[]) {
460-
const oldSet = new Set(oldFiles);
461-
const newSet = new Set(newFiles);
462-
463-
for (const file of oldSet) {
464-
if (!newSet.has(file)) {
465-
return true;
466-
}
467-
}
468-
469-
for (const file of newSet) {
470-
if (!oldSet.has(file)) {
471-
return true;
472-
}
473-
}
474-
475-
return false;
476-
}
477-
478440
function getScriptFileNames() {
479441
const projectFiles = languageServiceReducedMode
480442
? []
@@ -747,6 +709,7 @@ async function createLanguageService(
747709
return;
748710
}
749711

712+
const oldProgram = project?.program;
750713
const program = languageService.getProgram();
751714
svelteModuleLoader.clearPendingInvalidations();
752715

@@ -755,9 +718,30 @@ async function createLanguageService(
755718
}
756719

757720
dirty = false;
721+
722+
for (const fileName of changedFilesForExportCache) {
723+
const oldFile = oldProgram?.getSourceFile(fileName);
724+
const newFile = program?.getSourceFile(fileName);
725+
726+
// file for another tsconfig
727+
if (!oldFile && !newFile) {
728+
continue;
729+
}
730+
731+
if (oldFile && newFile) {
732+
host.getCachedExportInfoMap?.().onFileChanged?.(oldFile, newFile, false);
733+
} else {
734+
// new file or deleted file
735+
host.getCachedExportInfoMap?.().clear();
736+
}
737+
}
738+
changedFilesForExportCache.clear();
758739
}
759740

760-
function scheduleUpdate() {
741+
function scheduleUpdate(triggeredFile?: string) {
742+
if (triggeredFile) {
743+
changedFilesForExportCache.add(triggeredFile);
744+
}
761745
if (dirty) {
762746
return;
763747
}

packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts

+37
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,43 @@ describe('CompletionProviderImpl', function () {
14601460
assert.strictEqual(detail, 'Add import from "./Bar.svelte"\n\nclass Bar');
14611461
});
14621462

1463+
it('can auto import new export', async () => {
1464+
const virtualTestDir = getRandomVirtualDirPath(testFilesDir);
1465+
const { document, lsAndTsDocResolver, lsConfigManager, virtualSystem } =
1466+
setupVirtualEnvironment({
1467+
filename: 'index.svelte',
1468+
fileContent: '<script>import {} from "./foo";f</script>',
1469+
testDir: virtualTestDir
1470+
});
1471+
1472+
const completionProvider = new CompletionsProviderImpl(lsAndTsDocResolver, lsConfigManager);
1473+
const tsFile = join(virtualTestDir, 'foo.ts');
1474+
1475+
virtualSystem.writeFile(tsFile, 'export {}');
1476+
1477+
const completions = await completionProvider.getCompletions(document, {
1478+
line: 0,
1479+
character: 31
1480+
});
1481+
1482+
const item = completions?.items.find((item) => item.label === 'foo');
1483+
1484+
assert.equal(item, undefined);
1485+
1486+
virtualSystem.writeFile(tsFile, 'export function foo() {}');
1487+
lsAndTsDocResolver.updateExistingTsOrJsFile(tsFile);
1488+
1489+
const completions2 = await completionProvider.getCompletions(document, {
1490+
line: 0,
1491+
character: 31
1492+
});
1493+
1494+
const item2 = completions2?.items.find((item) => item.label === 'foo');
1495+
const { detail } = await completionProvider.resolveCompletion(document, item2!);
1496+
1497+
assert.strictEqual(detail, 'Update import from "./foo"\n\nfunction foo(): void');
1498+
});
1499+
14631500
it('provides completions for object literal member', async () => {
14641501
const { completionProvider, document } = setup('object-member.svelte');
14651502

0 commit comments

Comments
 (0)