Skip to content

Commit cc76d0f

Browse files
committed
refact: clean a bit
1 parent d7b42d6 commit cc76d0f

File tree

2 files changed

+83
-85
lines changed

2 files changed

+83
-85
lines changed

src/index.test.ts

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,44 @@
11
import * as ts from "typescript";
22
import { resolve } from "path";
33
import transformer from "./";
4+
import { readFileSync } from "fs";
45

56
describe("transformer", () => {
67
it("should compile", () => {
78
const inputFile = resolve(__dirname, "__fixtures/input.ts");
8-
const result = compile(inputFile);
9+
const result = compileCode(readFileSync(inputFile).toString());
910
expect(result).toMatchSnapshot();
1011
});
1112
});
1213

13-
function compile(file: string): string {
14-
let content = "";
15-
const program = ts.createProgram([file], {
16-
target: ts.ScriptTarget.ESNext,
17-
module: ts.ModuleKind.CommonJS
18-
});
19-
program.emit(
20-
undefined,
21-
(_, result) => (content = result),
22-
undefined,
23-
undefined,
24-
{
25-
after: [transformer(program)]
14+
// function compile(file: string): string {
15+
// let content = "";
16+
// const program = ts.createProgram([file], {
17+
// target: ts.ScriptTarget.ESNext,
18+
// module: ts.ModuleKind.CommonJS
19+
// });
20+
// program.emit(
21+
// undefined,
22+
// (_, result) => (content = result),
23+
// undefined,
24+
// undefined,
25+
// {
26+
// after: [transformer(program)]
27+
// }
28+
// );
29+
// return content;
30+
// }
31+
32+
function compileCode(source: string): string {
33+
let result = ts.transpileModule(source, {
34+
transformers: {
35+
before: [transformer()]
36+
},
37+
compilerOptions: {
38+
target: ts.ScriptTarget.ESNext,
39+
module: ts.ModuleKind.CommonJS
2640
}
27-
);
28-
return content;
41+
});
42+
43+
return result.outputText;
2944
}

src/index.ts

Lines changed: 52 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import * as ts from "typescript";
22

3-
interface Macro {
4-
name: ts.Identifier;
5-
value: ts.Expression;
6-
}
7-
83
class Transformer {
94
counter = 0;
10-
rootMacros: Macro[] = [];
5+
rootMacros: Record<string, ts.Expression> = {};
116
constructor(public context: ts.TransformationContext) {}
127
transform(node: ts.Node): ts.Node {
138
const postExtract = ts.visitNode(node, this.extractMacros);
@@ -30,7 +25,7 @@ class Transformer {
3025
);
3126
}
3227
const value = firstDeclaration.initializer.arguments[0];
33-
this.rootMacros.push({ name, value });
28+
this.rootMacros[name.text] = value;
3429
return undefined;
3530
}
3631
}
@@ -90,71 +85,66 @@ class Transformer {
9085
// Actually replace the macros in the code
9186
private replaceMacros = (
9287
block: ts.BlockLike,
93-
macros: Macro[]
88+
macros: Record<string, ts.Expression>
9489
): ts.Statement[] => {
9590
const visit = (child: ts.Node): ts.Node => {
9691
if (ts.isBlock(child)) {
9792
return ts.createBlock(this.replaceMacros(child, macros));
9893
}
99-
const identifier = getIdentifier(child);
100-
if (identifier) {
101-
for (const { name, value } of macros) {
102-
if (identifier.text === name.text) {
103-
if (ts.isIdentifier(child)) {
104-
return value;
105-
}
106-
if (ts.isCallExpression(child)) {
107-
if (!ts.isArrowFunction(value)) {
108-
throw new Error("Expected function expression for macro value");
109-
}
110-
const newMacros = macros.slice();
111-
for (
112-
let i = 0;
113-
i < child.arguments.length && i < value.parameters.length;
114-
i++
115-
) {
116-
const name = value.parameters[i].name;
117-
if (!ts.isIdentifier(name)) {
118-
throw new Error(
119-
"Expected identifier in macro function definition"
120-
);
121-
}
122-
const arg = child.arguments[i];
123-
newMacros.push({ name, value: arg });
124-
}
125-
126-
const block = ts.isBlock(value.body)
127-
? value.body
128-
: ts.createBlock([ts.createReturn(value.body)]);
129-
this.counter++;
130-
const [resultName, resultBlock] = this.fixMacros(
131-
ts.createBlock(this.replaceMacros(block, newMacros))
132-
);
133-
result = result.concat(resultBlock.statements);
134-
if (!resultName) {
135-
throw new Error("Macro should return value");
136-
}
137-
return resultName;
138-
}
139-
throw new Error("Expected macro as call expression or identifier");
140-
}
141-
}
94+
if (
95+
ts.isIdentifier(child) &&
96+
(macros as Object).hasOwnProperty(child.text)
97+
) {
98+
return macros[child.text];
14299
}
143100
if (
144101
ts.isCallExpression(child) &&
145-
ts.isPropertyAccessExpression(child.expression)
102+
ts.isIdentifier(child.expression) &&
103+
(macros as Object).hasOwnProperty(child.expression.text)
146104
) {
147-
for (const { name, value } of macros) {
148-
if (child.expression.name.text === name.text) {
149-
return ts.visitNode(
150-
ts.updateCall(child, child.expression.name, child.typeArguments, [
151-
child.expression.expression,
152-
...child.arguments
153-
]),
154-
visit
155-
);
105+
const value = macros[child.expression.text];
106+
if (!ts.isArrowFunction(value)) {
107+
throw new Error("Expected function expression for macro value");
108+
}
109+
const newMacros = { ...macros };
110+
for (
111+
let i = 0;
112+
i < child.arguments.length && i < value.parameters.length;
113+
i++
114+
) {
115+
const argName = value.parameters[i].name;
116+
if (!ts.isIdentifier(argName)) {
117+
throw new Error("Expected identifier in macro function definition");
156118
}
119+
const argValue = child.arguments[i];
120+
newMacros[argName.text] = argValue;
121+
}
122+
123+
const block = ts.isBlock(value.body)
124+
? value.body
125+
: ts.createBlock([ts.createReturn(value.body)]);
126+
this.counter++;
127+
const [resultName, resultBlock] = this.fixMacros(
128+
ts.createBlock(this.replaceMacros(block, newMacros))
129+
);
130+
result = result.concat(resultBlock.statements);
131+
if (!resultName) {
132+
throw new Error("Macro should return value");
157133
}
134+
return resultName;
135+
}
136+
if (
137+
ts.isCallExpression(child) &&
138+
ts.isPropertyAccessExpression(child.expression) &&
139+
(macros as Object).hasOwnProperty(child.expression.name.text)
140+
) {
141+
return ts.visitNode(
142+
ts.updateCall(child, child.expression.name, child.typeArguments, [
143+
child.expression.expression,
144+
...child.arguments
145+
]),
146+
visit
147+
);
158148
}
159149
return ts.visitEachChild(child, visit, this.context);
160150
};
@@ -168,15 +158,8 @@ class Transformer {
168158
}
169159

170160
const transformer = (
171-
_program: ts.Program
161+
_program?: ts.Program
172162
): ts.TransformerFactory<any> => context => node =>
173163
new Transformer(context).transform(node);
174164

175-
function getIdentifier(node: ts.Node): ts.Identifier | undefined {
176-
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression))
177-
return node.expression;
178-
if (ts.isIdentifier(node)) return node;
179-
return undefined;
180-
}
181-
182165
export default transformer;

0 commit comments

Comments
 (0)