Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(typescript): sys cache is not updated correctly in case sensitive FS #153

Merged
merged 2 commits into from
Mar 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 55 additions & 21 deletions packages/typescript/lib/protocol/createSys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import * as path from 'path-browserify';
import { matchFiles } from '../typescript/utilities';

interface File {
name: string;
text?: string;
stat?: FileStat;
requestedText?: boolean;
requestedStat?: boolean;
requestedText: boolean;
requestedStat: boolean;
}

interface Dir {
name: string;
dirs: Map<string, Dir>;
files: Map<string, File>;
exists?: boolean;
Expand All @@ -27,11 +29,13 @@ export function createSys(
version: number;
sync(): Promise<number>;
} & Disposable {

let version = 0;

// sys is undefined in browser
const sys = ts.sys as ts.System | undefined;
const caseSensitive = sys?.useCaseSensitiveFileNames ?? false;
const root: Dir = {
name: '',
dirs: new Map(),
files: new Map(),
requestedRead: false,
Expand All @@ -46,18 +50,21 @@ export function createSys(
if (dir.files.has(baseName) || dir.requestedRead) { // is requested file or directory
version++;
if (change.type === 1 satisfies typeof FileChangeType.Created || change.type === 2 satisfies typeof FileChangeType.Changed) {
dir.files.set(baseName, {
dir.files.set(normalizeFileId(baseName), {
name: baseName,
stat: {
type: 1 satisfies FileType.File,
ctime: Date.now(),
mtime: Date.now(),
size: -1,
},
requestedStat: false,
requestedText: false,
});
}
else if (change.type === 3 satisfies typeof FileChangeType.Deleted) {
dir.files.set(baseName, {
dir.files.set(normalizeFileId(baseName), {
name: baseName,
stat: undefined,
text: undefined,
requestedStat: true,
Expand All @@ -74,7 +81,7 @@ export function createSys(
},
args: sys?.args ?? [],
newLine: sys?.newLine ?? '\n',
useCaseSensitiveFileNames: sys?.useCaseSensitiveFileNames ?? false,
useCaseSensitiveFileNames: caseSensitive,
realpath: sys?.realpath,
write: sys?.write ?? (() => { }),
writeFile: sys?.writeFile ?? (() => { }),
Expand Down Expand Up @@ -127,7 +134,7 @@ export function createSys(
const name = path.basename(fileName);

readFileWorker(fileName, encoding, dir);
return dir.files.get(name)?.text;
return dir.files.get(normalizeFileId(name))?.text;
}

function directoryExists(dirName: string): boolean {
Expand Down Expand Up @@ -205,9 +212,13 @@ export function createSys(
const dirPath = path.dirname(fileName);
const baseName = path.basename(fileName);
const dir = getDir(dirPath);
let file = dir.files.get(baseName);
let file = dir.files.get(normalizeFileId(baseName));
if (!file) {
dir.files.set(baseName, file = {});
dir.files.set(normalizeFileId(baseName), file = {
name: baseName,
requestedStat: false,
requestedText: false,
});
}

return file;
Expand All @@ -218,7 +229,9 @@ export function createSys(
dirName = resolvePath(dirName);
readDirectoryWorker(dirName);
const dir = getDir(dirName);
return [...dir.dirs.entries()].filter(([_, dir]) => dir.exists).map(([name]) => name);
return [...dir.dirs.values()]
.filter(dir => dir.exists)
.map(dir => dir.name);
}

function readDirectory(
Expand All @@ -234,7 +247,7 @@ export function createSys(
extensions,
excludes,
includes,
sys?.useCaseSensitiveFileNames ?? false,
caseSensitive,
currentDirectory,
depth,
dirPath => {
Expand All @@ -244,8 +257,12 @@ export function createSys(
const dir = getDir(dirPath);

return {
files: [...dir.files.entries()].filter(([_, file]) => file.stat?.type === 1 satisfies FileType.File).map(([name]) => name),
directories: [...dir.dirs.entries()].filter(([_, dir]) => dir.exists).map(([name]) => name),
files: [...dir.files.values()]
.filter(file => file.stat?.type === 1 satisfies FileType.File)
.map(file => file.name),
directories: [...dir.dirs.values()]
.filter(dir => dir.exists)
.map(dir => dir.name),
};
},
sys?.realpath ? (path => sys.realpath!(path)) : (path => path),
Expand All @@ -257,9 +274,13 @@ export function createSys(

const name = path.basename(fileName);

let file = dir.files.get(name);
let file = dir.files.get(normalizeFileId(name));
if (!file) {
dir.files.set(name, file = {});
dir.files.set(normalizeFileId(name), file = {
name,
requestedStat: false,
requestedText: false,
});
}

if (file.requestedText) {
Expand Down Expand Up @@ -330,9 +351,13 @@ export function createSys(
stat.then(stat => {
promises.delete(promise);
if (stat?.type === 1 satisfies FileType.File) {
let file = dir.files.get(name);
let file = dir.files.get(normalizeFileId(name));
if (!file) {
dir.files.set(name, file = {});
dir.files.set(normalizeFileId(name), file = {
name,
requestedStat: false,
requestedText: false,
});
}
if (stat.type !== file.stat?.type || stat.mtime !== file.stat?.mtime) {
version++;
Expand All @@ -354,9 +379,13 @@ export function createSys(
}
}
if (fileType === 1 satisfies FileType.File) {
let file = dir.files.get(name);
let file = dir.files.get(normalizeFileId(name));
if (!file) {
dir.files.set(name, file = {});
dir.files.set(normalizeFileId(name), file = {
name,
requestedStat: false,
requestedText: false,
});
}
if (!file.stat) {
file.stat = {
Expand Down Expand Up @@ -405,13 +434,18 @@ export function createSys(
}

function getDirFromDir(dir: Dir, name: string) {
let target = dir.dirs.get(name);
let target = dir.dirs.get(normalizeFileId(name));
if (!target) {
dir.dirs.set(name, target = {
dir.dirs.set(normalizeFileId(name), target = {
name,
dirs: new Map(),
files: new Map(),
});
}
return target;
}

function normalizeFileId(fileName: string) {
return caseSensitive ? fileName : fileName.toLowerCase();
}
}