Skip to content

Commit

Permalink
feat(store): add META_REDUCERS replacement migration (#1640)
Browse files Browse the repository at this point in the history
  • Loading branch information
timdeschryver authored and brandonroberts committed Apr 1, 2019
1 parent da1ec80 commit 57bacf5
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 0 deletions.
113 changes: 113 additions & 0 deletions modules/store/migrations/8_0_0/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Tree } from '@angular-devkit/schematics';
import {
SchematicTestRunner,
UnitTestTree,
} from '@angular-devkit/schematics/testing';
import * as path from 'path';
import { createPackageJson } from '../../../schematics-core/testing/create-package';

describe('Store Migration 8_0_0', () => {
let appTree: UnitTestTree;
const collectionPath = path.join(__dirname, '../migration.json');
const pkgName = 'store';
beforeEach(() => {
appTree = new UnitTestTree(Tree.empty());
appTree.create(
'/tsconfig.json',
`
{
"include": [**./*.ts"]
}
`
);
createPackageJson('', pkgName, appTree);
});

it(`should replace the meta reducer imports`, () => {
const contents = `
import {
RuntimeChecks,
META_REDUCERS,
Store,
META_REDUCERS,
StoreModule,
META_REDUCERS as foo,
} from '@ngrx/store';`;
const expected = `
import {
RuntimeChecks,
USER_PROVIDED_META_REDUCERS,
Store,
USER_PROVIDED_META_REDUCERS,
StoreModule,
USER_PROVIDED_META_REDUCERS as foo,
} from '@ngrx/store';`;

appTree.create('./app.module.ts', contents);
const runner = new SchematicTestRunner('schematics', collectionPath);

const newTree = runner.runSchematic(
`ngrx-${pkgName}-migration-02`,
{},
appTree
);
const file = newTree.readContent('app.module.ts');

expect(file).toBe(expected);
});

it(`should replace the meta reducer assignments`, () => {
const contents = `
@NgModule({
imports: [
CommonModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
AuthModule,
AppRoutingModule,
StoreModule.forRoot(reducers),
],
providers: [
{
provide: META_REDUCERS,
useValue: [fooReducer, barReducer]
}
]
bootstrap: [AppComponent],
})
export class AppModule {}`;
const expected = `
@NgModule({
imports: [
CommonModule,
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
AuthModule,
AppRoutingModule,
StoreModule.forRoot(reducers),
],
providers: [
{
provide: USER_PROVIDED_META_REDUCERS,
useValue: [fooReducer, barReducer]
}
]
bootstrap: [AppComponent],
})
export class AppModule {}`;

appTree.create('./app.module.ts', contents);
const runner = new SchematicTestRunner('schematics', collectionPath);

const newTree = runner.runSchematic(
`ngrx-${pkgName}-migration-02`,
{},
appTree
);
const file = newTree.readContent('app.module.ts');

expect(file).toBe(expected);
});
});
120 changes: 120 additions & 0 deletions modules/store/migrations/8_0_0/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as ts from 'typescript';
import { Rule, chain, Tree } from '@angular-devkit/schematics';
import { Path } from '@angular-devkit/core';
import { ReplaceChange } 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;
}

const createChange = (node: ts.Node) =>
new ReplaceChange(
path,
node.getStart(sourceFile),
META_REDUCERS,
'USER_PROVIDED_META_REDUCERS'
);

const changes: ReplaceChange[] = [];
changes.push(
...findMetaReducersImportStatements(sourceFile, createChange)
);
changes.push(...findMetaReducersAssignment(sourceFile, createChange));

if (changes.length < 1) {
return;
}

const recorder = createChangeRecorder(tree, path, changes);
tree.commitUpdate(recorder);
});
};
}

export default function(): Rule {
return chain([updateMetaReducersToken()]);
}

function findMetaReducersImportStatements(
sourceFile: ts.SourceFile,
createChange: (node: ts.Node) => ReplaceChange
) {
const metaReducerImports = sourceFile.statements
.filter(ts.isImportDeclaration)
.filter(isNgRxStoreImport)
.map(p =>
(p.importClause!.namedBindings! as ts.NamedImports).elements.filter(
isMetaReducersImportSpecifier
)
)
.reduce((imports, curr) => imports.concat(curr), []);

const changes = metaReducerImports.map(createChange);
return changes;

function isNgRxStoreImport(importDeclaration: ts.ImportDeclaration) {
return (
importDeclaration.moduleSpecifier.getText(sourceFile) === "'@ngrx/store'"
);
}

function isMetaReducersImportSpecifier(importSpecifier: ts.ImportSpecifier) {
const isImport = () => importSpecifier.name.text === META_REDUCERS;
const isRenamedImport = () =>
importSpecifier.propertyName &&
importSpecifier.propertyName.text === META_REDUCERS;

return (
ts.isImportSpecifier(importSpecifier) && (isImport() || isRenamedImport())
);
}
}

function findMetaReducersAssignment(
sourceFile: ts.SourceFile,
createChange: (node: ts.Node) => ReplaceChange
) {
let changes: ReplaceChange[] = [];
ts.forEachChild(sourceFile, node => findMetaReducers(node, changes));
return changes;

function findMetaReducers(node: ts.Node, changes: ReplaceChange[]) {
if (
ts.isPropertyAssignment(node) &&
node.initializer.getText(sourceFile) === META_REDUCERS
) {
changes.push(createChange(node.initializer));
}

ts.forEachChild(node, childNode => findMetaReducers(childNode, changes));
}
}

function createChangeRecorder(
tree: Tree,
path: Path,
changes: ReplaceChange[]
) {
const recorder = tree.beginUpdate(path);
for (const change of changes) {
const action = <any>change;
recorder.remove(action.pos, action.oldText.length);
recorder.insertLeft(action.pos, action.newText);
}
return recorder;
}
1 change: 1 addition & 0 deletions modules/store/migrations/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ ts_library(
deps = [
"//modules/store/schematics-core",
"@npm//@angular-devkit/schematics",
"@npm//typescript",
],
)

Expand Down
5 changes: 5 additions & 0 deletions modules/store/migrations/migration.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"description": "The road to v6",
"version": "5.2",
"factory": "./6_0_0/index"
},
"ngrx-store-migration-02": {
"description": "The road to v8",
"version": "7.0",
"factory": "./8_0_0/index"
}
}
}

0 comments on commit 57bacf5

Please sign in to comment.