Skip to content

Commit 383e689

Browse files
authored
perf: optimize path normalization (#2907)
1 parent 7985299 commit 383e689

File tree

5 files changed

+70
-17
lines changed

5 files changed

+70
-17
lines changed

.changeset/cozy-foxes-shine.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte-language-server': patch
3+
---
4+
5+
perf: optimize path normalization

packages/language-server/src/plugins/typescript/module-loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class ModuleResolutionCache {
8888
}
8989

9090
oneOfResolvedModuleChanged(path: string) {
91-
return this.pendingInvalidations.has(path);
91+
return this.pendingInvalidations.size > 0 && this.pendingInvalidations.has(path);
9292
}
9393
}
9494

@@ -325,7 +325,7 @@ export function createSvelteModuleLoader(
325325
return (
326326
moduleCache.oneOfResolvedModuleChanged(path) ||
327327
// tried but failed file might now exist
328-
failedLocationInvalidated.has(path)
328+
(failedLocationInvalidated.size > 0 && failedLocationInvalidated.has(path))
329329
);
330330
}
331331

packages/language-server/src/plugins/typescript/svelte-sys.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,29 @@ export function createSvelteSys(tsSystem: ts.System) {
1414

1515
// First check if there's a `.svelte.d.ts` or `.d.svelte.ts` file, which should take precedence
1616
const dtsPath = sveltePath.slice(0, -7) + '.svelte.d.ts';
17-
const dtsPathExists = fileExistsCache.get(dtsPath) ?? tsSystem.fileExists(dtsPath);
18-
fileExistsCache.set(dtsPath, dtsPathExists);
17+
const dtsPathExists = getOrCreateFileExistCache(dtsPath);
1918
if (dtsPathExists) return false;
2019

21-
const svelteDtsPathExists = fileExistsCache.get(path) ?? tsSystem.fileExists(path);
22-
fileExistsCache.set(path, svelteDtsPathExists);
20+
const svelteDtsPathExists = getOrCreateFileExistCache(path);
2321
if (svelteDtsPathExists) return false;
2422

25-
const sveltePathExists =
26-
fileExistsCache.get(sveltePath) ?? tsSystem.fileExists(sveltePath);
27-
fileExistsCache.set(sveltePath, sveltePathExists);
23+
const sveltePathExists = getOrCreateFileExistCache(sveltePath);
2824
return sveltePathExists;
2925
} else {
3026
return false;
3127
}
3228
}
3329

30+
function getOrCreateFileExistCache(path: string) {
31+
const cached = fileExistsCache.get(path);
32+
if (cached !== undefined) {
33+
return cached;
34+
}
35+
const exists = tsSystem.fileExists(path);
36+
fileExistsCache.set(path, exists);
37+
return exists;
38+
}
39+
3440
function getRealSveltePathIfExists(path: string) {
3541
return svelteFileExists(path) ? toRealSvelteFilePath(path) : path;
3642
}
@@ -48,9 +54,7 @@ export function createSvelteSys(tsSystem: ts.System) {
4854
const sveltePathExists = svelteFileExists(path);
4955
if (sveltePathExists) return true;
5056

51-
const exists = fileExistsCache.get(path) ?? tsSystem.fileExists(path);
52-
fileExistsCache.set(path, exists);
53-
return exists;
57+
return getOrCreateFileExistCache(path);
5458
},
5559
readFile(path: string) {
5660
// No getSnapshot here, because TS will very rarely call this and only for files that are not in the project

packages/language-server/src/utils.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { isEqual, sum, uniqWith } from 'lodash';
2-
import { FoldingRange, Node } from 'vscode-html-languageservice';
1+
import { isEqual, uniqWith } from 'lodash';
2+
import { Node } from 'vscode-html-languageservice';
33
import { Position, Range } from 'vscode-languageserver';
44
import { URI } from 'vscode-uri';
5-
import { Document, TagInformation } from './lib/documents';
65

76
type Predicate<T> = (x: T) => boolean;
87

@@ -38,12 +37,27 @@ export function pathToUrl(path: string) {
3837
return URI.file(path).toString();
3938
}
4039

40+
const backslashRegEx = /\\/g;
41+
4142
/**
4243
* Some paths (on windows) start with a upper case driver letter, some don't.
4344
* This is normalized here.
4445
*/
4546
export function normalizePath(path: string): string {
46-
return URI.file(path).fsPath.replace(/\\/g, '/');
47+
return normalizeDriveLetter(path.replace(backslashRegEx, '/'));
48+
}
49+
50+
function normalizeDriveLetter(path: string): string {
51+
if (path.charCodeAt(1) !== /*:*/ 58) {
52+
return path;
53+
}
54+
55+
const driveLetter = path.charCodeAt(0);
56+
if (driveLetter >= /*A*/ 65 && driveLetter <= /*Z*/ 90) {
57+
return String.fromCharCode(driveLetter + 32) + path.slice(1);
58+
}
59+
60+
return path;
4761
}
4862

4963
/**

packages/language-server/test/utils.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { isBeforeOrEqualToPosition, modifyLines, regexLastIndexOf } from '../src/utils';
1+
import {
2+
isBeforeOrEqualToPosition,
3+
modifyLines,
4+
normalizePath,
5+
regexLastIndexOf
6+
} from '../src/utils';
27
import { Position } from 'vscode-languageserver';
38
import * as assert from 'assert';
9+
import { URI } from 'vscode-uri';
410

511
describe('utils', () => {
612
describe('#isBeforeOrEqualToPosition', () => {
@@ -61,4 +67,28 @@ describe('utils', () => {
6167
assert.deepStrictEqual(idxs, [0, 1, 2, 3]);
6268
});
6369
});
70+
71+
describe('path normalization on Windows', () => {
72+
it('should lowercase drive letters and normalize slashes', () => {
73+
assert.strictEqual(
74+
normalizePath('C:\\Users\\Test\\project\\file.ts'),
75+
'c:/Users/Test/project/file.ts'
76+
);
77+
78+
assert.strictEqual(
79+
normalizePath('D:/Some/Other/Path/file.ts'),
80+
'd:/Some/Other/Path/file.ts'
81+
);
82+
83+
assert.strictEqual(
84+
normalizePath('e:\\Mixed/Slashes\\Path/file.ts'),
85+
'e:/Mixed/Slashes/Path/file.ts'
86+
);
87+
88+
assert.strictEqual(
89+
normalizePath('/already/normalized/path/file.ts'),
90+
'/already/normalized/path/file.ts'
91+
);
92+
});
93+
});
6494
});

0 commit comments

Comments
 (0)