[英]I need to read a file written in TypeScript (An Angular Module) and programatically add code to the original file. Any ideas on how can I do it?
This is the app.module.ts file I want to read (Written In TypeScript). 这是我想要阅读的app.module.ts文件(用TypeScript编写)。
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
Then, basically I want to programatically add another component like this: 然后,基本上我想以编程方式添加另一个组件,如下所示:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroesComponent } from './heroes/heroes.component';
import { ShowsComponent } from './shows/shows.component';//** NEW LINE
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent },
{ path: 'shows', component: ShowsComponent }//** New Line
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
So, the program would receive the original file as input and then when finish the original file would be modified with the new code. 因此,程序将接收原始文件作为输入,然后在完成时将使用新代码修改原始文件。 The "component" to be added can be received as a parameter.
可以接收要添加的“组件”作为参数。
How would you go about solving this? 你会怎么解决这个问题?
PD: I want to do it so I detect the symbols properly. PD:我想这样做,所以我正确地检测了符号。 I mean, the code has to work as long as the syntax of the target TS file is valid.
我的意思是,只要目标TS文件的语法有效,代码就必须工作。
PD2: I've been checking the Compiler Api https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API https://www.npmjs.com/package/ts-node PD2:我一直在检查编译器Api https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API https://www.npmjs.com/package/ts-node
Thanks! 谢谢!
I would go with typescript compiler API. 我会使用typescript编译器API。
Let's say we add import at the end of all other imports and also add route at the end of all other routes. 假设我们在所有其他导入的末尾添加导入,并在所有其他路由的末尾添加路由。
Here's a simplified version . 这是一个简化版本 。 You can improve it if:
您可以在以下情况下改进它
you need to check if there is already added route. 你需要检查是否已经添加了路线。
or for instance if there is added import path then we do not need to add new import but rather add clause to exising. 或者例如,如果添加了导入路径,那么我们不需要添加新的导入,而是添加子句来进行导出。
or something else depending on your demands. 或其他取决于您的要求。
interface Replacement {
atPosition: number;
toInsert: string;
}
function replace(content: string) {
const sourceFile = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true);
const replacements: Replacement[] = [
addRoute({ path: 'shows', component: 'ShowsComponent' }, sourceFile),
addImport({ name: 'ShowsComponent', path: './shows/shows.component'}, sourceFile)
]
for (const replacement of replacements) {
content = content.substring(0, replacement.atPosition) + replacement.toInsert + content.substring(replacement.atPosition);
}
return content;
}
function addRoute(route: { path: string, component: string }, sourceFile: ts.SourceFile): Replacement {
const routesDefinition = getRoutesArrayNode(sourceFile);
const routes = findNodes(routesDefinition, ts.SyntaxKind.ObjectLiteralExpression);
const toInsert = `,\n { path: '${route.path}', component: ${route.component} }`;
return insertToTheEnd(routes, toInsert);
}
function addImport(toImport: { name: string, path: string }, sourceFile: ts.SourceFile): Replacement {
const allImports = findNodes(sourceFile, ts.SyntaxKind.ImportDeclaration);
const toInsert = `\nimport { ${toImport.name} } from '${toImport.path}';`;
return insertToTheEnd(allImports, toInsert);;
}
function insertToTheEnd(nodes: any[], toInsert: string): Replacement {
const lastItem = nodes.sort((first: ts.Node, second: ts.Node): number => first.getStart() - second.getStart()).pop();
const atPosition: number = lastItem.getEnd();
return { atPosition, toInsert };
}
function getRoutesArrayNode(sourceFile: ts.SourceFile): ts.Node {
let result: ts.Node | null = null;
ts.forEachChild(sourceFile, (node) => {
if (node.kind === ts.SyntaxKind.VariableStatement) {
const variableStatement = <ts.VariableStatement>node;
for (const variableDeclaration of variableStatement.declarationList.declarations) {
if (variableDeclaration.name.kind == ts.SyntaxKind.Identifier && variableDeclaration.initializer) {
const initializerNode = variableDeclaration.initializer;
if (initializerNode.kind === ts.SyntaxKind.ArrayLiteralExpression) {
if (isRoutesArray(variableDeclaration)) {
result = initializerNode;
}
}
}
}
}
});
return result;
}
function isRoutesArray(node: ts.Node): boolean {
let result = false;
ts.forEachChild(node, child => {
if (child.kind === ts.SyntaxKind.TypeReference) {
const typeReferenceNode = <ts.TypeReferenceNode>child;
const typeNameNode = typeReferenceNode.typeName;
if (typeNameNode.text === 'Routes') {
result = true;
}
}
});
return result;
}
function findNodes(node: ts.Node, kind: ts.SyntaxKind): any[] {
const arr: any[] = [];
if (node.kind === kind) {
arr.push(node);
}
for (const child of node.getChildren()) {
findNodes(child, kind).forEach(node => {
arr.push(node);
});
}
return arr;
}
These links might be also helpful for you: 这些链接也可能对您有所帮助:
https://github.com/angular/devkit/blob/master/packages/schematics/angular/utility/ast-utils.ts https://github.com/angular/devkit/blob/master/packages/schematics/angular/utility/ast-utils.ts
https://github.com/angular/angular/blob/2c2b62f45f29e7658028d85be5a26db812c0525d/packages/compiler-cli/src/metadata/evaluator.ts#L253 https://github.com/angular/angular/blob/2c2b62f45f29e7658028d85be5a26db812c0525d/packages/compiler-cli/src/metadata/evaluator.ts#L253
PS If you're on node.js then I suppose you know how work with fs.readFile
and fs.writeFile
:) PS如果你在node.js上,那么我想你知道如何使用
fs.readFile
和fs.writeFile
:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.