@@ -510,3 +510,79 @@ export function unwrapTSNode(node: Node): Node {
510
510
return node
511
511
}
512
512
}
513
+
514
+ export function isStaticNode ( node : Node ) : boolean {
515
+ node = unwrapTSNode ( node )
516
+
517
+ switch ( node . type ) {
518
+ case 'UnaryExpression' : // void 0, !true
519
+ return isStaticNode ( node . argument )
520
+
521
+ case 'LogicalExpression' : // 1 > 2
522
+ case 'BinaryExpression' : // 1 + 2
523
+ return isStaticNode ( node . left ) && isStaticNode ( node . right )
524
+
525
+ case 'ConditionalExpression' : {
526
+ // 1 ? 2 : 3
527
+ return (
528
+ isStaticNode ( node . test ) &&
529
+ isStaticNode ( node . consequent ) &&
530
+ isStaticNode ( node . alternate )
531
+ )
532
+ }
533
+
534
+ case 'SequenceExpression' : // (1, 2)
535
+ case 'TemplateLiteral' : // `foo${1}`
536
+ return node . expressions . every ( expr => isStaticNode ( expr ) )
537
+
538
+ case 'ParenthesizedExpression' : // (1)
539
+ return isStaticNode ( node . expression )
540
+
541
+ case 'StringLiteral' :
542
+ case 'NumericLiteral' :
543
+ case 'BooleanLiteral' :
544
+ case 'NullLiteral' :
545
+ case 'BigIntLiteral' :
546
+ return true
547
+ }
548
+ return false
549
+ }
550
+
551
+ export function isConstantNode (
552
+ node : Node ,
553
+ onIdentifier : ( name : string ) => boolean ,
554
+ ) : boolean {
555
+ if ( isStaticNode ( node ) ) return true
556
+
557
+ node = unwrapTSNode ( node )
558
+ switch ( node . type ) {
559
+ case 'Identifier' :
560
+ return onIdentifier ( node . name )
561
+ case 'RegExpLiteral' :
562
+ return true
563
+ case 'ObjectExpression' :
564
+ return node . properties . every ( prop => {
565
+ // { bar() {} } object methods are not considered static nodes
566
+ if ( prop . type === 'ObjectMethod' ) return false
567
+ // { ...{ foo: 1 } }
568
+ if ( prop . type === 'SpreadElement' )
569
+ return isConstantNode ( prop . argument , onIdentifier )
570
+ // { foo: 1 }
571
+ return (
572
+ ( ! prop . computed || isConstantNode ( prop . key , onIdentifier ) ) &&
573
+ isConstantNode ( prop . value , onIdentifier )
574
+ )
575
+ } )
576
+ case 'ArrayExpression' :
577
+ return node . elements . every ( element => {
578
+ // [1, , 3]
579
+ if ( element === null ) return true
580
+ // [1, ...[2, 3]]
581
+ if ( element . type === 'SpreadElement' )
582
+ return isConstantNode ( element . argument , onIdentifier )
583
+ // [1, 2]
584
+ return isConstantNode ( element , onIdentifier )
585
+ } )
586
+ }
587
+ return false
588
+ }
0 commit comments