fix(compiler-cli): ensure `MockFileSystem` handles case-sensitivity (#36859)
Previously this class used the file passed in directly to look up files in the in-memory mock file-system. But this doesn't match the behaviour of case-insensitive file-systems. Now the look up is done on the canonical file paths. PR Close #36859
This commit is contained in:
parent
fc4741f638
commit
26eacd4fcb
|
@ -119,7 +119,7 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureDir(path: AbsoluteFsPath): void {
|
ensureDir(path: AbsoluteFsPath): void {
|
||||||
const segments = this.splitPath(path);
|
const segments = this.splitPath(path).map(segment => this.getCanonicalPath(segment));
|
||||||
let current: Folder = this._fileTree;
|
let current: Folder = this._fileTree;
|
||||||
|
|
||||||
// Convert the root folder to a canonical empty string `''` (on Windows it would be `'C:'`).
|
// Convert the root folder to a canonical empty string `''` (on Windows it would be `'C:'`).
|
||||||
|
@ -212,12 +212,29 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
protected abstract splitPath<T extends PathString>(path: T): string[];
|
protected abstract splitPath<T extends PathString>(path: T): string[];
|
||||||
|
|
||||||
dump(): Folder {
|
dump(): Folder {
|
||||||
return cloneFolder(this._fileTree);
|
return this.cloneFolder(this._fileTree);
|
||||||
}
|
}
|
||||||
init(folder: Folder): void {
|
init(folder: Folder): void {
|
||||||
this._fileTree = cloneFolder(folder);
|
this._fileTree = this.cloneFolder(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private cloneFolder(folder: Folder): Folder {
|
||||||
|
const clone: Folder = {};
|
||||||
|
for (const path in folder) {
|
||||||
|
const item = folder[path];
|
||||||
|
const canonicalPath = this.getCanonicalPath(path);
|
||||||
|
if (isSymLink(item)) {
|
||||||
|
clone[canonicalPath] = new SymLink(this.getCanonicalPath(item.path));
|
||||||
|
} else if (isFolder(item)) {
|
||||||
|
clone[canonicalPath] = this.cloneFolder(item);
|
||||||
|
} else {
|
||||||
|
clone[canonicalPath] = folder[path];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult {
|
protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult {
|
||||||
const followSymLinks = !!options && options.followSymLinks;
|
const followSymLinks = !!options && options.followSymLinks;
|
||||||
const segments = this.splitPath(path);
|
const segments = this.splitPath(path);
|
||||||
|
@ -229,7 +246,7 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
segments[0] = '';
|
segments[0] = '';
|
||||||
let current: Entity|null = this._fileTree;
|
let current: Entity|null = this._fileTree;
|
||||||
while (segments.length) {
|
while (segments.length) {
|
||||||
current = current[segments.shift()!];
|
current = current[this.getCanonicalPath(segments.shift()!)];
|
||||||
if (current === undefined) {
|
if (current === undefined) {
|
||||||
return {path, entity: null};
|
return {path, entity: null};
|
||||||
}
|
}
|
||||||
|
@ -252,10 +269,14 @@ export abstract class MockFileSystem implements FileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
|
protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
|
||||||
const segments = this.splitPath(path);
|
const segments = this.splitPath(this.getCanonicalPath(path));
|
||||||
const file = segments.pop()!;
|
const file = segments.pop()!;
|
||||||
return [path.substring(0, path.length - file.length - 1) as AbsoluteFsPath, file];
|
return [path.substring(0, path.length - file.length - 1) as AbsoluteFsPath, file];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getCanonicalPath<T extends string>(p: T): T {
|
||||||
|
return this.isCaseSensitive() ? p : p.toLowerCase() as T;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export interface FindResult {
|
export interface FindResult {
|
||||||
path: AbsoluteFsPath;
|
path: AbsoluteFsPath;
|
||||||
|
@ -300,18 +321,3 @@ export function isSymLink(item: Entity|null): item is SymLink {
|
||||||
export function isFolder(item: Entity|null): item is Folder {
|
export function isFolder(item: Entity|null): item is Folder {
|
||||||
return item !== null && !isFile(item) && !isSymLink(item);
|
return item !== null && !isFile(item) && !isSymLink(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneFolder(folder: Folder): Folder {
|
|
||||||
const clone: Folder = {};
|
|
||||||
for (const path in folder) {
|
|
||||||
const item = folder[path];
|
|
||||||
if (isSymLink(item)) {
|
|
||||||
clone[path] = new SymLink(item.path);
|
|
||||||
} else if (isFolder(item)) {
|
|
||||||
clone[path] = cloneFolder(item);
|
|
||||||
} else {
|
|
||||||
clone[path] = folder[path];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue