@@ -69,6 +69,13 @@ export interface CodegenResult {
69
69
map ?: RawSourceMap
70
70
}
71
71
72
+ const enum NewlineType {
73
+ Start = 0 ,
74
+ End = - 1 ,
75
+ None = - 2 ,
76
+ Unknown = - 3
77
+ }
78
+
72
79
export interface CodegenContext
73
80
extends Omit < Required < CodegenOptions > , 'bindingMetadata' | 'inline' > {
74
81
source : string
@@ -80,7 +87,7 @@ export interface CodegenContext
80
87
pure : boolean
81
88
map ?: SourceMapGenerator
82
89
helper ( key : symbol ) : string
83
- push ( code : string , node ?: CodegenNode ) : void
90
+ push ( code : string , newlineIndex ?: number , node ?: CodegenNode ) : void
84
91
indent ( ) : void
85
92
deindent ( withoutNewLine ?: boolean ) : void
86
93
newline ( ) : void
@@ -127,7 +134,7 @@ function createCodegenContext(
127
134
helper ( key ) {
128
135
return `_${ helperNameMap [ key ] } `
129
136
} ,
130
- push ( code , node ) {
137
+ push ( code , newlineIndex = NewlineType . None , node ) {
131
138
context . code += code
132
139
if ( ! __BROWSER__ && context . map ) {
133
140
if ( node ) {
@@ -140,7 +147,41 @@ function createCodegenContext(
140
147
}
141
148
addMapping ( node . loc . start , name )
142
149
}
143
- advancePositionWithMutation ( context , code )
150
+ if ( newlineIndex === NewlineType . Unknown ) {
151
+ // multiple newlines, full iteration
152
+ advancePositionWithMutation ( context , code )
153
+ } else {
154
+ // fast paths
155
+ context . offset += code . length
156
+ if ( newlineIndex === NewlineType . None ) {
157
+ // no newlines; fast path to avoid newline detection
158
+ if ( __TEST__ && code . includes ( '\n' ) ) {
159
+ throw new Error (
160
+ `CodegenContext.push() called newlineIndex: none, but contains` +
161
+ `newlines: ${ code . replace ( / \n / g, '\\n' ) } `
162
+ )
163
+ }
164
+ context . column += code . length
165
+ } else {
166
+ // single newline at known index
167
+ if ( newlineIndex === NewlineType . End ) {
168
+ newlineIndex = code . length - 1
169
+ }
170
+ if (
171
+ __TEST__ &&
172
+ ( code . charAt ( newlineIndex ) !== '\n' ||
173
+ code . slice ( 0 , newlineIndex ) . includes ( '\n' ) ||
174
+ code . slice ( newlineIndex + 1 ) . includes ( '\n' ) )
175
+ ) {
176
+ throw new Error (
177
+ `CodegenContext.push() called with newlineIndex: ${ newlineIndex } ` +
178
+ `but does not conform: ${ code . replace ( / \n / g, '\\n' ) } `
179
+ )
180
+ }
181
+ context . line ++
182
+ context . column = code . length - newlineIndex
183
+ }
184
+ }
144
185
if ( node && node . loc !== locStub ) {
145
186
addMapping ( node . loc . end )
146
187
}
@@ -162,7 +203,7 @@ function createCodegenContext(
162
203
}
163
204
164
205
function newline ( n : number ) {
165
- context . push ( '\n' + ` ` . repeat ( n ) )
206
+ context . push ( '\n' + ` ` . repeat ( n ) , NewlineType . Start )
166
207
}
167
208
168
209
function addMapping ( loc : Position , name ?: string ) {
@@ -250,8 +291,10 @@ export function generate(
250
291
// function mode const declarations should be inside with block
251
292
// also they should be renamed to avoid collision with user properties
252
293
if ( hasHelpers ) {
253
- push ( `const { ${ helpers . map ( aliasHelper ) . join ( ', ' ) } } = _Vue` )
254
- push ( `\n` )
294
+ push (
295
+ `const { ${ helpers . map ( aliasHelper ) . join ( ', ' ) } } = _Vue\n` ,
296
+ NewlineType . End
297
+ )
255
298
newline ( )
256
299
}
257
300
}
@@ -282,7 +325,7 @@ export function generate(
282
325
}
283
326
}
284
327
if ( ast . components . length || ast . directives . length || ast . temps ) {
285
- push ( `\n` )
328
+ push ( `\n` , NewlineType . Start )
286
329
newline ( )
287
330
}
288
331
@@ -334,11 +377,14 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
334
377
const helpers = Array . from ( ast . helpers )
335
378
if ( helpers . length > 0 ) {
336
379
if ( ! __BROWSER__ && prefixIdentifiers ) {
337
- push ( `const { ${ helpers . map ( aliasHelper ) . join ( ', ' ) } } = ${ VueBinding } \n` )
380
+ push (
381
+ `const { ${ helpers . map ( aliasHelper ) . join ( ', ' ) } } = ${ VueBinding } \n` ,
382
+ NewlineType . End
383
+ )
338
384
} else {
339
385
// "with" mode.
340
386
// save Vue in a separate variable to avoid collision
341
- push ( `const _Vue = ${ VueBinding } \n` )
387
+ push ( `const _Vue = ${ VueBinding } \n` , NewlineType . End )
342
388
// in "with" mode, helpers are declared inside the with block to avoid
343
389
// has check cost, but hoists are lifted out of the function - we need
344
390
// to provide the helper here.
@@ -353,7 +399,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
353
399
. filter ( helper => helpers . includes ( helper ) )
354
400
. map ( aliasHelper )
355
401
. join ( ', ' )
356
- push ( `const { ${ staticHelpers } } = _Vue\n` )
402
+ push ( `const { ${ staticHelpers } } = _Vue\n` , NewlineType . End )
357
403
}
358
404
}
359
405
}
@@ -363,7 +409,8 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
363
409
push (
364
410
`const { ${ ast . ssrHelpers
365
411
. map ( aliasHelper )
366
- . join ( ', ' ) } } = require("${ ssrRuntimeModuleName } ")\n`
412
+ . join ( ', ' ) } } = require("${ ssrRuntimeModuleName } ")\n`,
413
+ NewlineType . End
367
414
)
368
415
}
369
416
genHoists ( ast . hoists , context )
@@ -402,18 +449,21 @@ function genModulePreamble(
402
449
push (
403
450
`import { ${ helpers
404
451
. map ( s => helperNameMap [ s ] )
405
- . join ( ', ' ) } } from ${ JSON . stringify ( runtimeModuleName ) } \n`
452
+ . join ( ', ' ) } } from ${ JSON . stringify ( runtimeModuleName ) } \n`,
453
+ NewlineType . End
406
454
)
407
455
push (
408
456
`\n// Binding optimization for webpack code-split\nconst ${ helpers
409
457
. map ( s => `_${ helperNameMap [ s ] } = ${ helperNameMap [ s ] } ` )
410
- . join ( ', ' ) } \n`
458
+ . join ( ', ' ) } \n`,
459
+ NewlineType . End
411
460
)
412
461
} else {
413
462
push (
414
463
`import { ${ helpers
415
464
. map ( s => `${ helperNameMap [ s ] } as _${ helperNameMap [ s ] } ` )
416
- . join ( ', ' ) } } from ${ JSON . stringify ( runtimeModuleName ) } \n`
465
+ . join ( ', ' ) } } from ${ JSON . stringify ( runtimeModuleName ) } \n`,
466
+ NewlineType . End
417
467
)
418
468
}
419
469
}
@@ -422,7 +472,8 @@ function genModulePreamble(
422
472
push (
423
473
`import { ${ ast . ssrHelpers
424
474
. map ( s => `${ helperNameMap [ s ] } as _${ helperNameMap [ s ] } ` )
425
- . join ( ', ' ) } } from "${ ssrRuntimeModuleName } "\n`
475
+ . join ( ', ' ) } } from "${ ssrRuntimeModuleName } "\n`,
476
+ NewlineType . End
426
477
)
427
478
}
428
479
@@ -554,7 +605,7 @@ function genNodeList(
554
605
for ( let i = 0 ; i < nodes . length ; i ++ ) {
555
606
const node = nodes [ i ]
556
607
if ( isString ( node ) ) {
557
- push ( node )
608
+ push ( node , NewlineType . Unknown )
558
609
} else if ( isArray ( node ) ) {
559
610
genNodeListAsArray ( node , context )
560
611
} else {
@@ -573,7 +624,7 @@ function genNodeList(
573
624
574
625
function genNode ( node : CodegenNode | symbol | string , context : CodegenContext ) {
575
626
if ( isString ( node ) ) {
576
- context . push ( node )
627
+ context . push ( node , NewlineType . Unknown )
577
628
return
578
629
}
579
630
if ( isSymbol ( node ) ) {
@@ -671,12 +722,16 @@ function genText(
671
722
node : TextNode | SimpleExpressionNode ,
672
723
context : CodegenContext
673
724
) {
674
- context . push ( JSON . stringify ( node . content ) , node )
725
+ context . push ( JSON . stringify ( node . content ) , NewlineType . Unknown , node )
675
726
}
676
727
677
728
function genExpression ( node : SimpleExpressionNode , context : CodegenContext ) {
678
729
const { content, isStatic } = node
679
- context . push ( isStatic ? JSON . stringify ( content ) : content , node )
730
+ context . push (
731
+ isStatic ? JSON . stringify ( content ) : content ,
732
+ NewlineType . Unknown ,
733
+ node
734
+ )
680
735
}
681
736
682
737
function genInterpolation ( node : InterpolationNode , context : CodegenContext ) {
@@ -694,7 +749,7 @@ function genCompoundExpression(
694
749
for ( let i = 0 ; i < node . children ! . length ; i ++ ) {
695
750
const child = node . children ! [ i ]
696
751
if ( isString ( child ) ) {
697
- context . push ( child )
752
+ context . push ( child , NewlineType . Unknown )
698
753
} else {
699
754
genNode ( child , context )
700
755
}
@@ -715,9 +770,9 @@ function genExpressionAsPropertyKey(
715
770
const text = isSimpleIdentifier ( node . content )
716
771
? node . content
717
772
: JSON . stringify ( node . content )
718
- push ( text , node )
773
+ push ( text , NewlineType . None , node )
719
774
} else {
720
- push ( `[${ node . content } ]` , node )
775
+ push ( `[${ node . content } ]` , NewlineType . Unknown , node )
721
776
}
722
777
}
723
778
@@ -726,7 +781,11 @@ function genComment(node: CommentNode, context: CodegenContext) {
726
781
if ( pure ) {
727
782
push ( PURE_ANNOTATION )
728
783
}
729
- push ( `${ helper ( CREATE_COMMENT ) } (${ JSON . stringify ( node . content ) } )` , node )
784
+ push (
785
+ `${ helper ( CREATE_COMMENT ) } (${ JSON . stringify ( node . content ) } )` ,
786
+ NewlineType . Unknown ,
787
+ node
788
+ )
730
789
}
731
790
732
791
function genVNodeCall ( node : VNodeCall , context : CodegenContext ) {
@@ -754,7 +813,7 @@ function genVNodeCall(node: VNodeCall, context: CodegenContext) {
754
813
const callHelper : symbol = isBlock
755
814
? getVNodeBlockHelper ( context . inSSR , isComponent )
756
815
: getVNodeHelper ( context . inSSR , isComponent )
757
- push ( helper ( callHelper ) + `(` , node )
816
+ push ( helper ( callHelper ) + `(` , NewlineType . None , node )
758
817
genNodeList (
759
818
genNullableArgs ( [ tag , props , children , patchFlag , dynamicProps ] ) ,
760
819
context
@@ -785,7 +844,7 @@ function genCallExpression(node: CallExpression, context: CodegenContext) {
785
844
if ( pure ) {
786
845
push ( PURE_ANNOTATION )
787
846
}
788
- push ( callee + `(` , node )
847
+ push ( callee + `(` , NewlineType . None , node )
789
848
genNodeList ( node . arguments , context )
790
849
push ( `)` )
791
850
}
@@ -794,7 +853,7 @@ function genObjectExpression(node: ObjectExpression, context: CodegenContext) {
794
853
const { push, indent, deindent, newline } = context
795
854
const { properties } = node
796
855
if ( ! properties . length ) {
797
- push ( `{}` , node )
856
+ push ( `{}` , NewlineType . None , node )
798
857
return
799
858
}
800
859
const multilines =
@@ -834,7 +893,7 @@ function genFunctionExpression(
834
893
// wrap slot functions with owner context
835
894
push ( `_${ helperNameMap [ WITH_CTX ] } (` )
836
895
}
837
- push ( `(` , node )
896
+ push ( `(` , NewlineType . None , node )
838
897
if ( isArray ( params ) ) {
839
898
genNodeList ( params , context )
840
899
} else if ( params ) {
@@ -934,7 +993,7 @@ function genTemplateLiteral(node: TemplateLiteral, context: CodegenContext) {
934
993
for ( let i = 0 ; i < l ; i ++ ) {
935
994
const e = node . elements [ i ]
936
995
if ( isString ( e ) ) {
937
- push ( e . replace ( / ( ` | \$ | \\ ) / g, '\\$1' ) )
996
+ push ( e . replace ( / ( ` | \$ | \\ ) / g, '\\$1' ) , NewlineType . Unknown )
938
997
} else {
939
998
push ( '${' )
940
999
if ( multilines ) indent ( )
0 commit comments