diff --git a/goldens/public-api/angular_devkit/schematics/index.md b/goldens/public-api/angular_devkit/schematics/index.md
index 0d16c2974b54..05f844128ad5 100644
--- a/goldens/public-api/angular_devkit/schematics/index.md
+++ b/goldens/public-api/angular_devkit/schematics/index.md
@@ -7,6 +7,7 @@
///
import { BaseException } from '@angular-devkit/core';
+import { JsonValue } from '@angular-devkit/core';
import { logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { Path } from '@angular-devkit/core';
@@ -235,6 +236,10 @@ export class DelegateTree implements Tree_2 {
// (undocumented)
read(path: string): Buffer | null;
// (undocumented)
+ readJson(path: string): JsonValue;
+ // (undocumented)
+ readText(path: string): string;
+ // (undocumented)
rename(from: string, to: string): void;
// (undocumented)
get root(): DirEntry;
@@ -547,6 +552,10 @@ export class HostTree implements Tree_2 {
// (undocumented)
read(path: string): Buffer | null;
// (undocumented)
+ readJson(path: string): JsonValue;
+ // (undocumented)
+ readText(path: string): string;
+ // (undocumented)
rename(from: string, to: string): void;
// (undocumented)
get root(): DirEntry;
diff --git a/goldens/public-api/angular_devkit/schematics/testing/index.md b/goldens/public-api/angular_devkit/schematics/testing/index.md
index 9358b5a8390a..06e24643a9fe 100644
--- a/goldens/public-api/angular_devkit/schematics/testing/index.md
+++ b/goldens/public-api/angular_devkit/schematics/testing/index.md
@@ -6,6 +6,7 @@
///
+import { JsonValue } from '@angular-devkit/core';
import { logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { Path } from '@angular-devkit/core';
diff --git a/goldens/public-api/angular_devkit/schematics/tools/index.md b/goldens/public-api/angular_devkit/schematics/tools/index.md
index d968860a625f..b4bf5f2fa17b 100644
--- a/goldens/public-api/angular_devkit/schematics/tools/index.md
+++ b/goldens/public-api/angular_devkit/schematics/tools/index.md
@@ -8,6 +8,7 @@
import { BaseException } from '@angular-devkit/core';
import { JsonObject } from '@angular-devkit/core';
+import { JsonValue } from '@angular-devkit/core';
import { logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { Path } from '@angular-devkit/core';
diff --git a/packages/angular_devkit/schematics/BUILD.bazel b/packages/angular_devkit/schematics/BUILD.bazel
index 0cccea0629fc..d9907050747d 100644
--- a/packages/angular_devkit/schematics/BUILD.bazel
+++ b/packages/angular_devkit/schematics/BUILD.bazel
@@ -37,6 +37,7 @@ ts_library(
"//packages/angular_devkit/core",
"//packages/angular_devkit/core/node", # TODO: get rid of this for 6.0
"@npm//@types/node",
+ "@npm//jsonc-parser",
"@npm//magic-string",
"@npm//rxjs",
],
diff --git a/packages/angular_devkit/schematics/src/tree/delegate.ts b/packages/angular_devkit/schematics/src/tree/delegate.ts
index 147997964d59..e1fb75b04f04 100644
--- a/packages/angular_devkit/schematics/src/tree/delegate.ts
+++ b/packages/angular_devkit/schematics/src/tree/delegate.ts
@@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
+import { JsonValue } from '@angular-devkit/core';
import { Action } from './action';
import {
DirEntry,
@@ -35,6 +36,12 @@ export class DelegateTree implements Tree {
read(path: string): Buffer | null {
return this._other.read(path);
}
+ readText(path: string): string {
+ return this._other.readText(path);
+ }
+ readJson(path: string): JsonValue {
+ return this._other.readJson(path);
+ }
exists(path: string): boolean {
return this._other.exists(path);
}
diff --git a/packages/angular_devkit/schematics/src/tree/host-tree.ts b/packages/angular_devkit/schematics/src/tree/host-tree.ts
index ba5b6b75f8fb..edcda81b5baf 100644
--- a/packages/angular_devkit/schematics/src/tree/host-tree.ts
+++ b/packages/angular_devkit/schematics/src/tree/host-tree.ts
@@ -7,6 +7,7 @@
*/
import {
+ JsonValue,
Path,
PathFragment,
PathIsDirectoryException,
@@ -16,8 +17,10 @@ import {
normalize,
virtualFs,
} from '@angular-devkit/core';
+import { ParseError, parse as jsoncParse, printParseErrorCode } from 'jsonc-parser';
import { EMPTY, Observable } from 'rxjs';
import { concatMap, map, mergeMap } from 'rxjs/operators';
+import { TextDecoder } from 'util';
import {
ContentHasMutatedException,
FileAlreadyExistException,
@@ -162,10 +165,10 @@ export class HostTree implements Tree {
return tree._ancestry.has(this._id);
}
if (tree instanceof DelegateTree) {
- return this.isAncestorOf(((tree as unknown) as { _other: Tree })._other);
+ return this.isAncestorOf((tree as unknown as { _other: Tree })._other);
}
if (tree instanceof ScopedTree) {
- return this.isAncestorOf(((tree as unknown) as { _base: Tree })._base);
+ return this.isAncestorOf((tree as unknown as { _base: Tree })._base);
}
return false;
@@ -206,9 +209,9 @@ export class HostTree implements Tree {
throw new MergeConflictException(path);
}
- this._record.overwrite(path, (content as {}) as virtualFs.FileBuffer).subscribe();
+ this._record.overwrite(path, content as {} as virtualFs.FileBuffer).subscribe();
} else {
- this._record.create(path, (content as {}) as virtualFs.FileBuffer).subscribe();
+ this._record.create(path, content as {} as virtualFs.FileBuffer).subscribe();
}
return;
@@ -234,7 +237,7 @@ export class HostTree implements Tree {
}
// We use write here as merge validation has already been done, and we want to let
// the CordHost do its job.
- this._record.write(path, (content as {}) as virtualFs.FileBuffer).subscribe();
+ this._record.write(path, content as {} as virtualFs.FileBuffer).subscribe();
return;
}
@@ -289,6 +292,42 @@ export class HostTree implements Tree {
return entry ? entry.content : null;
}
+
+ readText(path: string): string {
+ const data = this.read(path);
+ if (data === null) {
+ throw new FileDoesNotExistException(path);
+ }
+
+ const decoder = new TextDecoder('utf-8', { fatal: true });
+
+ try {
+ // With the `fatal` option enabled, invalid data will throw a TypeError
+ return decoder.decode(data);
+ } catch (e) {
+ if (e instanceof TypeError) {
+ throw new Error(`Failed to decode "${path}" as UTF-8 text.`);
+ }
+ throw e;
+ }
+ }
+
+ readJson(path: string): JsonValue {
+ const content = this.readText(path);
+ const errors: ParseError[] = [];
+ const result = jsoncParse(content, errors, { allowTrailingComma: true });
+
+ // If there is a parse error throw with the error information
+ if (errors[0]) {
+ const { error, offset } = errors[0];
+ throw new Error(
+ `Failed to parse "${path}" as JSON. ${printParseErrorCode(error)} at offset: ${offset}.`,
+ );
+ }
+
+ return result;
+ }
+
exists(path: string): boolean {
return this._recordSync.isFile(this._normalizePath(path));
}
@@ -337,7 +376,7 @@ export class HostTree implements Tree {
throw new FileDoesNotExistException(p);
}
const c = typeof content == 'string' ? Buffer.from(content) : content;
- this._record.overwrite(p, (c as {}) as virtualFs.FileBuffer).subscribe();
+ this._record.overwrite(p, c as {} as virtualFs.FileBuffer).subscribe();
}
beginUpdate(path: string): UpdateRecorder {
const entry = this.get(path);
@@ -371,7 +410,7 @@ export class HostTree implements Tree {
throw new FileAlreadyExistException(p);
}
const c = typeof content == 'string' ? Buffer.from(content) : content;
- this._record.create(p, (c as {}) as virtualFs.FileBuffer).subscribe();
+ this._record.create(p, c as {} as virtualFs.FileBuffer).subscribe();
}
delete(path: string): void {
this._recordSync.delete(this._normalizePath(path));
@@ -476,7 +515,7 @@ export class FilterHostTree extends HostTree {
return EMPTY;
}
- return newBackend.write(path, (content as {}) as virtualFs.FileBuffer);
+ return newBackend.write(path, content as {} as virtualFs.FileBuffer);
}),
);
};
diff --git a/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts b/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts
index 9c1a499fd8e3..2687ea14e8ed 100644
--- a/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts
+++ b/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts
@@ -11,6 +11,84 @@ import { FilterHostTree, HostTree } from './host-tree';
import { MergeStrategy } from './interface';
describe('HostTree', () => {
+ describe('readText', () => {
+ it('returns text when reading a file that exists', () => {
+ const tree = new HostTree();
+ tree.create('/textfile1', 'abc');
+ tree.create('/textfile2', '123');
+ expect(tree.readText('/textfile1')).toEqual('abc');
+ expect(tree.readText('/textfile2')).toEqual('123');
+ });
+
+ it('throws an error when a file does not exist', () => {
+ const tree = new HostTree();
+ const path = '/textfile1';
+ expect(() => tree.readText(path)).toThrowError(`Path "${path}" does not exist.`);
+ });
+
+ it('throws an error when invalid UTF-8 characters are present', () => {
+ const tree = new HostTree();
+ const path = '/textfile1';
+ tree.create(path, Buffer.from([0xff, 0xff, 0xff, 0xff]));
+ expect(() => tree.readText(path)).toThrowError(`Failed to decode "${path}" as UTF-8 text.`);
+ });
+ });
+
+ describe('readJson', () => {
+ it('returns a JSON value when reading a file that exists', () => {
+ const tree = new HostTree();
+ tree.create('/textfile1', '{ "a": true, "b": "xyz" }');
+ tree.create('/textfile2', '123');
+ tree.create('/textfile3', 'null');
+ expect(tree.readJson('/textfile1')).toEqual({ a: true, b: 'xyz' });
+ expect(tree.readJson('/textfile2')).toEqual(123);
+ expect(tree.readJson('/textfile3')).toBeNull();
+ });
+
+ it('returns a JSON value when reading a file with comments', () => {
+ const tree = new HostTree();
+ tree.create(
+ '/textfile1',
+ '{ "a": true, /* inner object\nmultiline comment\n */ "b": "xyz" }',
+ );
+ tree.create('/textfile2', '123 // number value');
+ tree.create('/textfile3', 'null // null value');
+ expect(tree.readJson('/textfile1')).toEqual({ a: true, b: 'xyz' });
+ expect(tree.readJson('/textfile2')).toEqual(123);
+ expect(tree.readJson('/textfile3')).toBeNull();
+ });
+
+ it('returns a JSON value when reading a file with trailing commas', () => {
+ const tree = new HostTree();
+ tree.create('/textfile1', '{ "a": true, "b": "xyz", }');
+ tree.create('/textfile2', '[5, 4, 3, 2, 1, ]');
+ expect(tree.readJson('/textfile1')).toEqual({ a: true, b: 'xyz' });
+ expect(tree.readJson('/textfile2')).toEqual([5, 4, 3, 2, 1]);
+ });
+
+ it('throws an error when a file does not exist', () => {
+ const tree = new HostTree();
+ const path = '/textfile1';
+ expect(() => tree.readJson(path)).toThrowError(`Path "${path}" does not exist.`);
+ });
+
+ it('throws an error if the JSON is malformed', () => {
+ const tree = new HostTree();
+ const path = '/textfile1';
+ tree.create(path, '{ "a": true;;;;; "b": "xyz" }');
+ expect(() => tree.readJson(path)).toThrowError(
+ `Failed to parse "${path}" as JSON. InvalidSymbol at offset: 7.`,
+ );
+ });
+
+ it('throws an error when invalid UTF-8 characters are present', () => {
+ const tree = new HostTree();
+ const path = '/textfile1';
+ tree.create(path, Buffer.from([0xff, 0xff, 0xff, 0xff]));
+ expect(() => tree.readJson(path)).toThrowError(`Failed to decode "${path}" as UTF-8 text.`);
+ });
+ });
+
describe('merge', () => {
it('should create files from each tree', () => {
const tree = new HostTree();
diff --git a/packages/angular_devkit/schematics/src/tree/interface.ts b/packages/angular_devkit/schematics/src/tree/interface.ts
index e05be51aa6a3..87792b659723 100644
--- a/packages/angular_devkit/schematics/src/tree/interface.ts
+++ b/packages/angular_devkit/schematics/src/tree/interface.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import { Path, PathFragment } from '@angular-devkit/core';
+import { JsonValue, Path, PathFragment } from '@angular-devkit/core';
import { Action } from './action';
export enum MergeStrategy {
@@ -83,6 +83,31 @@ export interface Tree {
// Readonly.
read(path: string): Buffer | null;
+
+ /**
+ * Reads a file from the Tree as a UTF-8 encoded text file.
+ *
+ * @param path The path of the file to read.
+ * @returns A string containing the contents of the file.
+ * @throws {@link FileDoesNotExistException} if the file is not found.
+ * @throws An error if the file contains invalid UTF-8 characters.
+ */
+ readText(path: string): string;
+
+ /**
+ * Reads and parses a file from the Tree as a UTF-8 encoded JSON file.
+ * Supports parsing JSON (RFC 8259) with the following extensions:
+ * * Single-line and multi-line JavaScript comments
+ * * Trailing commas within objects and arrays
+ *
+ * @param path The path of the file to read.
+ * @returns A JsonValue containing the parsed contents of the file.
+ * @throws {@link FileDoesNotExistException} if the file is not found.
+ * @throws An error if the file contains invalid UTF-8 characters.
+ * @throws An error if the file contains malformed JSON.
+ */
+ readJson(path: string): JsonValue;
+
exists(path: string): boolean;
get(path: string): FileEntry | null;
getDir(path: string): DirEntry;
diff --git a/packages/angular_devkit/schematics/src/tree/null.ts b/packages/angular_devkit/schematics/src/tree/null.ts
index 48469a3c3370..cbace2bf3211 100644
--- a/packages/angular_devkit/schematics/src/tree/null.ts
+++ b/packages/angular_devkit/schematics/src/tree/null.ts
@@ -6,7 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
-import { BaseException, Path, PathFragment, dirname, join, normalize } from '@angular-devkit/core';
+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';
@@ -57,6 +65,12 @@ export class NullTree implements Tree {
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;
}
diff --git a/packages/angular_devkit/schematics/src/tree/scoped.ts b/packages/angular_devkit/schematics/src/tree/scoped.ts
index f77af03635a1..205769204439 100644
--- a/packages/angular_devkit/schematics/src/tree/scoped.ts
+++ b/packages/angular_devkit/schematics/src/tree/scoped.ts
@@ -7,6 +7,7 @@
*/
import {
+ JsonValue,
NormalizedRoot,
Path,
PathFragment,
@@ -113,6 +114,12 @@ export class ScopedTree implements Tree {
read(path: string): Buffer | null {
return this._base.read(this._fullPath(path));
}
+ readText(path: string): string {
+ return this._base.readText(this._fullPath(path));
+ }
+ readJson(path: string): JsonValue {
+ return this._base.readJson(this._fullPath(path));
+ }
exists(path: string): boolean {
return this._base.exists(this._fullPath(path));
}
diff --git a/packages/angular_devkit/schematics_cli/blank/factory.ts b/packages/angular_devkit/schematics_cli/blank/factory.ts
index d8eeb16cc3d5..6585ea95b59c 100644
--- a/packages/angular_devkit/schematics_cli/blank/factory.ts
+++ b/packages/angular_devkit/schematics_cli/blank/factory.ts
@@ -28,13 +28,9 @@ function addSchematicToCollectionJson(
description: JsonObject,
): Rule {
return (tree: Tree) => {
- const collectionJsonContent = tree.read(collectionPath);
- if (!collectionJsonContent) {
- throw new Error('Invalid collection path: ' + collectionPath);
- }
+ const collectionJson = tree.readJson(collectionPath);
- const collectionJson = JSON.parse(collectionJsonContent.toString());
- if (!isJsonObject(collectionJson.schematics)) {
+ if (!isJsonObject(collectionJson) || !isJsonObject(collectionJson.schematics)) {
throw new Error('Invalid collection.json; schematics needs to be an object.');
}
@@ -55,16 +51,13 @@ export default function (options: Schema): Rule {
let collectionPath: Path | undefined;
try {
- const packageJsonContent = tree.read('/package.json');
- if (packageJsonContent) {
- const packageJson = JSON.parse(packageJsonContent.toString()) as {
- schematics: unknown;
- };
- if (typeof packageJson.schematics === 'string') {
- const p = normalize(packageJson.schematics);
- if (tree.exists(p)) {
- collectionPath = p;
- }
+ const packageJson = tree.readJson('/package.json') as {
+ schematics: unknown;
+ };
+ if (typeof packageJson.schematics === 'string') {
+ const p = normalize(packageJson.schematics);
+ if (tree.exists(p)) {
+ collectionPath = p;
}
}
} catch {}
diff --git a/packages/schematics/angular/app-shell/index.ts b/packages/schematics/angular/app-shell/index.ts
index f7caa44cabcf..0e7e966368e9 100644
--- a/packages/schematics/angular/app-shell/index.ts
+++ b/packages/schematics/angular/app-shell/index.ts
@@ -35,11 +35,7 @@ import { BrowserBuilderOptions, Builders, ServerBuilderOptions } from '../utilit
import { Schema as AppShellOptions } from './schema';
function getSourceFile(host: Tree, path: string): ts.SourceFile {
- const buffer = host.read(path);
- if (!buffer) {
- throw new SchematicsException(`Could not find ${path}.`);
- }
- const content = buffer.toString();
+ const content = host.readText(path);
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
return source;
@@ -82,10 +78,9 @@ function getComponentTemplate(host: Tree, compPath: string, tmplInfo: TemplateIn
const templateUrl = (tmplInfo.templateUrlProp.initializer as ts.StringLiteral).text;
const dir = dirname(normalize(compPath));
const templatePath = join(dir, templateUrl);
- const buffer = host.read(templatePath);
- if (buffer) {
- template = buffer.toString();
- }
+ try {
+ template = host.readText(templatePath);
+ } catch {}
}
return template;
diff --git a/packages/schematics/angular/component/index.ts b/packages/schematics/angular/component/index.ts
index 177b5eac276a..2fbbb7bcb1c0 100644
--- a/packages/schematics/angular/component/index.ts
+++ b/packages/schematics/angular/component/index.ts
@@ -32,11 +32,7 @@ import { buildDefaultPath, getWorkspace } from '../utility/workspace';
import { Schema as ComponentOptions, Style } from './schema';
function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString('utf-8');
+ const sourceText = host.readText(modulePath);
return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
}
diff --git a/packages/schematics/angular/directive/index.ts b/packages/schematics/angular/directive/index.ts
index 666a181b5b48..4a4a1bdbe8b4 100644
--- a/packages/schematics/angular/directive/index.ts
+++ b/packages/schematics/angular/directive/index.ts
@@ -36,11 +36,7 @@ function addDeclarationToNgModule(options: DirectiveOptions): Rule {
}
const modulePath = options.module;
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString('utf-8');
+ const sourceText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const directivePath =
@@ -66,11 +62,7 @@ function addDeclarationToNgModule(options: DirectiveOptions): Rule {
if (options.export) {
// Need to refresh the AST because we overwrote the file in the host.
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString('utf-8');
+ const sourceText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const exportRecorder = host.beginUpdate(modulePath);
diff --git a/packages/schematics/angular/module/index.ts b/packages/schematics/angular/module/index.ts
index 4c6840011c25..6c599c418bce 100644
--- a/packages/schematics/angular/module/index.ts
+++ b/packages/schematics/angular/module/index.ts
@@ -55,11 +55,7 @@ function addDeclarationToNgModule(options: ModuleOptions): Rule {
const modulePath = options.module;
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString();
+ const sourceText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const relativePath = buildRelativeModulePath(options, modulePath);
@@ -101,12 +97,8 @@ function addRouteDeclarationToNgModule(
path = options.module;
}
- const text = host.read(path);
- if (!text) {
- throw new Error(`Couldn't find the module nor its routing module.`);
- }
+ const sourceText = host.readText(path);
- const sourceText = text.toString();
const addDeclaration = addRouteDeclarationToModule(
ts.createSourceFile(path, sourceText, ts.ScriptTarget.Latest, true),
path,
diff --git a/packages/schematics/angular/pipe/index.ts b/packages/schematics/angular/pipe/index.ts
index e18c432eabc2..e7ab1e7d8e95 100644
--- a/packages/schematics/angular/pipe/index.ts
+++ b/packages/schematics/angular/pipe/index.ts
@@ -35,11 +35,7 @@ function addDeclarationToNgModule(options: PipeOptions): Rule {
}
const modulePath = options.module;
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString('utf-8');
+ const sourceText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const pipePath =
@@ -63,11 +59,7 @@ function addDeclarationToNgModule(options: PipeOptions): Rule {
host.commitUpdate(recorder);
if (options.export) {
- const text = host.read(modulePath);
- if (text === null) {
- throw new SchematicsException(`File ${modulePath} does not exist.`);
- }
- const sourceText = text.toString('utf-8');
+ const sourceText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const exportRecorder = host.beginUpdate(modulePath);
diff --git a/packages/schematics/angular/service-worker/index.ts b/packages/schematics/angular/service-worker/index.ts
index 774493083855..f35e47019d5f 100644
--- a/packages/schematics/angular/service-worker/index.ts
+++ b/packages/schematics/angular/service-worker/index.ts
@@ -122,11 +122,7 @@ function updateAppModule(mainPath: string): Rule {
}
function getTsSourceFile(host: Tree, path: string): ts.SourceFile {
- const buffer = host.read(path);
- if (!buffer) {
- throw new SchematicsException(`Could not read file (${path}).`);
- }
- const content = buffer.toString();
+ const content = host.readText(path);
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
return source;
diff --git a/packages/schematics/angular/universal/index.ts b/packages/schematics/angular/universal/index.ts
index 95fe3d26e93f..c660995305bc 100644
--- a/packages/schematics/angular/universal/index.ts
+++ b/packages/schematics/angular/universal/index.ts
@@ -99,12 +99,7 @@ function updateConfigFile(options: UniversalOptions, tsConfigDirectory: Path): R
}
function findBrowserModuleImport(host: Tree, modulePath: string): ts.Node {
- const moduleBuffer = host.read(modulePath);
- if (!moduleBuffer) {
- throw new SchematicsException(`Module file (${modulePath}) not found`);
- }
- const moduleFileText = moduleBuffer.toString('utf-8');
-
+ const moduleFileText = host.readText(modulePath);
const source = ts.createSourceFile(modulePath, moduleFileText, ts.ScriptTarget.Latest, true);
const decoratorMetadata = getDecoratorMetadata(source, 'NgModule', '@angular/core')[0];
diff --git a/packages/schematics/angular/utility/json-file.ts b/packages/schematics/angular/utility/json-file.ts
index 647199ef848d..6bb532416f2e 100644
--- a/packages/schematics/angular/utility/json-file.ts
+++ b/packages/schematics/angular/utility/json-file.ts
@@ -27,12 +27,7 @@ export class JSONFile {
content: string;
constructor(private readonly host: Tree, private readonly path: string) {
- const buffer = this.host.read(this.path);
- if (buffer) {
- this.content = buffer.toString();
- } else {
- throw new Error(`Could not read '${path}'.`);
- }
+ this.content = this.host.readText(this.path);
}
private _jsonAst: Node | undefined;
diff --git a/packages/schematics/angular/utility/ng-ast-utils.ts b/packages/schematics/angular/utility/ng-ast-utils.ts
index e55effeeea17..c0dfb8374b90 100644
--- a/packages/schematics/angular/utility/ng-ast-utils.ts
+++ b/packages/schematics/angular/utility/ng-ast-utils.ts
@@ -13,11 +13,7 @@ import * as ts from '../third_party/github.com/Microsoft/TypeScript/lib/typescri
import { findNode, getSourceNodes } from '../utility/ast-utils';
export function findBootstrapModuleCall(host: Tree, mainPath: string): ts.CallExpression | null {
- const mainBuffer = host.read(mainPath);
- if (!mainBuffer) {
- throw new SchematicsException(`Main file (${mainPath}) not found`);
- }
- const mainText = mainBuffer.toString('utf-8');
+ const mainText = host.readText(mainPath);
const source = ts.createSourceFile(mainPath, mainText, ts.ScriptTarget.Latest, true);
const allNodes = getSourceNodes(source);
@@ -58,11 +54,7 @@ export function findBootstrapModulePath(host: Tree, mainPath: string): string {
const bootstrapModule = bootstrapCall.arguments[0];
- const mainBuffer = host.read(mainPath);
- if (!mainBuffer) {
- throw new SchematicsException(`Client application main file (${mainPath}) not found`);
- }
- const mainText = mainBuffer.toString('utf-8');
+ const mainText = host.readText(mainPath);
const source = ts.createSourceFile(mainPath, mainText, ts.ScriptTarget.Latest, true);
const allNodes = getSourceNodes(source);
const bootstrapModuleRelativePath = allNodes
diff --git a/packages/schematics/angular/utility/workspace.ts b/packages/schematics/angular/utility/workspace.ts
index 07bf2c9ffc64..9354f4beab14 100644
--- a/packages/schematics/angular/utility/workspace.ts
+++ b/packages/schematics/angular/utility/workspace.ts
@@ -6,19 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
-import { json, virtualFs, workspaces } from '@angular-devkit/core';
+import { json, workspaces } from '@angular-devkit/core';
import { Rule, Tree, noop } from '@angular-devkit/schematics';
import { ProjectType } from './workspace-models';
function createHost(tree: Tree): workspaces.WorkspaceHost {
return {
async readFile(path: string): Promise {
- const data = tree.read(path);
- if (!data) {
- throw new Error('File not found.');
- }
-
- return virtualFs.fileBufferToString(data);
+ return tree.readText(path);
},
async writeFile(path: string, data: string): Promise {
return tree.overwrite(path, data);
diff --git a/packages/schematics/angular/web-worker/index.ts b/packages/schematics/angular/web-worker/index.ts
index bda1d4740887..1e0564045a75 100644
--- a/packages/schematics/angular/web-worker/index.ts
+++ b/packages/schematics/angular/web-worker/index.ts
@@ -65,7 +65,7 @@ function addSnippet(options: WebWorkerOptions): Rule {
`;
// Append the worker creation snippet.
- const originalContent = host.read(siblingModulePath);
+ const originalContent = host.readText(siblingModulePath);
host.overwrite(siblingModulePath, originalContent + '\n' + workerCreationSnippet);
return host;