diff --git a/.gitignore b/.gitignore index 270ff844..882c7881 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .idea node_modules npm-debug.log -**/**.js **/**.js.map \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 00000000..e6ccd2cd --- /dev/null +++ b/index.js @@ -0,0 +1,20 @@ +"use strict"; +const Obfuscator_1 = require('./src/Obfuscator'); +let escodegen = require('escodegen'), esprima = require('esprima'); +class JavaScriptObfuscator { + static obfuscate(sourceCode, options) { + let astTree = esprima.parse(sourceCode), obfuscator = new Obfuscator_1.Obfuscator(options); + obfuscator.obfuscateNode(astTree); + return JavaScriptObfuscator.generateCode(astTree); + } + static generateCode(astTree) { + return escodegen.generate(astTree, JavaScriptObfuscator.escodegenParams); + } +} +JavaScriptObfuscator.escodegenParams = { + format: {}, + verbatim: 'x-verbatim-property' +}; +exports.JavaScriptObfuscator = JavaScriptObfuscator; +module.exports = JavaScriptObfuscator; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/src/Obfuscator.js b/src/Obfuscator.js new file mode 100644 index 00000000..b3c86fc3 --- /dev/null +++ b/src/Obfuscator.js @@ -0,0 +1,89 @@ +"use strict"; +const AppendState_1 = require('./enums/AppendState'); +const FunctionDeclarationObfuscator_1 = require('./node-obfuscators/FunctionDeclarationObfuscator'); +const FunctionObfuscator_1 = require('./node-obfuscators/FunctionObfuscator'); +const LiteralObfuscator_1 = require('./node-obfuscators/LiteralObfuscator'); +const MemberExpressionObfuscator_1 = require('./node-obfuscators/MemberExpressionObfuscator'); +const MethodDefinitionObfuscator_1 = require('./node-obfuscators/MethodDefinitionObfuscator'); +const ObjectExpressionObfuscator_1 = require('./node-obfuscators/ObjectExpressionObfuscator'); +const UnicodeArrayNode_1 = require('./nodes/UnicodeArrayNode'); +const UnicodeArrayNodesGroup_1 = require('./node-groups/UnicodeArrayNodesGroup'); +const Utils_1 = require('./Utils'); +const VariableDeclarationObfuscator_1 = require('./node-obfuscators/VariableDeclarationObfuscator'); +let estraverse = require('estraverse'); +class Obfuscator { + constructor(options) { + this.nodes = new Map(); + this.nodeObfuscators = new Map([ + ['ClassDeclaration', [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator]], + ['FunctionDeclaration', [ + FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator, + FunctionObfuscator_1.FunctionObfuscator + ]], + ['ArrowFunctionExpression', [FunctionObfuscator_1.FunctionObfuscator]], + ['FunctionExpression', [FunctionObfuscator_1.FunctionObfuscator]], + ['MethodDefinition', [MethodDefinitionObfuscator_1.MethodDefinitionObfuscator]], + ['VariableDeclaration', [VariableDeclarationObfuscator_1.VariableDeclarationObfuscator]], + ['ObjectExpression', [ObjectExpressionObfuscator_1.ObjectExpressionObfuscator]], + ['MemberExpression', [MemberExpressionObfuscator_1.MemberExpressionObfuscator]], + ['Literal', [LiteralObfuscator_1.LiteralObfuscator]] + ]); + this.options = { + rotateUnicodeArray: true + }; + Object.assign(this.options, options); + } + obfuscateNode(node) { + if (this.options['rotateUnicodeArray']) { + this.setNodesGroup('unicodeArrayNodesGroup', new UnicodeArrayNodesGroup_1.UnicodeArrayNodesGroup(node)); + } + else { + this.setNode('unicodeArrayNode', new UnicodeArrayNode_1.UnicodeArrayNode(node, Utils_1.Utils.getRandomVariableName(UnicodeArrayNode_1.UnicodeArrayNode.UNICODE_ARRAY_RANDOM_LENGTH))); + } + this.beforeObfuscation(node); + estraverse.replace(node, { + leave: (node, parent) => this.nodeController(node, parent) + }); + this.afterObfuscation(node); + } + setNode(nodeName, node) { + this.nodes.set(nodeName, node); + } + setNodesGroup(groupName, nodesGroup) { + let nodes = nodesGroup.getNodes(); + nodes.forEach((node, key) => { + this.nodes.set(key, node); + }); + } + afterObfuscation(node) { + this.nodes.forEach((node) => { + if (node.getAppendState() === AppendState_1.AppendState.AfterObfuscation) { + node.appendNode(); + } + }); + } + beforeObfuscation(node) { + this.nodes.forEach((node) => { + if (node.getAppendState() === AppendState_1.AppendState.BeforeObfuscation) { + node.appendNode(); + } + }); + } + ; + nodeController(node, parent) { + switch (node.type) { + default: + this.initializeNodeObfuscators(node, parent); + } + } + initializeNodeObfuscators(node, parent) { + if (!this.nodeObfuscators.has(node.type)) { + return; + } + this.nodeObfuscators.get(node.type).forEach((obfuscator) => { + new obfuscator(this.nodes).obfuscateNode(node, parent); + }); + } +} +exports.Obfuscator = Obfuscator; +//# sourceMappingURL=Obfuscator.js.map \ No newline at end of file diff --git a/src/Utils.js b/src/Utils.js new file mode 100644 index 00000000..1cadc2b2 --- /dev/null +++ b/src/Utils.js @@ -0,0 +1,37 @@ +"use strict"; +class Utils { + static arrayRotate(array, times, reverse = false) { + if (times < 0) { + return; + } + let newArray = array, temp; + while (times--) { + if (!reverse) { + temp = newArray.pop(); + newArray.unshift(temp); + } + else { + temp = newArray.shift(); + newArray.push(temp); + } + } + return newArray; + } + static decToHex(dec) { + return (dec + Math.pow(16, 6)).toString(16).substr(-6); + } + static getRandomInteger(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + static getRandomVariableName(length = 6) { + const prefix = '_0x'; + return `${prefix}${(Utils.decToHex(Utils.getRandomInteger(10000, 9999999))).substr(0, length)}`; + } + static stringToUnicode(string) { + return `'${string.replace(/[\s\S]/g, (escape) => { + return `\\u${('0000' + escape.charCodeAt(0).toString(16)).slice(-4)}`; + })}'`; + } +} +exports.Utils = Utils; +//# sourceMappingURL=Utils.js.map \ No newline at end of file diff --git a/src/enums/AppendState.js b/src/enums/AppendState.js new file mode 100644 index 00000000..debe74a3 --- /dev/null +++ b/src/enums/AppendState.js @@ -0,0 +1,7 @@ +"use strict"; +(function (AppendState) { + AppendState[AppendState["BeforeObfuscation"] = 0] = "BeforeObfuscation"; + AppendState[AppendState["AfterObfuscation"] = 1] = "AfterObfuscation"; +})(exports.AppendState || (exports.AppendState = {})); +var AppendState = exports.AppendState; +//# sourceMappingURL=AppendState.js.map \ No newline at end of file diff --git a/src/interfaces/INode.js b/src/interfaces/INode.js new file mode 100644 index 00000000..7b4f01d1 --- /dev/null +++ b/src/interfaces/INode.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=INode.js.map \ No newline at end of file diff --git a/src/interfaces/INodeObfuscator.js b/src/interfaces/INodeObfuscator.js new file mode 100644 index 00000000..c8210376 --- /dev/null +++ b/src/interfaces/INodeObfuscator.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=INodeObfuscator.js.map \ No newline at end of file diff --git a/src/interfaces/INodesGroup.js b/src/interfaces/INodesGroup.js new file mode 100644 index 00000000..bb149a22 --- /dev/null +++ b/src/interfaces/INodesGroup.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=INodesGroup.js.map \ No newline at end of file diff --git a/src/node-groups/NodesGroup.js b/src/node-groups/NodesGroup.js new file mode 100644 index 00000000..76fd38f4 --- /dev/null +++ b/src/node-groups/NodesGroup.js @@ -0,0 +1,8 @@ +"use strict"; +class NodesGroup { + getNodes() { + return this.nodes; + } +} +exports.NodesGroup = NodesGroup; +//# sourceMappingURL=NodesGroup.js.map \ No newline at end of file diff --git a/src/node-groups/UnicodeArrayNodesGroup.js b/src/node-groups/UnicodeArrayNodesGroup.js new file mode 100644 index 00000000..9fa552ac --- /dev/null +++ b/src/node-groups/UnicodeArrayNodesGroup.js @@ -0,0 +1,29 @@ +"use strict"; +const NodesGroup_1 = require('./NodesGroup'); +const UnicodeArrayNode_1 = require('../nodes/UnicodeArrayNode'); +const UnicodeArrayRotateFunctionCallNode_1 = require('../nodes/UnicodeArrayRotateFunctionCallNode'); +const UnicodeArrayRotateFunctionNode_1 = require('../nodes/UnicodeArrayRotateFunctionNode'); +const Utils_1 = require('../Utils'); +class UnicodeArrayNodesGroup extends NodesGroup_1.NodesGroup { + constructor(astTree) { + super(); + this.unicodeArrayRotateFunctionIdentifier = Utils_1.Utils.getRandomVariableName(); + let unicodeArrayName = Utils_1.Utils.getRandomVariableName(UnicodeArrayNode_1.UnicodeArrayNode.UNICODE_ARRAY_RANDOM_LENGTH), unicodeArrayRotateValue = Utils_1.Utils.getRandomInteger(100, 500); + this.nodes = new Map([ + [ + 'unicodeArrayNode', + new UnicodeArrayNode_1.UnicodeArrayNode(astTree, unicodeArrayName, unicodeArrayRotateValue) + ], + [ + 'unicodeArrayRotateFunctionNode', + new UnicodeArrayRotateFunctionNode_1.UnicodeArrayRotateFunctionNode(astTree, this.unicodeArrayRotateFunctionIdentifier, unicodeArrayName) + ], + [ + 'unicodeArrayRotateFunctionCallNode', + new UnicodeArrayRotateFunctionCallNode_1.UnicodeArrayRotateFunctionCallNode(astTree, this.unicodeArrayRotateFunctionIdentifier, unicodeArrayName, unicodeArrayRotateValue) + ] + ]); + } +} +exports.UnicodeArrayNodesGroup = UnicodeArrayNodesGroup; +//# sourceMappingURL=UnicodeArrayNodesGroup.js.map \ No newline at end of file diff --git a/src/node-obfuscators/FunctionDeclarationObfuscator.js b/src/node-obfuscators/FunctionDeclarationObfuscator.js new file mode 100644 index 00000000..24c523d0 --- /dev/null +++ b/src/node-obfuscators/FunctionDeclarationObfuscator.js @@ -0,0 +1,37 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +const Utils_1 = require('../Utils'); +let estraverse = require('estraverse'); +class FunctionDeclarationObfuscator extends NodeObfuscator_1.NodeObfuscator { + constructor(...args) { + super(...args); + this.functionName = new Map(); + } + obfuscateNode(functionDeclarationNode, parentNode) { + if (parentNode.type === 'Program') { + return; + } + this.replaceFunctionName(functionDeclarationNode); + this.replaceFunctionCalls(parentNode); + } + replaceFunctionName(functionDeclarationNode) { + estraverse.replace(functionDeclarationNode.id, { + leave: (node) => { + if (node.type !== 'Identifier') { + return; + } + this.functionName.set(node.name, Utils_1.Utils.getRandomVariableName()); + node.name = this.functionName.get(node.name); + } + }); + } + replaceFunctionCalls(functionParentNode) { + estraverse.replace(functionParentNode, { + leave: (node, parentNode) => { + this.replaceNodeIdentifierByNewValue(node, parentNode, this.functionName); + } + }); + } +} +exports.FunctionDeclarationObfuscator = FunctionDeclarationObfuscator; +//# sourceMappingURL=FunctionDeclarationObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/FunctionObfuscator.js b/src/node-obfuscators/FunctionObfuscator.js new file mode 100644 index 00000000..be2b4155 --- /dev/null +++ b/src/node-obfuscators/FunctionObfuscator.js @@ -0,0 +1,36 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +const Utils_1 = require('../Utils'); +let estraverse = require('estraverse'); +class FunctionObfuscator extends NodeObfuscator_1.NodeObfuscator { + constructor(...args) { + super(...args); + this.functionParams = new Map(); + } + obfuscateNode(functionNode) { + this.replaceFunctionParams(functionNode); + this.replaceFunctionParamsInBody(functionNode); + } + replaceFunctionParams(functionNode) { + functionNode.params.forEach((paramsNode) => { + estraverse.replace(paramsNode, { + leave: (node, parentNode) => { + if (node.type !== 'Identifier') { + return; + } + this.functionParams.set(node.name, Utils_1.Utils.getRandomVariableName()); + node.name = this.functionParams.get(node.name); + } + }); + }); + } + replaceFunctionParamsInBody(functionNode) { + estraverse.replace(functionNode.body, { + leave: (node, parentNode) => { + this.replaceNodeIdentifierByNewValue(node, parentNode, this.functionParams); + } + }); + } +} +exports.FunctionObfuscator = FunctionObfuscator; +//# sourceMappingURL=FunctionObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/LiteralObfuscator.js b/src/node-obfuscators/LiteralObfuscator.js new file mode 100644 index 00000000..fd4fc1e3 --- /dev/null +++ b/src/node-obfuscators/LiteralObfuscator.js @@ -0,0 +1,23 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +let escodegen = require('escodegen'), estraverse = require('estraverse'); +class LiteralObfuscator extends NodeObfuscator_1.NodeObfuscator { + obfuscateNode(literalNode, parentNode) { + if (parentNode.type === 'Property' && parentNode.key === literalNode) { + return; + } + switch (typeof literalNode.value) { + case 'string': + if (literalNode['x-verbatim-property']) { + break; + } + literalNode['x-verbatim-property'] = { + content: this.replaceLiteralStringByArrayElement(literalNode.value), + precedence: escodegen.Precedence.Primary + }; + break; + } + } +} +exports.LiteralObfuscator = LiteralObfuscator; +//# sourceMappingURL=LiteralObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/MemberExpressionObfuscator.js b/src/node-obfuscators/MemberExpressionObfuscator.js new file mode 100644 index 00000000..54986032 --- /dev/null +++ b/src/node-obfuscators/MemberExpressionObfuscator.js @@ -0,0 +1,49 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +let escodegen = require('escodegen'), estraverse = require('estraverse'); +class MemberExpressionObfuscator extends NodeObfuscator_1.NodeObfuscator { + obfuscateNode(memberExpressionNode) { + estraverse.replace(memberExpressionNode.property, { + leave: (node, parentNode) => { + switch (node.type) { + case 'Literal': + this.literalNodeController(node); + break; + case 'Identifier': + if (memberExpressionNode.computed) { + break; + } + memberExpressionNode.computed = true; + this.identifierNodeController(node); + break; + } + } + }); + } + identifierNodeController(node) { + let nodeValue = node['name']; + node['type'] = 'Literal'; + node['value'] = nodeValue; + node['raw'] = `'${nodeValue}'`; + node['x-verbatim-property'] = { + content: this.replaceLiteralStringByArrayElement(nodeValue), + precedence: escodegen['Precedence']['Primary'] + }; + delete node['name']; + } + literalNodeController(node) { + switch (typeof node.value) { + case 'string': + if (node['x-verbatim-property']) { + break; + } + node['x-verbatim-property'] = { + content: this.replaceLiteralStringByArrayElement(node.value), + precedence: escodegen['Precedence']['Primary'] + }; + break; + } + } +} +exports.MemberExpressionObfuscator = MemberExpressionObfuscator; +//# sourceMappingURL=MemberExpressionObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/MethodDefinitionObfuscator.js b/src/node-obfuscators/MethodDefinitionObfuscator.js new file mode 100644 index 00000000..2a0a4b97 --- /dev/null +++ b/src/node-obfuscators/MethodDefinitionObfuscator.js @@ -0,0 +1,28 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +let estraverse = require('estraverse'); +class MethodDefinitionObfuscator extends NodeObfuscator_1.NodeObfuscator { + constructor(...args) { + super(...args); + this.methodName = new Map(); + this.ignoredNames = ['constructor']; + } + obfuscateNode(methodDefinitionNode, parentNode) { + this.replaceMethodName(methodDefinitionNode); + } + replaceMethodName(methodDefinitionNode) { + estraverse.replace(methodDefinitionNode.key, { + leave: (node) => { + if (node.type !== 'Identifier' || + this.ignoredNames.indexOf(node.name) >= 0 || + methodDefinitionNode.computed === true) { + return; + } + methodDefinitionNode.computed = true; + node.name = this.replaceLiteralStringByArrayElement(node.name); + } + }); + } +} +exports.MethodDefinitionObfuscator = MethodDefinitionObfuscator; +//# sourceMappingURL=MethodDefinitionObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/NodeObfuscator.js b/src/node-obfuscators/NodeObfuscator.js new file mode 100644 index 00000000..8f517528 --- /dev/null +++ b/src/node-obfuscators/NodeObfuscator.js @@ -0,0 +1,29 @@ +"use strict"; +const Utils_1 = require('../Utils'); +class NodeObfuscator { + constructor(nodes) { + this.nodes = nodes; + } + replaceNodeIdentifierByNewValue(node, parentNode, namesMap) { + if (node.type === 'Identifier' && namesMap.has(node.name)) { + if ((parentNode.type === 'Property' && parentNode.key === node) || + (parentNode.type === 'MemberExpression' && parentNode.computed === false && parentNode.property === node)) { + return; + } + node.name = namesMap.get(node.name); + } + } + replaceLiteralStringByArrayElement(nodeValue) { + let value = Utils_1.Utils.stringToUnicode(nodeValue), unicodeArray = this.nodes.get('unicodeArrayNode').getNodeData(), sameIndex = unicodeArray.indexOf(value), index; + if (sameIndex < 0) { + index = unicodeArray.length; + unicodeArray.push(Utils_1.Utils.stringToUnicode(nodeValue)); + } + else { + index = sameIndex; + } + return `${this.nodes.get('unicodeArrayNode').getNodeIdentifier()}[${index}]`; + } +} +exports.NodeObfuscator = NodeObfuscator; +//# sourceMappingURL=NodeObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/ObjectExpressionObfuscator.js b/src/node-obfuscators/ObjectExpressionObfuscator.js new file mode 100644 index 00000000..29e1e8c2 --- /dev/null +++ b/src/node-obfuscators/ObjectExpressionObfuscator.js @@ -0,0 +1,48 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +const Utils_1 = require('../Utils'); +let escodegen = require('escodegen'), estraverse = require('estraverse'); +class ObjectExpressionObfuscator extends NodeObfuscator_1.NodeObfuscator { + obfuscateNode(objectExpressionNode) { + objectExpressionNode.properties.forEach((property) => { + estraverse.replace(property.key, { + leave: (node, parentNode) => { + switch (node.type) { + case 'Literal': + this.literalNodeController(node); + break; + case 'Identifier': + this.identifierNodeController(node); + break; + } + } + }); + }); + } + literalNodeController(node) { + switch (typeof node.value) { + case 'string': + if (node['x-verbatim-property']) { + break; + } + node['x-verbatim-property'] = { + content: Utils_1.Utils.stringToUnicode(node.value), + precedence: escodegen['Precedence']['Primary'] + }; + break; + } + } + identifierNodeController(node) { + let nodeValue = node['name']; + node['type'] = 'Literal'; + node['value'] = nodeValue; + node['raw'] = `'${nodeValue}'`; + node['x-verbatim-property'] = { + content: Utils_1.Utils.stringToUnicode(nodeValue), + precedence: escodegen['Precedence']['Primary'] + }; + delete node['name']; + } +} +exports.ObjectExpressionObfuscator = ObjectExpressionObfuscator; +//# sourceMappingURL=ObjectExpressionObfuscator.js.map \ No newline at end of file diff --git a/src/node-obfuscators/VariableDeclarationObfuscator.js b/src/node-obfuscators/VariableDeclarationObfuscator.js new file mode 100644 index 00000000..6adc67e9 --- /dev/null +++ b/src/node-obfuscators/VariableDeclarationObfuscator.js @@ -0,0 +1,43 @@ +"use strict"; +const NodeObfuscator_1 = require('./NodeObfuscator'); +const Utils_1 = require('../Utils'); +let estraverse = require('estraverse'); +class VariableDeclarationObfuscator extends NodeObfuscator_1.NodeObfuscator { + constructor(...args) { + super(...args); + this.variableName = new Map(); + } + obfuscateNode(variableDeclarationNode, parentNode) { + if (parentNode.type === 'Program') { + return; + } + this.replaceVariableName(variableDeclarationNode); + this.replaceVariableCalls(parentNode); + } + replaceVariableName(variableDeclarationNode) { + variableDeclarationNode.declarations.forEach((declarationNode) => { + estraverse.replace(declarationNode, { + leave: (node) => { + if (node.type !== 'VariableDeclarator') { + return; + } + estraverse.replace(node.id, { + leave: (node) => { + this.variableName.set(node.name, Utils_1.Utils.getRandomVariableName()); + node.name = this.variableName.get(node.name); + } + }); + } + }); + }); + } + replaceVariableCalls(variableParentNode) { + estraverse.replace(variableParentNode, { + leave: (node, parentNode) => { + this.replaceNodeIdentifierByNewValue(node, parentNode, this.variableName); + } + }); + } +} +exports.VariableDeclarationObfuscator = VariableDeclarationObfuscator; +//# sourceMappingURL=VariableDeclarationObfuscator.js.map \ No newline at end of file diff --git a/src/nodes/Node.js b/src/nodes/Node.js new file mode 100644 index 00000000..8fbba11e --- /dev/null +++ b/src/nodes/Node.js @@ -0,0 +1,21 @@ +"use strict"; +const AppendState_1 = require('../enums/AppendState'); +class Node { + constructor() { + this.appendState = AppendState_1.AppendState.BeforeObfuscation; + } + getAppendState() { + return this.appendState; + } + getNode() { + return this.node; + } + setNode(node) { + this.node = node; + } + updateNode() { + this.node = this.getNodeStructure(); + } +} +exports.Node = Node; +//# sourceMappingURL=Node.js.map \ No newline at end of file diff --git a/src/nodes/UnicodeArrayNode.js b/src/nodes/UnicodeArrayNode.js new file mode 100644 index 00000000..667878cf --- /dev/null +++ b/src/nodes/UnicodeArrayNode.js @@ -0,0 +1,70 @@ +"use strict"; +const Node_1 = require('./Node'); +const Utils_1 = require('../Utils'); +const AppendState_1 = require('../enums/AppendState'); +let escodegen = require('escodegen'), estraverse = require('estraverse'); +class UnicodeArrayNode extends Node_1.Node { + constructor(astTree, unicodeArrayName, unicodeArrayRotateValue = 0) { + super(); + this.appendState = AppendState_1.AppendState.AfterObfuscation; + this.unicodeArray = []; + this.astTree = astTree; + this.unicodeArrayName = unicodeArrayName; + this.unicodeArrayRotateValue = unicodeArrayRotateValue; + this.node = this.getNodeStructure(); + } + appendNode() { + estraverse.replace(this.astTree, { + leave: (node, parent) => { + switch (node.type) { + case 'Program': + node.body.unshift(this.getNode()); + break; + } + } + }); + } + getNodeIdentifier() { + return this.unicodeArrayName; + } + getNodeData() { + return this.unicodeArray; + } + getNode() { + Utils_1.Utils.arrayRotate(this.unicodeArray, this.unicodeArrayRotateValue); + this.updateNode(); + return this.node; + } + getNodeStructure() { + return { + 'type': 'VariableDeclaration', + 'declarations': [ + { + 'type': 'VariableDeclarator', + 'id': { + 'type': 'Identifier', + 'name': this.unicodeArrayName + }, + 'init': { + 'type': 'ArrayExpression', + 'elements': this.unicodeArray.map((value) => { + return { + 'type': 'Literal', + 'value': value, + 'raw': `'${value}'`, + 'x-verbatim-property': { + 'content': value, + precedence: escodegen.Precedence.Primary + } + }; + }) + } + } + ], + 'kind': 'var' + }; + } +} +UnicodeArrayNode.UNICODE_ARRAY_RANDOM_LENGTH = 4; +exports.UnicodeArrayNode = UnicodeArrayNode; +//# sourceMappingURL=UnicodeArrayNode.js.map \ No newline at end of file diff --git a/src/nodes/UnicodeArrayRotateFunctionCallNode.js b/src/nodes/UnicodeArrayRotateFunctionCallNode.js new file mode 100644 index 00000000..1afc9a39 --- /dev/null +++ b/src/nodes/UnicodeArrayRotateFunctionCallNode.js @@ -0,0 +1,54 @@ +"use strict"; +const Node_1 = require('./Node'); +let estraverse = require('estraverse'); +class UnicodeArrayRotateFunctionCallNode extends Node_1.Node { + constructor(astTree, unicodeArrayRotateFunctionName, unicodeArrayName, unicodeArrayRotateValue) { + super(); + this.astTree = astTree; + this.unicodeArrayRotateFunctionName = unicodeArrayRotateFunctionName; + this.unicodeArrayName = unicodeArrayName; + this.unicodeArrayRotateValue = unicodeArrayRotateValue; + this.node = this.getNodeStructure(); + } + appendNode() { + estraverse.replace(this.astTree, { + leave: (node, parent) => { + switch (node.type) { + case 'Program': + node.body.unshift(this.getNode()); + break; + } + } + }); + } + getNodeStructure() { + return { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'CallExpression', + 'callee': { + 'type': 'Identifier', + 'name': this.unicodeArrayRotateFunctionName + }, + 'arguments': [ + { + 'type': 'Identifier', + 'name': this.unicodeArrayName + }, + { + 'type': 'Literal', + 'value': this.unicodeArrayRotateValue, + 'raw': `'${this.unicodeArrayRotateValue}'` + }, + { + 'type': 'Literal', + 'value': true, + 'raw': 'true' + } + ] + } + }; + } +} +exports.UnicodeArrayRotateFunctionCallNode = UnicodeArrayRotateFunctionCallNode; +//# sourceMappingURL=UnicodeArrayRotateFunctionCallNode.js.map \ No newline at end of file diff --git a/src/nodes/UnicodeArrayRotateFunctionNode.js b/src/nodes/UnicodeArrayRotateFunctionNode.js new file mode 100644 index 00000000..f0125856 --- /dev/null +++ b/src/nodes/UnicodeArrayRotateFunctionNode.js @@ -0,0 +1,269 @@ +"use strict"; +const Node_1 = require('./Node'); +const Utils_1 = require('../Utils'); +let estraverse = require('estraverse'); +class UnicodeArrayRotateFunctionNode extends Node_1.Node { + constructor(astTree, unicodeArrayRotateFunctionName, unicodeArrayName) { + super(); + this.astTree = astTree; + this.unicodeArrayRotateFunctionName = unicodeArrayRotateFunctionName; + this.unicodeArrayName = unicodeArrayName; + this.node = this.getNodeStructure(); + } + appendNode() { + estraverse.replace(this.astTree, { + leave: (node, parent) => { + switch (node.type) { + case 'Program': + node.body.push(this.getNode()); + break; + } + } + }); + } + getNodeIdentifier() { + return this.unicodeArrayRotateFunctionName; + } + getNodeStructure() { + return { + 'type': 'FunctionExpression', + 'id': { + 'type': 'Identifier', + 'name': this.unicodeArrayRotateFunctionName + }, + 'params': [ + { + 'type': 'Identifier', + 'name': 'array' + }, + { + 'type': 'Identifier', + 'name': 'times' + }, + { + 'type': 'Identifier', + 'name': 'reverse' + } + ], + 'defaults': [], + 'body': { + 'type': 'BlockStatement', + 'body': [ + { + 'type': 'IfStatement', + 'test': { + 'type': 'BinaryExpression', + 'operator': '<', + 'left': { + 'type': 'Identifier', + 'name': 'times' + }, + 'right': { + 'type': 'Literal', + 'value': 0, + 'raw': '0' + } + }, + 'consequent': { + 'type': 'BlockStatement', + 'body': [ + { + 'type': 'ReturnStatement', + 'argument': null + } + ] + }, + 'alternate': null + }, + { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'AssignmentExpression', + 'operator': '=', + 'left': { + 'type': 'Identifier', + 'name': 'reverse' + }, + 'right': { + 'type': 'LogicalExpression', + 'operator': '||', + 'left': { + 'type': 'Identifier', + 'name': 'reverse' + }, + 'right': { + 'type': 'Literal', + 'value': false, + 'raw': 'false' + } + } + } + }, + { + 'type': 'VariableDeclaration', + 'declarations': [ + { + 'type': 'VariableDeclarator', + 'id': { + 'type': 'Identifier', + 'name': 'temp' + }, + 'init': null + } + ], + 'kind': 'var' + }, + { + 'type': 'WhileStatement', + 'test': { + 'type': 'UpdateExpression', + 'operator': '--', + 'argument': { + 'type': 'Identifier', + 'name': 'times' + }, + 'prefix': false + }, + 'body': { + 'type': 'BlockStatement', + 'body': [ + { + 'type': 'IfStatement', + 'test': { + 'type': 'UnaryExpression', + 'operator': '!', + 'argument': { + 'type': 'Identifier', + 'name': 'reverse' + }, + 'prefix': true + }, + 'consequent': { + 'type': 'BlockStatement', + 'body': [ + { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'AssignmentExpression', + 'operator': '=', + 'left': { + 'type': 'Identifier', + 'name': 'temp' + }, + 'right': { + 'type': 'CallExpression', + 'callee': { + 'type': 'MemberExpression', + 'computed': true, + 'object': { + 'type': 'Identifier', + 'name': 'array' + }, + 'property': { + 'type': 'Literal', + 'name': 'pop', + 'x-verbatim-property': Utils_1.Utils.stringToUnicode('pop') + } + }, + 'arguments': [] + } + } + }, + { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'CallExpression', + 'callee': { + 'type': 'MemberExpression', + 'computed': true, + 'object': { + 'type': 'Identifier', + 'name': 'array' + }, + 'property': { + 'type': 'Literal', + 'name': 'unshift', + 'x-verbatim-property': Utils_1.Utils.stringToUnicode('unshift') + } + }, + 'arguments': [ + { + 'type': 'Identifier', + 'name': 'temp' + } + ] + } + } + ] + }, + 'alternate': { + 'type': 'BlockStatement', + 'body': [ + { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'AssignmentExpression', + 'operator': '=', + 'left': { + 'type': 'Identifier', + 'name': 'temp' + }, + 'right': { + 'type': 'CallExpression', + 'callee': { + 'type': 'MemberExpression', + 'computed': true, + 'object': { + 'type': 'Identifier', + 'name': 'array' + }, + 'property': { + 'type': 'Literal', + 'name': 'shift', + 'x-verbatim-property': Utils_1.Utils.stringToUnicode('shift') + } + }, + 'arguments': [] + } + } + }, + { + 'type': 'ExpressionStatement', + 'expression': { + 'type': 'CallExpression', + 'callee': { + 'type': 'MemberExpression', + 'computed': true, + 'object': { + 'type': 'Identifier', + 'name': 'array' + }, + 'property': { + 'type': 'Literal', + 'name': 'push', + 'x-verbatim-property': Utils_1.Utils.stringToUnicode('push') + } + }, + 'arguments': [ + { + 'type': 'Identifier', + 'name': 'temp' + } + ] + } + } + ] + } + } + ] + } + } + ] + }, + 'generator': false, + 'expression': false + }; + } +} +exports.UnicodeArrayRotateFunctionNode = UnicodeArrayRotateFunctionNode; +//# sourceMappingURL=UnicodeArrayRotateFunctionNode.js.map \ No newline at end of file