Charles Lyding 33f9f3de86 feat(@angular-devkit/schematics): support reading JSON content directly from a Tree
The schematics `Tree` now contains an additional `readJSON` method that supports directly
reading and parsing the content of a file as UTF-8 JSON with comment support. This avoids the need to manually
decode a Buffer, parse and handle JSON comments within a schematic when JSON content is needed.
If a file path does not exist, an exception will be thrown. While this differs from the semantics of `read`,
it helps reduce the amount of code needed for common schematic use cases. JSON parse errors will also result
in an exception being thrown with a message detailing the error.
2022-04-26 19:24:55 -04:00

114 lines
2.8 KiB
TypeScript

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {
BaseException,
JsonValue,
Path,
PathFragment,
dirname,
join,
normalize,
} from '@angular-devkit/core';
import { FileDoesNotExistException } from '../exception/exception';
import { Action } from './action';
import { DirEntry, MergeStrategy, Tree, TreeSymbol, UpdateRecorder } from './interface';
import { UpdateRecorderBase } from './recorder';
export class CannotCreateFileException extends BaseException {
constructor(path: string) {
super(`Cannot create file "${path}".`);
}
}
export class NullTreeDirEntry implements DirEntry {
get parent(): DirEntry | null {
return this.path == '/' ? null : new NullTreeDirEntry(dirname(this.path));
}
constructor(public readonly path: Path) {}
readonly subdirs: PathFragment[] = [];
readonly subfiles: PathFragment[] = [];
dir(name: PathFragment): DirEntry {
return new NullTreeDirEntry(join(this.path, name));
}
file(_name: PathFragment) {
return null;
}
visit() {}
}
export class NullTree implements Tree {
[TreeSymbol]() {
return this;
}
branch(): Tree {
return new NullTree();
}
merge(_other: Tree, _strategy?: MergeStrategy): void {}
readonly root: DirEntry = new NullTreeDirEntry(normalize('/'));
// Simple readonly file system operations.
exists(_path: string) {
return false;
}
read(_path: string) {
return null;
}
readText(path: string): string {
throw new FileDoesNotExistException(path);
}
readJson(path: string): JsonValue {
throw new FileDoesNotExistException(path);
}
get(_path: string) {
return null;
}
getDir(path: string) {
return new NullTreeDirEntry(normalize('/' + path));
}
visit() {}
// Change content of host files.
beginUpdate(path: string): never {
throw new FileDoesNotExistException(path);
}
commitUpdate(record: UpdateRecorder): never {
throw new FileDoesNotExistException(
record instanceof UpdateRecorderBase ? record.path : '<unknown>',
);
}
// Change structure of the host.
copy(path: string, _to: string): never {
throw new FileDoesNotExistException(path);
}
delete(path: string): never {
throw new FileDoesNotExistException(path);
}
create(path: string, _content: Buffer | string): never {
throw new CannotCreateFileException(path);
}
rename(path: string, _to: string): never {
throw new FileDoesNotExistException(path);
}
overwrite(path: string, _content: Buffer | string): never {
throw new FileDoesNotExistException(path);
}
apply(_action: Action, _strategy?: MergeStrategy): void {}
get actions(): Action[] {
return [];
}
}