js-confuser 1.7.3 → 2.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +6 -4
- package/CHANGELOG.md +70 -0
- package/Migration.md +57 -0
- package/README.md +23 -929
- package/dist/constants.js +65 -14
- package/dist/index.js +108 -160
- package/dist/obfuscator.js +316 -118
- package/dist/options.js +1 -119
- package/dist/order.js +30 -30
- package/dist/presets.js +47 -45
- package/dist/probability.js +25 -32
- package/dist/templates/bufferToStringTemplate.js +9 -0
- package/dist/templates/deadCodeTemplates.js +9 -0
- package/dist/templates/getGlobalTemplate.js +19 -0
- package/dist/templates/integrityTemplate.js +30 -0
- package/dist/templates/setFunctionLengthTemplate.js +9 -0
- package/dist/templates/stringCompressionTemplate.js +10 -0
- package/dist/templates/tamperProtectionTemplates.js +21 -0
- package/dist/templates/template.js +199 -184
- package/dist/transforms/astScrambler.js +100 -0
- package/dist/transforms/calculator.js +70 -127
- package/dist/transforms/controlFlowFlattening.js +1182 -0
- package/dist/transforms/deadCode.js +62 -587
- package/dist/transforms/dispatcher.js +300 -313
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +88 -189
- package/dist/transforms/extraction/objectExtraction.js +131 -215
- package/dist/transforms/finalizer.js +56 -59
- package/dist/transforms/flatten.js +275 -276
- package/dist/transforms/functionOutlining.js +230 -0
- package/dist/transforms/identifier/globalConcealing.js +214 -135
- package/dist/transforms/identifier/movedDeclarations.js +167 -91
- package/dist/transforms/identifier/renameVariables.js +239 -193
- package/dist/transforms/lock/integrity.js +61 -184
- package/dist/transforms/lock/lock.js +261 -387
- package/dist/transforms/minify.js +431 -436
- package/dist/transforms/opaquePredicates.js +65 -118
- package/dist/transforms/pack.js +160 -0
- package/dist/transforms/plugin.js +179 -0
- package/dist/transforms/preparation.js +261 -173
- package/dist/transforms/renameLabels.js +132 -56
- package/dist/transforms/rgf.js +140 -267
- package/dist/transforms/shuffle.js +52 -145
- package/dist/transforms/string/encoding.js +44 -175
- package/dist/transforms/string/stringCompression.js +79 -155
- package/dist/transforms/string/stringConcealing.js +189 -225
- package/dist/transforms/string/stringEncoding.js +32 -40
- package/dist/transforms/string/stringSplitting.js +54 -55
- package/dist/transforms/variableMasking.js +232 -0
- package/dist/utils/ControlObject.js +125 -0
- package/dist/utils/IntGen.js +46 -0
- package/dist/utils/NameGen.js +106 -0
- package/dist/utils/ast-utils.js +560 -0
- package/dist/utils/function-utils.js +56 -0
- package/dist/utils/gen-utils.js +48 -0
- package/dist/utils/node.js +77 -0
- package/dist/utils/object-utils.js +21 -0
- package/dist/utils/random-utils.js +91 -0
- package/dist/utils/static-utils.js +64 -0
- package/dist/validateOptions.js +122 -0
- package/index.d.ts +1 -17
- package/package.json +27 -22
- package/src/constants.ts +139 -82
- package/src/index.ts +70 -165
- package/src/obfuscationResult.ts +43 -0
- package/src/obfuscator.ts +328 -135
- package/src/options.ts +149 -658
- package/src/order.ts +14 -14
- package/src/presets.ts +39 -34
- package/src/probability.ts +21 -36
- package/src/templates/bufferToStringTemplate.ts +57 -0
- package/src/templates/deadCodeTemplates.ts +1185 -0
- package/src/templates/getGlobalTemplate.ts +72 -0
- package/src/templates/integrityTemplate.ts +69 -0
- package/src/templates/setFunctionLengthTemplate.ts +11 -0
- package/src/templates/stringCompressionTemplate.ts +42 -0
- package/src/templates/tamperProtectionTemplates.ts +116 -0
- package/src/templates/template.ts +149 -157
- package/src/transforms/astScrambler.ts +99 -0
- package/src/transforms/calculator.ts +96 -226
- package/src/transforms/controlFlowFlattening.ts +1594 -0
- package/src/transforms/deadCode.ts +85 -676
- package/src/transforms/dispatcher.ts +431 -640
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +147 -295
- package/src/transforms/extraction/objectExtraction.ts +160 -333
- package/src/transforms/finalizer.ts +63 -64
- package/src/transforms/flatten.ts +439 -557
- package/src/transforms/functionOutlining.ts +225 -0
- package/src/transforms/identifier/globalConcealing.ts +255 -266
- package/src/transforms/identifier/movedDeclarations.ts +228 -142
- package/src/transforms/identifier/renameVariables.ts +250 -271
- package/src/transforms/lock/integrity.ts +85 -263
- package/src/transforms/lock/lock.ts +338 -579
- package/src/transforms/minify.ts +523 -663
- package/src/transforms/opaquePredicates.ts +90 -229
- package/src/transforms/pack.ts +195 -0
- package/src/transforms/plugin.ts +185 -0
- package/src/transforms/preparation.ts +337 -231
- package/src/transforms/renameLabels.ts +176 -77
- package/src/transforms/rgf.ts +293 -424
- package/src/transforms/shuffle.ts +80 -254
- package/src/transforms/string/encoding.ts +20 -126
- package/src/transforms/string/stringCompression.ts +117 -307
- package/src/transforms/string/stringConcealing.ts +254 -342
- package/src/transforms/string/stringEncoding.ts +28 -47
- package/src/transforms/string/stringSplitting.ts +61 -75
- package/src/transforms/variableMasking.ts +257 -0
- package/src/utils/ControlObject.ts +141 -0
- package/src/utils/IntGen.ts +33 -0
- package/src/utils/NameGen.ts +106 -0
- package/src/utils/ast-utils.ts +667 -0
- package/src/utils/function-utils.ts +50 -0
- package/src/utils/gen-utils.ts +48 -0
- package/src/utils/node.ts +78 -0
- package/src/utils/object-utils.ts +21 -0
- package/src/utils/random-utils.ts +79 -0
- package/src/utils/static-utils.ts +66 -0
- package/src/validateOptions.ts +256 -0
- package/tsconfig.json +13 -8
- package/babel.config.js +0 -12
- package/dev.js +0 -8
- package/dist/compiler.js +0 -34
- package/dist/parser.js +0 -59
- package/dist/precedence.js +0 -66
- package/dist/templates/bufferToString.js +0 -129
- package/dist/templates/core.js +0 -35
- package/dist/templates/crash.js +0 -28
- package/dist/templates/es5.js +0 -137
- package/dist/templates/functionLength.js +0 -34
- package/dist/templates/globals.js +0 -9
- package/dist/transforms/antiTooling.js +0 -88
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +0 -1287
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +0 -131
- package/dist/transforms/es5/antiClass.js +0 -164
- package/dist/transforms/es5/antiDestructuring.js +0 -193
- package/dist/transforms/es5/antiES6Object.js +0 -185
- package/dist/transforms/es5/antiSpreadOperator.js +0 -35
- package/dist/transforms/es5/antiTemplate.js +0 -66
- package/dist/transforms/es5/es5.js +0 -123
- package/dist/transforms/extraction/classExtraction.js +0 -83
- package/dist/transforms/identifier/globalAnalysis.js +0 -83
- package/dist/transforms/identifier/variableAnalysis.js +0 -104
- package/dist/transforms/lock/antiDebug.js +0 -76
- package/dist/transforms/stack.js +0 -349
- package/dist/transforms/transform.js +0 -372
- package/dist/traverse.js +0 -110
- package/dist/util/compare.js +0 -145
- package/dist/util/gen.js +0 -564
- package/dist/util/guard.js +0 -14
- package/dist/util/identifiers.js +0 -355
- package/dist/util/insert.js +0 -362
- package/dist/util/math.js +0 -19
- package/dist/util/object.js +0 -40
- package/dist/util/random.js +0 -156
- package/dist/util/scope.js +0 -20
- package/docs/ControlFlowFlattening.md +0 -595
- package/docs/Countermeasures.md +0 -70
- package/docs/ES5.md +0 -197
- package/docs/Integrity.md +0 -82
- package/docs/RGF.md +0 -424
- package/docs/RenameVariables.md +0 -116
- package/docs/TamperProtection.md +0 -100
- package/docs/Template.md +0 -117
- package/samples/example.js +0 -15
- package/samples/high.js +0 -1
- package/samples/input.js +0 -3
- package/samples/javascriptobfuscator.com.js +0 -8
- package/samples/jscrambler_advanced.js +0 -1894
- package/samples/jscrambler_light.js +0 -1134
- package/samples/low.js +0 -1
- package/samples/medium.js +0 -1
- package/samples/obfuscator.io.js +0 -1686
- package/samples/preemptive.com.js +0 -16
- package/src/compiler.ts +0 -35
- package/src/parser.ts +0 -49
- package/src/precedence.ts +0 -61
- package/src/templates/bufferToString.ts +0 -136
- package/src/templates/core.ts +0 -29
- package/src/templates/crash.ts +0 -23
- package/src/templates/es5.ts +0 -131
- package/src/templates/functionLength.ts +0 -32
- package/src/templates/globals.ts +0 -3
- package/src/transforms/antiTooling.ts +0 -102
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +0 -2153
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +0 -179
- package/src/transforms/es5/antiClass.ts +0 -276
- package/src/transforms/es5/antiDestructuring.ts +0 -294
- package/src/transforms/es5/antiES6Object.ts +0 -267
- package/src/transforms/es5/antiSpreadOperator.ts +0 -56
- package/src/transforms/es5/antiTemplate.ts +0 -98
- package/src/transforms/es5/es5.ts +0 -149
- package/src/transforms/extraction/classExtraction.ts +0 -168
- package/src/transforms/identifier/globalAnalysis.ts +0 -102
- package/src/transforms/identifier/variableAnalysis.ts +0 -118
- package/src/transforms/lock/antiDebug.ts +0 -112
- package/src/transforms/stack.ts +0 -557
- package/src/transforms/transform.ts +0 -441
- package/src/traverse.ts +0 -120
- package/src/types.ts +0 -133
- package/src/util/compare.ts +0 -181
- package/src/util/gen.ts +0 -651
- package/src/util/guard.ts +0 -17
- package/src/util/identifiers.ts +0 -494
- package/src/util/insert.ts +0 -419
- package/src/util/math.ts +0 -15
- package/src/util/object.ts +0 -39
- package/src/util/random.ts +0 -221
- package/src/util/scope.ts +0 -21
- package/test/code/Cash.src.js +0 -1011
- package/test/code/Cash.test.ts +0 -132
- package/test/code/Dynamic.src.js +0 -118
- package/test/code/Dynamic.test.ts +0 -49
- package/test/code/ES6.src.js +0 -235
- package/test/code/ES6.test.ts +0 -42
- package/test/code/NewFeatures.test.ts +0 -19
- package/test/code/StrictMode.src.js +0 -65
- package/test/code/StrictMode.test.js +0 -37
- package/test/compare.test.ts +0 -104
- package/test/index.test.ts +0 -249
- package/test/options.test.ts +0 -150
- package/test/presets.test.ts +0 -22
- package/test/probability.test.ts +0 -44
- package/test/templates/template.test.ts +0 -224
- package/test/transforms/antiTooling.test.ts +0 -52
- package/test/transforms/calculator.test.ts +0 -78
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +0 -1274
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +0 -192
- package/test/transforms/deadCode.test.ts +0 -85
- package/test/transforms/dispatcher.test.ts +0 -457
- package/test/transforms/es5/antiClass.test.ts +0 -427
- package/test/transforms/es5/antiDestructuring.test.ts +0 -157
- package/test/transforms/es5/antiES6Object.test.ts +0 -245
- package/test/transforms/es5/antiTemplate.test.ts +0 -116
- package/test/transforms/es5/es5.test.ts +0 -110
- package/test/transforms/extraction/classExtraction.test.ts +0 -86
- package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +0 -200
- package/test/transforms/extraction/objectExtraction.test.ts +0 -491
- package/test/transforms/flatten.test.ts +0 -721
- package/test/transforms/hexadecimalNumbers.test.ts +0 -62
- package/test/transforms/identifier/globalConcealing.test.ts +0 -142
- package/test/transforms/identifier/movedDeclarations.test.ts +0 -275
- package/test/transforms/identifier/renameVariables.test.ts +0 -695
- package/test/transforms/lock/antiDebug.test.ts +0 -66
- package/test/transforms/lock/browserLock.test.ts +0 -129
- package/test/transforms/lock/countermeasures.test.ts +0 -100
- package/test/transforms/lock/integrity.test.ts +0 -161
- package/test/transforms/lock/lock.test.ts +0 -204
- package/test/transforms/lock/osLock.test.ts +0 -312
- package/test/transforms/lock/selfDefending.test.ts +0 -68
- package/test/transforms/lock/tamperProtection.test.ts +0 -336
- package/test/transforms/minify.test.ts +0 -575
- package/test/transforms/opaquePredicates.test.ts +0 -43
- package/test/transforms/preparation.test.ts +0 -157
- package/test/transforms/renameLabels.test.ts +0 -95
- package/test/transforms/rgf.test.ts +0 -378
- package/test/transforms/shuffle.test.ts +0 -135
- package/test/transforms/stack.test.ts +0 -573
- package/test/transforms/string/stringCompression.test.ts +0 -120
- package/test/transforms/string/stringConcealing.test.ts +0 -299
- package/test/transforms/string/stringEncoding.test.ts +0 -95
- package/test/transforms/string/stringSplitting.test.ts +0 -135
- package/test/transforms/transform.test.ts +0 -66
- package/test/traverse.test.ts +0 -139
- package/test/util/compare.test.ts +0 -34
- package/test/util/gen.test.ts +0 -121
- package/test/util/identifiers.test.ts +0 -253
- package/test/util/insert.test.ts +0 -142
- package/test/util/math.test.ts +0 -5
- package/test/util/random.test.ts +0 -71
- /package/dist/{types.js → obfuscationResult.js} +0 -0
|
@@ -1,82 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as babelTypes from "@babel/types";
|
|
2
|
+
import { parse } from "@babel/parser";
|
|
3
|
+
import traverse from "@babel/traverse";
|
|
4
|
+
import { NodePath } from "@babel/traverse";
|
|
3
5
|
import { ok } from "assert";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
6
|
+
import { getRandomString } from "../utils/random-utils";
|
|
7
|
+
import { NodeSymbol } from "../constants";
|
|
8
|
+
|
|
9
|
+
// Create a union type of the symbol keys in NodeSymbol
|
|
10
|
+
type NodeSymbolKeys = keyof {
|
|
11
|
+
[K in keyof NodeSymbol as K extends symbol ? K : never]: NodeSymbol[K];
|
|
12
|
+
};
|
|
7
13
|
|
|
8
14
|
export interface TemplateVariables {
|
|
9
15
|
[varName: string]:
|
|
10
16
|
| string
|
|
11
|
-
|
|
|
12
|
-
| Node
|
|
13
|
-
| Node
|
|
17
|
+
| number
|
|
18
|
+
| (() => babelTypes.Node | babelTypes.Node[] | Template)
|
|
19
|
+
| babelTypes.Node
|
|
20
|
+
| babelTypes.Node[]
|
|
14
21
|
| Template;
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
/**
|
|
18
|
-
* Templates provides an easy way to parse code snippets into AST subtrees.
|
|
19
|
-
*
|
|
20
|
-
* These AST subtrees can added to the obfuscated code, tailored with variable names.
|
|
21
|
-
*
|
|
22
|
-
* 1. Basic string interpolation
|
|
23
|
-
*
|
|
24
|
-
* ```js
|
|
25
|
-
* var Base64Template = new Template(`
|
|
26
|
-
* function {name}(str){
|
|
27
|
-
* return btoa(str)
|
|
28
|
-
* }
|
|
29
|
-
* `);
|
|
30
|
-
*
|
|
31
|
-
* var functionDeclaration = Base64Template.single({ name: "atob" });
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* 2. AST subtree insertion
|
|
35
|
-
*
|
|
36
|
-
* ```js
|
|
37
|
-
* var Base64Template = new Template(`
|
|
38
|
-
* function {name}(str){
|
|
39
|
-
* {getWindow}
|
|
40
|
-
*
|
|
41
|
-
* return {getWindowName}btoa(str)
|
|
42
|
-
* }`)
|
|
43
|
-
*
|
|
44
|
-
* var functionDeclaration = Base64Template.single({
|
|
45
|
-
* name: "atob",
|
|
46
|
-
* getWindowName: "newWindow",
|
|
47
|
-
* getWindow: () => {
|
|
48
|
-
* return acorn.parse("var newWindow = {}").body[0];
|
|
49
|
-
* }
|
|
50
|
-
* });
|
|
51
|
-
* ```
|
|
52
|
-
*
|
|
53
|
-
* Here, the `getWindow` variable is a function that returns an AST subtree. This must be a `Node[]` array or Template.
|
|
54
|
-
* Optionally, the function can be replaced with just the `Node[]` array or Template if it's already computed.
|
|
55
|
-
*
|
|
56
|
-
* 3. Template subtree insertion
|
|
57
|
-
*
|
|
58
|
-
* ```js
|
|
59
|
-
* var NewWindowTemplate = new Template(`
|
|
60
|
-
* var newWindow = {};
|
|
61
|
-
* `);
|
|
62
|
-
*
|
|
63
|
-
* var Base64Template = new Template(`
|
|
64
|
-
* function {name}(str){
|
|
65
|
-
* {NewWindowTemplate}
|
|
66
|
-
*
|
|
67
|
-
* return newWindow.btoa(str)
|
|
68
|
-
* }`)
|
|
69
|
-
*
|
|
70
|
-
* var functionDeclaration = Base64Template.single({
|
|
71
|
-
* name: "atob",
|
|
72
|
-
* NewWindowTemplate: NewWindowTemplate
|
|
73
|
-
* });
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
24
|
export default class Template {
|
|
77
|
-
templates: string[];
|
|
78
|
-
defaultVariables: TemplateVariables;
|
|
79
|
-
requiredVariables: Set<string>;
|
|
25
|
+
private templates: string[];
|
|
26
|
+
private defaultVariables: TemplateVariables;
|
|
27
|
+
private requiredVariables: Set<string>;
|
|
28
|
+
private astVariableMappings: Map<string, string>;
|
|
29
|
+
private astIdentifierPrefix = "__t_" + getRandomString(6);
|
|
30
|
+
private symbols: NodeSymbolKeys[] = [];
|
|
80
31
|
|
|
81
32
|
constructor(...templates: string[]) {
|
|
82
33
|
this.templates = templates;
|
|
@@ -86,145 +37,186 @@ export default class Template {
|
|
|
86
37
|
this.findRequiredVariables();
|
|
87
38
|
}
|
|
88
39
|
|
|
40
|
+
addSymbols(...symbols: NodeSymbolKeys[]): this {
|
|
41
|
+
this.symbols.push(...symbols);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
89
45
|
setDefaultVariables(defaultVariables: TemplateVariables): this {
|
|
90
46
|
this.defaultVariables = defaultVariables;
|
|
91
47
|
return this;
|
|
92
48
|
}
|
|
93
49
|
|
|
94
50
|
private findRequiredVariables() {
|
|
95
|
-
|
|
51
|
+
const matches = this.templates[0].match(/{[$A-Za-z0-9_]+}/g);
|
|
96
52
|
if (matches !== null) {
|
|
97
53
|
matches.forEach((variable) => {
|
|
98
|
-
|
|
54
|
+
const name = variable.slice(1, -1);
|
|
99
55
|
|
|
100
|
-
|
|
101
|
-
if (name.startsWith("$")) {
|
|
102
|
-
throw new Error("Default variables are no longer supported.");
|
|
103
|
-
} else {
|
|
104
|
-
this.requiredVariables.add(name);
|
|
105
|
-
}
|
|
56
|
+
this.requiredVariables.add(name);
|
|
106
57
|
});
|
|
107
58
|
}
|
|
108
59
|
}
|
|
109
60
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
*
|
|
115
|
-
* @param variables
|
|
116
|
-
*/
|
|
117
|
-
private interpolateTemplate(variables: TemplateVariables = {}) {
|
|
118
|
-
var allVariables = { ...this.defaultVariables, ...variables };
|
|
119
|
-
|
|
120
|
-
// Validate all variables were passed in
|
|
121
|
-
for (var requiredVariable of this.requiredVariables) {
|
|
61
|
+
private interpolateTemplate(variables: TemplateVariables) {
|
|
62
|
+
const allVariables = { ...this.defaultVariables, ...variables };
|
|
63
|
+
|
|
64
|
+
for (const requiredVariable of this.requiredVariables) {
|
|
122
65
|
if (typeof allVariables[requiredVariable] === "undefined") {
|
|
123
66
|
throw new Error(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
67
|
+
`${
|
|
68
|
+
this.templates[0]
|
|
69
|
+
} missing variable: ${requiredVariable} from ${JSON.stringify(
|
|
70
|
+
allVariables
|
|
71
|
+
)}`
|
|
129
72
|
);
|
|
130
73
|
}
|
|
131
74
|
}
|
|
132
75
|
|
|
133
|
-
|
|
134
|
-
|
|
76
|
+
const template =
|
|
77
|
+
this.templates[Math.floor(Math.random() * this.templates.length)];
|
|
78
|
+
let output = template;
|
|
79
|
+
|
|
80
|
+
this.astVariableMappings = new Map();
|
|
135
81
|
|
|
136
82
|
Object.keys(allVariables).forEach((name) => {
|
|
137
|
-
|
|
83
|
+
const bracketName = `{${name.replace("$", "\\$")}}`;
|
|
84
|
+
let value = allVariables[name] as string;
|
|
138
85
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
86
|
+
if (this.isASTVariable(value)) {
|
|
87
|
+
let astIdentifierName = this.astIdentifierPrefix + name;
|
|
88
|
+
this.astVariableMappings.set(name, astIdentifierName);
|
|
143
89
|
|
|
144
|
-
|
|
90
|
+
value = astIdentifierName;
|
|
91
|
+
}
|
|
145
92
|
|
|
93
|
+
const reg = new RegExp(bracketName, "g");
|
|
146
94
|
output = output.replace(reg, value);
|
|
147
95
|
});
|
|
148
96
|
|
|
149
97
|
return { output, template };
|
|
150
98
|
}
|
|
151
99
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
traverse(ast, (o, p) => {
|
|
171
|
-
if (o.type === "Identifier" && allVariables[o.name]) {
|
|
172
|
-
return () => {
|
|
173
|
-
var value = allVariables[o.name];
|
|
174
|
-
ok(typeof value !== "string");
|
|
175
|
-
|
|
176
|
-
var insertNodes = typeof value === "function" ? value() : value;
|
|
177
|
-
if (insertNodes instanceof Template) {
|
|
178
|
-
insertNodes = insertNodes.compile(allVariables);
|
|
179
|
-
}
|
|
100
|
+
private isASTVariable(variable: any): boolean {
|
|
101
|
+
return typeof variable !== "string" && typeof variable !== "number";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private interpolateAST(ast: babelTypes.Node, variables: TemplateVariables) {
|
|
105
|
+
if (this.astVariableMappings.size === 0) return;
|
|
106
|
+
|
|
107
|
+
const allVariables = { ...this.defaultVariables, ...variables };
|
|
108
|
+
const template = this;
|
|
109
|
+
|
|
110
|
+
// Reverse the lookup map
|
|
111
|
+
// Before {name -> __t_m4H6nk_name}
|
|
112
|
+
// After {__t_m4H6nk_name -> name}
|
|
113
|
+
const reverseMappings = new Map<string, string>();
|
|
114
|
+
this.astVariableMappings.forEach((value, key) => {
|
|
115
|
+
reverseMappings.set(value, key);
|
|
116
|
+
});
|
|
180
117
|
|
|
181
|
-
|
|
182
|
-
// Replace with expression
|
|
118
|
+
const insertedVariables = new Set<string>();
|
|
183
119
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
var body: Node[] = p[1] as any;
|
|
120
|
+
traverse(ast, {
|
|
121
|
+
Identifier(path: NodePath<babelTypes.Identifier>) {
|
|
122
|
+
const idName = path.node.name;
|
|
123
|
+
if (!idName.startsWith(template.astIdentifierPrefix)) return;
|
|
189
124
|
|
|
190
|
-
|
|
191
|
-
|
|
125
|
+
const variableName = reverseMappings.get(idName);
|
|
126
|
+
ok(variableName, `Variable ${idName} not found in mappings`);
|
|
192
127
|
|
|
193
|
-
|
|
128
|
+
let value = allVariables[variableName];
|
|
129
|
+
let isSingleUse = true; // Hard-coded nodes are deemed 'single use'
|
|
130
|
+
if (typeof value === "function") {
|
|
131
|
+
value = value();
|
|
132
|
+
isSingleUse = false;
|
|
133
|
+
}
|
|
194
134
|
|
|
195
|
-
|
|
135
|
+
if (value instanceof Template) {
|
|
136
|
+
value = value.compile(allVariables);
|
|
137
|
+
isSingleUse = false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Duplicate node check
|
|
141
|
+
if (isSingleUse) {
|
|
142
|
+
if (insertedVariables.has(variableName)) {
|
|
143
|
+
ok(false, "Duplicate node inserted for variable: " + variableName);
|
|
196
144
|
}
|
|
197
|
-
|
|
198
|
-
|
|
145
|
+
insertedVariables.add(variableName);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Insert new nodes
|
|
149
|
+
if (!Array.isArray(value)) {
|
|
150
|
+
path.replaceWith(value as babelTypes.Node);
|
|
151
|
+
} else {
|
|
152
|
+
path.replaceWithMultiple(value as babelTypes.Node[]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
path.skip();
|
|
156
|
+
},
|
|
199
157
|
});
|
|
200
158
|
}
|
|
201
159
|
|
|
202
|
-
|
|
203
|
-
|
|
160
|
+
file(variables: TemplateVariables = {}): babelTypes.File {
|
|
161
|
+
const { output } = this.interpolateTemplate(variables);
|
|
204
162
|
|
|
205
|
-
|
|
163
|
+
let file: babelTypes.File;
|
|
206
164
|
try {
|
|
207
|
-
|
|
165
|
+
file = parse(output, {
|
|
166
|
+
sourceType: "module",
|
|
167
|
+
allowReturnOutsideFunction: true,
|
|
168
|
+
});
|
|
208
169
|
} catch (e) {
|
|
209
|
-
throw new Error(
|
|
170
|
+
throw new Error(
|
|
171
|
+
output + "\n" + "Template failed to parse: " + (e as Error).message
|
|
172
|
+
);
|
|
210
173
|
}
|
|
211
174
|
|
|
212
|
-
this.interpolateAST(
|
|
175
|
+
this.interpolateAST(file, variables);
|
|
213
176
|
|
|
214
|
-
|
|
177
|
+
if (this.symbols.length > 0) {
|
|
178
|
+
file.program.body.forEach((node) => {
|
|
179
|
+
for (const symbol of this.symbols) {
|
|
180
|
+
node[symbol] = true;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return file;
|
|
215
186
|
}
|
|
216
187
|
|
|
217
|
-
|
|
218
|
-
|
|
188
|
+
compile(variables: TemplateVariables = {}): babelTypes.Statement[] {
|
|
189
|
+
const file = this.file(variables);
|
|
190
|
+
|
|
191
|
+
return file.program.body;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
single<T extends babelTypes.Statement>(variables: TemplateVariables = {}): T {
|
|
195
|
+
const nodes = this.compile(variables);
|
|
219
196
|
|
|
220
197
|
if (nodes.length !== 1) {
|
|
221
|
-
|
|
198
|
+
const filteredNodes = nodes.filter(
|
|
199
|
+
(node) => node.type !== "EmptyStatement"
|
|
200
|
+
);
|
|
222
201
|
ok(
|
|
223
|
-
|
|
224
|
-
`Expected single node, got ${
|
|
202
|
+
filteredNodes.length === 1,
|
|
203
|
+
`Expected single node, got ${filteredNodes
|
|
204
|
+
.map((node) => node.type)
|
|
205
|
+
.join(", ")}`
|
|
225
206
|
);
|
|
207
|
+
return filteredNodes[0] as T;
|
|
226
208
|
}
|
|
227
209
|
|
|
228
|
-
return nodes[0];
|
|
210
|
+
return nodes[0] as T;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
expression<T extends babelTypes.Expression>(
|
|
214
|
+
variables: TemplateVariables = {}
|
|
215
|
+
): T {
|
|
216
|
+
const statement = this.single(variables);
|
|
217
|
+
|
|
218
|
+
babelTypes.assertExpressionStatement(statement);
|
|
219
|
+
|
|
220
|
+
return statement.expression as T;
|
|
229
221
|
}
|
|
230
222
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { NodePath } from "@babel/core";
|
|
2
|
+
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import { ok } from "assert";
|
|
5
|
+
import { Order } from "../order";
|
|
6
|
+
import { NodeSymbol, SKIP } from "../constants";
|
|
7
|
+
import Template from "../templates/template";
|
|
8
|
+
import { append } from "../utils/ast-utils";
|
|
9
|
+
|
|
10
|
+
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
11
|
+
const me = Plugin(Order.AstScrambler, {
|
|
12
|
+
changeData: {
|
|
13
|
+
expressions: 0,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
var callExprName: string;
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
visitor: {
|
|
20
|
+
"Block|SwitchCase": {
|
|
21
|
+
exit(_path) {
|
|
22
|
+
const path = _path as NodePath<t.Block | t.SwitchCase>;
|
|
23
|
+
const isProgram = path.isProgram();
|
|
24
|
+
|
|
25
|
+
let containerKey: string;
|
|
26
|
+
if (path.isSwitchCase()) {
|
|
27
|
+
containerKey = "consequent";
|
|
28
|
+
} else if (path.isBlock()) {
|
|
29
|
+
containerKey = "body";
|
|
30
|
+
}
|
|
31
|
+
var container: t.Statement[] = path.node[containerKey];
|
|
32
|
+
var newContainer: t.Statement[] = [];
|
|
33
|
+
|
|
34
|
+
ok(Array.isArray(container));
|
|
35
|
+
|
|
36
|
+
var expressions: t.Expression[] = [];
|
|
37
|
+
|
|
38
|
+
const flushExpressions = () => {
|
|
39
|
+
if (!expressions.length) return;
|
|
40
|
+
|
|
41
|
+
// Not enough expressions to require a call expression
|
|
42
|
+
if (expressions.length === 1) {
|
|
43
|
+
newContainer.push(t.expressionStatement(expressions[0]));
|
|
44
|
+
expressions = [];
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!callExprName) {
|
|
49
|
+
callExprName = me.getPlaceholder() + "_ast";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
me.changeData.expressions += expressions.length;
|
|
53
|
+
|
|
54
|
+
newContainer.push(
|
|
55
|
+
t.expressionStatement(
|
|
56
|
+
t.callExpression(t.identifier(callExprName), expressions)
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
expressions = [];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
for (var statement of container) {
|
|
63
|
+
if (
|
|
64
|
+
// Preserve last expression at the top level
|
|
65
|
+
(isProgram ? statement !== container.at(-1) : true) &&
|
|
66
|
+
t.isExpressionStatement(statement) &&
|
|
67
|
+
!(statement as NodeSymbol)[SKIP]
|
|
68
|
+
) {
|
|
69
|
+
if (t.isSequenceExpression(statement.expression)) {
|
|
70
|
+
expressions.push(...statement.expression.expressions);
|
|
71
|
+
} else {
|
|
72
|
+
expressions.push(statement.expression);
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
flushExpressions();
|
|
76
|
+
newContainer.push(statement);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
flushExpressions();
|
|
81
|
+
|
|
82
|
+
path.node[containerKey] = newContainer;
|
|
83
|
+
|
|
84
|
+
if (path.isProgram()) {
|
|
85
|
+
if (callExprName) {
|
|
86
|
+
var functionDeclaration = new Template(`
|
|
87
|
+
function ${callExprName}(){
|
|
88
|
+
${callExprName} = function(){};
|
|
89
|
+
}
|
|
90
|
+
`).single();
|
|
91
|
+
|
|
92
|
+
append(path, functionDeclaration);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
};
|