@@ -37,7 +37,11 @@ export function shouldTransform(src: string): boolean {
37
37
return transformCheckRE . test ( src )
38
38
}
39
39
40
- type Scope = Record < string , boolean | 'prop' >
40
+ interface Binding {
41
+ isConst ?: boolean
42
+ isProp ?: boolean
43
+ }
44
+ type Scope = Record < string , Binding | false >
41
45
42
46
export interface RefTransformOptions {
43
47
filename ?: string
@@ -118,6 +122,7 @@ export function transformAST(
118
122
{
119
123
local : string // local identifier, may be different
120
124
default ?: any
125
+ isConst ?: boolean
121
126
}
122
127
>
123
128
) : {
@@ -168,17 +173,20 @@ export function transformAST(
168
173
let escapeScope : CallExpression | undefined // inside $$()
169
174
const excludedIds = new WeakSet < Identifier > ( )
170
175
const parentStack : Node [ ] = [ ]
171
- const propsLocalToPublicMap = Object . create ( null )
176
+ const propsLocalToPublicMap : Record < string , string > = Object . create ( null )
172
177
173
178
if ( knownRefs ) {
174
179
for ( const key of knownRefs ) {
175
- rootScope [ key ] = true
180
+ rootScope [ key ] = { }
176
181
}
177
182
}
178
183
if ( knownProps ) {
179
184
for ( const key in knownProps ) {
180
- const { local } = knownProps [ key ]
181
- rootScope [ local ] = 'prop'
185
+ const { local, isConst } = knownProps [ key ]
186
+ rootScope [ local ] = {
187
+ isProp : true ,
188
+ isConst : ! ! isConst
189
+ }
182
190
propsLocalToPublicMap [ local ] = key
183
191
}
184
192
}
@@ -218,7 +226,7 @@ export function transformAST(
218
226
return false
219
227
}
220
228
221
- function error ( msg : string , node : Node ) {
229
+ function error ( msg : string , node : Node ) : never {
222
230
const e = new Error ( msg )
223
231
; ( e as any ) . node = node
224
232
throw e
@@ -229,10 +237,10 @@ export function transformAST(
229
237
return `_${ msg } `
230
238
}
231
239
232
- function registerBinding ( id : Identifier , isRef = false ) {
240
+ function registerBinding ( id : Identifier , binding ?: Binding ) {
233
241
excludedIds . add ( id )
234
242
if ( currentScope ) {
235
- currentScope [ id . name ] = isRef
243
+ currentScope [ id . name ] = binding ? binding : false
236
244
} else {
237
245
error (
238
246
'registerBinding called without active scope, something is wrong.' ,
@@ -241,7 +249,8 @@ export function transformAST(
241
249
}
242
250
}
243
251
244
- const registerRefBinding = ( id : Identifier ) => registerBinding ( id , true )
252
+ const registerRefBinding = ( id : Identifier , isConst = false ) =>
253
+ registerBinding ( id , { isConst } )
245
254
246
255
let tempVarCount = 0
247
256
function genTempVar ( ) {
@@ -296,7 +305,12 @@ export function transformAST(
296
305
isCall &&
297
306
( refCall = isRefCreationCall ( ( decl as any ) . init . callee . name ) )
298
307
) {
299
- processRefDeclaration ( refCall , decl . id , decl . init as CallExpression )
308
+ processRefDeclaration (
309
+ refCall ,
310
+ decl . id ,
311
+ decl . init as CallExpression ,
312
+ stmt . kind === 'const'
313
+ )
300
314
} else {
301
315
const isProps =
302
316
isRoot && isCall && ( decl as any ) . init . callee . name === 'defineProps'
@@ -316,7 +330,8 @@ export function transformAST(
316
330
function processRefDeclaration (
317
331
method : string ,
318
332
id : VariableDeclarator [ 'id' ] ,
319
- call : CallExpression
333
+ call : CallExpression ,
334
+ isConst : boolean
320
335
) {
321
336
excludedIds . add ( call . callee as Identifier )
322
337
if ( method === convertSymbol ) {
@@ -325,16 +340,16 @@ export function transformAST(
325
340
s . remove ( call . callee . start ! + offset , call . callee . end ! + offset )
326
341
if ( id . type === 'Identifier' ) {
327
342
// single variable
328
- registerRefBinding ( id )
343
+ registerRefBinding ( id , isConst )
329
344
} else if ( id . type === 'ObjectPattern' ) {
330
- processRefObjectPattern ( id , call )
345
+ processRefObjectPattern ( id , call , isConst )
331
346
} else if ( id . type === 'ArrayPattern' ) {
332
- processRefArrayPattern ( id , call )
347
+ processRefArrayPattern ( id , call , isConst )
333
348
}
334
349
} else {
335
350
// shorthands
336
351
if ( id . type === 'Identifier' ) {
337
- registerRefBinding ( id )
352
+ registerRefBinding ( id , isConst )
338
353
// replace call
339
354
s . overwrite (
340
355
call . start ! + offset ,
@@ -350,6 +365,7 @@ export function transformAST(
350
365
function processRefObjectPattern (
351
366
pattern : ObjectPattern ,
352
367
call : CallExpression ,
368
+ isConst : boolean ,
353
369
tempVar ?: string ,
354
370
path : PathSegment [ ] = [ ]
355
371
) {
@@ -384,21 +400,27 @@ export function transformAST(
384
400
// { foo: bar }
385
401
nameId = p . value
386
402
} else if ( p . value . type === 'ObjectPattern' ) {
387
- processRefObjectPattern ( p . value , call , tempVar , [ ...path , key ] )
403
+ processRefObjectPattern ( p . value , call , isConst , tempVar , [
404
+ ...path ,
405
+ key
406
+ ] )
388
407
} else if ( p . value . type === 'ArrayPattern' ) {
389
- processRefArrayPattern ( p . value , call , tempVar , [ ...path , key ] )
408
+ processRefArrayPattern ( p . value , call , isConst , tempVar , [
409
+ ...path ,
410
+ key
411
+ ] )
390
412
} else if ( p . value . type === 'AssignmentPattern' ) {
391
413
if ( p . value . left . type === 'Identifier' ) {
392
414
// { foo: bar = 1 }
393
415
nameId = p . value . left
394
416
defaultValue = p . value . right
395
417
} else if ( p . value . left . type === 'ObjectPattern' ) {
396
- processRefObjectPattern ( p . value . left , call , tempVar , [
418
+ processRefObjectPattern ( p . value . left , call , isConst , tempVar , [
397
419
...path ,
398
420
[ key , p . value . right ]
399
421
] )
400
422
} else if ( p . value . left . type === 'ArrayPattern' ) {
401
- processRefArrayPattern ( p . value . left , call , tempVar , [
423
+ processRefArrayPattern ( p . value . left , call , isConst , tempVar , [
402
424
...path ,
403
425
[ key , p . value . right ]
404
426
] )
@@ -412,7 +434,7 @@ export function transformAST(
412
434
error ( `reactivity destructure does not support rest elements.` , p )
413
435
}
414
436
if ( nameId ) {
415
- registerRefBinding ( nameId )
437
+ registerRefBinding ( nameId , isConst )
416
438
// inject toRef() after original replaced pattern
417
439
const source = pathToString ( tempVar , path )
418
440
const keyStr = isString ( key )
@@ -437,6 +459,7 @@ export function transformAST(
437
459
function processRefArrayPattern (
438
460
pattern : ArrayPattern ,
439
461
call : CallExpression ,
462
+ isConst : boolean ,
440
463
tempVar ?: string ,
441
464
path : PathSegment [ ] = [ ]
442
465
) {
@@ -462,12 +485,12 @@ export function transformAST(
462
485
// [...a]
463
486
error ( `reactivity destructure does not support rest elements.` , e )
464
487
} else if ( e . type === 'ObjectPattern' ) {
465
- processRefObjectPattern ( e , call , tempVar , [ ...path , i ] )
488
+ processRefObjectPattern ( e , call , isConst , tempVar , [ ...path , i ] )
466
489
} else if ( e . type === 'ArrayPattern' ) {
467
- processRefArrayPattern ( e , call , tempVar , [ ...path , i ] )
490
+ processRefArrayPattern ( e , call , isConst , tempVar , [ ...path , i ] )
468
491
}
469
492
if ( nameId ) {
470
- registerRefBinding ( nameId )
493
+ registerRefBinding ( nameId , isConst )
471
494
// inject toRef() after original replaced pattern
472
495
const source = pathToString ( tempVar , path )
473
496
const defaultStr = defaultValue ? `, ${ snip ( defaultValue ) } ` : ``
@@ -520,9 +543,18 @@ export function transformAST(
520
543
parentStack : Node [ ]
521
544
) : boolean {
522
545
if ( hasOwn ( scope , id . name ) ) {
523
- const bindingType = scope [ id . name ]
524
- if ( bindingType ) {
525
- const isProp = bindingType === 'prop'
546
+ const binding = scope [ id . name ]
547
+
548
+ if ( binding ) {
549
+ if (
550
+ binding . isConst &&
551
+ ( ( parent . type === 'AssignmentExpression' && id === parent . left ) ||
552
+ parent . type === 'UpdateExpression' )
553
+ ) {
554
+ error ( `Assignment to constant variable.` , id )
555
+ }
556
+
557
+ const { isProp } = binding
526
558
if ( isStaticProperty ( parent ) && parent . shorthand ) {
527
559
// let binding used in a property shorthand
528
560
// skip for destructure patterns
@@ -638,18 +670,20 @@ export function transformAST(
638
670
return this . skip ( )
639
671
}
640
672
641
- if (
642
- node . type === 'Identifier' &&
643
- // if inside $$(), skip unless this is a destructured prop binding
644
- ! ( escapeScope && rootScope [ node . name ] !== 'prop' ) &&
645
- isReferencedIdentifier ( node , parent ! , parentStack ) &&
646
- ! excludedIds . has ( node )
647
- ) {
648
- // walk up the scope chain to check if id should be appended .value
649
- let i = scopeStack . length
650
- while ( i -- ) {
651
- if ( rewriteId ( scopeStack [ i ] , node , parent ! , parentStack ) ) {
652
- return
673
+ if ( node . type === 'Identifier' ) {
674
+ const binding = rootScope [ node . name ]
675
+ if (
676
+ // if inside $$(), skip unless this is a destructured prop binding
677
+ ! ( escapeScope && ( ! binding || ! binding . isProp ) ) &&
678
+ isReferencedIdentifier ( node , parent ! , parentStack ) &&
679
+ ! excludedIds . has ( node )
680
+ ) {
681
+ // walk up the scope chain to check if id should be appended .value
682
+ let i = scopeStack . length
683
+ while ( i -- ) {
684
+ if ( rewriteId ( scopeStack [ i ] , node , parent ! , parentStack ) ) {
685
+ return
686
+ }
653
687
}
654
688
}
655
689
}
@@ -729,7 +763,10 @@ export function transformAST(
729
763
} )
730
764
731
765
return {
732
- rootRefs : Object . keys ( rootScope ) . filter ( key => rootScope [ key ] === true ) ,
766
+ rootRefs : Object . keys ( rootScope ) . filter ( key => {
767
+ const binding = rootScope [ key ]
768
+ return binding && ! binding . isProp
769
+ } ) ,
733
770
importedHelpers : [ ...importedHelpers ]
734
771
}
735
772
}
0 commit comments