Skip to content

Commit 76bbe4a

Browse files
committed
Implement AST code generation
1 parent d74a4da commit 76bbe4a

37 files changed

Lines changed: 661 additions & 396 deletions

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@
77
}
88
],
99
"@babel/preset-typescript"
10+
],
11+
"plugins": [
12+
"@babel/plugin-proposal-class-properties"
1013
]
1114
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules
22
lib
33
.idea
4+
/example/
45
.vscode

.vscode/settings.json

Lines changed: 0 additions & 5 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"devDependencies": {
4141
"@babel/cli": "^7.10.1",
4242
"@babel/core": "^7.10.1",
43+
"@babel/plugin-proposal-class-properties": "^7.10.1",
4344
"@babel/preset-env": "^7.10.1",
4445
"@babel/preset-typescript": "^7.10.1",
4546
"@types/babel-generator": "^6.25.3",

src/core/FileGenerateManager.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { getComponentVariables, getHOCVariables, getHookVariables } from '../utils';
2+
import { FileService } from './FileService';
3+
import { TemplateGenerator } from './TemplateGenerator';
4+
import { HOCTemplate } from './temlpates/components/HOCTemplate';
5+
import { ComponentTemplate } from './temlpates/components/ComponentTemplate';
6+
import { ComponentTestTemplate } from './temlpates/components/ComponentTestTemplate';
7+
import { HookTemplate } from './temlpates/components/HookTemplate';
8+
9+
export class FileGenerateManager {
10+
static generateHook(answers) {
11+
const variables = getHookVariables(answers);
12+
13+
const fileService = new FileService(variables.fileName);
14+
const templateGenerator = new TemplateGenerator(variables);
15+
16+
fileService.createDir();
17+
18+
const jsTemplate = templateGenerator.generateTemplate(HookTemplate);
19+
fileService.genJs(jsTemplate);
20+
}
21+
22+
static generateHOC(answers) {
23+
const variables = getHOCVariables(answers);
24+
25+
const fileService = new FileService(variables.fileName);
26+
const templateGenerator = new TemplateGenerator(variables);
27+
28+
fileService.createDir();
29+
30+
const jsTemplate = templateGenerator.generateTemplate(HOCTemplate);
31+
fileService.genJs(jsTemplate);
32+
}
33+
34+
static generateComponent(answers) {
35+
const variables = getComponentVariables(answers);
36+
37+
const fileService = new FileService(variables.fileName);
38+
const templateGenerator = new TemplateGenerator(variables);
39+
40+
fileService.createDir();
41+
42+
const jsTemplate = templateGenerator.generateTemplate(ComponentTemplate);
43+
fileService.genJs(jsTemplate);
44+
45+
if (variables.test) {
46+
const testTemplate = templateGenerator.generateTemplate(ComponentTestTemplate);
47+
fileService.genTest(testTemplate);
48+
}
49+
50+
fileService.genStyle('');
51+
}
52+
}

src/core/Logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class Logger {
4141
return log(value);
4242
}
4343

44-
static log(value: LoggerValue, color = 'white', icon: string) {
44+
static log(value: LoggerValue, color = 'white', icon?: string) {
4545
if (typeof value === 'function') value = value(chalk);
4646

4747
if (icon) return console.log(icon, chalk[color](value));

src/core/TemplateBase.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as c from './temlpates/shared/utils';
2+
3+
export class TemplateBase {
4+
constructor(protected vars) {}
5+
6+
protected getReactImportSpecifier() {
7+
return this.vars.hooks.map(hook => c.importSpec(hook));
8+
}
9+
10+
protected hasHook(hook: string) {
11+
return this.vars.hooks.includes(hook);
12+
}
13+
14+
protected hasMod(mod: string) {
15+
return this.vars.mods?.includes(mod);
16+
}
17+
}

src/core/TemplateGenerator.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as t from '@babel/types';
2+
import generate from '@babel/generator';
3+
import prettier from 'prettier';
4+
import { IComponentVariables, IHOCVariables, IHookVariables } from '../types';
5+
6+
export type IVariables = IHookVariables | IHOCVariables | IComponentVariables;
7+
8+
export interface Template {
9+
generateAST(): t.File;
10+
}
11+
12+
export class TemplateGenerator {
13+
constructor(private vars: IVariables) {}
14+
15+
private static addEmptyLines(template) {
16+
return template.replace(/^\s*;$/gm, '');
17+
}
18+
19+
generateTemplate(FileTemplate) {
20+
let template;
21+
const ast = new FileTemplate(this.vars).generateAST();
22+
23+
template = generate(ast).code;
24+
template = TemplateGenerator.addEmptyLines(template);
25+
template = prettier.format(template, { parser: 'babel' });
26+
27+
return template;
28+
}
29+
}

src/core/TemplateService.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as t from '@babel/types';
2+
import * as c from '../shared';
3+
import { Template } from '../../TemplateGenerator';
4+
import { TemplateBase } from '../../TemplateBase';
5+
import { generateHooks } from '../shared';
6+
7+
export class ComponentTemplate extends TemplateBase implements Template {
8+
getStyleImportStringLiteral() {
9+
const name = `${this.vars.fileName}.styles.${this.vars.ext.style}`;
10+
return t.stringLiteral(name);
11+
}
12+
13+
generateAST() {
14+
const body: t.Statement[] = [];
15+
16+
body.push(c.importDefault('React', 'react', this.getReactImportSpecifier()));
17+
18+
if (this.hasMod('propTypes')) {
19+
body.push(c.importDefault('PropTypes', 'prop-types'));
20+
}
21+
22+
body.push(t.importDeclaration([], this.getStyleImportStringLiteral()));
23+
body.push(t.emptyStatement());
24+
25+
if (this.hasHook('useReducer')) {
26+
body.push(c.useReducerInit());
27+
body.push(t.emptyStatement());
28+
}
29+
30+
body.push(c.component(this.vars.componentName, generateHooks(this.vars.hooks)));
31+
body.push(t.emptyStatement());
32+
33+
if (this.hasMod('propTypes')) {
34+
body.push(c.propTypes(this.vars.componentName));
35+
}
36+
37+
return c.program(body);
38+
}
39+
}

0 commit comments

Comments
 (0)