Skip to content

Commit 4146650

Browse files
timdeschryverbrandonroberts
authored andcommitted
feat(store): add ngrx-store-freeze migration (#1901)
Closes #1896
1 parent 5a09844 commit 4146650

File tree

39 files changed

+1343
-123
lines changed

39 files changed

+1343
-123
lines changed

modules/data/schematics-core/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
addExportToModule,
2222
addImportToModule,
2323
addProviderToModule,
24+
replaceImport,
2425
} from './utility/ast-utils';
2526

2627
export {
@@ -71,3 +72,5 @@ export { parseName } from './utility/parse-name';
7172
export { addPackageToPackageJson } from './utility/package';
7273

7374
export { platformVersion } from './utility/libs-version';
75+
76+
export { visitTSSourceFiles } from './utility/visit-utils';

modules/data/schematics-core/utility/ast-utils.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
* found in the LICENSE file at https://angular.io/license
88
*/
99
import * as ts from 'typescript';
10-
import { Change, InsertChange, NoopChange } from './change';
10+
import {
11+
Change,
12+
InsertChange,
13+
NoopChange,
14+
createReplaceChange,
15+
ReplaceChange,
16+
} from './change';
17+
import { Path } from '@angular-devkit/core';
1118

1219
/**
1320
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
@@ -636,3 +643,52 @@ export function insertImport(
636643
ts.SyntaxKind.StringLiteral
637644
);
638645
}
646+
647+
export function replaceImport(
648+
sourceFile: ts.SourceFile,
649+
path: Path,
650+
importFrom: string,
651+
importAsIs: string,
652+
importToBe: string
653+
): ReplaceChange[] {
654+
const imports = sourceFile.statements
655+
.filter(ts.isImportDeclaration)
656+
.filter(
657+
({ moduleSpecifier }) =>
658+
moduleSpecifier.getText(sourceFile) === `'${importFrom}'` ||
659+
moduleSpecifier.getText(sourceFile) === `"${importFrom}"`
660+
);
661+
662+
if (imports.length === 0) {
663+
return [];
664+
}
665+
666+
const changes = imports
667+
.map(p => (p.importClause!.namedBindings! as ts.NamedImports).elements)
668+
.reduce((imports, curr) => imports.concat(curr), [] as ts.ImportSpecifier[])
669+
.map(specifier => {
670+
if (!ts.isImportSpecifier(specifier)) {
671+
return { hit: false };
672+
}
673+
674+
if (specifier.name.text === importAsIs) {
675+
return { hit: true, specifier, text: specifier.name.text };
676+
}
677+
678+
// if import is renamed
679+
if (
680+
specifier.propertyName &&
681+
specifier.propertyName.text === importAsIs
682+
) {
683+
return { hit: true, specifier, text: specifier.propertyName.text };
684+
}
685+
686+
return { hit: false };
687+
})
688+
.filter(({ hit }) => hit)
689+
.map(({ specifier, text }) =>
690+
createReplaceChange(sourceFile, path, specifier!, text!, importToBe)
691+
);
692+
693+
return changes;
694+
}

modules/data/schematics-core/utility/change.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,18 @@ export class RemoveChange implements Change {
7777
order: number;
7878
description: string;
7979

80-
constructor(
81-
public path: string,
82-
private pos: number,
83-
private toRemove: string
84-
) {
85-
if (pos < 0) {
80+
constructor(public path: string, public pos: number, public end: number) {
81+
if (pos < 0 || end < 0) {
8682
throw new Error('Negative positions are invalid');
8783
}
88-
this.description = `Removed ${toRemove} into position ${pos} of ${path}`;
84+
this.description = `Removed text in position ${pos} to ${end} of ${path}`;
8985
this.order = pos;
9086
}
9187

9288
apply(host: Host): Promise<void> {
9389
return host.read(this.path).then(content => {
9490
const prefix = content.substring(0, this.pos);
95-
const suffix = content.substring(this.pos + this.toRemove.length);
91+
const suffix = content.substring(this.end);
9692

9793
// TODO: throw error if toRemove doesn't match removed string.
9894
return host.write(this.path, `${prefix}${suffix}`);
@@ -109,7 +105,7 @@ export class ReplaceChange implements Change {
109105

110106
constructor(
111107
public path: string,
112-
private pos: number,
108+
public pos: number,
113109
public oldText: string,
114110
public newText: string
115111
) {
@@ -150,14 +146,19 @@ export function createReplaceChange(
150146

151147
export function createChangeRecorder(
152148
tree: Tree,
153-
path: Path,
154-
changes: ReplaceChange[]
149+
path: string,
150+
changes: Change[]
155151
): UpdateRecorder {
156152
const recorder = tree.beginUpdate(path);
157153
for (const change of changes) {
158-
const action = <any>change;
159-
recorder.remove(action.pos, action.oldText.length);
160-
recorder.insertLeft(action.pos, action.newText);
154+
if (change instanceof InsertChange) {
155+
recorder.insertLeft(change.pos, change.toAdd);
156+
} else if (change instanceof RemoveChange) {
157+
recorder.remove(change.pos, change.end - change.pos);
158+
} else if (change instanceof ReplaceChange) {
159+
recorder.remove(change.pos, change.oldText.length);
160+
recorder.insertLeft(change.pos, change.newText);
161+
}
161162
}
162163
return recorder;
163164
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as ts from 'typescript';
2+
import { Tree } from '@angular-devkit/schematics';
3+
4+
export function visitTSSourceFiles<Result = void>(
5+
tree: Tree,
6+
visitor: (
7+
sourceFile: ts.SourceFile,
8+
tree: Tree,
9+
result?: Result
10+
) => Result | undefined
11+
): Result | undefined {
12+
let result: Result | undefined = undefined;
13+
14+
tree.visit(path => {
15+
if (!path.endsWith('.ts')) {
16+
return;
17+
}
18+
19+
const sourceFile = ts.createSourceFile(
20+
path,
21+
tree.read(path)!.toString(),
22+
ts.ScriptTarget.Latest
23+
);
24+
25+
if (sourceFile.isDeclarationFile) {
26+
return;
27+
}
28+
29+
result = visitor(sourceFile, tree, result);
30+
});
31+
32+
return result;
33+
}

modules/effects/schematics-core/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
addExportToModule,
2222
addImportToModule,
2323
addProviderToModule,
24+
replaceImport,
2425
} from './utility/ast-utils';
2526

2627
export {
@@ -71,3 +72,5 @@ export { parseName } from './utility/parse-name';
7172
export { addPackageToPackageJson } from './utility/package';
7273

7374
export { platformVersion } from './utility/libs-version';
75+
76+
export { visitTSSourceFiles } from './utility/visit-utils';

modules/effects/schematics-core/utility/ast-utils.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
* found in the LICENSE file at https://angular.io/license
88
*/
99
import * as ts from 'typescript';
10-
import { Change, InsertChange, NoopChange } from './change';
10+
import {
11+
Change,
12+
InsertChange,
13+
NoopChange,
14+
createReplaceChange,
15+
ReplaceChange,
16+
} from './change';
17+
import { Path } from '@angular-devkit/core';
1118

1219
/**
1320
* Find all nodes from the AST in the subtree of node of SyntaxKind kind.
@@ -636,3 +643,52 @@ export function insertImport(
636643
ts.SyntaxKind.StringLiteral
637644
);
638645
}
646+
647+
export function replaceImport(
648+
sourceFile: ts.SourceFile,
649+
path: Path,
650+
importFrom: string,
651+
importAsIs: string,
652+
importToBe: string
653+
): ReplaceChange[] {
654+
const imports = sourceFile.statements
655+
.filter(ts.isImportDeclaration)
656+
.filter(
657+
({ moduleSpecifier }) =>
658+
moduleSpecifier.getText(sourceFile) === `'${importFrom}'` ||
659+
moduleSpecifier.getText(sourceFile) === `"${importFrom}"`
660+
);
661+
662+
if (imports.length === 0) {
663+
return [];
664+
}
665+
666+
const changes = imports
667+
.map(p => (p.importClause!.namedBindings! as ts.NamedImports).elements)
668+
.reduce((imports, curr) => imports.concat(curr), [] as ts.ImportSpecifier[])
669+
.map(specifier => {
670+
if (!ts.isImportSpecifier(specifier)) {
671+
return { hit: false };
672+
}
673+
674+
if (specifier.name.text === importAsIs) {
675+
return { hit: true, specifier, text: specifier.name.text };
676+
}
677+
678+
// if import is renamed
679+
if (
680+
specifier.propertyName &&
681+
specifier.propertyName.text === importAsIs
682+
) {
683+
return { hit: true, specifier, text: specifier.propertyName.text };
684+
}
685+
686+
return { hit: false };
687+
})
688+
.filter(({ hit }) => hit)
689+
.map(({ specifier, text }) =>
690+
createReplaceChange(sourceFile, path, specifier!, text!, importToBe)
691+
);
692+
693+
return changes;
694+
}

modules/effects/schematics-core/utility/change.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,18 @@ export class RemoveChange implements Change {
7777
order: number;
7878
description: string;
7979

80-
constructor(
81-
public path: string,
82-
private pos: number,
83-
private toRemove: string
84-
) {
85-
if (pos < 0) {
80+
constructor(public path: string, public pos: number, public end: number) {
81+
if (pos < 0 || end < 0) {
8682
throw new Error('Negative positions are invalid');
8783
}
88-
this.description = `Removed ${toRemove} into position ${pos} of ${path}`;
84+
this.description = `Removed text in position ${pos} to ${end} of ${path}`;
8985
this.order = pos;
9086
}
9187

9288
apply(host: Host): Promise<void> {
9389
return host.read(this.path).then(content => {
9490
const prefix = content.substring(0, this.pos);
95-
const suffix = content.substring(this.pos + this.toRemove.length);
91+
const suffix = content.substring(this.end);
9692

9793
// TODO: throw error if toRemove doesn't match removed string.
9894
return host.write(this.path, `${prefix}${suffix}`);
@@ -109,7 +105,7 @@ export class ReplaceChange implements Change {
109105

110106
constructor(
111107
public path: string,
112-
private pos: number,
108+
public pos: number,
113109
public oldText: string,
114110
public newText: string
115111
) {
@@ -150,14 +146,19 @@ export function createReplaceChange(
150146

151147
export function createChangeRecorder(
152148
tree: Tree,
153-
path: Path,
154-
changes: ReplaceChange[]
149+
path: string,
150+
changes: Change[]
155151
): UpdateRecorder {
156152
const recorder = tree.beginUpdate(path);
157153
for (const change of changes) {
158-
const action = <any>change;
159-
recorder.remove(action.pos, action.oldText.length);
160-
recorder.insertLeft(action.pos, action.newText);
154+
if (change instanceof InsertChange) {
155+
recorder.insertLeft(change.pos, change.toAdd);
156+
} else if (change instanceof RemoveChange) {
157+
recorder.remove(change.pos, change.end - change.pos);
158+
} else if (change instanceof ReplaceChange) {
159+
recorder.remove(change.pos, change.oldText.length);
160+
recorder.insertLeft(change.pos, change.newText);
161+
}
161162
}
162163
return recorder;
163164
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as ts from 'typescript';
2+
import { Tree } from '@angular-devkit/schematics';
3+
4+
export function visitTSSourceFiles<Result = void>(
5+
tree: Tree,
6+
visitor: (
7+
sourceFile: ts.SourceFile,
8+
tree: Tree,
9+
result?: Result
10+
) => Result | undefined
11+
): Result | undefined {
12+
let result: Result | undefined = undefined;
13+
14+
tree.visit(path => {
15+
if (!path.endsWith('.ts')) {
16+
return;
17+
}
18+
19+
const sourceFile = ts.createSourceFile(
20+
path,
21+
tree.read(path)!.toString(),
22+
ts.ScriptTarget.Latest
23+
);
24+
25+
if (sourceFile.isDeclarationFile) {
26+
return;
27+
}
28+
29+
result = visitor(sourceFile, tree, result);
30+
});
31+
32+
return result;
33+
}

modules/entity/schematics-core/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export {
2121
addExportToModule,
2222
addImportToModule,
2323
addProviderToModule,
24+
replaceImport,
2425
} from './utility/ast-utils';
2526

2627
export {
@@ -71,3 +72,5 @@ export { parseName } from './utility/parse-name';
7172
export { addPackageToPackageJson } from './utility/package';
7273

7374
export { platformVersion } from './utility/libs-version';
75+
76+
export { visitTSSourceFiles } from './utility/visit-utils';

0 commit comments

Comments
 (0)