refactor(compiler-cli): split the `FileSystem` interface up (#40281)
This interface now extends `ReadonlyFileSystem` which in turn extends `PathManipulation`. This means consumers of these interfaces can be more specific about what is needed, and so providers do not need to implement unnecessary methods. PR Close #40281
This commit is contained in:
parent
da6c739bb6
commit
80b1ba9f95
|
@ -3,7 +3,15 @@
|
||||||
To improve cross platform support, all file access (and path manipulation)
|
To improve cross platform support, all file access (and path manipulation)
|
||||||
is now done through a well known interface (`FileSystem`).
|
is now done through a well known interface (`FileSystem`).
|
||||||
|
|
||||||
For testing a number of `MockFileSystem` implementations are supplied.
|
Note that `FileSystem` extends `ReadonlyFileSystem`, which itself extends
|
||||||
|
`PathManipulation`.
|
||||||
|
If you are using a file-system object you should only ask for the type that supports
|
||||||
|
all the methods that you require.
|
||||||
|
For example, if you have a function (`foo()`) that only needs to resolve paths then
|
||||||
|
it should only require `PathManipulation`: `foo(fs: PathManipulation)`.
|
||||||
|
This allows the caller to avoid implementing unneeded functionality.
|
||||||
|
|
||||||
|
For testing, a number of `MockFileSystem` implementations are supplied.
|
||||||
These provide an in-memory file-system which emulates operating systems
|
These provide an in-memory file-system which emulates operating systems
|
||||||
like OS/X, Unix and Windows.
|
like OS/X, Unix and Windows.
|
||||||
|
|
||||||
|
@ -16,6 +24,11 @@ To prevent this happening accidentally the current file system always starts out
|
||||||
as an instance of `InvalidFileSystem`, which will throw an error if any of its
|
as an instance of `InvalidFileSystem`, which will throw an error if any of its
|
||||||
methods are called.
|
methods are called.
|
||||||
|
|
||||||
|
Generally it is safer to explicitly pass file-system objects to constructors or
|
||||||
|
free-standing functions if possible. This avoids confusing bugs where the
|
||||||
|
global file-system has not been set-up correctly before calling functions that
|
||||||
|
expect there to be a file-system configured globally.
|
||||||
|
|
||||||
You can set the current file-system by calling `setFileSystem()`.
|
You can set the current file-system by calling `setFileSystem()`.
|
||||||
During testing you can call the helper function `initMockFileSystem(os)`
|
During testing you can call the helper function `initMockFileSystem(os)`
|
||||||
which takes a string name of the OS to emulate, and will also monkey-patch
|
which takes a string name of the OS to emulate, and will also monkey-patch
|
||||||
|
|
|
@ -9,5 +9,5 @@ export {NgtscCompilerHost} from './src/compiler_host';
|
||||||
export {absoluteFrom, absoluteFromSourceFile, basename, dirname, getFileSystem, isLocalRelativePath, isRoot, isRooted, join, relative, relativeFrom, resolve, setFileSystem, toRelativeImport} from './src/helpers';
|
export {absoluteFrom, absoluteFromSourceFile, basename, dirname, getFileSystem, isLocalRelativePath, isRoot, isRooted, join, relative, relativeFrom, resolve, setFileSystem, toRelativeImport} from './src/helpers';
|
||||||
export {LogicalFileSystem, LogicalProjectPath} from './src/logical';
|
export {LogicalFileSystem, LogicalProjectPath} from './src/logical';
|
||||||
export {NodeJSFileSystem} from './src/node_js_file_system';
|
export {NodeJSFileSystem} from './src/node_js_file_system';
|
||||||
export {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './src/types';
|
export {AbsoluteFsPath, FileStats, FileSystem, PathManipulation, PathSegment, PathString, ReadonlyFileSystem} from './src/types';
|
||||||
export {getSourceFileOrError} from './src/util';
|
export {getSourceFileOrError} from './src/util';
|
||||||
|
|
|
@ -29,33 +29,14 @@ export type AbsoluteFsPath = BrandedPath<'AbsoluteFsPath'>;
|
||||||
export type PathSegment = BrandedPath<'PathSegment'>;
|
export type PathSegment = BrandedPath<'PathSegment'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic interface to abstract the underlying file-system.
|
* An abstraction over the path manipulation aspects of a file-system.
|
||||||
*
|
|
||||||
* This makes it easier to provide mock file-systems in unit tests,
|
|
||||||
* but also to create clever file-systems that have features such as caching.
|
|
||||||
*/
|
*/
|
||||||
export interface FileSystem {
|
export interface PathManipulation {
|
||||||
exists(path: AbsoluteFsPath): boolean;
|
|
||||||
readFile(path: AbsoluteFsPath): string;
|
|
||||||
readFileBuffer(path: AbsoluteFsPath): Uint8Array;
|
|
||||||
writeFile(path: AbsoluteFsPath, data: string|Uint8Array, exclusive?: boolean): void;
|
|
||||||
removeFile(path: AbsoluteFsPath): void;
|
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
|
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[];
|
|
||||||
lstat(path: AbsoluteFsPath): FileStats;
|
|
||||||
stat(path: AbsoluteFsPath): FileStats;
|
|
||||||
pwd(): AbsoluteFsPath;
|
|
||||||
chdir(path: AbsoluteFsPath): void;
|
|
||||||
extname(path: AbsoluteFsPath|PathSegment): string;
|
extname(path: AbsoluteFsPath|PathSegment): string;
|
||||||
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
|
||||||
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
|
||||||
ensureDir(path: AbsoluteFsPath): void;
|
|
||||||
removeDeep(path: AbsoluteFsPath): void;
|
|
||||||
isCaseSensitive(): boolean;
|
|
||||||
isRoot(path: AbsoluteFsPath): boolean;
|
isRoot(path: AbsoluteFsPath): boolean;
|
||||||
isRooted(path: string): boolean;
|
isRooted(path: string): boolean;
|
||||||
resolve(...paths: string[]): AbsoluteFsPath;
|
|
||||||
dirname<T extends PathString>(file: T): T;
|
dirname<T extends PathString>(file: T): T;
|
||||||
|
extname(path: AbsoluteFsPath|PathSegment): string;
|
||||||
join<T extends PathString>(basePath: T, ...paths: string[]): T;
|
join<T extends PathString>(basePath: T, ...paths: string[]): T;
|
||||||
/**
|
/**
|
||||||
* Compute the relative path between `from` and `to`.
|
* Compute the relative path between `from` and `to`.
|
||||||
|
@ -66,9 +47,41 @@ export interface FileSystem {
|
||||||
*/
|
*/
|
||||||
relative<T extends PathString>(from: T, to: T): PathSegment|AbsoluteFsPath;
|
relative<T extends PathString>(from: T, to: T): PathSegment|AbsoluteFsPath;
|
||||||
basename(filePath: string, extension?: string): PathSegment;
|
basename(filePath: string, extension?: string): PathSegment;
|
||||||
|
normalize<T extends PathString>(path: T): T;
|
||||||
|
resolve(...paths: string[]): AbsoluteFsPath;
|
||||||
|
pwd(): AbsoluteFsPath;
|
||||||
|
chdir(path: AbsoluteFsPath): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstraction over the read-only aspects of a file-system.
|
||||||
|
*/
|
||||||
|
export interface ReadonlyFileSystem extends PathManipulation {
|
||||||
|
isCaseSensitive(): boolean;
|
||||||
|
exists(path: AbsoluteFsPath): boolean;
|
||||||
|
readFile(path: AbsoluteFsPath): string;
|
||||||
|
readFileBuffer(path: AbsoluteFsPath): Uint8Array;
|
||||||
|
readdir(path: AbsoluteFsPath): PathSegment[];
|
||||||
|
lstat(path: AbsoluteFsPath): FileStats;
|
||||||
|
stat(path: AbsoluteFsPath): FileStats;
|
||||||
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath;
|
realpath(filePath: AbsoluteFsPath): AbsoluteFsPath;
|
||||||
getDefaultLibLocation(): AbsoluteFsPath;
|
getDefaultLibLocation(): AbsoluteFsPath;
|
||||||
normalize<T extends PathString>(path: T): T;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic interface to abstract the underlying file-system.
|
||||||
|
*
|
||||||
|
* This makes it easier to provide mock file-systems in unit tests,
|
||||||
|
* but also to create clever file-systems that have features such as caching.
|
||||||
|
*/
|
||||||
|
export interface FileSystem extends ReadonlyFileSystem {
|
||||||
|
writeFile(path: AbsoluteFsPath, data: string|Uint8Array, exclusive?: boolean): void;
|
||||||
|
removeFile(path: AbsoluteFsPath): void;
|
||||||
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
|
||||||
|
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
||||||
|
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
|
||||||
|
ensureDir(path: AbsoluteFsPath): void;
|
||||||
|
removeDeep(path: AbsoluteFsPath): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PathString = string|AbsoluteFsPath|PathSegment;
|
export type PathString = string|AbsoluteFsPath|PathSegment;
|
||||||
|
|
Loading…
Reference in New Issue