diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts index 26481d46cf..00b057b3e7 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts @@ -54,6 +54,12 @@ export class CachedFileSystem implements FileSystem { this.existsCache.set(path, true); } + removeFile(path: AbsoluteFsPath): void { + this.delegate.removeFile(path); + this.readFileCache.delete(path); + this.existsCache.set(path, false); + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { this.delegate.symlink(target, path); this.existsCache.set(path, true); diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts index 36e7858caa..11b2c8ab15 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts @@ -19,6 +19,7 @@ export class InvalidFileSystem implements FileSystem { exists(path: AbsoluteFsPath): boolean { throw makeError(); } readFile(path: AbsoluteFsPath): string { throw makeError(); } writeFile(path: AbsoluteFsPath, data: string): void { throw makeError(); } + removeFile(path: AbsoluteFsPath): void { throw makeError(); } symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); } readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); } lstat(path: AbsoluteFsPath): FileStats { throw makeError(); } diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts index 891426f969..9670504d6a 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts @@ -18,9 +18,8 @@ export class NodeJSFileSystem implements FileSystem { private _caseSensitive: boolean|undefined = undefined; exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); } readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); } - writeFile(path: AbsoluteFsPath, data: string): void { - return fs.writeFileSync(path, data, 'utf8'); - } + writeFile(path: AbsoluteFsPath, data: string): void { fs.writeFileSync(path, data, 'utf8'); } + removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); } symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); } readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; } lstat(path: AbsoluteFsPath): FileStats { return fs.lstatSync(path); } diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts index 9c3dc11bf6..eb3410d032 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts @@ -38,6 +38,7 @@ export interface FileSystem { exists(path: AbsoluteFsPath): boolean; readFile(path: AbsoluteFsPath): string; writeFile(path: AbsoluteFsPath, data: string): void; + removeFile(path: AbsoluteFsPath): void; symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void; readdir(path: AbsoluteFsPath): PathSegment[]; lstat(path: AbsoluteFsPath): FileStats; diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts index d817045c57..401b9f1bdf 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts @@ -110,6 +110,23 @@ describe('CachedFileSystem', () => { }); }); + describe('removeFile()', () => { + it('should call delegate', () => { + const spy = spyOn(delegate, 'removeFile'); + fs.removeFile(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); + }); + + it('should update the exists cache', () => { + spyOn(delegate, 'removeFile'); + const existsSpy = spyOn(delegate, 'exists'); + + fs.removeFile(abcPath); + expect(fs.exists(abcPath)).toBe(false); + expect(existsSpy).not.toHaveBeenCalled(); + }); + }); + describe('readdir()', () => { it('should call delegate', () => { const spy = spyOn(delegate, 'readdir'); diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts index 34fe48dfd6..c4f5161c3d 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts @@ -51,6 +51,14 @@ describe('NodeJSFileSystem', () => { }); }); + describe('removeFile()', () => { + it('should delegate to fs.unlink()', () => { + const spy = spyOn(realFs, 'unlinkSync'); + fs.removeFile(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); + }); + }); + describe('readdir()', () => { it('should delegate to fs.readdirSync()', () => { const spy = spyOn(realFs, 'readdirSync').and.returnValue(['x', 'y/z']); diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts index a1609ab28c..d8bae1db87 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts @@ -44,6 +44,20 @@ export abstract class MockFileSystem implements FileSystem { entity[basename] = data; } + removeFile(path: AbsoluteFsPath): void { + const [folderPath, basename] = this.splitIntoFolderAndFile(path); + const {entity} = this.findFromPath(folderPath); + if (entity === null || !isFolder(entity)) { + throw new MockFileSystemError( + 'ENOENT', path, `Unable to remove file "${path}". The containing folder does not exist.`); + } + if (isFolder(entity[basename])) { + throw new MockFileSystemError( + 'EISDIR', path, `Unable to remove file "${path}". The path to remove is a folder.`); + } + delete entity[basename]; + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { const [folderPath, basename] = this.splitIntoFolderAndFile(path); const {entity} = this.findFromPath(folderPath);