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/router": "^7.2.1",
|
||||
"@angular/upgrade": "^7.2.1",
|
||||
"@ngrx/effects": "6.1.2",
|
||||
"@ngrx/router-store": "6.1.2",
|
||||
"@ngrx/schematics": "6.1.2",
|
||||
"@ngrx/store": "6.1.2",
|
||||
"@ngrx/store-devtools": "6.1.2",
|
||||
"@ngrx/effects": "7.1.0",
|
||||
"@ngrx/router-store": "7.1.0",
|
||||
"@ngrx/schematics": "7.1.0",
|
||||
"@ngrx/store": "7.1.0",
|
||||
"@ngrx/store-devtools": "7.1.0",
|
||||
"@schematics/angular": "~7.2.2",
|
||||
"@types/jasmine": "~2.8.6",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
|
||||
@ -157,15 +157,17 @@ describe('DataPersistence', () => {
|
||||
const root = TestBed.createComponent(RootCmp);
|
||||
|
||||
const router: Router = TestBed.get(Router);
|
||||
let action;
|
||||
TestBed.get(Actions).subscribe(a => (action = a));
|
||||
let actions: any[] = [];
|
||||
TestBed.get(Actions).subscribe((a: any) => actions.push(a));
|
||||
|
||||
router.navigateByUrl('/todo/123');
|
||||
tick(0);
|
||||
root.detectChanges(false);
|
||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||
expect(action.type).toEqual('ERROR');
|
||||
expect(action.payload.error.message).toEqual('boom');
|
||||
expect(actions.map(a => a.type)).toContain('ERROR');
|
||||
expect(
|
||||
actions.find(a => a.type === 'ERROR').payload.error.message
|
||||
).toEqual('boom');
|
||||
|
||||
// can recover after an error
|
||||
router.navigateByUrl('/todo/456');
|
||||
@ -205,15 +207,17 @@ describe('DataPersistence', () => {
|
||||
const root = TestBed.createComponent(RootCmp);
|
||||
|
||||
const router: Router = TestBed.get(Router);
|
||||
let action;
|
||||
TestBed.get(Actions).subscribe(a => (action = a));
|
||||
let actions: any[] = [];
|
||||
TestBed.get(Actions).subscribe((a: any) => actions.push(a));
|
||||
|
||||
router.navigateByUrl('/todo/123');
|
||||
tick(0);
|
||||
root.detectChanges(false);
|
||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||
expect(action.type).toEqual('ERROR');
|
||||
expect(action.payload.error).toEqual('boom');
|
||||
expect(actions.map(a => a.type)).toContain('ERROR');
|
||||
expect(actions.find(a => a.type === 'ERROR').payload.error).toEqual(
|
||||
'boom'
|
||||
);
|
||||
|
||||
router.navigateByUrl('/todo/456');
|
||||
tick(0);
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
},
|
||||
"update-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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,96 @@
|
||||
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 { serializeJson } from '../../src/utils/fileutils';
|
||||
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', () => {
|
||||
let initialTree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
initialTree = Tree.empty();
|
||||
initialTree = new UnitTestTree(Tree.empty());
|
||||
|
||||
initialTree.create(
|
||||
'package.json',
|
||||
serializeJson({
|
||||
dependencies: {
|
||||
'@ngrx/effects': '6.1.2',
|
||||
'@ngrx/router-store': '6.1.2',
|
||||
'@ngrx/store': '6.1.2'
|
||||
},
|
||||
devDependencies: {
|
||||
'@angular/cli': '7.1.0',
|
||||
typescript: '~3.1.0'
|
||||
'@ngrx/schematics': '6.1.2',
|
||||
'@ngrx/store-devtools': '6.1.2'
|
||||
}
|
||||
})
|
||||
);
|
||||
@ -29,41 +101,125 @@ describe('Update 7.6.0', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should add vscode extension recommendations', async () => {
|
||||
const result = await schematicRunner
|
||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||
.toPromise();
|
||||
describe('VSCode Extension Recommendations', () => {
|
||||
it('should be added', async () => {
|
||||
const result = await schematicRunner
|
||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
||||
recommendations: [
|
||||
'nrwl.angular-console',
|
||||
'angular.ng-template',
|
||||
'esbenp.prettier-vscode'
|
||||
]
|
||||
expect(readJsonInTree(result, '.vscode/extensions.json')).toEqual({
|
||||
recommendations: [
|
||||
'nrwl.angular-console',
|
||||
'angular.ng-template',
|
||||
'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 () => {
|
||||
initialTree = await schematicRunner
|
||||
.callRule(
|
||||
updateJsonInTree('.vscode/extensions.json', () => ({
|
||||
recommendations: ['eamodio.gitlens', 'angular.ng-template']
|
||||
})),
|
||||
initialTree
|
||||
)
|
||||
.toPromise();
|
||||
describe('NgRx Migration', () => {
|
||||
it('should update ngrx to 7.1.0', async () => {
|
||||
const result = await schematicRunner
|
||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const result = await schematicRunner
|
||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||
.toPromise();
|
||||
expect(readJsonInTree(result, 'package.json')).toEqual({
|
||||
dependencies: {
|
||||
'@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({
|
||||
recommendations: [
|
||||
'eamodio.gitlens',
|
||||
'angular.ng-template',
|
||||
'nrwl.angular-console',
|
||||
'esbenp.prettier-vscode'
|
||||
]
|
||||
it('should convert ofType code', async () => {
|
||||
initialTree.create('user.effects.ts', effectContents);
|
||||
const result = await schematicRunner
|
||||
.runSchematicAsync('update-7.6.0', {}, initialTree)
|
||||
.toPromise();
|
||||
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(
|
||||
'.vscode/extensions.json',
|
||||
@ -20,6 +35,339 @@ const addExtensionRecommendations = updateJsonInTree(
|
||||
}
|
||||
);
|
||||
|
||||
export default function(): Rule {
|
||||
return chain([addExtensionRecommendations]);
|
||||
function addItemToImport(
|
||||
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 angularDevkitVersion = '~0.11.2';
|
||||
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 nxVersion = '*';
|
||||
export const schematicsVersion = '*';
|
||||
|
||||
@ -248,7 +248,7 @@ export function removeFromNgModule(
|
||||
return [
|
||||
new RemoveChange(
|
||||
modulePath,
|
||||
matchingProperty.pos,
|
||||
matchingProperty.getStart(source),
|
||||
matchingProperty.getFullText(source)
|
||||
)
|
||||
];
|
||||
@ -545,6 +545,9 @@ export function addGlobal(
|
||||
}
|
||||
|
||||
export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
||||
if (changes.length < 1) {
|
||||
return;
|
||||
}
|
||||
const recorder = host.beginUpdate(modulePath);
|
||||
for (const change of changes) {
|
||||
if (change instanceof InsertChange) {
|
||||
@ -555,8 +558,8 @@ export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
||||
// do nothing
|
||||
} else if (change instanceof ReplaceChange) {
|
||||
const action = <any>change;
|
||||
recorder.remove(action.pos + 1, action.oldText.length);
|
||||
recorder.insertLeft(action.pos + 1, action.newText);
|
||||
recorder.remove(action.pos, action.oldText.length);
|
||||
recorder.insertLeft(action.pos, action.newText);
|
||||
} else {
|
||||
throw new Error(`Unexpected Change '${change}'`);
|
||||
}
|
||||
@ -941,6 +944,11 @@ export function replaceNodeValue(
|
||||
content: string
|
||||
) {
|
||||
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"
|
||||
glob-to-regexp "^0.3.0"
|
||||
|
||||
"@ngrx/effects@6.1.2":
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-6.1.2.tgz#602f3ee9798e00179075ddef030ded88c28b1aa1"
|
||||
integrity sha512-RUuQ5/7ofxGEZnRRdlC1oE9ugVlTYGm92MVj7c6IirHrVN9W5yQjjMTYEYceVCDOYsiXP7Pyw0dcPp6J5wD2EQ==
|
||||
"@ngrx/effects@7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-7.1.0.tgz#c42966a92096d605b72a1959599ad6c90a1e15a2"
|
||||
integrity sha512-0oF9VaixL8TNzIyBfFieLXunoz66uuceGfh5EaepQu+qPcVhnFq5KvYHDQOdCq0uuQYB7rVwNFYjOD7pO5LE5A==
|
||||
|
||||
"@ngrx/router-store@6.1.2":
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-6.1.2.tgz#63bfcd3710c53ea2c5456b82c57fd433e5af25bc"
|
||||
integrity sha512-sj083ZYrx0aY+vU/t8Ub0KYDHcMpatXJIOJR/eDNSuH54fPiBM9MrdI3hs/XHoXHxSaHOJoZ7f6I8XcUeptxyA==
|
||||
"@ngrx/router-store@7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/router-store/-/router-store-7.1.0.tgz#931bdc902d806b3d026e99604748ebfefcd82dc3"
|
||||
integrity sha512-xLTtdLvbgwFyhXU9A/kYsuVruvp8w7WcNorGq0LyWCwI+rk4twaNFJLUx/rVnLbzfXLichU8kHAiRmR8VD438A==
|
||||
|
||||
"@ngrx/schematics@6.1.2":
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-6.1.2.tgz#52dce7f2d4275791732805576eaf007d1043ef58"
|
||||
integrity sha512-hiu8rdYAJIfIoJHPlAJr+mBkXab7OLRyg8Z/i5lUpmE382yvESfcVI9hqYsGXWBbyfY5Al+BGzGhBth5gc5AvA==
|
||||
"@ngrx/schematics@7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/schematics/-/schematics-7.1.0.tgz#ddc4faebd506f28ac181df04091b630c70ced713"
|
||||
integrity sha512-4+drIY4jCMgsOZWo6LTpUL8uLxv8RrbzS5CNEcm8EvwmUrzd/GKoCZ9rKqzoAlF5EyA+1OraMppeOHV0j8DZ3w==
|
||||
|
||||
"@ngrx/store-devtools@6.1.2":
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-6.1.2.tgz#b9cb8d6bcd7ee0d171dde86c9bdd5e6a5bc5563a"
|
||||
integrity sha512-hvWMKcRIAtAFb2lb4woRenPHPgOiLFjy8R2PtCiw4uP3WrBVB4JHqUuP230/iRMcU5XmySp+LhNqhkk1zsoUqQ==
|
||||
"@ngrx/store-devtools@7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/store-devtools/-/store-devtools-7.1.0.tgz#ea5248d616b2bdf7607e9f4a1c80aa4365e0f830"
|
||||
integrity sha512-r0LUFQKxKOhFIO2TBK7k6eoOCT6WGQFXzOFTWwctU7teQgSSpzyUVQfsULfAyFpGN9f1hog9leY/J/EVjdwBQQ==
|
||||
|
||||
"@ngrx/store@6.1.2":
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-6.1.2.tgz#20fb5ab4d79571b804a348093aa11a167fe2946f"
|
||||
integrity sha512-W9MbXrwhIRmN1BlINF9BT+rHR046e1HNk7GqykcDJrK9wW74PJW3aE5iuPb2sTPipBMjPHsXzc73E4U/+OTAyw==
|
||||
"@ngrx/store@7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-7.1.0.tgz#072f22e062e264c62859f37d9807dfac860f161d"
|
||||
integrity sha512-tM8ZGxbLTyQ5JUHow3/PSFU3FWfYJs/wAVyRlxzTxfY7Krs/TJ64GgI4lOa6gVizi2UiYfLtI31pJrxzXyxEoA==
|
||||
|
||||
"@ngtools/json-schema@^1.1.0":
|
||||
version "1.1.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user