@@ -7,6 +7,12 @@ import { jsStringEscape } from '@ast-core/escape'
77
88export type EvalHandler = ( source : string , opts : IJsHandlerOptions ) => JsHandlerResult
99
10+ const evalHandlerOptionsCache = new WeakMap < IJsHandlerOptions , {
11+ stringLiteralOptions ?: IJsHandlerOptions
12+ templateLiteralOptions ?: IJsHandlerOptions
13+ } > ( )
14+ const EVAL_SCOPE_ERROR_REGEXP = / p a s s a s c o p e a n d p a r e n t P a t h | t r a v e r s i n g a P r o g r a m \/ F i l e / i
15+
1016export function isEvalPath ( path : NodePath < Node > ) {
1117 if ( path . isCallExpression ( ) ) {
1218 const calleePath = path . get ( 'callee' )
@@ -60,15 +66,11 @@ function createEvalReplacementToken(
6066
6167function handleEvalStringLiteral (
6268 path : NodePath < StringLiteral > ,
63- options : IJsHandlerOptions ,
69+ handlerOptions : IJsHandlerOptions ,
6470 updater : JsTokenUpdater ,
6571 handler : EvalHandler ,
6672) {
67- const { code } = handler ( path . node . value , {
68- ...options ,
69- needEscaped : false ,
70- generateMap : false ,
71- } )
73+ const { code } = handler ( path . node . value , handlerOptions )
7274
7375 if ( ! code ) {
7476 return
@@ -82,14 +84,11 @@ function handleEvalStringLiteral(
8284
8385function handleEvalTemplateElement (
8486 path : NodePath < TemplateElement > ,
85- options : IJsHandlerOptions ,
87+ handlerOptions : IJsHandlerOptions ,
8688 updater : JsTokenUpdater ,
8789 handler : EvalHandler ,
8890) {
89- const { code } = handler ( path . node . value . raw , {
90- ...options ,
91- generateMap : false ,
92- } )
91+ const { code } = handler ( path . node . value . raw , handlerOptions )
9392
9493 if ( ! code ) {
9594 return
@@ -101,29 +100,74 @@ function handleEvalTemplateElement(
101100 }
102101}
103102
103+ function getEvalStringHandlerOptions ( options : IJsHandlerOptions ) {
104+ if ( options . needEscaped === false && options . generateMap === false ) {
105+ return options
106+ }
107+
108+ let cached = evalHandlerOptionsCache . get ( options )
109+ if ( ! cached ) {
110+ cached = { }
111+ evalHandlerOptionsCache . set ( options , cached )
112+ }
113+
114+ if ( ! cached . stringLiteralOptions ) {
115+ cached . stringLiteralOptions = {
116+ ...options ,
117+ needEscaped : false ,
118+ generateMap : false ,
119+ }
120+ }
121+
122+ return cached . stringLiteralOptions
123+ }
124+
125+ function getEvalTemplateHandlerOptions ( options : IJsHandlerOptions ) {
126+ if ( options . generateMap === false ) {
127+ return options
128+ }
129+
130+ let cached = evalHandlerOptionsCache . get ( options )
131+ if ( ! cached ) {
132+ cached = { }
133+ evalHandlerOptionsCache . set ( options , cached )
134+ }
135+
136+ if ( ! cached . templateLiteralOptions ) {
137+ cached . templateLiteralOptions = {
138+ ...options ,
139+ generateMap : false ,
140+ }
141+ }
142+
143+ return cached . templateLiteralOptions
144+ }
145+
104146export function walkEvalExpression (
105147 path : NodePath < CallExpression > ,
106148 options : IJsHandlerOptions ,
107149 updater : JsTokenUpdater ,
108150 handler : EvalHandler ,
109151) {
152+ const stringHandlerOptions = getEvalStringHandlerOptions ( options )
153+ const templateHandlerOptions = getEvalTemplateHandlerOptions ( options )
110154 // 优先走 NodePath 的 traverse(测试桩会用到),若因 noScope 缺少作用域报错则降级到手工参数遍历。
111155 const maybeTraverse = ( path as any ) ?. traverse as ( ( v : any ) => void ) | undefined
112156 if ( typeof maybeTraverse === 'function' ) {
113157 try {
114158 return maybeTraverse . call ( path , {
115159 StringLiteral ( innerPath : NodePath < StringLiteral > ) {
116- handleEvalStringLiteral ( innerPath , options , updater , handler )
160+ handleEvalStringLiteral ( innerPath , stringHandlerOptions , updater , handler )
117161 } ,
118162 TemplateElement ( innerPath : NodePath < TemplateElement > ) {
119- handleEvalTemplateElement ( innerPath , options , updater , handler )
163+ handleEvalTemplateElement ( innerPath , templateHandlerOptions , updater , handler )
120164 } ,
121165 } )
122166 }
123167 catch ( error ) {
124168 // 若是因为缺少 scope/parentPath 的错误,则继续走手工参数遍历;其他错误透出。
125169 const msg = ( error as Error ) ?. message ?? ''
126- const scopeError = / p a s s a s c o p e a n d p a r e n t P a t h | t r a v e r s i n g a P r o g r a m \/ F i l e / i . test ( msg )
170+ const scopeError = EVAL_SCOPE_ERROR_REGEXP . test ( msg )
127171 if ( ! scopeError ) {
128172 throw error
129173 }
@@ -135,12 +179,12 @@ export function walkEvalExpression(
135179 if ( Array . isArray ( getArgs ) ) {
136180 for ( const arg of getArgs as Array < NodePath < Node > > ) {
137181 if ( ( arg as any ) ?. isStringLiteral ?.( ) ) {
138- handleEvalStringLiteral ( arg as unknown as NodePath < StringLiteral > , options , updater , handler )
182+ handleEvalStringLiteral ( arg as unknown as NodePath < StringLiteral > , stringHandlerOptions , updater , handler )
139183 continue
140184 }
141185 if ( ( arg as any ) ?. isTemplateLiteral ?.( ) ) {
142186 for ( const quasi of ( arg as any ) . get ( 'quasis' ) as Array < NodePath < TemplateElement > > ) {
143- handleEvalTemplateElement ( quasi , options , updater , handler )
187+ handleEvalTemplateElement ( quasi , templateHandlerOptions , updater , handler )
144188 }
145189 }
146190 }
@@ -156,15 +200,15 @@ export function walkEvalExpression(
156200 node : n as StringLiteral ,
157201 isStringLiteral : ( ) => true ,
158202 } as unknown as NodePath < StringLiteral >
159- handleEvalStringLiteral ( stub , options , updater , handler )
203+ handleEvalStringLiteral ( stub , stringHandlerOptions , updater , handler )
160204 }
161205 else if ( n ?. type === 'TemplateLiteral' && Array . isArray ( n . quasis ) ) {
162206 for ( const q of n . quasis as any [ ] ) {
163207 const stub = {
164208 node : q as TemplateElement ,
165209 isTemplateElement : ( ) => true ,
166210 } as unknown as NodePath < TemplateElement >
167- handleEvalTemplateElement ( stub , options , updater , handler )
211+ handleEvalTemplateElement ( stub , templateHandlerOptions , updater , handler )
168212 }
169213 }
170214 }
0 commit comments