@@ -12,6 +12,7 @@ import {
12
12
StringLiteral ,
13
13
TemplateLiteral ,
14
14
SourceLocation ,
15
+ Identifier ,
15
16
} from "@babel/types"
16
17
import type { NodePath } from "@babel/traverse"
17
18
@@ -22,9 +23,15 @@ import {
22
23
MACRO_REACT_PACKAGE ,
23
24
MACRO_LEGACY_PACKAGE ,
24
25
MsgDescriptorPropKey ,
26
+ JsMacroName ,
25
27
} from "./constants"
26
28
import cleanJSXElementLiteralChild from "./utils/cleanJSXElementLiteralChild"
27
29
import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils"
30
+ import {
31
+ createMacroJsContext ,
32
+ MacroJsContext ,
33
+ tokenizeExpression ,
34
+ } from "./macroJsAst"
28
35
29
36
const pluralRuleRe = / ( _ [ \d \w ] + | z e r o | o n e | t w o | f e w | m a n y | o t h e r ) /
30
37
const jsx2icuExactChoice = ( value : string ) =>
@@ -43,25 +50,34 @@ function maybeNodeValue(node: Node): { text: string; loc: SourceLocation } {
43
50
return null
44
51
}
45
52
53
+ export type MacroJsxContext = MacroJsContext & {
54
+ elementIndex : ( ) => number
55
+ transImportName : string
56
+ }
57
+
46
58
export type MacroJsxOpts = {
47
59
stripNonEssentialProps : boolean
48
60
stripMessageProp : boolean
49
61
transImportName : string
62
+ isLinguiIdentifier : ( node : Identifier , macro : JsMacroName ) => boolean
50
63
}
51
64
52
65
export class MacroJSX {
53
66
types : typeof babelTypes
54
- expressionIndex = makeCounter ( )
55
- elementIndex = makeCounter ( )
56
- stripNonEssentialProps : boolean
57
- stripMessageProp : boolean
58
- transImportName : string
67
+ ctx : MacroJsxContext
59
68
60
69
constructor ( { types } : { types : typeof babelTypes } , opts : MacroJsxOpts ) {
61
70
this . types = types
62
- this . stripNonEssentialProps = opts . stripNonEssentialProps
63
- this . stripMessageProp = opts . stripMessageProp
64
- this . transImportName = opts . transImportName
71
+
72
+ this . ctx = {
73
+ ...createMacroJsContext (
74
+ opts . isLinguiIdentifier ,
75
+ opts . stripNonEssentialProps ,
76
+ opts . stripMessageProp
77
+ ) ,
78
+ transImportName : opts . transImportName ,
79
+ elementIndex : makeCounter ( ) ,
80
+ }
65
81
}
66
82
67
83
replacePath = ( path : NodePath ) : false | Node => {
@@ -86,8 +102,8 @@ export class MacroJSX {
86
102
const messageDescriptor = createMessageDescriptorFromTokens (
87
103
tokens ,
88
104
path . node . loc ,
89
- this . stripNonEssentialProps ,
90
- this . stripMessageProp ,
105
+ this . ctx . stripNonEssentialProps ,
106
+ this . ctx . stripMessageProp ,
91
107
{
92
108
id,
93
109
context,
@@ -99,7 +115,7 @@ export class MacroJSX {
99
115
100
116
const newNode = this . types . jsxElement (
101
117
this . types . jsxOpeningElement (
102
- this . types . jsxIdentifier ( this . transImportName ) ,
118
+ this . types . jsxIdentifier ( this . ctx . transImportName ) ,
103
119
attributes ,
104
120
true
105
121
) ,
@@ -278,7 +294,7 @@ export class MacroJSX {
278
294
) ( attr . node )
279
295
} )
280
296
281
- const token : Token = {
297
+ let token : Token = {
282
298
type : "arg" ,
283
299
format,
284
300
name : null ,
@@ -305,10 +321,12 @@ export class MacroJSX {
305
321
| NodePath < JSXExpressionContainer >
306
322
307
323
if ( name === "value" ) {
308
- const exp = value . isLiteral ( ) ? value : value . get ( "expression" )
309
-
310
- token . name = this . expressionToArgument ( exp )
311
- token . value = exp . node as Expression
324
+ token = {
325
+ ...token ,
326
+ ...this . tokenizeExpression (
327
+ value . isLiteral ( ) ? value : value . get ( "expression" )
328
+ ) ,
329
+ }
312
330
} else if ( format !== "select" && name === "offset" ) {
313
331
// offset is static parameter, so it must be either string or number
314
332
token . options . offset =
@@ -345,7 +363,7 @@ export class MacroJSX {
345
363
tokenizeElement = ( path : NodePath < JSXElement > ) : ElementToken => {
346
364
// !!! Important: Calculate element index before traversing children.
347
365
// That way outside elements are numbered before inner elements. (...and it looks pretty).
348
- const name = this . elementIndex ( )
366
+ const name = this . ctx . elementIndex ( )
349
367
350
368
return {
351
369
type : "element" ,
@@ -363,11 +381,7 @@ export class MacroJSX {
363
381
}
364
382
365
383
tokenizeExpression = ( path : NodePath < Expression | Node > ) : ArgToken => {
366
- return {
367
- type : "arg" ,
368
- name : this . expressionToArgument ( path ) ,
369
- value : path . node as Expression ,
370
- }
384
+ return tokenizeExpression ( path . node , this . ctx )
371
385
}
372
386
373
387
tokenizeConditionalExpression = (
@@ -382,11 +396,7 @@ export class MacroJSX {
382
396
} ,
383
397
} )
384
398
385
- return {
386
- type : "arg" ,
387
- name : this . expressionToArgument ( exp ) ,
388
- value : exp . node ,
389
- }
399
+ return this . tokenizeExpression ( exp )
390
400
}
391
401
392
402
tokenizeText = ( value : string ) : TextToken => {
@@ -396,10 +406,6 @@ export class MacroJSX {
396
406
}
397
407
}
398
408
399
- expressionToArgument ( path : NodePath < Expression | Node > ) : string {
400
- return path . isIdentifier ( ) ? path . node . name : String ( this . expressionIndex ( ) )
401
- }
402
-
403
409
isLinguiComponent = (
404
410
path : NodePath ,
405
411
name : JsxMacroName
0 commit comments