feat(schematics): update ngrx to 7.2.0
This commit is contained in:
parent
e2f482afd3
commit
dbf59af6a5
10
package.json
10
package.json
@ -33,11 +33,11 @@
|
|||||||
"@angular/platform-browser-dynamic": "^7.2.1",
|
"@angular/platform-browser-dynamic": "^7.2.1",
|
||||||
"@angular/router": "^7.2.1",
|
"@angular/router": "^7.2.1",
|
||||||
"@angular/upgrade": "^7.2.1",
|
"@angular/upgrade": "^7.2.1",
|
||||||
"@ngrx/effects": "6.1.2",
|
"@ngrx/effects": "7.1.0",
|
||||||
"@ngrx/router-store": "6.1.2",
|
"@ngrx/router-store": "7.1.0",
|
||||||
"@ngrx/schematics": "6.1.2",
|
"@ngrx/schematics": "7.1.0",
|
||||||
"@ngrx/store": "6.1.2",
|
"@ngrx/store": "7.1.0",
|
||||||
"@ngrx/store-devtools": "6.1.2",
|
"@ngrx/store-devtools": "7.1.0",
|
||||||
"@schematics/angular": "~7.2.2",
|
"@schematics/angular": "~7.2.2",
|
||||||
"@types/jasmine": "~2.8.6",
|
"@types/jasmine": "~2.8.6",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
|||||||
@ -157,15 +157,17 @@ describe('DataPersistence', () => {
|
|||||||
const root = TestBed.createComponent(RootCmp);
|
const root = TestBed.createComponent(RootCmp);
|
||||||
|
|
||||||
const router: Router = TestBed.get(Router);
|
const router: Router = TestBed.get(Router);
|
||||||
let action;
|
let actions: any[] = [];
|
||||||
TestBed.get(Actions).subscribe(a => (action = a));
|
TestBed.get(Actions).subscribe((a: any) => actions.push(a));
|
||||||
|
|
||||||
router.navigateByUrl('/todo/123');
|
router.navigateByUrl('/todo/123');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||||
expect(action.type).toEqual('ERROR');
|
expect(actions.map(a => a.type)).toContain('ERROR');
|
||||||
expect(action.payload.error.message).toEqual('boom');
|
expect(
|
||||||
|
actions.find(a => a.type === 'ERROR').payload.error.message
|
||||||
|
).toEqual('boom');
|
||||||
|
|
||||||
// can recover after an error
|
// can recover after an error
|
||||||
router.navigateByUrl('/todo/456');
|
router.navigateByUrl('/todo/456');
|
||||||
@ -205,15 +207,17 @@ describe('DataPersistence', () => {
|
|||||||
const root = TestBed.createComponent(RootCmp);
|
const root = TestBed.createComponent(RootCmp);
|
||||||
|
|
||||||
const router: Router = TestBed.get(Router);
|
const router: Router = TestBed.get(Router);
|
||||||
let action;
|
let actions: any[] = [];
|
||||||
TestBed.get(Actions).subscribe(a => (action = a));
|
TestBed.get(Actions).subscribe((a: any) => actions.push(a));
|
||||||
|
|
||||||
router.navigateByUrl('/todo/123');
|
router.navigateByUrl('/todo/123');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||||
expect(action.type).toEqual('ERROR');
|
expect(actions.map(a => a.type)).toContain('ERROR');
|
||||||
expect(action.payload.error).toEqual('boom');
|
expect(actions.find(a => a.type === 'ERROR').payload.error).toEqual(
|
||||||
|
'boom'
|
||||||
|
);
|
||||||
|
|
||||||
router.navigateByUrl('/todo/456');
|
router.navigateByUrl('/todo/456');
|
||||||
tick(0);
|
tick(0);
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
},
|
},
|
||||||
"update-7.6.0": {
|
"update-7.6.0": {
|
||||||
"version": "7.6.0",
|
"version": "7.6.0",
|
||||||
"description": "Add VSCode Extensions",
|
"description": "Add VSCode Extensions and Update NgRx",
|
||||||
"factory": "./update-7-6-0/update-7-6-0"
|
"factory": "./update-7-6-0/update-7-6-0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,96 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
import {
|
||||||
|
SchematicTestRunner,
|
||||||
|
UnitTestTree
|
||||||
|
} from '@angular-devkit/schematics/testing';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { serializeJson } from '../../src/utils/fileutils';
|
import { serializeJson } from '../../src/utils/fileutils';
|
||||||
import { readJsonInTree, updateJsonInTree } from '../../src/utils/ast-utils';
|
import { readJsonInTree, updateJsonInTree } from '../../src/utils/ast-utils';
|
||||||
|
|
||||||
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
|
|
||||||
|
const effectContents = `
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Effect, Actions } from '@ngrx/effects';
|
||||||
|
import { DataPersistence } from '@nrwl/nx';
|
||||||
|
|
||||||
|
import { UserPartialState } from './user.reducer';
|
||||||
|
import {
|
||||||
|
LoadUser,
|
||||||
|
UserLoaded,
|
||||||
|
UserLoadError,
|
||||||
|
UserActionTypes
|
||||||
|
} from './user.actions';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserEffects {
|
||||||
|
@Effect() effect$ = this.actions$.ofType(LoadUser).pipe(mapTo(UserLoaded));
|
||||||
|
@Effect() effect2$ = this.actions$.ofType<UserLoaded>(LoadUser).pipe(mapTo(UserLoaded));
|
||||||
|
@Effect() effect3$ = this.actions$.ofType<UserLoaded>(LoadUser).pipe(withLatestFrom(this.store.select(selector)), mapTo(UserLoaded));
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private actions$: Actions,
|
||||||
|
private dataPersistence: DataPersistence<UserPartialState>,
|
||||||
|
private store: Store<AppState>
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
const selectorContents = `
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { AppState, selector } from '../+state';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app',
|
||||||
|
template: '',
|
||||||
|
styles: []
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
slice$ = this.store.select(selector).pipe(
|
||||||
|
map(a => a)
|
||||||
|
);
|
||||||
|
|
||||||
|
slice2$: Observable<string>;
|
||||||
|
|
||||||
|
slice3$ = Observable.from([]).pipe(
|
||||||
|
withLatestFrom(this.store.select(selector5))
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<AppState>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.slice2$ = this.store.select(selector2);
|
||||||
|
this.store.select(selector3).subscribe(console.log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
describe('Update 7.6.0', () => {
|
describe('Update 7.6.0', () => {
|
||||||
let initialTree: Tree;
|
let initialTree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree = Tree.empty();
|
initialTree = new UnitTestTree(Tree.empty());
|
||||||
|
|
||||||
initialTree.create(
|
initialTree.create(
|
||||||
'package.json',
|
'package.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
|
dependencies: {
|
||||||
|
'@ngrx/effects': '6.1.2',
|
||||||
|
'@ngrx/router-store': '6.1.2',
|
||||||
|
'@ngrx/store': '6.1.2'
|
||||||
|
},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
'@angular/cli': '7.1.0',
|
'@ngrx/schematics': '6.1.2',
|
||||||
typescript: '~3.1.0'
|
'@ngrx/store-devtools': '6.1.2'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -29,41 +101,125 @@ describe('Update 7.6.0', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add vscode extension recommendations', async () => {
|
describe('VSCode Extension Recommendations', () => {
|
||||||
const result = await schematicRunner
|
it('should be added', async () => {
|
||||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
const result = await schematicRunner
|
||||||
.toPromise();
|
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
||||||
recommendations: [
|
recommendations: [
|
||||||
'nrwl.angular-console',
|
'nrwl.angular-console',
|
||||||
'angular.ng-template',
|
'angular.ng-template',
|
||||||
'esbenp.prettier-vscode'
|
'esbenp.prettier-vscode'
|
||||||
]
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be added to existing recommendations', async () => {
|
||||||
|
initialTree = await schematicRunner
|
||||||
|
.callRule(
|
||||||
|
updateJsonInTree('.vscode/extensions.json', () => ({
|
||||||
|
recommendations: ['eamodio.gitlens', 'angular.ng-template']
|
||||||
|
})),
|
||||||
|
initialTree
|
||||||
|
)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
const result = await schematicRunner
|
||||||
|
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
||||||
|
recommendations: [
|
||||||
|
'eamodio.gitlens',
|
||||||
|
'angular.ng-template',
|
||||||
|
'nrwl.angular-console',
|
||||||
|
'esbenp.prettier-vscode'
|
||||||
|
]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add to existing vscode extension recommendations', async () => {
|
describe('NgRx Migration', () => {
|
||||||
initialTree = await schematicRunner
|
it('should update ngrx to 7.1.0', async () => {
|
||||||
.callRule(
|
const result = await schematicRunner
|
||||||
updateJsonInTree('.vscode/extensions.json', () => ({
|
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||||
recommendations: ['eamodio.gitlens', 'angular.ng-template']
|
.toPromise();
|
||||||
})),
|
|
||||||
initialTree
|
|
||||||
)
|
|
||||||
.toPromise();
|
|
||||||
|
|
||||||
const result = await schematicRunner
|
expect(readJsonInTree(result, 'package.json')).toEqual({
|
||||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
dependencies: {
|
||||||
.toPromise();
|
'@ngrx/effects': '7.2.0',
|
||||||
|
'@ngrx/router-store': '7.2.0',
|
||||||
|
'@ngrx/store': '7.2.0'
|
||||||
|
},
|
||||||
|
devDependencies: {
|
||||||
|
'@ngrx/schematics': '7.2.0',
|
||||||
|
'@ngrx/store-devtools': '7.2.0'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
it('should convert ofType code', async () => {
|
||||||
recommendations: [
|
initialTree.create('user.effects.ts', effectContents);
|
||||||
'eamodio.gitlens',
|
const result = await schematicRunner
|
||||||
'angular.ng-template',
|
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||||
'nrwl.angular-console',
|
.toPromise();
|
||||||
'esbenp.prettier-vscode'
|
const contents = result.readContent('user.effects.ts');
|
||||||
]
|
expect(contents).toContain(
|
||||||
|
"import { Effect, Actions, ofType } from '@ngrx/effects';"
|
||||||
|
);
|
||||||
|
expect(stripIndents`${contents}`).toContain(
|
||||||
|
stripIndents`
|
||||||
|
@Effect() effect$ = this.actions$.pipe(
|
||||||
|
ofType(LoadUser),
|
||||||
|
mapTo(UserLoaded)
|
||||||
|
);`
|
||||||
|
);
|
||||||
|
expect(stripIndents`${contents}`).toContain(
|
||||||
|
stripIndents`
|
||||||
|
@Effect() effect2$ = this.actions$.pipe(
|
||||||
|
ofType<UserLoaded>(LoadUser),
|
||||||
|
mapTo(UserLoaded)
|
||||||
|
);`
|
||||||
|
);
|
||||||
|
expect(stripIndents`${contents}`).toContain(
|
||||||
|
stripIndents`
|
||||||
|
@Effect() effect3$ = this.actions$.pipe(
|
||||||
|
ofType<UserLoaded>(LoadUser),
|
||||||
|
withLatestFrom(this.store.pipe(select(selector))),
|
||||||
|
mapTo(UserLoaded)
|
||||||
|
);`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert select code', async () => {
|
||||||
|
initialTree.create('app.component.ts', selectorContents);
|
||||||
|
const result = await schematicRunner
|
||||||
|
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||||
|
.toPromise();
|
||||||
|
const contents = result.readContent('app.component.ts');
|
||||||
|
expect(contents).toContain(
|
||||||
|
"import { Store, select } from '@ngrx/store';"
|
||||||
|
);
|
||||||
|
expect(stripIndents`${contents}`).toContain(
|
||||||
|
stripIndents`
|
||||||
|
slice$ = this.store.pipe(
|
||||||
|
select(selector),
|
||||||
|
map(a => a)
|
||||||
|
);`
|
||||||
|
);
|
||||||
|
expect(contents).toContain(
|
||||||
|
'this.slice2$ = this.store.pipe(select(selector2))'
|
||||||
|
);
|
||||||
|
expect(contents).toContain(
|
||||||
|
'this.store.pipe(select(selector3)).subscribe(console.log);'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(stripIndents`${contents}`).toContain(stripIndents`
|
||||||
|
slice3$ = Observable.from([]).pipe(
|
||||||
|
withLatestFrom(this.store.pipe(select(selector5)))
|
||||||
|
);`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,21 @@
|
|||||||
import { Rule, chain, externalSchematic } from '@angular-devkit/schematics';
|
import {
|
||||||
|
Rule,
|
||||||
|
chain,
|
||||||
|
SchematicContext,
|
||||||
|
Tree
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
|
||||||
import { updateJsonInTree } from '../../src/utils/ast-utils';
|
import { ReplaceChange } from '@schematics/angular/utility/change';
|
||||||
|
import { getSourceNodes } from '@schematics/angular/utility/ast-utils';
|
||||||
|
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {
|
||||||
|
updateJsonInTree,
|
||||||
|
readJsonInTree,
|
||||||
|
insert
|
||||||
|
} from '../../src/utils/ast-utils';
|
||||||
|
import { formatFiles } from '../../src/utils/rules/format-files';
|
||||||
|
|
||||||
const addExtensionRecommendations = updateJsonInTree(
|
const addExtensionRecommendations = updateJsonInTree(
|
||||||
'.vscode/extensions.json',
|
'.vscode/extensions.json',
|
||||||
@ -20,6 +35,339 @@ const addExtensionRecommendations = updateJsonInTree(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function(): Rule {
|
function addItemToImport(
|
||||||
return chain([addExtensionRecommendations]);
|
path: string,
|
||||||
|
sourceFile: ts.SourceFile,
|
||||||
|
printer: ts.Printer,
|
||||||
|
importStatement: ts.ImportDeclaration,
|
||||||
|
symbol: string
|
||||||
|
) {
|
||||||
|
const newImport = ts.createImportDeclaration(
|
||||||
|
importStatement.decorators,
|
||||||
|
importStatement.modifiers,
|
||||||
|
ts.createImportClause(
|
||||||
|
importStatement.importClause.name,
|
||||||
|
ts.createNamedImports([
|
||||||
|
...(importStatement.importClause.namedBindings as ts.NamedImports)
|
||||||
|
.elements,
|
||||||
|
ts.createImportSpecifier(undefined, ts.createIdentifier(symbol))
|
||||||
|
])
|
||||||
|
),
|
||||||
|
importStatement.moduleSpecifier
|
||||||
|
);
|
||||||
|
return new ReplaceChange(
|
||||||
|
path,
|
||||||
|
importStatement.getStart(sourceFile),
|
||||||
|
importStatement.getText(sourceFile),
|
||||||
|
printer.printNode(ts.EmitHint.Unspecified, newImport, sourceFile)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isEffectDecorator(decorator: ts.Decorator) {
|
||||||
|
return (
|
||||||
|
ts.isCallExpression(decorator.expression) &&
|
||||||
|
ts.isIdentifier(decorator.expression.expression) &&
|
||||||
|
decorator.expression.expression.text === 'Effect'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImport(sourceFile: ts.SourceFile, path: string, symbol: string) {
|
||||||
|
return sourceFile.statements
|
||||||
|
.filter(ts.isImportDeclaration)
|
||||||
|
.filter(statement =>
|
||||||
|
statement.moduleSpecifier.getText(sourceFile).includes(path)
|
||||||
|
)
|
||||||
|
.find(statement => {
|
||||||
|
if (!ts.isNamedImports(statement.importClause.namedBindings)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return statement.importClause.namedBindings.elements.some(
|
||||||
|
element => element.getText(sourceFile) === symbol
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOfTypeCode(path: string, sourceFile: ts.SourceFile) {
|
||||||
|
const effectsImport = getImport(sourceFile, '@ngrx/effects', 'Effect');
|
||||||
|
if (!effectsImport) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const effects: ts.PropertyDeclaration[] = [];
|
||||||
|
const changes: ReplaceChange[] = [];
|
||||||
|
|
||||||
|
const printer = ts.createPrinter();
|
||||||
|
|
||||||
|
sourceFile.statements
|
||||||
|
.filter(ts.isClassDeclaration)
|
||||||
|
.map(clazz =>
|
||||||
|
clazz.members
|
||||||
|
.filter(ts.isPropertyDeclaration)
|
||||||
|
.filter(
|
||||||
|
member =>
|
||||||
|
member.decorators && member.decorators.some(isEffectDecorator)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.forEach(properties => {
|
||||||
|
effects.push(...properties);
|
||||||
|
});
|
||||||
|
|
||||||
|
effects.forEach(effect => {
|
||||||
|
if (
|
||||||
|
ts.isCallExpression(effect.initializer) &&
|
||||||
|
ts.isPropertyAccessExpression(effect.initializer.expression) &&
|
||||||
|
effect.initializer.expression.name.text === 'pipe' &&
|
||||||
|
ts.isCallExpression(effect.initializer.expression.expression) &&
|
||||||
|
ts.isPropertyAccessExpression(
|
||||||
|
effect.initializer.expression.expression.expression
|
||||||
|
) &&
|
||||||
|
effect.initializer.expression.expression.expression.name.text === 'ofType'
|
||||||
|
) {
|
||||||
|
const originalText = effect.initializer.getText(sourceFile);
|
||||||
|
|
||||||
|
const ofTypeExpression = ts.createCall(
|
||||||
|
ts.createIdentifier('ofType'),
|
||||||
|
effect.initializer.expression.expression.typeArguments,
|
||||||
|
effect.initializer.expression.expression.arguments
|
||||||
|
);
|
||||||
|
|
||||||
|
const node = ts.createCall(
|
||||||
|
ts.createPropertyAccess(
|
||||||
|
effect.initializer.expression.expression.expression.expression,
|
||||||
|
'pipe'
|
||||||
|
),
|
||||||
|
effect.initializer.typeArguments,
|
||||||
|
ts.createNodeArray([
|
||||||
|
ofTypeExpression,
|
||||||
|
...(effect.initializer as ts.CallExpression).arguments
|
||||||
|
])
|
||||||
|
);
|
||||||
|
const newEffect = printer.printNode(
|
||||||
|
ts.EmitHint.Expression,
|
||||||
|
node,
|
||||||
|
sourceFile
|
||||||
|
);
|
||||||
|
|
||||||
|
const change = new ReplaceChange(
|
||||||
|
path,
|
||||||
|
effect.initializer.getStart(sourceFile),
|
||||||
|
originalText,
|
||||||
|
newEffect
|
||||||
|
);
|
||||||
|
changes.push(change);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (changes.length > 0) {
|
||||||
|
changes.unshift(
|
||||||
|
addItemToImport(path, sourceFile, printer, effectsImport, 'ofType')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConstructor(
|
||||||
|
classDeclaration: ts.ClassDeclaration
|
||||||
|
): ts.ConstructorDeclaration {
|
||||||
|
return classDeclaration.members.find(ts.isConstructorDeclaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStoreProperty(
|
||||||
|
sourceFile: ts.SourceFile,
|
||||||
|
constructor: ts.ConstructorDeclaration
|
||||||
|
): string {
|
||||||
|
const storeParameter = constructor.parameters.find(
|
||||||
|
parameter =>
|
||||||
|
parameter.type && parameter.type.getText(sourceFile).includes('Store')
|
||||||
|
);
|
||||||
|
return storeParameter ? storeParameter.name.getText(sourceFile) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelectorCode(path: string, sourceFile: ts.SourceFile) {
|
||||||
|
const storeImport = getImport(sourceFile, '@ngrx/store', 'Store');
|
||||||
|
if (!storeImport) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const changes: ReplaceChange[] = [];
|
||||||
|
|
||||||
|
const printer = ts.createPrinter();
|
||||||
|
|
||||||
|
sourceFile.statements
|
||||||
|
.filter(ts.isClassDeclaration)
|
||||||
|
.forEach(classDeclaration => {
|
||||||
|
const constructor = getConstructor(classDeclaration);
|
||||||
|
if (!constructor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storeProperty = getStoreProperty(sourceFile, constructor);
|
||||||
|
getSourceNodes(sourceFile).forEach(node => {
|
||||||
|
if (
|
||||||
|
ts.isCallExpression(node) &&
|
||||||
|
ts.isPropertyAccessExpression(node.expression) &&
|
||||||
|
ts.isPropertyAccessExpression(node.expression.expression) &&
|
||||||
|
ts.isIdentifier(node.expression.name) &&
|
||||||
|
ts.isIdentifier(node.expression.expression.name) &&
|
||||||
|
node.expression.name.getText(sourceFile) === 'select' &&
|
||||||
|
node.expression.expression.name.getText(sourceFile) ===
|
||||||
|
storeProperty &&
|
||||||
|
node.expression.expression.expression.kind ===
|
||||||
|
ts.SyntaxKind.ThisKeyword
|
||||||
|
) {
|
||||||
|
const newExpression = ts.createCall(
|
||||||
|
ts.createPropertyAccess(
|
||||||
|
ts.createPropertyAccess(
|
||||||
|
ts.createIdentifier('this'),
|
||||||
|
ts.createIdentifier(storeProperty)
|
||||||
|
),
|
||||||
|
ts.createIdentifier('pipe')
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
ts.createCall(
|
||||||
|
ts.createIdentifier('select'),
|
||||||
|
node.typeArguments,
|
||||||
|
node.arguments
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
const newNode = printer.printNode(
|
||||||
|
ts.EmitHint.Expression,
|
||||||
|
newExpression,
|
||||||
|
sourceFile
|
||||||
|
);
|
||||||
|
changes.push(
|
||||||
|
new ReplaceChange(
|
||||||
|
path,
|
||||||
|
node.getStart(sourceFile),
|
||||||
|
node.getText(sourceFile),
|
||||||
|
newNode
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (changes.length > 0) {
|
||||||
|
changes.unshift(
|
||||||
|
addItemToImport(path, sourceFile, printer, storeImport, 'select')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateNgrx(host: Tree, context: SchematicContext) {
|
||||||
|
const ngrxVersion = readJsonInTree(host, 'package.json').dependencies[
|
||||||
|
'@ngrx/store'
|
||||||
|
];
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
ngrxVersion.startsWith('6.') ||
|
||||||
|
ngrxVersion.startsWith('~6.') ||
|
||||||
|
ngrxVersion.startsWith('^6.')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
host.visit(path => {
|
||||||
|
if (!path.endsWith('.ts')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sourceFile = ts.createSourceFile(
|
||||||
|
path,
|
||||||
|
host.read(path).toString(),
|
||||||
|
ts.ScriptTarget.Latest
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sourceFile.isDeclarationFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(host, path, updateOfTypeCode(path, sourceFile));
|
||||||
|
|
||||||
|
sourceFile = ts.createSourceFile(
|
||||||
|
path,
|
||||||
|
host.read(path).toString(),
|
||||||
|
ts.ScriptTarget.Latest
|
||||||
|
);
|
||||||
|
|
||||||
|
insert(host, path, updateSelectorCode(path, sourceFile));
|
||||||
|
|
||||||
|
sourceFile = ts.createSourceFile(
|
||||||
|
path,
|
||||||
|
host.read(path).toString(),
|
||||||
|
ts.ScriptTarget.Latest
|
||||||
|
);
|
||||||
|
|
||||||
|
insert(host, path, cleanUpDoublePipes(path, sourceFile));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanUpDoublePipes(
|
||||||
|
path: string,
|
||||||
|
sourceFile: ts.SourceFile
|
||||||
|
): ReplaceChange[] {
|
||||||
|
const changes: ReplaceChange[] = [];
|
||||||
|
|
||||||
|
const printer = ts.createPrinter();
|
||||||
|
|
||||||
|
getSourceNodes(sourceFile).forEach(node => {
|
||||||
|
if (
|
||||||
|
ts.isCallExpression(node) &&
|
||||||
|
ts.isPropertyAccessExpression(node.expression) &&
|
||||||
|
ts.isCallExpression(node.expression.expression) &&
|
||||||
|
ts.isPropertyAccessExpression(node.expression.expression.expression) &&
|
||||||
|
node.expression.name.text === 'pipe' &&
|
||||||
|
node.expression.expression.expression.name.text === 'pipe'
|
||||||
|
) {
|
||||||
|
const singlePipe = ts.createCall(
|
||||||
|
node.expression.expression.expression,
|
||||||
|
node.typeArguments,
|
||||||
|
[...node.expression.expression.arguments, ...node.arguments]
|
||||||
|
);
|
||||||
|
changes.push(
|
||||||
|
new ReplaceChange(
|
||||||
|
path,
|
||||||
|
node.getStart(sourceFile),
|
||||||
|
node.getText(sourceFile),
|
||||||
|
printer.printNode(ts.EmitHint.Expression, singlePipe, sourceFile)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateNgrx = updateJsonInTree('package.json', json => {
|
||||||
|
json.devDependencies = json.devDependencies || {};
|
||||||
|
json.dependencies = json.dependencies || {};
|
||||||
|
|
||||||
|
json.dependencies = {
|
||||||
|
...json.dependencies,
|
||||||
|
'@ngrx/effects': '7.2.0',
|
||||||
|
'@ngrx/router-store': '7.2.0',
|
||||||
|
'@ngrx/store': '7.2.0'
|
||||||
|
};
|
||||||
|
|
||||||
|
json.devDependencies = {
|
||||||
|
...json.devDependencies,
|
||||||
|
'@ngrx/schematics': '7.2.0',
|
||||||
|
'@ngrx/store-devtools': '7.2.0'
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function(): Rule {
|
||||||
|
return chain([
|
||||||
|
addExtensionRecommendations,
|
||||||
|
migrateNgrx,
|
||||||
|
updateNgrx,
|
||||||
|
formatFiles()
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ export const angularCliVersion = '~7.2.2';
|
|||||||
export const angularVersion = '^7.0.0';
|
export const angularVersion = '^7.0.0';
|
||||||
export const angularDevkitVersion = '~0.11.2';
|
export const angularDevkitVersion = '~0.11.2';
|
||||||
export const angularJsVersion = '1.6.6';
|
export const angularJsVersion = '1.6.6';
|
||||||
export const ngrxVersion = '6.1.2';
|
export const ngrxVersion = '7.2.0';
|
||||||
export const ngrxStoreFreezeVersion = '0.2.4';
|
export const ngrxStoreFreezeVersion = '0.2.4';
|
||||||
export const nxVersion = '*';
|
export const nxVersion = '*';
|
||||||
export const schematicsVersion = '*';
|
export const schematicsVersion = '*';
|
||||||
|
|||||||
@ -248,7 +248,7 @@ export function removeFromNgModule(
|
|||||||
return [
|
return [
|
||||||
new RemoveChange(
|
new RemoveChange(
|
||||||
modulePath,
|
modulePath,
|
||||||
matchingProperty.pos,
|
matchingProperty.getStart(source),
|
||||||
matchingProperty.getFullText(source)
|
matchingProperty.getFullText(source)
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
@ -545,6 +545,9 @@ export function addGlobal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
||||||
|
if (changes.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const recorder = host.beginUpdate(modulePath);
|
const recorder = host.beginUpdate(modulePath);
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
if (change instanceof InsertChange) {
|
if (change instanceof InsertChange) {
|
||||||
@ -555,8 +558,8 @@ export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
|||||||
// do nothing
|
// do nothing
|
||||||
} else if (change instanceof ReplaceChange) {
|
} else if (change instanceof ReplaceChange) {
|
||||||
const action = <any>change;
|
const action = <any>change;
|
||||||
recorder.remove(action.pos + 1, action.oldText.length);
|
recorder.remove(action.pos, action.oldText.length);
|
||||||
recorder.insertLeft(action.pos + 1, action.newText);
|
recorder.insertLeft(action.pos, action.newText);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unexpected Change '${change}'`);
|
throw new Error(`Unexpected Change '${change}'`);
|
||||||
}
|
}
|
||||||
@ -941,6 +944,11 @@ export function replaceNodeValue(
|
|||||||
content: string
|
content: string
|
||||||
) {
|
) {
|
||||||
insert(host, modulePath, [
|
insert(host, modulePath, [
|
||||||
new ReplaceChange(modulePath, node.pos, node.getFullText(), content)
|
new ReplaceChange(
|
||||||
|
modulePath,
|
||||||
|
node.getStart(node.getSourceFile()),
|
||||||
|
node.getFullText(),
|
||||||
|
content
|
||||||
|
)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
40
yarn.lock
40
yarn.lock
@ -225,30 +225,30 @@
|
|||||||
call-me-maybe "^1.0.1"
|
call-me-maybe "^1.0.1"
|
||||||
glob-to-regexp "^0.3.0"
|
glob-to-regexp "^0.3.0"
|
||||||
|
|
||||||
"@ngrx/effects@6.1.2":
|
"@ngrx/effects@7.1.0":
|
||||||
version "6.1.2"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-6.1.2.tgz#602f3ee9798e00179075ddef030ded88c28b1aa1"
|
resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-7.1.0.tgz#c42966a92096d605b72a1959599ad6c90a1e15a2"
|
||||||
integrity sha512-RUuQ5/7ofxGEZnRRdlC1oE9ugVlTYGm92MVj7c6IirHrVN9W5yQjjMTYEYceVCDOYsiXP7Pyw0dcPp6J5wD2EQ==
|
integrity sha512-0oF9VaixL8TNzIyBfFieLXunoz66uuceGfh5EaepQu+qPcVhnFq5KvYHDQOdCq0uuQYB7rVwNFYjOD7pO5LE5A==
|
||||||
|
|
||||||
"@ngrx/router-store@6.1.2":
|
"@ngrx/router-store@7.1.0":
|
||||||
version "6.1.2"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-6.1.2.tgz#63bfcd3710c53ea2c5456b82c57fd433e5af25bc"
|
resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-7.1.0.tgz#931bdc902d806b3d026e99604748ebfefcd82dc3"
|
||||||
integrity sha512-sj083ZYrx0aY+vU/t8Ub0KYDHcMpatXJIOJR/eDNSuH54fPiBM9MrdI3hs/XHoXHxSaHOJoZ7f6I8XcUeptxyA==
|
integrity sha512-xLTtdLvbgwFyhXU9A/kYsuVruvp8w7WcNorGq0LyWCwI+rk4twaNFJLUx/rVnLbzfXLichU8kHAiRmR8VD438A==
|
||||||
|
|
||||||
"@ngrx/schematics@6.1.2":
|
"@ngrx/schematics@7.1.0":
|
||||||
version "6.1.2"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-6.1.2.tgz#52dce7f2d4275791732805576eaf007d1043ef58"
|
resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-7.1.0.tgz#ddc4faebd506f28ac181df04091b630c70ced713"
|
||||||
integrity sha512-hiu8rdYAJIfIoJHPlAJr+mBkXab7OLRyg8Z/i5lUpmE382yvESfcVI9hqYsGXWBbyfY5Al+BGzGhBth5gc5AvA==
|
integrity sha512-4+drIY4jCMgsOZWo6LTpUL8uLxv8RrbzS5CNEcm8EvwmUrzd/GKoCZ9rKqzoAlF5EyA+1OraMppeOHV0j8DZ3w==
|
||||||
|
|
||||||
"@ngrx/store-devtools@6.1.2":
|
"@ngrx/store-devtools@7.1.0":
|
||||||
version "6.1.2"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-6.1.2.tgz#b9cb8d6bcd7ee0d171dde86c9bdd5e6a5bc5563a"
|
resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-7.1.0.tgz#ea5248d616b2bdf7607e9f4a1c80aa4365e0f830"
|
||||||
integrity sha512-hvWMKcRIAtAFb2lb4woRenPHPgOiLFjy8R2PtCiw4uP3WrBVB4JHqUuP230/iRMcU5XmySp+LhNqhkk1zsoUqQ==
|
integrity sha512-r0LUFQKxKOhFIO2TBK7k6eoOCT6WGQFXzOFTWwctU7teQgSSpzyUVQfsULfAyFpGN9f1hog9leY/J/EVjdwBQQ==
|
||||||
|
|
||||||
"@ngrx/store@6.1.2":
|
"@ngrx/store@7.1.0":
|
||||||
version "6.1.2"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-6.1.2.tgz#20fb5ab4d79571b804a348093aa11a167fe2946f"
|
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-7.1.0.tgz#072f22e062e264c62859f37d9807dfac860f161d"
|
||||||
integrity sha512-W9MbXrwhIRmN1BlINF9BT+rHR046e1HNk7GqykcDJrK9wW74PJW3aE5iuPb2sTPipBMjPHsXzc73E4U/+OTAyw==
|
integrity sha512-tM8ZGxbLTyQ5JUHow3/PSFU3FWfYJs/wAVyRlxzTxfY7Krs/TJ64GgI4lOa6gVizi2UiYfLtI31pJrxzXyxEoA==
|
||||||
|
|
||||||
"@ngtools/json-schema@^1.1.0":
|
"@ngtools/json-schema@^1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user