js-confuser 1.6.0 → 1.7.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/CHANGELOG.md +23 -0
- package/README.md +215 -170
- package/dist/constants.js +6 -2
- package/dist/obfuscator.js +0 -6
- package/dist/options.js +4 -4
- package/dist/presets.js +6 -7
- package/dist/templates/crash.js +2 -2
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/dispatcher.js +4 -1
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +89 -58
- package/dist/transforms/flatten.js +224 -147
- package/dist/transforms/identifier/movedDeclarations.js +38 -85
- package/dist/transforms/identifier/renameVariables.js +94 -41
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +2 -2
- package/dist/transforms/rgf.js +139 -246
- package/dist/transforms/stack.js +42 -1
- package/dist/transforms/transform.js +1 -1
- package/dist/util/gen.js +2 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +24 -3
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +1 -1
- package/src/constants.ts +3 -0
- package/src/obfuscator.ts +0 -4
- package/src/options.ts +9 -86
- package/src/presets.ts +6 -7
- package/src/templates/crash.ts +10 -10
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/dispatcher.ts +5 -1
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +130 -129
- package/src/transforms/flatten.ts +357 -290
- package/src/transforms/identifier/movedDeclarations.ts +50 -96
- package/src/transforms/identifier/renameVariables.ts +120 -56
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +11 -2
- package/src/transforms/rgf.ts +214 -404
- package/src/transforms/stack.ts +62 -0
- package/src/transforms/transform.ts +6 -2
- package/src/util/gen.ts +7 -2
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +26 -2
- package/test/code/ES6.src.js +24 -0
- package/test/transforms/flatten.test.ts +352 -88
- package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
- package/test/transforms/identifier/renameVariables.test.ts +37 -0
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +19 -0
- package/test/transforms/rgf.test.ts +262 -353
- package/test/transforms/stack.test.ts +52 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
package/dist/presets.js
CHANGED
|
@@ -22,7 +22,7 @@ exports.default = void 0;
|
|
|
22
22
|
* 10. Minified output
|
|
23
23
|
*
|
|
24
24
|
* ## **`Disabled features`**
|
|
25
|
-
* - `
|
|
25
|
+
* - `rgf` Use at your own risk!
|
|
26
26
|
*
|
|
27
27
|
* ### Potential Issues
|
|
28
28
|
* 1. *String Encoding* can corrupt files. Disable `stringEncoding` manually if this happens.
|
|
@@ -57,7 +57,6 @@ const highPreset = {
|
|
|
57
57
|
stringEncoding: true,
|
|
58
58
|
stringSplitting: 0.75,
|
|
59
59
|
// Use at own risk
|
|
60
|
-
eval: false,
|
|
61
60
|
rgf: false
|
|
62
61
|
};
|
|
63
62
|
/**
|
|
@@ -71,9 +70,9 @@ const mediumPreset = {
|
|
|
71
70
|
calculator: true,
|
|
72
71
|
compact: true,
|
|
73
72
|
hexadecimalNumbers: true,
|
|
74
|
-
controlFlowFlattening: 0.
|
|
73
|
+
controlFlowFlattening: 0.25,
|
|
75
74
|
deadCode: 0.025,
|
|
76
|
-
dispatcher: 0.
|
|
75
|
+
dispatcher: 0.5,
|
|
77
76
|
duplicateLiteralsRemoval: 0.5,
|
|
78
77
|
globalConcealing: true,
|
|
79
78
|
identifierGenerator: "randomized",
|
|
@@ -99,10 +98,10 @@ const lowPreset = {
|
|
|
99
98
|
calculator: true,
|
|
100
99
|
compact: true,
|
|
101
100
|
hexadecimalNumbers: true,
|
|
102
|
-
controlFlowFlattening: 0.
|
|
101
|
+
controlFlowFlattening: 0.1,
|
|
103
102
|
deadCode: 0.01,
|
|
104
|
-
dispatcher: 0.
|
|
105
|
-
duplicateLiteralsRemoval:
|
|
103
|
+
dispatcher: 0.25,
|
|
104
|
+
duplicateLiteralsRemoval: 0.5,
|
|
106
105
|
identifierGenerator: "randomized",
|
|
107
106
|
minify: true,
|
|
108
107
|
movedDeclarations: true,
|
package/dist/templates/crash.js
CHANGED
|
@@ -9,9 +9,9 @@ var _template = _interopRequireDefault(require("./template"));
|
|
|
9
9
|
|
|
10
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
11
|
|
|
12
|
-
const CrashTemplate1 = (0, _template.default)("\nvar {var} = \"a\";\nwhile(1){\n {var} = {var} += \"a\"
|
|
12
|
+
const CrashTemplate1 = (0, _template.default)("\nvar {var} = \"a\";\nwhile(1){\n {var} = {var} += \"a\";\n}\n");
|
|
13
13
|
exports.CrashTemplate1 = CrashTemplate1;
|
|
14
14
|
const CrashTemplate2 = (0, _template.default)("\nwhile(true) {\n var {var} = 99;\n for({var} = 99; {var} == {var}; {var} *= {var}) {\n !{var} && console.log({var});\n if ({var} <= 10){\n break;\n }\n };\n if({var} === 100) {\n {var}--\n }\n };");
|
|
15
15
|
exports.CrashTemplate2 = CrashTemplate2;
|
|
16
|
-
const CrashTemplate3 = (0, _template.default)("\ntry {\n function {$2}(y, x){\n return x;\n }\n \n var {$1} = {$2}(this, function () {\n var {$3} = function () {\n var regExp = {$3}\n .constructor('return /\" + this + \"/')()\n .constructor('^([^ ]+( +[^ ]+)+)+[^ ]}');\n \n return !regExp.call({$1});\n };\n \n return {$3}();\n });\n \n {$1}();\n} catch ( e ) {\n while(e ? e : !e){\n var b;\n var c = 0;\n (e ? !e : e) ? (function(e){\n c = e ? 0 : !e ? 1 : 0;\n })(e) : b = 1;\n\n if(b&&c){break;}\n if(b){continue;}\n }\n}\n");
|
|
16
|
+
const CrashTemplate3 = (0, _template.default)("\ntry {\n function {$2}(y, x){\n return x;\n }\n \n var {$1} = {$2}(this, function () {\n var {$3} = function () {\n var regExp = {$3}\n .constructor('return /\" + this + \"/')()\n .constructor('^([^ ]+( +[^ ]+)+)+[^ ]}');\n \n return !regExp.call({$1});\n };\n \n return {$3}();\n });\n \n {$1}();\n} catch ( {$1}e ) {\n while({$1}e ? {$1}e : !{$1}e){\n var {$1}b;\n var {$1}c = 0;\n ({$1}e ? !{$1}e : {$1}e) ? (function({$1}e){\n {$1}c = {$1}e ? 0 : !{$1}e ? 1 : 0;\n })({$1}e) : {$1}b = 1;\n\n if({$1}b&&{$1}c){break;}\n if({$1}b){continue;}\n }\n}\n");
|
|
17
17
|
exports.CrashTemplate3 = CrashTemplate3;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.FunctionLengthTemplate = void 0;
|
|
7
|
+
|
|
8
|
+
var _template = _interopRequireDefault(require("./template"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Helper function to set `function.length` property.
|
|
14
|
+
*/
|
|
15
|
+
const FunctionLengthTemplate = (0, _template.default)("\nfunction {name}(functionObject, functionLength){\n Object[\"defineProperty\"](functionObject, \"length\", {\n \"value\": functionLength,\n \"configurable\": true\n });\n return functionObject;\n}\n");
|
|
16
|
+
exports.FunctionLengthTemplate = FunctionLengthTemplate;
|
|
@@ -56,9 +56,12 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
56
56
|
* 3. using `this`
|
|
57
57
|
*/
|
|
58
58
|
class Dispatcher extends _transform.default {
|
|
59
|
+
// Debug mode preserves function names
|
|
59
60
|
constructor(o) {
|
|
60
61
|
super(o, _order.ObfuscateOrder.Dispatcher);
|
|
61
62
|
|
|
63
|
+
_defineProperty(this, "isDebug", false);
|
|
64
|
+
|
|
62
65
|
_defineProperty(this, "count", void 0);
|
|
63
66
|
|
|
64
67
|
this.count = 0;
|
|
@@ -158,7 +161,7 @@ class Dispatcher extends _transform.default {
|
|
|
158
161
|
|
|
159
162
|
var gen = this.getGenerator();
|
|
160
163
|
Object.keys(functionDeclarations).forEach(name => {
|
|
161
|
-
newFnNames[name] = gen.generate();
|
|
164
|
+
newFnNames[name] = this.isDebug ? "_dispatcher_" + this.count + "_" + name : gen.generate();
|
|
162
165
|
}); // set containing new name
|
|
163
166
|
|
|
164
167
|
var set = new Set(Object.keys(newFnNames)); // Only make a dispatcher function if it caught any functions
|
|
@@ -23,6 +23,8 @@ var _assert = require("assert");
|
|
|
23
23
|
|
|
24
24
|
var _random = require("../../util/random");
|
|
25
25
|
|
|
26
|
+
var _traverse = require("../../traverse");
|
|
27
|
+
|
|
26
28
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
27
29
|
|
|
28
30
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
@@ -46,12 +48,19 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
46
48
|
* ```
|
|
47
49
|
*/
|
|
48
50
|
class DuplicateLiteralsRemoval extends _transform.default {
|
|
51
|
+
// The array holding all the duplicate literals
|
|
52
|
+
// The array expression node to be inserted into the program
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Literals in the array
|
|
56
|
+
*/
|
|
57
|
+
|
|
49
58
|
/**
|
|
50
|
-
*
|
|
59
|
+
* Literals are saved here the first time they are seen.
|
|
51
60
|
*/
|
|
52
61
|
|
|
53
62
|
/**
|
|
54
|
-
*
|
|
63
|
+
* Block -> { functionName, indexShift }
|
|
55
64
|
*/
|
|
56
65
|
constructor(o) {
|
|
57
66
|
super(o, _order.ObfuscateOrder.DuplicateLiteralsRemoval);
|
|
@@ -64,23 +73,45 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
64
73
|
|
|
65
74
|
_defineProperty(this, "first", void 0);
|
|
66
75
|
|
|
67
|
-
_defineProperty(this, "
|
|
68
|
-
|
|
69
|
-
_defineProperty(this, "fnGetters", void 0);
|
|
76
|
+
_defineProperty(this, "functions", void 0);
|
|
70
77
|
|
|
71
78
|
this.map = new Map();
|
|
72
79
|
this.first = new Map();
|
|
73
|
-
this.
|
|
74
|
-
this.fnGetters = new Map();
|
|
80
|
+
this.functions = new Map();
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
apply(tree) {
|
|
78
84
|
super.apply(tree);
|
|
79
85
|
|
|
80
|
-
if (this.arrayName && this.arrayExpression.elements.length) {
|
|
86
|
+
if (this.arrayName && this.arrayExpression.elements.length > 0) {
|
|
87
|
+
// This function simply returns the array
|
|
81
88
|
var getArrayFn = this.getPlaceholder();
|
|
82
|
-
(0, _insert.append)(tree, (0, _gen.FunctionDeclaration)(getArrayFn, [], [(0, _gen.ReturnStatement)(this.arrayExpression)]));
|
|
83
|
-
|
|
89
|
+
(0, _insert.append)(tree, (0, _gen.FunctionDeclaration)(getArrayFn, [], [(0, _gen.ReturnStatement)(this.arrayExpression)])); // This variable holds the array
|
|
90
|
+
|
|
91
|
+
(0, _insert.prepend)(tree, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(this.arrayName, (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(getArrayFn), (0, _gen.Literal)("call"), true), [(0, _gen.ThisExpression)()])))); // Create all the functions needed
|
|
92
|
+
|
|
93
|
+
for (var blockNode of this.functions.keys()) {
|
|
94
|
+
var {
|
|
95
|
+
functionName,
|
|
96
|
+
indexShift
|
|
97
|
+
} = this.functions.get(blockNode);
|
|
98
|
+
var propertyNode = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)("index_param"), (0, _gen.Literal)(indexShift));
|
|
99
|
+
var indexRangeInclusive = [0 + indexShift - 1, this.map.size + indexShift]; // The function uses mangling to hide the index being accessed
|
|
100
|
+
|
|
101
|
+
var mangleCount = (0, _random.getRandomInteger)(1, 10);
|
|
102
|
+
|
|
103
|
+
for (var i = 0; i < mangleCount; i++) {
|
|
104
|
+
var operator = (0, _random.choice)([">", "<"]);
|
|
105
|
+
var compareValue = (0, _random.choice)(indexRangeInclusive);
|
|
106
|
+
var test = (0, _gen.BinaryExpression)(operator, (0, _gen.Identifier)("index_param"), (0, _gen.Literal)(compareValue));
|
|
107
|
+
var alternate = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)("index_param"), (0, _gen.Literal)((0, _random.getRandomInteger)(-100, 100)));
|
|
108
|
+
var testValue = operator === ">" && compareValue === indexRangeInclusive[0] || operator === "<" && compareValue === indexRangeInclusive[1];
|
|
109
|
+
propertyNode = (0, _gen.ConditionalExpression)(test, testValue ? propertyNode : alternate, !testValue ? propertyNode : alternate);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var returnArgument = (0, _gen.MemberExpression)((0, _gen.Identifier)(this.arrayName), propertyNode, true);
|
|
113
|
+
(0, _insert.prepend)(blockNode, (0, _gen.FunctionDeclaration)(functionName, [(0, _gen.Identifier)("index_param")], [(0, _gen.ReturnStatement)(returnArgument)]));
|
|
114
|
+
}
|
|
84
115
|
}
|
|
85
116
|
}
|
|
86
117
|
|
|
@@ -95,43 +126,39 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
95
126
|
*/
|
|
96
127
|
|
|
97
128
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
var getterNames = [object, ...parents].map(x => this.fnGetters.get(x)).filter(x => x); // use random getter function
|
|
101
|
-
|
|
102
|
-
var getterName = (0, _random.choice)(getterNames); // get this literals context
|
|
129
|
+
transformLiteral(object, parents, index) {
|
|
130
|
+
var blockNode = (0, _random.choice)(parents.filter(x => this.functions.has(x))); // Create initial function if none exist
|
|
103
131
|
|
|
104
|
-
|
|
105
|
-
|
|
132
|
+
if (this.functions.size === 0) {
|
|
133
|
+
var root = parents[parents.length - 1];
|
|
134
|
+
var rootFunctionName = this.getPlaceholder() + "_dLR_0";
|
|
135
|
+
this.functions.set(root, {
|
|
136
|
+
functionName: rootFunctionName,
|
|
137
|
+
indexShift: (0, _random.getRandomInteger)(-100, 100)
|
|
138
|
+
});
|
|
139
|
+
blockNode = root;
|
|
140
|
+
} // If no function here exist, possibly create new chained function
|
|
106
141
|
|
|
107
|
-
var shouldCreateNew = !getterName || !hasGetterHere && Math.random() > 0.9;
|
|
108
142
|
|
|
109
|
-
|
|
110
|
-
(0, _assert.ok)(!this.fnGetters.has(lexContext));
|
|
111
|
-
var lexContextIndex = parents.findIndex(x => x !== lexContext && (0, _insert.isLexContext)(x));
|
|
112
|
-
var basedOn = lexContextIndex !== -1 ? (0, _random.choice)(parents.slice(lexContextIndex + 1).map(x => this.fnGetters.get(x)).filter(x => x)) : null;
|
|
113
|
-
var body = [];
|
|
114
|
-
var thisShift = (0, _random.getRandomInteger)(-250, 250); // the name of the getter
|
|
143
|
+
var block = (0, _traverse.getBlock)(object, parents);
|
|
115
144
|
|
|
116
|
-
|
|
145
|
+
if (!this.functions.has(block) && (0, _random.chance)(50 - this.functions.size)) {
|
|
146
|
+
var newFunctionName = this.getPlaceholder() + "_dLR_" + this.functions.size;
|
|
147
|
+
this.functions.set(block, {
|
|
148
|
+
functionName: newFunctionName,
|
|
149
|
+
indexShift: (0, _random.getRandomInteger)(-100, 100)
|
|
150
|
+
});
|
|
151
|
+
blockNode = block;
|
|
152
|
+
} // Derive the function to call from the selected blockNode
|
|
117
153
|
|
|
118
|
-
if (basedOn) {
|
|
119
|
-
var shift = this.fnShifts.get(basedOn);
|
|
120
|
-
(0, _assert.ok)(typeof shift === "number");
|
|
121
|
-
body = [(0, _gen.ReturnStatement)((0, _gen.CallExpression)((0, _gen.Identifier)(basedOn), [(0, _gen.BinaryExpression)("+", (0, _gen.Identifier)("index"), (0, _gen.Literal)(thisShift))]))];
|
|
122
|
-
this.fnShifts.set(getterName, shift + thisShift);
|
|
123
|
-
} else {
|
|
124
|
-
// from scratch
|
|
125
|
-
body = [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(this.arrayName), (0, _gen.BinaryExpression)("+", (0, _gen.Identifier)("index"), (0, _gen.Literal)(thisShift)), true))];
|
|
126
|
-
this.fnShifts.set(getterName, thisShift);
|
|
127
|
-
}
|
|
128
154
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
155
|
+
var {
|
|
156
|
+
functionName,
|
|
157
|
+
indexShift
|
|
158
|
+
} = this.functions.get(blockNode); // Call the function given it's indexShift
|
|
132
159
|
|
|
133
|
-
var
|
|
134
|
-
this.replaceIdentifierOrLiteral(object,
|
|
160
|
+
var callExpression = (0, _gen.CallExpression)((0, _gen.Identifier)(functionName), [(0, _gen.Literal)(index + indexShift)]);
|
|
161
|
+
this.replaceIdentifierOrLiteral(object, callExpression, parents);
|
|
135
162
|
}
|
|
136
163
|
|
|
137
164
|
transform(object, parents) {
|
|
@@ -147,19 +174,19 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
147
174
|
} // HARD CODED LIMIT of 10,000 (after 1,000 elements)
|
|
148
175
|
|
|
149
176
|
|
|
150
|
-
if (this.map.size > 1000 &&
|
|
177
|
+
if (this.map.size > 1000 && (0, _random.chance)(this.map.size / 100)) return;
|
|
151
178
|
|
|
152
179
|
if (this.arrayName && parents[0].object && parents[0].object.name == this.arrayName) {
|
|
153
180
|
return;
|
|
154
181
|
}
|
|
155
182
|
|
|
156
|
-
var
|
|
183
|
+
var stringValue;
|
|
157
184
|
|
|
158
185
|
if (object.type == "Literal") {
|
|
159
|
-
|
|
186
|
+
stringValue = typeof object.value + ":" + object.value;
|
|
160
187
|
|
|
161
188
|
if (object.value === null) {
|
|
162
|
-
|
|
189
|
+
stringValue = "null:null";
|
|
163
190
|
} else {
|
|
164
191
|
// Skip empty strings
|
|
165
192
|
if (typeof object.value === "string" && !object.value) {
|
|
@@ -167,38 +194,42 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
167
194
|
}
|
|
168
195
|
}
|
|
169
196
|
} else if (object.type == "Identifier") {
|
|
170
|
-
|
|
197
|
+
stringValue = "identifier:" + object.name;
|
|
171
198
|
} else {
|
|
172
199
|
throw new Error("Unsupported primitive type: " + object.type);
|
|
173
200
|
}
|
|
174
201
|
|
|
175
|
-
(0, _assert.ok)(
|
|
202
|
+
(0, _assert.ok)(stringValue);
|
|
176
203
|
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
} else {
|
|
204
|
+
if (this.map.has(stringValue) || this.first.has(stringValue)) {
|
|
205
|
+
// Create the array if not already made
|
|
180
206
|
if (!this.arrayName) {
|
|
181
207
|
this.arrayName = this.getPlaceholder();
|
|
182
208
|
this.arrayExpression = (0, _gen.ArrayExpression)([]);
|
|
183
|
-
}
|
|
209
|
+
} // Delete with first location
|
|
184
210
|
|
|
185
|
-
|
|
211
|
+
|
|
212
|
+
var firstLocation = this.first.get(stringValue);
|
|
186
213
|
|
|
187
214
|
if (firstLocation) {
|
|
188
|
-
this.first.set(value, null);
|
|
189
215
|
var index = this.map.size;
|
|
190
|
-
(0, _assert.ok)(!this.map.has(
|
|
191
|
-
this.map.set(
|
|
216
|
+
(0, _assert.ok)(!this.map.has(stringValue));
|
|
217
|
+
this.map.set(stringValue, index);
|
|
218
|
+
this.first.delete(stringValue);
|
|
192
219
|
var pushing = (0, _insert.clone)(object);
|
|
193
220
|
this.arrayExpression.elements.push(pushing);
|
|
194
221
|
(0, _assert.ok)(this.arrayExpression.elements[index] === pushing);
|
|
195
|
-
this.
|
|
222
|
+
this.transformLiteral(firstLocation[0], firstLocation[1], index);
|
|
196
223
|
}
|
|
197
224
|
|
|
198
|
-
var index = this.map.get(
|
|
225
|
+
var index = this.map.get(stringValue);
|
|
199
226
|
(0, _assert.ok)(typeof index === "number");
|
|
200
|
-
this.
|
|
201
|
-
|
|
227
|
+
this.transformLiteral(object, parents, index);
|
|
228
|
+
return;
|
|
229
|
+
} // Save this, maybe a duplicate will be found.
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
this.first.set(stringValue, [object, parents]);
|
|
202
233
|
};
|
|
203
234
|
}
|
|
204
235
|
|