From 5fcdd3bf877a84d75d4457fe8d2251895ce9dd4d Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 7 Jun 2019 00:16:43 +0200 Subject: [PATCH] perf: fine tune schematics to only commit changes (#1925) --- modules/data/schematics-core/index.ts | 1 + .../data/schematics-core/utility/ast-utils.ts | 2 +- .../data/schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/data/schematics/ng-add/index.ts | 14 ++---- modules/data/tsconfig-build.json | 1 + modules/effects/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../effects/schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/effects/tsconfig-build.json | 1 + modules/entity/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../entity/schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/entity/tsconfig-build.json | 1 + .../router-store/migrations/8_0_0/index.ts | 26 ++--------- modules/router-store/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/router-store/tsconfig-build.json | 1 + modules/schematics-core/index.ts | 1 + modules/schematics-core/utility/ast-utils.ts | 2 +- modules/schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/schematics/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/schematics/tsconfig-build.json | 1 + .../store-devtools/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/store-devtools/tsconfig-build.json | 1 + modules/store/migrations/8_0_0-beta/index.ts | 27 ++---------- modules/store/migrations/8_0_0-rc/index.ts | 31 +++++++------ modules/store/schematics-core/index.ts | 1 + .../schematics-core/utility/ast-utils.ts | 2 +- .../store/schematics-core/utility/change.ts | 18 +++++++- .../schematics-core/utility/visit-utils.ts | 43 ++++++++++++------- modules/store/tsconfig-build.json | 1 + tsconfig.json | 1 + 44 files changed, 398 insertions(+), 220 deletions(-) diff --git a/modules/data/schematics-core/index.ts b/modules/data/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/data/schematics-core/index.ts +++ b/modules/data/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/data/schematics-core/utility/ast-utils.ts b/modules/data/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/data/schematics-core/utility/ast-utils.ts +++ b/modules/data/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/data/schematics-core/utility/change.ts b/modules/data/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/data/schematics-core/utility/change.ts +++ b/modules/data/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/data/schematics-core/utility/visit-utils.ts b/modules/data/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/data/schematics-core/utility/visit-utils.ts +++ b/modules/data/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/data/schematics/ng-add/index.ts b/modules/data/schematics/ng-add/index.ts index 46dc965814..fba1f6e0b8 100644 --- a/modules/data/schematics/ng-add/index.ts +++ b/modules/data/schematics/ng-add/index.ts @@ -22,7 +22,6 @@ import { createChangeRecorder, } from '@ngrx/data/schematics-core'; import { Schema as EntityDataOptions } from './schema'; -import { Path } from '@angular-devkit/core'; function addNgRxDataToPackageJson() { return (host: Tree, context: SchematicContext) => { @@ -133,9 +132,9 @@ function renameNgrxDataModule(options: EntityDataOptions) { } const changes = [ - ...findNgrxDataImports(sourceFile, path, ngrxDataImports), - ...findNgrxDataImportDeclarations(sourceFile, path, ngrxDataImports), - ...findNgrxDataReplacements(sourceFile, path), + ...findNgrxDataImports(sourceFile, ngrxDataImports), + ...findNgrxDataImportDeclarations(sourceFile, ngrxDataImports), + ...findNgrxDataReplacements(sourceFile), ]; if (changes.length === 0) { @@ -150,13 +149,11 @@ function renameNgrxDataModule(options: EntityDataOptions) { function findNgrxDataImports( sourceFile: ts.SourceFile, - path: Path, imports: ts.ImportDeclaration[] ) { const changes = imports.map(specifier => createReplaceChange( sourceFile, - path, specifier.moduleSpecifier, "'ngrx-data'", "'@ngrx/data'" @@ -168,7 +165,6 @@ function findNgrxDataImports( function findNgrxDataImportDeclarations( sourceFile: ts.SourceFile, - path: Path, imports: ts.ImportDeclaration[] ) { const changes = imports @@ -198,7 +194,6 @@ function findNgrxDataImportDeclarations( .map(({ specifier, text }) => createReplaceChange( sourceFile, - path, specifier!, text!, (renames as any)[text!] @@ -208,7 +203,7 @@ function findNgrxDataImportDeclarations( return changes; } -function findNgrxDataReplacements(sourceFile: ts.SourceFile, path: Path) { +function findNgrxDataReplacements(sourceFile: ts.SourceFile) { const renameKeys = Object.keys(renames); let changes: ReplaceChange[] = []; ts.forEachChild(sourceFile, node => find(node, changes)); @@ -252,7 +247,6 @@ function findNgrxDataReplacements(sourceFile: ts.SourceFile, path: Path) { changes.push( createReplaceChange( sourceFile, - path, change.node, change.text, (renames as any)[change.text] diff --git a/modules/data/tsconfig-build.json b/modules/data/tsconfig-build.json index adb4f6ccf3..691f0c424b 100644 --- a/modules/data/tsconfig-build.json +++ b/modules/data/tsconfig-build.json @@ -11,6 +11,7 @@ "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": true, + "downlevelIteration": true, "outDir": "../../dist/packages/data", "paths": { "@ngrx/store": ["../../dist/packages/store"], diff --git a/modules/effects/schematics-core/index.ts b/modules/effects/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/effects/schematics-core/index.ts +++ b/modules/effects/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/effects/schematics-core/utility/ast-utils.ts b/modules/effects/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/effects/schematics-core/utility/ast-utils.ts +++ b/modules/effects/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/effects/schematics-core/utility/change.ts b/modules/effects/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/effects/schematics-core/utility/change.ts +++ b/modules/effects/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/effects/schematics-core/utility/visit-utils.ts b/modules/effects/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/effects/schematics-core/utility/visit-utils.ts +++ b/modules/effects/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/effects/tsconfig-build.json b/modules/effects/tsconfig-build.json index f65e550575..a1955524d8 100644 --- a/modules/effects/tsconfig-build.json +++ b/modules/effects/tsconfig-build.json @@ -11,6 +11,7 @@ "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": true, + "downlevelIteration": true, "outDir": "../../dist/packages/effects", "paths": { "@ngrx/store": ["../../dist/packages/store"] diff --git a/modules/entity/schematics-core/index.ts b/modules/entity/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/entity/schematics-core/index.ts +++ b/modules/entity/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/entity/schematics-core/utility/ast-utils.ts b/modules/entity/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/entity/schematics-core/utility/ast-utils.ts +++ b/modules/entity/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/entity/schematics-core/utility/change.ts b/modules/entity/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/entity/schematics-core/utility/change.ts +++ b/modules/entity/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/entity/schematics-core/utility/visit-utils.ts b/modules/entity/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/entity/schematics-core/utility/visit-utils.ts +++ b/modules/entity/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/entity/tsconfig-build.json b/modules/entity/tsconfig-build.json index 1c2772c655..e44f26b91f 100644 --- a/modules/entity/tsconfig-build.json +++ b/modules/entity/tsconfig-build.json @@ -11,6 +11,7 @@ "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": true, + "downlevelIteration": true, "outDir": "../../dist/packages/entity", "paths": { "@ngrx/store": ["../../dist/packages/store"] diff --git a/modules/router-store/migrations/8_0_0/index.ts b/modules/router-store/migrations/8_0_0/index.ts index 4d1b13f294..66e377debd 100644 --- a/modules/router-store/migrations/8_0_0/index.ts +++ b/modules/router-store/migrations/8_0_0/index.ts @@ -2,26 +2,14 @@ import * as ts from 'typescript'; import { Rule, chain, Tree } from '@angular-devkit/schematics'; import { ReplaceChange, - createChangeRecorder, createReplaceChange, + visitTSSourceFiles, + commitChanges, } from '@ngrx/router-store/schematics-core'; function updateRouterStoreImport(): Rule { return (tree: Tree) => { - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); - - if (sourceFile.isDeclarationFile) { - return; - } + visitTSSourceFiles(tree, sourceFile => { let changes: ReplaceChange[] = []; ts.forEachChild(sourceFile, function findDecorator(node) { if (!ts.isDecorator(node)) { @@ -43,7 +31,6 @@ function updateRouterStoreImport(): Rule { changes.push( createReplaceChange( sourceFile, - path, element, 'StoreRouterConnectingModule', 'StoreRouterConnectingModule.forRoot()' @@ -56,12 +43,7 @@ function updateRouterStoreImport(): Rule { }); }); - if (changes.length < 1) { - return; - } - - const recorder = createChangeRecorder(tree, path, changes); - tree.commitUpdate(recorder); + commitChanges(tree, sourceFile.fileName, changes); }); }; } diff --git a/modules/router-store/schematics-core/index.ts b/modules/router-store/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/router-store/schematics-core/index.ts +++ b/modules/router-store/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/router-store/schematics-core/utility/ast-utils.ts b/modules/router-store/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/router-store/schematics-core/utility/ast-utils.ts +++ b/modules/router-store/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/router-store/schematics-core/utility/change.ts b/modules/router-store/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/router-store/schematics-core/utility/change.ts +++ b/modules/router-store/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/router-store/schematics-core/utility/visit-utils.ts b/modules/router-store/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/router-store/schematics-core/utility/visit-utils.ts +++ b/modules/router-store/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/router-store/tsconfig-build.json b/modules/router-store/tsconfig-build.json index 8177527c26..5c37803783 100644 --- a/modules/router-store/tsconfig-build.json +++ b/modules/router-store/tsconfig-build.json @@ -11,6 +11,7 @@ "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": true, + "downlevelIteration": true, "outDir": "../../dist/packages/router-store", "paths": { "@ngrx/store": ["../../dist/packages/store"] diff --git a/modules/schematics-core/index.ts b/modules/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/schematics-core/index.ts +++ b/modules/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/schematics-core/utility/ast-utils.ts b/modules/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/schematics-core/utility/ast-utils.ts +++ b/modules/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/schematics-core/utility/change.ts b/modules/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/schematics-core/utility/change.ts +++ b/modules/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/schematics-core/utility/visit-utils.ts b/modules/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/schematics-core/utility/visit-utils.ts +++ b/modules/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/schematics/schematics-core/index.ts b/modules/schematics/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/schematics/schematics-core/index.ts +++ b/modules/schematics/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/schematics/schematics-core/utility/ast-utils.ts b/modules/schematics/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/schematics/schematics-core/utility/ast-utils.ts +++ b/modules/schematics/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/schematics/schematics-core/utility/change.ts b/modules/schematics/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/schematics/schematics-core/utility/change.ts +++ b/modules/schematics/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/schematics/schematics-core/utility/visit-utils.ts b/modules/schematics/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/schematics/schematics-core/utility/visit-utils.ts +++ b/modules/schematics/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/schematics/tsconfig-build.json b/modules/schematics/tsconfig-build.json index 385f00bde4..939a2efb49 100644 --- a/modules/schematics/tsconfig-build.json +++ b/modules/schematics/tsconfig-build.json @@ -4,6 +4,7 @@ "experimentalDecorators": true, "strictPropertyInitialization": false, "moduleResolution": "node", + "downlevelIteration": true, "outDir": "../../dist/packages/schematics", "sourceMap": true, "inlineSources": true, diff --git a/modules/store-devtools/schematics-core/index.ts b/modules/store-devtools/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/store-devtools/schematics-core/index.ts +++ b/modules/store-devtools/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/store-devtools/schematics-core/utility/ast-utils.ts b/modules/store-devtools/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/store-devtools/schematics-core/utility/ast-utils.ts +++ b/modules/store-devtools/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/store-devtools/schematics-core/utility/change.ts b/modules/store-devtools/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/store-devtools/schematics-core/utility/change.ts +++ b/modules/store-devtools/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/store-devtools/schematics-core/utility/visit-utils.ts b/modules/store-devtools/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/store-devtools/schematics-core/utility/visit-utils.ts +++ b/modules/store-devtools/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/store-devtools/tsconfig-build.json b/modules/store-devtools/tsconfig-build.json index 3a64869207..12e375582c 100644 --- a/modules/store-devtools/tsconfig-build.json +++ b/modules/store-devtools/tsconfig-build.json @@ -11,6 +11,7 @@ "noEmitOnError": false, "noImplicitAny": true, "noImplicitReturns": true, + "downlevelIteration": true, "outDir": "../../dist/packages/store-devtools", "paths": { "@ngrx/store": ["../../dist/packages/store"] diff --git a/modules/store/migrations/8_0_0-beta/index.ts b/modules/store/migrations/8_0_0-beta/index.ts index a7c0e65794..433fd0ba59 100644 --- a/modules/store/migrations/8_0_0-beta/index.ts +++ b/modules/store/migrations/8_0_0-beta/index.ts @@ -2,33 +2,19 @@ import * as ts from 'typescript'; import { Rule, chain, Tree } from '@angular-devkit/schematics'; import { ReplaceChange, - createChangeRecorder, createReplaceChange, + visitTSSourceFiles, + commitChanges, } from '@ngrx/store/schematics-core'; const META_REDUCERS = 'META_REDUCERS'; function updateMetaReducersToken(): Rule { return (tree: Tree) => { - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); - - if (sourceFile.isDeclarationFile) { - return; - } - + visitTSSourceFiles(tree, sourceFile => { const createChange = (node: ts.Node) => createReplaceChange( sourceFile, - path, node, META_REDUCERS, 'USER_PROVIDED_META_REDUCERS' @@ -40,12 +26,7 @@ function updateMetaReducersToken(): Rule { ); changes.push(...findMetaReducersAssignment(sourceFile, createChange)); - if (changes.length < 1) { - return; - } - - const recorder = createChangeRecorder(tree, path, changes); - tree.commitUpdate(recorder); + return commitChanges(tree, sourceFile.fileName, changes); }); }; } diff --git a/modules/store/migrations/8_0_0-rc/index.ts b/modules/store/migrations/8_0_0-rc/index.ts index 5af3b71bbe..263c3c48b1 100644 --- a/modules/store/migrations/8_0_0-rc/index.ts +++ b/modules/store/migrations/8_0_0-rc/index.ts @@ -6,10 +6,10 @@ import { SchematicsException, } from '@angular-devkit/schematics'; import { - createChangeRecorder, RemoveChange, InsertChange, visitTSSourceFiles, + commitChanges, } from '@ngrx/store/schematics-core'; function replaceWithRuntimeChecks(): Rule { @@ -56,28 +56,33 @@ function removeUsages( tree: Tree, ngrxStoreFreezeIsUsed?: boolean ) { + if ( + sourceFile.fileName.endsWith('.spec.ts') || + sourceFile.fileName.endsWith('.test.ts') + ) { + return ngrxStoreFreezeIsUsed; + } + const importRemovements = findStoreFreezeImportsToRemove(sourceFile); if (importRemovements.length === 0) { return ngrxStoreFreezeIsUsed; } const usageReplacements = findStoreFreezeUsagesToRemove(sourceFile); - const changes = [...importRemovements, ...usageReplacements]; - const recorder = createChangeRecorder(tree, sourceFile.fileName, changes); - tree.commitUpdate(recorder); - - return true; + return commitChanges(tree, sourceFile.fileName, changes); } function insertRuntimeChecks(sourceFile: ts.SourceFile, tree: Tree) { - const runtimeChecksInserts = findRuntimeCHecksToInsert(sourceFile); - const recorder = createChangeRecorder( - tree, - sourceFile.fileName, - runtimeChecksInserts - ); - tree.commitUpdate(recorder); + if ( + sourceFile.fileName.endsWith('.spec.ts') || + sourceFile.fileName.endsWith('.test.ts') + ) { + return; + } + + const changes = findRuntimeCHecksToInsert(sourceFile); + return commitChanges(tree, sourceFile.fileName, changes); } function findStoreFreezeImportsToRemove(sourceFile: ts.SourceFile) { diff --git a/modules/store/schematics-core/index.ts b/modules/store/schematics-core/index.ts index 82f2021e08..a696576992 100644 --- a/modules/store/schematics-core/index.ts +++ b/modules/store/schematics-core/index.ts @@ -33,6 +33,7 @@ export { ReplaceChange, createReplaceChange, createChangeRecorder, + commitChanges, } from './utility/change'; export { AppConfig, getWorkspace, getWorkspacePath } from './utility/config'; diff --git a/modules/store/schematics-core/utility/ast-utils.ts b/modules/store/schematics-core/utility/ast-utils.ts index f5d7d91dd6..0404340135 100644 --- a/modules/store/schematics-core/utility/ast-utils.ts +++ b/modules/store/schematics-core/utility/ast-utils.ts @@ -687,7 +687,7 @@ export function replaceImport( }) .filter(({ hit }) => hit) .map(({ specifier, text }) => - createReplaceChange(sourceFile, path, specifier!, text!, importToBe) + createReplaceChange(sourceFile, specifier!, text!, importToBe) ); return changes; diff --git a/modules/store/schematics-core/utility/change.ts b/modules/store/schematics-core/utility/change.ts index 51f451b8ba..98c7fc6405 100644 --- a/modules/store/schematics-core/utility/change.ts +++ b/modules/store/schematics-core/utility/change.ts @@ -136,12 +136,16 @@ export class ReplaceChange implements Change { export function createReplaceChange( sourceFile: ts.SourceFile, - path: Path, node: ts.Node, oldText: string, newText: string ): ReplaceChange { - return new ReplaceChange(path, node.getStart(sourceFile), oldText, newText); + return new ReplaceChange( + sourceFile.fileName, + node.getStart(sourceFile), + oldText, + newText + ); } export function createChangeRecorder( @@ -162,3 +166,13 @@ export function createChangeRecorder( } return recorder; } + +export function commitChanges(tree: Tree, path: string, changes: Change[]) { + if (changes.length === 0) { + return false; + } + + const recorder = createChangeRecorder(tree, path, changes); + tree.commitUpdate(recorder); + return true; +} diff --git a/modules/store/schematics-core/utility/visit-utils.ts b/modules/store/schematics-core/utility/visit-utils.ts index fc33b88227..c04c6c5650 100644 --- a/modules/store/schematics-core/utility/visit-utils.ts +++ b/modules/store/schematics-core/utility/visit-utils.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { Tree } from '@angular-devkit/schematics'; +import { Tree, DirEntry } from '@angular-devkit/schematics'; export function visitTSSourceFiles( tree: Tree, @@ -10,24 +10,35 @@ export function visitTSSourceFiles( ) => Result | undefined ): Result | undefined { let result: Result | undefined = undefined; + for (const sourceFile of visit(tree.root)) { + result = visitor(sourceFile, tree, result); + } - tree.visit(path => { - if (!path.endsWith('.ts')) { - return; - } - - const sourceFile = ts.createSourceFile( - path, - tree.read(path)!.toString(), - ts.ScriptTarget.Latest - ); + return result; +} - if (sourceFile.isDeclarationFile) { - return; +function* visit(directory: DirEntry): IterableIterator { + for (const path of directory.subfiles) { + if (path.endsWith('.ts') && !path.endsWith('.d.ts')) { + const entry = directory.file(path); + if (entry) { + const content = entry.content; + const source = ts.createSourceFile( + entry.path, + content.toString().replace(/^\uFEFF/, ''), + ts.ScriptTarget.Latest, + true + ); + yield source; + } } + } - result = visitor(sourceFile, tree, result); - }); + for (const path of directory.subdirs) { + if (path === 'node_modules') { + continue; + } - return result; + yield* visit(directory.dir(path)); + } } diff --git a/modules/store/tsconfig-build.json b/modules/store/tsconfig-build.json index 2517c27978..f5f8f08066 100644 --- a/modules/store/tsconfig-build.json +++ b/modules/store/tsconfig-build.json @@ -5,6 +5,7 @@ "stripInternal": true, "experimentalDecorators": true, "strictPropertyInitialization": false, + "downlevelIteration": true, "module": "es2015", "moduleResolution": "node", "outDir": "../../dist/packages/store", diff --git a/tsconfig.json b/tsconfig.json index afe04f4b0b..b10fbd6068 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "strictPropertyInitialization": false, + "downlevelIteration": true, "noStrictGenericChecks": true, "lib": ["es2016", "dom"], "outDir": "../out-tsc/app",