11import * as ts from "typescript" ;
22
3- interface Macro {
4- name : ts . Identifier ;
5- value : ts . Expression ;
6- }
7-
83class 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
170160const 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-
182165export default transformer ;
0 commit comments