Skip to content

Commit

Permalink
fix(routes): spread & dynamic value first support
Browse files Browse the repository at this point in the history
fix #452
  • Loading branch information
vogloblinsky committed Feb 10, 2018
1 parent 8b271cd commit 47fd133
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 40 deletions.
51 changes: 37 additions & 14 deletions src/app/compiler/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,41 @@ export class Dependencies {

let cleaner = (process.cwd() + path.sep).replace(/\\/g, '/');
let file = srcFile.fileName.replace(cleaner, '');
let scannedFile = srcFile;

// Search in file for variable statement as routes definitions

const astFile = (typeof ast.getSourceFile(srcFile.fileName) !== 'undefined') ? ast.getSourceFile(srcFile.fileName) : ast.addExistingSourceFile(srcFile.fileName);

const variableRoutesStatements = astFile.getVariableStatements();
let hasRoutesStatements = false;

if (variableRoutesStatements.length > 0) {
// Clean file for spread and dynamics inside routes definitions
variableRoutesStatements.forEach(s => {
const variableDeclarations = s.getDeclarations();
let len = variableDeclarations.length;
let i = 0;
for (i; i < len; i++) {
if (variableDeclarations[i].compilerNode.type) {
if (variableDeclarations[i].compilerNode.type.typeName &&
variableDeclarations[i].compilerNode.type.typeName.text === 'Routes') {
hasRoutesStatements = true;
}
}
}
});
}

if (hasRoutesStatements) {
// Clean file for spread and dynamics inside routes definitions
logger.info('Analysing routes definitions and clean them if necessary');

scannedFile = this.routerParser.cleanFileSpreads(astFile).compilerNode;
scannedFile = this.routerParser.cleanFileDynamics(astFile).compilerNode;

srcFile = scannedFile;
}

ts.forEachChild(srcFile, (node: ts.Node) => {
if (this.jsDocHelper.hasJSDocInternalTag(file, srcFile, node) && this.configuration.mainData.disableInternal) {
Expand Down Expand Up @@ -400,7 +435,7 @@ export class Dependencies {
outputSymbols.interfaces.push(interfaceDeps);
} else if (ts.isFunctionDeclaration(node)) {
let infos = this.visitFunctionDeclaration(node);
//let tags = this.visitFunctionDeclarationJSDocTags(node);
// let tags = this.visitFunctionDeclarationJSDocTags(node);
let name = infos.name;
let functionDep: IFunctionDecDep = {
name,
Expand Down Expand Up @@ -536,7 +571,7 @@ export class Dependencies {
this.routerParser.addModuleWithRoutes(name, [routingInitializer], file);
this.routerParser.addModule(name, [routingInitializer]);
}

outputSymbols.miscellaneous.variables.push(deps);
}
if (ts.isTypeAliasDeclaration(node)) {
Expand Down Expand Up @@ -593,7 +628,6 @@ export class Dependencies {

});


}
private debug(deps: IDep) {
if (deps) {
Expand Down Expand Up @@ -881,8 +915,6 @@ export class Dependencies {
return result;
}



private visitEnumDeclarationForRoutes(fileName, node) {
if (node.declarationList.declarations) {
let i = 0;
Expand Down Expand Up @@ -910,15 +942,6 @@ export class Dependencies {

if (ts.isVariableStatement(statement) && this.routerParser.isVariableRoutes(statement)) {
if (statement.pos === node.pos && statement.end === node.end) {
logger.info('Analysing routes definitions node and cleaning it if needed');
/*let cleanedStatementForSpreads = this.routerParser.cleanFileSpreads(sourceFile, statement);
if (typeof cleanedStatementForSpreads !== 'undefined') {
statement = cleanedStatementForSpreads;
}*/
let cleanedStatementForDynamics = this.routerParser.cleanFileDynamics(sourceFile, statement);
if (typeof cleanedStatementForDynamics !== 'undefined') {
statement = cleanedStatementForDynamics;
}
return directive.concat(this.visitEnumDeclarationForRoutes(filename, statement));
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/app/nodes/routing-graph-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface RoutingGraphNode {
kind?;
children?;
module?;
name?: string;
}
34 changes: 10 additions & 24 deletions src/utils/router-parser.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ImportsUtil } from './imports.util';

const traverse = require('traverse');

import Ast, { PropertyDeclaration, TypeGuards } from 'ts-simple-ast';
import Ast, { PropertyDeclaration, TypeGuards, SourceFile } from 'ts-simple-ast';

const ast = new Ast();

Expand Down Expand Up @@ -375,8 +375,8 @@ export class RouterParserUtil {
return result;
}

public cleanFileSpreads(sourceFile: ts.SourceFile, variableStatement: ts.VariableStatement): ts.VariableStatement {
const file = (typeof ast.getSourceFile(sourceFile.fileName) !== 'undefined') ? ast.getSourceFile(sourceFile.fileName) : ast.addExistingSourceFile(sourceFile.fileName);
public cleanFileSpreads(sourceFile: SourceFile): SourceFile {
let file = sourceFile;
const spreadElements = file.getDescendantsOfKind(ts.SyntaxKind.SpreadElement)
.filter(p => TypeGuards.isArrayLiteralExpression(p.getParentOrThrow()));

Expand All @@ -386,7 +386,7 @@ export class RouterParserUtil {
// Loop through their parents nodes, and if one is a variableStatement and === 'routes'
let foundParentVariableStatement = false;
let parent = spreadElement.getParentWhile((n) => {
if (n.getKind() === variableStatement.kind) {
if (n.getKind() === ts.SyntaxKind.VariableStatement) {
if (this.isVariableRoutes(n.compilerNode)) {
foundParentVariableStatement = true;
}
Expand Down Expand Up @@ -458,27 +458,20 @@ export class RouterParserUtil {
if (!TypeGuards.isVariableDeclaration(referencedDeclaration)) {
throw new Error(`Not implemented referenced declaration kind: ${referencedDeclaration.getKindName()}`);
}

const referencedArray = referencedDeclaration.getInitializerIfKindOrThrow(ts.SyntaxKind.ArrayLiteralExpression);
const spreadElementArray = spreadElement.getParentIfKindOrThrow(ts.SyntaxKind.ArrayLiteralExpression);
const insertIndex = spreadElementArray.getElements().indexOf(spreadElement);
spreadElementArray.removeElement(spreadElement);
spreadElementArray.insertElements(insertIndex, referencedArray.getElements().map(e => e.getText()));
}

// Get original variableStatement from edited file
const editedVariableStatement = file.getVariableStatement(s => {
return (variableStatement.pos === s.getPos())
});

if (editedVariableStatement) {
return editedVariableStatement.compilerNode;
}
return file;
}

public cleanFileDynamics(sourceFile: ts.SourceFile, variableStatement: ts.VariableStatement): ts.VariableStatement {
public cleanFileDynamics(sourceFile: SourceFile): SourceFile {

const file = (typeof ast.getSourceFile(sourceFile.fileName) !== 'undefined') ? ast.getSourceFile(sourceFile.fileName) : ast.addExistingSourceFile(sourceFile.fileName);
let file = sourceFile;
const propertyAccessExpressions = file.getDescendantsOfKind(ts.SyntaxKind.PropertyAccessExpression)
.filter(p => !TypeGuards.isPropertyAccessExpression(p.getParentOrThrow()));

Expand All @@ -488,7 +481,7 @@ export class RouterParserUtil {
// Loop through their parents nodes, and if one is a variableStatement and === 'routes'
let foundParentVariableStatement = false;
let parent = propertyAccessExpression.getParentWhile((n) => {
if (n.getKind() === variableStatement.kind) {
if (n.getKind() === ts.SyntaxKind.VariableStatement) {
if (this.isVariableRoutes(n.compilerNode)) {
foundParentVariableStatement = true;
}
Expand All @@ -510,14 +503,7 @@ export class RouterParserUtil {
propertyAccessExpression.replaceWithText(referencedDeclaration.getInitializerOrThrow().getText());
}

// Get original variableStatement from edited file
const editedVariableStatement = file.getVariableStatement(s => {
return (variableStatement.pos === s.getPos())
});

if (editedVariableStatement) {
return editedVariableStatement.compilerNode;
}
return file;
}

/**
Expand Down
8 changes: 6 additions & 2 deletions test/src/todomvc-ng2/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ enum APP_ENUM {
home = 'homeenuminfile'
}

export const APP_ROUTES: Routes = [
{ path: 'about', loadChildren: './about/about.module#AboutModule' },
const DEFAULT: Routes = [
{ path: '', redirectTo: APP_ENUMS.home, pathMatch: 'full'},
{ path: '**', redirectTo: APP_ENUM.home, pathMatch: 'full'}
];

export const APP_ROUTES: Routes = [
{ path: 'about', loadChildren: './about/about.module#AboutModule' },
...DEFAULT
];

/**
* Main module routing
*
Expand Down

0 comments on commit 47fd133

Please sign in to comment.