Suppose I already have some files generated by a generator and want to create some sub-generators that inserts contents into these files based on some content's template.
The goal is to create a generator of a multilayer architecture composed by 3 layers (for Angular2 app written in typescript):
For each layer, the main generator have to generate all files composing it: a module file, interfaces files, ... The main 3 files generated in this process looks like this:
hero.applicatif.ts:
import { Injectable } from '@angular/core';
import { IHeroApplicatif } from './hero.applicatif.interface';
import { HeroMetier } from '../metier/hero.metier';
@Injectable()
export class HeroApplicatif implements IHeroApplicatif {
constructor(private heroMetier: HeroMetier) {}
}
hero.metier.ts:
import { Injectable } from '@angular/core';
import { IHeroMetier } from './hero.metier.interface';
import { HeroBusinessDelegate } from '../business-delegate/hero.business-delegate';
@Injectable()
export class HeroMetier implements IHeroMetier {
constructor(private heroBusinessDelegate: HeroBusinessDelegate) {}
}
hero.business-delegate.ts:
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { IHeroBusinessDelegate } from './hero.business-delegate.interface';
@Injectable()
export class HeroBusinessDelegate implements IHeroBusinessDelegate {
constructor(private http: Http) {}
}
Generating these files based on templates doesn't pose problem. But I want sub-generators that prompt the user to input a method name, it's return type and parameters so the sub-generator have to modify each previously generated files to inserts codes that, by default, for each layer, pass the call to the next layer.
Suppose the sub-generator have prompt the user to input a method called getHero, the contents of the 3 files have to be modified like this:
hero.applicatif.ts:
import { Injectable } from '@angular/core';
import { IHeroApplicatif } from './hero.applicatif.interface';
import { HeroMetier } from '../metier/hero.metier';
@Injectable()
export class HeroApplicatif implements IHeroApplicatif {
constructor(private heroMetier: HeroMetier) {}
getHero(id:number): Promise<any> {
return this.heroMetier.getHero(id);
}
}
hero.metier.ts:
import { Injectable } from '@angular/core';
import { IHeroMetier } from './hero.metier.interface';
import { HeroBusinessDelegate } from '../business-delegate/hero.business-delegate';
@Injectable()
export class HeroMetier implements IHeroMetier {
constructor(private heroBusinessDelegate: HeroBusinessDelegate) {}
getHero(id:number): Promise<any> {
return this.heroBusinessDelegate.getHero(id);
}
}
hero.business-delegate.ts:
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { IHeroBusinessDelegate } from './hero.business-delegate.interface';
@Injectable()
export class HeroBusinessDelegate implements IHeroBusinessDelegate {
constructor(private http: Http) {}
getHero(id:number): Promise<any> {
return this.http.get(...).toPromise();
}
}
What is the simplest, safe, up to date way to do that?
To edit code files content in a safe way that won't mess up with un-predicted changes by the end user, the safest way is to modify a file Abstract Syntax Tree.
There's multiple AST parser available for Node. The two most popular being Esprima and Acorn. There's also a few tools built on those parser to modify AST more easily.
I wrote such a tool a while back if you want to check it out https://github.com/SBoudrias/AST-query - it might works for your use case.