Skip to content

Commit

Permalink
feat(component): add ngrxPush migration (#2452)
Browse files Browse the repository at this point in the history
Related to #2450
  • Loading branch information
timdeschryver committed May 21, 2020
1 parent 3545df2 commit 0775093
Show file tree
Hide file tree
Showing 21 changed files with 1,930 additions and 232 deletions.
10 changes: 9 additions & 1 deletion modules/data/schematics-core/index.ts
Expand Up @@ -81,4 +81,12 @@ export { addPackageToPackageJson } from './utility/package';

export { platformVersion } from './utility/libs-version';

export { visitTSSourceFiles, visitNgModuleImports } from './utility/visitors';
export {
visitTSSourceFiles,
visitNgModuleImports,
visitNgModuleExports,
visitComponents,
visitDecorator,
visitNgModules,
visitTemplates,
} from './utility/visitors';
213 changes: 185 additions & 28 deletions modules/data/schematics-core/utility/visitors.ts
@@ -1,4 +1,5 @@
import * as ts from 'typescript';
import { normalize, resolve } from '@angular-devkit/core';
import { Tree, DirEntry } from '@angular-devkit/schematics';

export function visitTSSourceFiles<Result = void>(
Expand All @@ -17,6 +18,190 @@ export function visitTSSourceFiles<Result = void>(
return result;
}

export function visitTemplates(
tree: Tree,
visitor: (
template: {
fileName: string;
content: string;
inline: boolean;
start: number;
},
tree: Tree
) => void
): void {
visitTSSourceFiles(tree, source => {
visitComponents(source, (_, decoratorExpressionNode) => {
ts.forEachChild(decoratorExpressionNode, function findTemplates(n) {
if (ts.isPropertyAssignment(n) && ts.isIdentifier(n.name)) {
if (
n.name.text === 'template' &&
ts.isStringLiteralLike(n.initializer)
) {
// Need to add an offset of one to the start because the template quotes are
// not part of the template content.
const templateStartIdx = n.initializer.getStart() + 1;
visitor(
{
fileName: source.fileName,
content: n.initializer.text,
inline: true,
start: templateStartIdx,
},
tree
);
return;
} else if (
n.name.text === 'templateUrl' &&
ts.isStringLiteralLike(n.initializer)
) {
const parts = normalize(source.fileName)
.split('/')
.slice(0, -1);
const templatePath = resolve(
normalize(parts.join('/')),
normalize(n.initializer.text)
);
if (!tree.exists(templatePath)) {
return;
}

const fileContent = tree.read(templatePath);
if (!fileContent) {
return;
}

visitor(
{
fileName: templatePath,
content: fileContent.toString(),
inline: false,
start: 0,
},
tree
);
return;
}
}

ts.forEachChild(n, findTemplates);
});
});
});
}

export function visitNgModuleImports(
sourceFile: ts.SourceFile,
callback: (
importNode: ts.PropertyAssignment,
elementExpressions: ts.NodeArray<ts.Expression>
) => void
) {
visitNgModuleProperty(sourceFile, callback, 'imports');
}

export function visitNgModuleExports(
sourceFile: ts.SourceFile,
callback: (
exportNode: ts.PropertyAssignment,
elementExpressions: ts.NodeArray<ts.Expression>
) => void
) {
visitNgModuleProperty(sourceFile, callback, 'exports');
}

function visitNgModuleProperty(
sourceFile: ts.SourceFile,
callback: (
nodes: ts.PropertyAssignment,
elementExpressions: ts.NodeArray<ts.Expression>
) => void,
property: string
) {
visitNgModules(sourceFile, (_, decoratorExpressionNode) => {
ts.forEachChild(decoratorExpressionNode, function findTemplates(n) {
if (
ts.isPropertyAssignment(n) &&
ts.isIdentifier(n.name) &&
n.name.text === property &&
ts.isArrayLiteralExpression(n.initializer)
) {
callback(n, n.initializer.elements);
return;
}

ts.forEachChild(n, findTemplates);
});
});
}
export function visitComponents(
sourceFile: ts.SourceFile,
callback: (
classDeclarationNode: ts.ClassDeclaration,
decoratorExpressionNode: ts.ObjectLiteralExpression
) => void
) {
visitDecorator(sourceFile, 'Component', callback);
}

export function visitNgModules(
sourceFile: ts.SourceFile,
callback: (
classDeclarationNode: ts.ClassDeclaration,
decoratorExpressionNode: ts.ObjectLiteralExpression
) => void
) {
visitDecorator(sourceFile, 'NgModule', callback);
}

export function visitDecorator(
sourceFile: ts.SourceFile,
decoratorName: string,
callback: (
classDeclarationNode: ts.ClassDeclaration,
decoratorExpressionNode: ts.ObjectLiteralExpression
) => void
) {
ts.forEachChild(sourceFile, function findClassDeclaration(node) {
if (!ts.isClassDeclaration(node)) {
ts.forEachChild(node, findClassDeclaration);
}

const classDeclarationNode = node as ts.ClassDeclaration;

if (
!classDeclarationNode.decorators ||
!classDeclarationNode.decorators.length
) {
return;
}

const componentDecorator = classDeclarationNode.decorators.find(d => {
return (
ts.isCallExpression(d.expression) &&
ts.isIdentifier(d.expression.expression) &&
d.expression.expression.text === decoratorName
);
});

if (!componentDecorator) {
return;
}

const { expression } = componentDecorator;
if (!ts.isCallExpression(expression)) {
return;
}

const [arg] = expression.arguments;
if (!ts.isObjectLiteralExpression(arg)) {
return;
}

callback(classDeclarationNode, arg);
});
}

function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
for (const path of directory.subfiles) {
if (path.endsWith('.ts') && !path.endsWith('.d.ts')) {
Expand All @@ -42,31 +227,3 @@ function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
yield* visit(directory.dir(path));
}
}

export function visitNgModuleImports(
sourceFile: ts.SourceFile,
callback: (
importNode: ts.PropertyAssignment,
elementExpressions: ts.NodeArray<ts.Expression>
) => void
) {
ts.forEachChild(sourceFile, function findDecorator(node) {
if (!ts.isDecorator(node)) {
ts.forEachChild(node, findDecorator);
return;
}

ts.forEachChild(node, function findImportsNode(n) {
if (
ts.isPropertyAssignment(n) &&
ts.isArrayLiteralExpression(n.initializer) &&
ts.isIdentifier(n.name) &&
n.name.text === 'imports'
) {
callback(n, n.initializer.elements);
}

ts.forEachChild(n, findImportsNode);
});
});
}
10 changes: 9 additions & 1 deletion modules/effects/schematics-core/index.ts
Expand Up @@ -81,4 +81,12 @@ export { addPackageToPackageJson } from './utility/package';

export { platformVersion } from './utility/libs-version';

export { visitTSSourceFiles, visitNgModuleImports } from './utility/visitors';
export {
visitTSSourceFiles,
visitNgModuleImports,
visitNgModuleExports,
visitComponents,
visitDecorator,
visitNgModules,
visitTemplates,
} from './utility/visitors';

0 comments on commit 0775093

Please sign in to comment.