refactor(compiler-cli): support Buffer files in `FileSystem` (#36843)

Adding `readFileBuffer()` method and allowing `writeFile()` to accept a
Buffer object will be useful when reading and writing non-text files,
such as is done in the `@angular/localize` package.

PR Close #36843
This commit is contained in:
Pete Bacon Darwin 2020-04-27 19:18:56 +01:00 committed by Misko Hevery
parent 352b9c78e0
commit 5d12c19ce9
5 changed files with 33 additions and 7 deletions

View File

@ -22,7 +22,10 @@ export class InvalidFileSystem implements FileSystem {
readFile(path: AbsoluteFsPath): string {
throw makeError();
}
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void {
readFileBuffer(path: AbsoluteFsPath): Buffer {
throw makeError();
}
writeFile(path: AbsoluteFsPath, data: string|Buffer, exclusive?: boolean): void {
throw makeError();
}
removeFile(path: AbsoluteFsPath): void {

View File

@ -23,7 +23,10 @@ export class NodeJSFileSystem implements FileSystem {
readFile(path: AbsoluteFsPath): string {
return fs.readFileSync(path, 'utf8');
}
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
readFileBuffer(path: AbsoluteFsPath): Buffer {
return fs.readFileSync(path);
}
writeFile(path: AbsoluteFsPath, data: string|Buffer, exclusive: boolean = false): void {
fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined);
}
removeFile(path: AbsoluteFsPath): void {

View File

@ -37,7 +37,8 @@ export type PathSegment = BrandedPath<'PathSegment'>;
export interface FileSystem {
exists(path: AbsoluteFsPath): boolean;
readFile(path: AbsoluteFsPath): string;
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void;
readFileBuffer(path: AbsoluteFsPath): Buffer;
writeFile(path: AbsoluteFsPath, data: string|Buffer, exclusive?: boolean): void;
removeFile(path: AbsoluteFsPath): void;
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
readdir(path: AbsoluteFsPath): PathSegment[];

View File

@ -44,6 +44,16 @@ describe('NodeJSFileSystem', () => {
});
});
describe('readFileBuffer()', () => {
it('should delegate to fs.readFileSync()', () => {
const buffer = new Buffer('Some contents');
const spy = spyOn(realFs, 'readFileSync').and.returnValue(buffer);
const result = fs.readFileBuffer(abcPath);
expect(result).toBe(buffer);
expect(spy).toHaveBeenCalledWith(abcPath);
});
});
describe('writeFile()', () => {
it('should delegate to fs.writeFileSync()', () => {
const spy = spyOn(realFs, 'writeFileSync');

View File

@ -32,13 +32,22 @@ export abstract class MockFileSystem implements FileSystem {
readFile(path: AbsoluteFsPath): string {
const {entity} = this.findFromPath(path);
if (isFile(entity)) {
return entity;
return entity.toString();
} else {
throw new MockFileSystemError('ENOENT', path, `File "${path}" does not exist.`);
}
}
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
readFileBuffer(path: AbsoluteFsPath): Buffer {
const {entity} = this.findFromPath(path);
if (isFile(entity)) {
return Buffer.isBuffer(entity) ? entity : new Buffer(entity);
} else {
throw new MockFileSystemError('ENOENT', path, `File "${path}" does not exist.`);
}
}
writeFile(path: AbsoluteFsPath, data: string|Buffer, exclusive: boolean = false): void {
const [folderPath, basename] = this.splitIntoFolderAndFile(path);
const {entity} = this.findFromPath(folderPath);
if (entity === null || !isFolder(entity)) {
@ -286,7 +295,7 @@ export type Entity = Folder|File|SymLink;
export interface Folder {
[pathSegments: string]: Entity;
}
export type File = string;
export type File = string|Buffer;
export class SymLink {
constructor(public path: AbsoluteFsPath) {}
}
@ -311,7 +320,7 @@ class MockFileSystemError extends Error {
}
export function isFile(item: Entity|null): item is File {
return typeof item === 'string';
return Buffer.isBuffer(item) || typeof item === 'string';
}
export function isSymLink(item: Entity|null): item is SymLink {