1
1
import Transform from "../transform" ;
2
- import { isBlock , walk } from "../../traverse" ;
2
+ import { isBlock } from "../../traverse" ;
3
3
import {
4
- Location ,
5
4
ExpressionStatement ,
6
5
AssignmentExpression ,
7
6
Identifier ,
8
7
Node ,
9
8
VariableDeclarator ,
10
- VariableDeclaration ,
11
9
} from "../../util/gen" ;
12
10
import { isForInitialize , prepend } from "../../util/insert" ;
13
11
import { ok } from "assert" ;
14
12
import { ObfuscateOrder } from "../../order" ;
15
- import { getIdentifierInfo } from "../../util/identifiers" ;
16
- import { isLexicalScope , getLexicalScope } from "../../util/scope" ;
17
13
18
14
/**
19
15
* Defines all the names at the top of every lexical block.
@@ -24,110 +20,68 @@ export default class MovedDeclarations extends Transform {
24
20
}
25
21
26
22
match ( object , parents ) {
27
- return isLexicalScope ( object ) ;
23
+ return (
24
+ object . type === "VariableDeclaration" &&
25
+ object . kind === "var" &&
26
+ object . declarations . length === 1 &&
27
+ object . declarations [ 0 ] . id . type === "Identifier"
28
+ ) ;
28
29
}
29
30
30
31
transform ( object : Node , parents : Node [ ] ) {
31
32
return ( ) => {
32
- var body = isBlock ( object ) ? object . body : object . consequent ;
33
- ok ( Array . isArray ( body ) ) ;
34
-
35
- var illegal = new Set < string > ( ) ;
36
- var defined = new Set < string > ( ) ;
37
- var variableDeclarations : {
38
- [ name : string ] : {
39
- location : Location ;
40
- replace : Node ;
33
+ var forInitializeType = isForInitialize ( object , parents ) ;
34
+
35
+ // Get the block statement or Program node
36
+ var blockIndex = parents . findIndex ( ( x ) => isBlock ( x ) ) ;
37
+ var block = parents [ blockIndex ] ;
38
+ var body = block . body ;
39
+ var bodyObject = parents [ blockIndex - 2 ] || object ;
40
+
41
+ // Make sure in the block statement, and not already at the top of it
42
+ var index = body . indexOf ( bodyObject ) ;
43
+ if ( index === - 1 || index === 0 ) return ;
44
+
45
+ var topVariableDeclaration ;
46
+ if ( body [ 0 ] . type === "VariableDeclaration" && body [ 0 ] . kind === "var" ) {
47
+ topVariableDeclaration = body [ 0 ] ;
48
+ } else {
49
+ topVariableDeclaration = {
50
+ type : "VariableDeclaration" ,
51
+ declarations : [ ] ,
52
+ kind : "var" ,
41
53
} ;
42
- } = Object . create ( null ) ;
43
-
44
- walk ( object , parents , ( o , p ) => {
45
- if ( o . type == "Identifier" ) {
46
- if ( o . hidden || getLexicalScope ( o , p ) !== object ) {
47
- illegal . add ( o . name ) ;
48
- } else {
49
- var info = getIdentifierInfo ( o , p ) ;
50
- if ( ! info . spec . isReferenced ) {
51
- return ;
52
- }
53
54
54
- if ( info . spec . isDefined ) {
55
- if ( info . isFunctionDeclaration || info . isClassDeclaration ) {
56
- illegal . add ( o . name ) ;
57
- } else {
58
- if ( defined . has ( o . name ) ) {
59
- illegal . add ( o . name ) ;
60
- } else {
61
- defined . add ( o . name ) ;
62
- }
63
- }
64
- }
65
- }
66
- }
55
+ prepend ( block , topVariableDeclaration ) ;
56
+ }
67
57
68
- if ( o . type == "VariableDeclaration" ) {
69
- return ( ) => {
70
- if (
71
- o . declarations . length === 1 &&
72
- o . declarations [ 0 ] . id . type === "Identifier"
73
- ) {
74
- var name = o . declarations [ 0 ] . id . name ;
58
+ var varName = object . declarations [ 0 ] . id . name ;
59
+ ok ( typeof varName === "string" ) ;
75
60
76
- // Check if duplicate
77
- if ( variableDeclarations [ name ] || o . kind !== "var" ) {
78
- illegal . add ( name ) ;
79
- return ;
80
- }
61
+ // Add `var x` at the top of the block
62
+ topVariableDeclaration . declarations . push (
63
+ VariableDeclarator ( Identifier ( varName ) )
64
+ ) ;
81
65
82
- // Check if already at top
83
- if ( body [ 0 ] === o ) {
84
- illegal . add ( name ) ;
85
- return ;
86
- }
66
+ var assignmentExpression = AssignmentExpression (
67
+ "=" ,
68
+ Identifier ( varName ) ,
69
+ object . declarations [ 0 ] . init || Identifier ( "undefined" )
70
+ ) ;
87
71
88
- var replace : Node = AssignmentExpression (
89
- "=" ,
90
- Identifier ( name ) ,
91
- o . declarations [ 0 ] . init || Identifier ( "undefined" )
92
- ) ;
72
+ if ( forInitializeType ) {
73
+ if ( forInitializeType === "initializer" ) {
74
+ // Replace `for (var i = 0...)` to `for (i = 0...)`
75
+ this . replace ( object , assignmentExpression ) ;
76
+ } else if ( forInitializeType === "left-hand" ) {
77
+ // Replace `for (var k in...)` to `for (k in ...)`
93
78
94
- var forType = isForInitialize ( o , p ) ;
95
- if ( forType === "left-hand" ) {
96
- replace = Identifier ( name ) ;
97
- } else if ( ! forType ) {
98
- replace = ExpressionStatement ( replace ) ;
99
- }
100
- variableDeclarations [ name ] = {
101
- location : [ o , p ] ,
102
- replace : replace ,
103
- } ;
104
- }
105
- } ;
79
+ this . replace ( object , Identifier ( varName ) ) ;
106
80
}
107
- } ) ;
108
-
109
- illegal . forEach ( ( name ) => {
110
- delete variableDeclarations [ name ] ;
111
- } ) ;
112
-
113
- var movingNames = Object . keys ( variableDeclarations ) ;
114
-
115
- if ( movingNames . length === 0 ) {
116
- return ;
81
+ } else {
82
+ // Replace `var x = value` to `x = value`
83
+ this . replace ( object , ExpressionStatement ( assignmentExpression ) ) ;
117
84
}
118
-
119
- var variableDeclaration = VariableDeclaration (
120
- movingNames . map ( ( name ) => {
121
- return VariableDeclarator ( name ) ;
122
- } )
123
- ) ;
124
-
125
- prepend ( object , variableDeclaration ) ;
126
-
127
- movingNames . forEach ( ( name ) => {
128
- var { location, replace } = variableDeclarations [ name ] ;
129
- this . replace ( location [ 0 ] , replace ) ;
130
- } ) ;
131
85
} ;
132
86
}
133
87
}
0 commit comments