message: fix(compiler-cli): ensure `MockFileSystem` handles case-sensitivity
  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
diff: @@ -119,7 +119,7 @@ export abstract class MockFileSystem implements FileSystem {
  }
  ensureDir(path: AbsoluteFsPath): void {
  - const segments = this.splitPath(path);
  + const segments = this.splitPath(path).map(segment => this.getCanonicalPath(segment));
  let current: Folder = this._fileTree;
  // Convert the root folder to a canonical empty string `''` (on Windows it would be `'C:'`).
  @@ -212,11 +212,28 @@ export abstract class MockFileSystem implements FileSystem {
  protected abstract splitPath<T extends PathString>(path: T): string[];
  dump(): Folder {
  - return cloneFolder(this._fileTree);
  + return this.cloneFolder(this._fileTree);
  }
  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 {
  const followSymLinks = !!options && options.followSymLinks;
  @@ -229,7 +246,7 @@ export abstract class MockFileSystem implements FileSystem {
  segments[0] = '';
  let current: Entity|null = this._fileTree;
  while (segments.length) {
  - current = current[segments.shift()!];
  + current = current[this.getCanonicalPath(segments.shift()!)];
  if (current === undefined) {
  return {path, entity: null};
  }
  @@ -252,10 +269,14 @@ export abstract class MockFileSystem implements FileSystem {
  }
  protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] {
  - const segments = this.splitPath(path);
  + const segments = this.splitPath(this.getCanonicalPath(path));
  const file = segments.pop()!;
  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 {
  path: AbsoluteFsPath;
  @@ -300,18 +321,3 @@ export function isSymLink(item: Entity|null): item is SymLink {
  export function isFolder(item: Entity|null): item is Folder {
  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;
  -}
  