@@ -185,47 +185,82 @@ export class Parser {
185
185
location , absoluteOffset , this . errors ) ;
186
186
}
187
187
188
+ /**
189
+ * Splits a string of text into "raw" text segments and expressions present in interpolations in
190
+ * the string.
191
+ * Returns `null` if there are no interpolations, otherwise a
192
+ * `SplitInterpolation` with splits that look like
193
+ * <raw text> <expression> <raw text> ... <raw text> <expression> <raw text>
194
+ */
188
195
splitInterpolation (
189
196
input : string , location : string ,
190
197
interpolationConfig : InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG ) : SplitInterpolation
191
198
| null {
192
- const regexp = _getInterpolateRegExp ( interpolationConfig ) ;
193
- const parts = input . split ( regexp ) ;
194
- if ( parts . length <= 1 ) {
195
- return null ;
196
- }
197
199
const strings : string [ ] = [ ] ;
198
200
const expressions : string [ ] = [ ] ;
199
201
const offsets : number [ ] = [ ] ;
200
202
const stringSpans : { start : number , end : number } [ ] = [ ] ;
201
203
const expressionSpans : { start : number , end : number } [ ] = [ ] ;
202
- let offset = 0 ;
203
- for ( let i = 0 ; i < parts . length ; i ++ ) {
204
- const part : string = parts [ i ] ;
205
- if ( i % 2 === 0 ) {
206
- // fixed string
204
+ let i = 0 ;
205
+ let atInterpolation = false ;
206
+ let extendLastString = false ;
207
+ let { start : interpStart , end : interpEnd } = interpolationConfig ;
208
+ while ( i < input . length ) {
209
+ if ( ! atInterpolation ) {
210
+ // parse until starting {{
211
+ const start = i ;
212
+ i = input . indexOf ( interpStart , i ) ;
213
+ if ( i === - 1 ) {
214
+ i = input . length ;
215
+ }
216
+ const part = input . substring ( start , i ) ;
207
217
strings . push ( part ) ;
208
- const start = offset ;
209
- offset += part . length ;
210
- stringSpans . push ( { start, end : offset } ) ;
211
- } else if ( part . trim ( ) . length > 0 ) {
212
- const start = offset ;
213
- offset += interpolationConfig . start . length ;
214
- expressions . push ( part ) ;
215
- offsets . push ( offset ) ;
216
- offset += part . length + interpolationConfig . end . length ;
217
- expressionSpans . push ( { start, end : offset } ) ;
218
+ stringSpans . push ( { start, end : i } ) ;
219
+
220
+ atInterpolation = true ;
221
+ } else {
222
+ // parse from starting {{ to ending }}
223
+ const fullStart = i ;
224
+ const exprStart = fullStart + interpStart . length ;
225
+ const exprEnd = input . indexOf ( interpEnd , exprStart ) ;
226
+ if ( exprEnd === - 1 ) {
227
+ // Could not find the end of the interpolation; do not parse an expression.
228
+ // Instead we should extend the content on the last raw string.
229
+ atInterpolation = false ;
230
+ extendLastString = true ;
231
+ break ;
232
+ }
233
+ const fullEnd = exprEnd + interpEnd . length ;
234
+
235
+ const part = input . substring ( exprStart , exprEnd ) ;
236
+ if ( part . trim ( ) . length > 0 ) {
237
+ expressions . push ( part ) ;
238
+ } else {
239
+ this . _reportError (
240
+ 'Blank expressions are not allowed in interpolated strings' , input ,
241
+ `at column ${ i } in` , location ) ;
242
+ expressions . push ( '$implicit' ) ;
243
+ }
244
+ offsets . push ( exprStart ) ;
245
+ expressionSpans . push ( { start : fullStart , end : fullEnd } ) ;
246
+
247
+ i = fullEnd ;
248
+ atInterpolation = false ;
249
+ }
250
+ }
251
+ if ( ! atInterpolation ) {
252
+ // If we are now at a text section, add the remaining content as a raw string.
253
+ if ( extendLastString ) {
254
+ strings [ strings . length - 1 ] += input . substring ( i ) ;
255
+ stringSpans [ stringSpans . length - 1 ] . end = input . length ;
218
256
} else {
219
- this . _reportError (
220
- 'Blank expressions are not allowed in interpolated strings' , input ,
221
- `at column ${ this . _findInterpolationErrorColumn ( parts , i , interpolationConfig ) } in` ,
222
- location ) ;
223
- expressions . push ( '$implicit' ) ;
224
- offsets . push ( offset ) ;
225
- expressionSpans . push ( { start : offset , end : offset } ) ;
257
+ strings . push ( input . substring ( i ) ) ;
258
+ stringSpans . push ( { start : i , end : input . length } ) ;
226
259
}
227
260
}
228
- return new SplitInterpolation ( strings , stringSpans , expressions , expressionSpans , offsets ) ;
261
+ return expressions . length === 0 ?
262
+ null :
263
+ new SplitInterpolation ( strings , stringSpans , expressions , expressionSpans , offsets ) ;
229
264
}
230
265
231
266
wrapLiteralPrimitive ( input : string | null , location : any , absoluteOffset : number ) : ASTWithSource {
0 commit comments