@@ -45,62 +45,94 @@ export function migrateNonStandardTemplateLiterals(path: t.NodePath<t.Node>) {
45
45
}
46
46
47
47
function StringLiteral ( string : t . NodePath < t . StringLiteral > ) {
48
- const templateLiteral = parseNonStandardTemplateLiteral ( string ) ;
49
- if ( templateLiteral ) {
50
- if (
51
- templateLiteral . expressions . length === 1 &&
52
- templateLiteral . quasis . length === 2 &&
53
- templateLiteral . quasis [ 0 ] . value . raw === "" &&
54
- templateLiteral . quasis [ 1 ] . value . raw === ""
55
- ) {
56
- diagnosticDeprecate ( string , {
57
- label : "Non-standard template literals are deprecated." ,
58
- fix ( ) {
59
- string . replaceWith ( templateLiteral . expressions [ 0 ] ) ;
60
- } ,
61
- } ) ;
62
- } else if ( templateLiteral . expressions . every ( isNotNullish ) ) {
63
- diagnosticDeprecate ( string , {
64
- label : "Non-standard template literals are deprecated." ,
65
- fix ( ) {
66
- string . replaceWith ( templateLiteral ) ;
67
- } ,
68
- } ) ;
48
+ const { file } = string . hub ;
49
+ const replacement = parseAllNonStandardTemplateLiterals ( file , string . node ) ;
50
+ if ( replacement ) {
51
+ if ( t . isTemplateLiteral ( replacement ) ) {
52
+ if ( replacement . expressions . every ( isNotNullish ) ) {
53
+ diagnosticDeprecate ( string , {
54
+ label : "Non-standard template literals are deprecated." ,
55
+ fix ( ) {
56
+ string . replaceWith ( replacement ) ;
57
+ } ,
58
+ } ) ;
59
+ } else {
60
+ diagnosticDeprecate ( string , {
61
+ label : "Non-standard template literals are deprecated." ,
62
+ fix : {
63
+ type : "confirm" ,
64
+ message :
65
+ "Are the interpolated values guaranteed to not be null or undefined?" ,
66
+ apply ( confirm ) {
67
+ if ( confirm ) {
68
+ string . replaceWith ( replacement ) ;
69
+ } else {
70
+ string . replaceWith (
71
+ t . templateLiteral (
72
+ replacement . quasis ,
73
+ replacement . expressions . map ( ( expr ) => {
74
+ return isNotNullish ( expr )
75
+ ? expr
76
+ : castNullishToString ( file , expr as t . Expression ) ;
77
+ } ) ,
78
+ ) ,
79
+ ) ;
80
+ }
81
+ } ,
82
+ } ,
83
+ } ) ;
84
+ }
69
85
} else {
70
86
diagnosticDeprecate ( string , {
71
87
label : "Non-standard template literals are deprecated." ,
72
- fix : {
73
- type : "confirm" ,
74
- message :
75
- "Are the interpolated values guaranteed to not be null or undefined?" ,
76
- apply ( confirm ) {
77
- if ( confirm ) {
78
- string . replaceWith ( templateLiteral ) ;
79
- } else {
80
- string . replaceWith (
81
- t . templateLiteral (
82
- templateLiteral . quasis ,
83
- templateLiteral . expressions . map ( ( expr ) => {
84
- return isNotNullish ( expr )
85
- ? expr
86
- : castNullishToString ( string , expr as t . Expression ) ;
87
- } ) ,
88
- ) ,
89
- ) ;
90
- }
91
- } ,
88
+ fix ( ) {
89
+ string . replaceWith ( replacement ) ;
92
90
} ,
93
91
} ) ;
94
92
}
95
93
}
96
94
}
97
95
98
- function castNullishToString ( string : t . NodePath , expression : t . Expression ) {
99
- let nullishHelper = nullishHelpers . get ( string . hub ) ;
96
+ function parseAllNonStandardTemplateLiterals (
97
+ file : t . BabelFile ,
98
+ node : t . StringLiteral ,
99
+ ) {
100
+ const templateLiteral = parseNonStandardTemplateLiteral ( file , node ) ;
101
+ if ( templateLiteral ) {
102
+ for ( let i = templateLiteral . expressions . length ; i -- ; ) {
103
+ traverseWithParent (
104
+ file ,
105
+ templateLiteral . expressions [ i ] ,
106
+ templateLiteral ,
107
+ i ,
108
+ replaceNestedNonStandardTemplateLiteral ,
109
+ ) ;
110
+ }
111
+
112
+ return isSingleExpressionTemplateLiteral ( templateLiteral )
113
+ ? templateLiteral . expressions [ 0 ]
114
+ : templateLiteral ;
115
+ }
116
+ }
117
+
118
+ function replaceNestedNonStandardTemplateLiteral (
119
+ file : t . BabelFile ,
120
+ node : t . Node ,
121
+ parent : t . Node ,
122
+ key : string | number ,
123
+ ) {
124
+ if ( node . type === "StringLiteral" ) {
125
+ ( parent as any ) [ key ] =
126
+ parseAllNonStandardTemplateLiterals ( file , node ) || node ;
127
+ }
128
+ }
129
+
130
+ function castNullishToString ( file : t . BabelFile , expression : t . Expression ) {
131
+ let nullishHelper = nullishHelpers . get ( file . hub ) ;
100
132
if ( ! nullishHelper ) {
101
- nullishHelper = string . scope . generateUidIdentifier ( "toString" ) ;
102
- nullishHelpers . set ( string . hub , nullishHelper ) ;
103
- string . hub . file . path . unshiftContainer (
133
+ nullishHelper = file . path . scope . generateUidIdentifier ( "toString" ) ;
134
+ nullishHelpers . set ( file . hub , nullishHelper ) ;
135
+ file . path . unshiftContainer (
104
136
"body" ,
105
137
t . markoScriptlet (
106
138
[
@@ -129,6 +161,15 @@ function castNullishToString(string: t.NodePath, expression: t.Expression) {
129
161
return t . callExpression ( nullishHelper , [ expression ] ) ;
130
162
}
131
163
164
+ function isSingleExpressionTemplateLiteral ( templateLiteral : t . TemplateLiteral ) {
165
+ return (
166
+ templateLiteral . expressions . length === 1 &&
167
+ templateLiteral . quasis . length === 2 &&
168
+ templateLiteral . quasis [ 0 ] . value . raw === "" &&
169
+ templateLiteral . quasis [ 1 ] . value . raw === ""
170
+ ) ;
171
+ }
172
+
132
173
function isNotNullish ( node : t . Node ) : boolean {
133
174
switch ( node . type ) {
134
175
case "ArrayExpression" :
@@ -162,3 +203,35 @@ function isNotNullish(node: t.Node): boolean {
162
203
return false ;
163
204
}
164
205
}
206
+
207
+ function traverseWithParent (
208
+ file : t . BabelFile ,
209
+ node : t . Node | null | undefined ,
210
+ parent : t . Node ,
211
+ key : string | number ,
212
+ enter : (
213
+ file : t . BabelFile ,
214
+ node : t . Node ,
215
+ parent : t . Node ,
216
+ key : string | number ,
217
+ ) => void ,
218
+ ) : void {
219
+ if ( ! node ) return ;
220
+
221
+ const keys = ( t as any ) . VISITOR_KEYS [ node . type ] ;
222
+ if ( ! keys ) return ;
223
+
224
+ enter ( file , node , parent , key ) ;
225
+
226
+ for ( const key of keys ) {
227
+ const value : t . Node | undefined | null = ( node as any ) [ key ] ;
228
+
229
+ if ( Array . isArray ( value ) ) {
230
+ for ( let i = 0 ; i < value . length ; i ++ ) {
231
+ traverseWithParent ( file , value [ i ] , value , i , enter ) ;
232
+ }
233
+ } else {
234
+ traverseWithParent ( file , value , parent , key , enter ) ;
235
+ }
236
+ }
237
+ }
0 commit comments