mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Syncing with master
This commit is contained in:
@@ -4,3 +4,4 @@
|
||||
coverage
|
||||
images
|
||||
test/fixtures/compile-performance.js
|
||||
test-tmp
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
Change Log
|
||||
===
|
||||
v0.14.3
|
||||
---
|
||||
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/195
|
||||
|
||||
v0.14.2
|
||||
---
|
||||
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/181
|
||||
|
||||
v0.14.1
|
||||
---
|
||||
* Temporary fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/181
|
||||
|
||||
v0.14.0
|
||||
---
|
||||
* **New option:** `identifiersPrefix` sets prefix for all generated identifiers.
|
||||
|
||||
Vendored
+1
-10051
File diff suppressed because one or more lines are too long
+6
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "0.14.0",
|
||||
"version": "0.14.3",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
@@ -19,7 +19,7 @@
|
||||
"javascript-obfuscator": "./bin/javascript-obfuscator"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "2.3.0",
|
||||
"chalk": "2.3.1",
|
||||
"chance": "1.0.13",
|
||||
"class-validator": "0.8.1",
|
||||
"commander": "2.14.1",
|
||||
@@ -47,7 +47,7 @@
|
||||
"@types/md5": "2.1.32",
|
||||
"@types/mkdirp": "0.5.2",
|
||||
"@types/mocha": "2.2.48",
|
||||
"@types/node": "9.4.5",
|
||||
"@types/node": "9.4.6",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"@types/sinon": "4.1.3",
|
||||
"@types/string-template": "1.0.2",
|
||||
@@ -60,17 +60,17 @@
|
||||
"chai": "4.1.2",
|
||||
"coveralls": "3.0.0",
|
||||
"istanbul": "1.1.0-alpha.1",
|
||||
"mocha": "5.0.0",
|
||||
"mocha": "5.0.1",
|
||||
"pre-commit": "1.2.2",
|
||||
"rimraf": "2.6.2",
|
||||
"sinon": "4.3.0",
|
||||
"threads": "0.10.1",
|
||||
"ts-node": "4.1.0",
|
||||
"tslint": "5.9.1",
|
||||
"tslint-eslint-rules": "4.1.1",
|
||||
"tslint-eslint-rules": "5.0.0",
|
||||
"tslint-language-service": "0.9.8",
|
||||
"tslint-webpack-plugin": "1.1.1",
|
||||
"typescript": "2.7.1",
|
||||
"typescript": "2.7.2",
|
||||
"webpack": "3.11.0",
|
||||
"webpack-node-externals": "1.6.0"
|
||||
},
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { inject, injectable, } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import * as estraverse from 'estraverse';
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TNodeWithScope } from '../../types/node/TNodeWithScope';
|
||||
import { TStatement } from '../../types/node/TStatement';
|
||||
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
@@ -12,6 +16,7 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { Nodes } from '../../node/Nodes';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
/**
|
||||
* Transform ES2015 template literals to ES5
|
||||
@@ -47,6 +52,11 @@ export class TemplateLiteralTransformer extends AbstractNodeTransformer {
|
||||
case TransformationStage.Converting:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (parentNode && NodeGuards.isReturnStatementNode(node) && node.argument === null) {
|
||||
return this.fixEsprimaReturnStatementTemplateLiteralNode(node);
|
||||
}
|
||||
},
|
||||
leave: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (parentNode && NodeGuards.isTemplateLiteralNode(node)) {
|
||||
return this.transformNode(node, parentNode);
|
||||
}
|
||||
@@ -66,7 +76,7 @@ export class TemplateLiteralTransformer extends AbstractNodeTransformer {
|
||||
public transformNode (templateLiteralNode: ESTree.TemplateLiteral, parentNode: ESTree.Node): ESTree.Node {
|
||||
const templateLiteralExpressions: ESTree.Expression[] = templateLiteralNode.expressions;
|
||||
|
||||
let nodes: (ESTree.Literal | ESTree.Expression)[] = [];
|
||||
let nodes: ESTree.Expression[] = [];
|
||||
|
||||
templateLiteralNode.quasis.forEach((templateElement: ESTree.TemplateElement) => {
|
||||
nodes.push(Nodes.getLiteralNode(templateElement.value.cooked));
|
||||
@@ -109,4 +119,56 @@ export class TemplateLiteralTransformer extends AbstractNodeTransformer {
|
||||
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReturnStatement} returnStatementNode
|
||||
* @returns {Node | VisitorOption}
|
||||
*/
|
||||
private fixEsprimaReturnStatementTemplateLiteralNode (returnStatementNode: ESTree.ReturnStatement): ESTree.Node | void {
|
||||
const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(returnStatementNode);
|
||||
const scopeBody: TStatement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
|
||||
? scopeNode.body
|
||||
: scopeNode.consequent;
|
||||
const indexInScope: number = scopeBody.indexOf(returnStatementNode);
|
||||
|
||||
// in incorrect AST-tree return statement node should be penultimate
|
||||
if (indexInScope !== scopeBody.length - 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextSiblingStatementNode: TStatement | null = scopeBody[indexInScope + 1];
|
||||
|
||||
if (!nextSiblingStatementNode || !NodeGuards.isExpressionStatementNode(nextSiblingStatementNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isSiblingStatementHasTemplateLiteralNode: boolean = false;
|
||||
|
||||
estraverse.traverse(nextSiblingStatementNode, {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): void | estraverse.VisitorOption => {
|
||||
if (!NodeGuards.isTemplateLiteralNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSiblingStatementHasTemplateLiteralNode = true;
|
||||
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isSiblingStatementHasTemplateLiteralNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
returnStatementNode.argument = nextSiblingStatementNode.expression;
|
||||
scopeBody.pop();
|
||||
|
||||
if (!NodeGuards.isSwitchCaseNode(scopeNode)) {
|
||||
scopeNode.body = [...scopeBody];
|
||||
} else {
|
||||
scopeNode.consequent = <ESTree.Statement[]>[...scopeBody];
|
||||
}
|
||||
|
||||
return returnStatementNode;
|
||||
}
|
||||
}
|
||||
|
||||
+104
-25
@@ -6,6 +6,7 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TDeadNodeInjectionCustomNodeFactory } from '../../types/container/custom-nodes/TDeadNodeInjectionCustomNodeFactory';
|
||||
import { TNodeWithBlockScope } from '../../types/node/TNodeWithBlockScope';
|
||||
import { TNodeWithScope } from '../../types/node/TNodeWithScope';
|
||||
|
||||
import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
@@ -97,15 +98,62 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} blockStatementNode
|
||||
* @param {Node} targetNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isValidBlockStatementNode (blockStatementNode: ESTree.Node): boolean {
|
||||
const isProhibitedNode: (node: ESTree.Node) => boolean =
|
||||
(node: ESTree.Node): boolean => NodeGuards.isBreakStatementNode(node) ||
|
||||
NodeGuards.isContinueStatementNode(node) ||
|
||||
NodeGuards.isAwaitExpressionNode(node) ||
|
||||
NodeGuards.isSuperNode(node);
|
||||
private static isProhibitedNodeInsideCollectedBlockStatement (targetNode: ESTree.Node): boolean {
|
||||
return NodeGuards.isBreakStatementNode(targetNode)
|
||||
|| NodeGuards.isContinueStatementNode(targetNode)
|
||||
|| NodeGuards.isAwaitExpressionNode(targetNode)
|
||||
|| NodeGuards.isSuperNode(targetNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} targetNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isScopeHoistingFunctionDeclaration (targetNode: ESTree.Node): boolean {
|
||||
if (!NodeGuards.isFunctionDeclarationNode(targetNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(targetNode);
|
||||
const scopeBody: ESTree.Statement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
|
||||
? <ESTree.Statement[]>scopeNode.body
|
||||
: scopeNode.consequent;
|
||||
const indexInScope: number = scopeBody.indexOf(targetNode);
|
||||
|
||||
if (indexInScope === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const slicedBody: ESTree.Statement[] = scopeBody.slice(0, indexInScope);
|
||||
const hostBlockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode(slicedBody);
|
||||
const functionDeclarationName: string = targetNode.id.name;
|
||||
|
||||
let isScopeHoistedFunctionDeclaration: boolean = false;
|
||||
|
||||
estraverse.traverse(hostBlockStatementNode, {
|
||||
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
|
||||
if (NodeGuards.isIdentifierNode(node) && node.name === functionDeclarationName) {
|
||||
isScopeHoistedFunctionDeclaration = true;
|
||||
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return isScopeHoistedFunctionDeclaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BlockStatement} blockStatementNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isValidCollectedBlockStatementNode (blockStatementNode: ESTree.BlockStatement): boolean {
|
||||
if (!blockStatementNode.body.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let nestedBlockStatementsCount: number = 0;
|
||||
let isValidBlockStatementNode: boolean = true;
|
||||
@@ -117,8 +165,9 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
|
||||
if (
|
||||
nestedBlockStatementsCount > DeadCodeInjectionTransformer.maxNestedBlockStatementsCount ||
|
||||
isProhibitedNode(node)
|
||||
nestedBlockStatementsCount > DeadCodeInjectionTransformer.maxNestedBlockStatementsCount
|
||||
|| DeadCodeInjectionTransformer.isProhibitedNodeInsideCollectedBlockStatement(node)
|
||||
|| DeadCodeInjectionTransformer.isScopeHoistingFunctionDeclaration(node)
|
||||
) {
|
||||
isValidBlockStatementNode = false;
|
||||
|
||||
@@ -130,6 +179,37 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
return isValidBlockStatementNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BlockStatement} blockStatementNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isValidWrappedBlockStatementNode (blockStatementNode: ESTree.BlockStatement): boolean {
|
||||
if (!blockStatementNode.body.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let isValidBlockStatementNode: boolean = true;
|
||||
|
||||
estraverse.traverse(blockStatementNode, {
|
||||
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
|
||||
if (DeadCodeInjectionTransformer.isScopeHoistingFunctionDeclaration(node)) {
|
||||
isValidBlockStatementNode = false;
|
||||
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!isValidBlockStatementNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const blockScopeOfBlockStatementNode: TNodeWithBlockScope = NodeUtils
|
||||
.getBlockScopesOfNode(blockStatementNode)[0];
|
||||
|
||||
return blockScopeOfBlockStatementNode.type !== NodeType.Program;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TransformationStage} transformationStage
|
||||
* @returns {IVisitor | null}
|
||||
@@ -183,7 +263,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
|
||||
let clonedBlockStatementNode: ESTree.BlockStatement = NodeUtils.clone(node);
|
||||
|
||||
if (!DeadCodeInjectionTransformer.isValidBlockStatementNode(clonedBlockStatementNode)) {
|
||||
if (!DeadCodeInjectionTransformer.isValidCollectedBlockStatementNode(clonedBlockStatementNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -209,23 +289,21 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
* @param {NodeGuards} parentNode
|
||||
* @returns {NodeGuards | VisitorOption}
|
||||
*/
|
||||
public transformNode (blockStatementNode: ESTree.BlockStatement, parentNode: ESTree.Node): ESTree.Node | estraverse.VisitorOption {
|
||||
if (this.collectedBlockStatementsTotalLength < DeadCodeInjectionTransformer.minCollectedBlockStatementsCount) {
|
||||
public transformNode (
|
||||
blockStatementNode: ESTree.BlockStatement,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Node | estraverse.VisitorOption {
|
||||
const canBreakTraverse: boolean = !this.collectedBlockStatements.length
|
||||
|| this.collectedBlockStatementsTotalLength < DeadCodeInjectionTransformer.minCollectedBlockStatementsCount;
|
||||
|
||||
if (canBreakTraverse) {
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
|
||||
if (!this.collectedBlockStatements.length) {
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
|
||||
if (this.randomGenerator.getMathRandom() > this.options.deadCodeInjectionThreshold) {
|
||||
return blockStatementNode;
|
||||
}
|
||||
|
||||
const blockScopeOfBlockStatementNode: TNodeWithBlockScope = NodeUtils
|
||||
.getBlockScopesOfNode(blockStatementNode)[0];
|
||||
|
||||
if (blockScopeOfBlockStatementNode.type === NodeType.Program) {
|
||||
if (
|
||||
this.randomGenerator.getMathRandom() > this.options.deadCodeInjectionThreshold
|
||||
|| !DeadCodeInjectionTransformer.isValidWrappedBlockStatementNode(blockStatementNode)
|
||||
) {
|
||||
return blockStatementNode;
|
||||
}
|
||||
|
||||
@@ -233,8 +311,9 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
|
||||
const maxInteger: number = this.collectedBlockStatements.length - 1;
|
||||
const randomIndex: number = this.randomGenerator.getRandomInteger(minInteger, maxInteger);
|
||||
const randomBlockStatementNode: ESTree.BlockStatement = this.collectedBlockStatements.splice(randomIndex, 1)[0];
|
||||
const isDuplicateBlockStatementNodes: boolean = randomBlockStatementNode === blockStatementNode;
|
||||
|
||||
if (randomBlockStatementNode === blockStatementNode) {
|
||||
if (isDuplicateBlockStatementNodes) {
|
||||
return blockStatementNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,22 @@ export class NodeUtils {
|
||||
return NodeUtils.getBlockScopesOfNodeRecursive(targetNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Statement} node
|
||||
* @returns {TStatement | null}
|
||||
*/
|
||||
public static getNextSiblingStatementNode (node: ESTree.Statement): TStatement | null {
|
||||
return NodeUtils.getSiblingStatementNodeByOffset(node, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Statement} node
|
||||
* @returns {TStatement | null}
|
||||
*/
|
||||
public static getPreviousSiblingStatementNode (node: ESTree.Statement): TStatement | null {
|
||||
return NodeUtils.getSiblingStatementNodeByOffset(node, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NodeGuards} node
|
||||
* @returns {TNodeWithScope}
|
||||
@@ -208,4 +224,19 @@ export class NodeUtils {
|
||||
|
||||
return blockScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Statement} node
|
||||
* @param {number} offset
|
||||
* @returns {TStatement | null}
|
||||
*/
|
||||
private static getSiblingStatementNodeByOffset (node: ESTree.Statement, offset: number): TStatement | null {
|
||||
const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(node);
|
||||
const scopeBody: TStatement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
|
||||
? scopeNode.body
|
||||
: scopeNode.consequent;
|
||||
const indexInScope: number = scopeBody.indexOf(node);
|
||||
|
||||
return scopeBody[indexInScope + offset] || null;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-5
@@ -7,18 +7,40 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
(function(){
|
||||
var foo = 'foo'; var bar = 'bar'; var bark = foo + bar,; var baz = 'baz';
|
||||
function foo () {
|
||||
var a = 1;
|
||||
inner1();
|
||||
var b = 2;
|
||||
function inner1 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function bar () {
|
||||
var a = 1;
|
||||
}
|
||||
function baz () {
|
||||
var a = 1;
|
||||
}
|
||||
function bark () {
|
||||
var a = 1;
|
||||
}
|
||||
function hawk () {
|
||||
var a = 1;
|
||||
}
|
||||
function eagle () {
|
||||
var a = 1;
|
||||
}
|
||||
})();
|
||||
`,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
compact: false,
|
||||
identifiersPrefix: 'foo',
|
||||
identifierNamesGenerator: 'mangled',
|
||||
renameGlobals: true
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
deadCodeInjection: true,
|
||||
deadCodeInjectionThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
console.log(obfuscatedCode);
|
||||
console.log(eval(obfuscatedCode));
|
||||
})();
|
||||
})();
|
||||
+70
-3
@@ -24,7 +24,74 @@ describe('TemplateLiteralTransformer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #1: simple template literal with expression only', () => {
|
||||
describe('variant #2: multiline template literals', () => {
|
||||
it('variant #1: should transform es6 multiline template literal to es5', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
);
|
||||
|
||||
assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'foo\\x0abar';$/);
|
||||
});
|
||||
|
||||
it('variant #2: should transform es6 multiline template literal inside return statement', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-return-statement-1.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
);
|
||||
|
||||
assert.match(obfuscationResult.getObfuscatedCode(), /{ *return *'foo\\x0abar'; *}$/);
|
||||
});
|
||||
|
||||
it('variant #3: should transform es6 multiline template literal inside return statement', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-return-statement-2.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
);
|
||||
|
||||
assert.match(obfuscationResult.getObfuscatedCode(), /case *!!\[] *: *return *'foo\\x0abar'; *} *}$/);
|
||||
});
|
||||
|
||||
it('variant #4: should transform es6 multiline template literal inside binary expression inside return statement', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-binary-expression-return-statement-1.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
);
|
||||
|
||||
assert.match(obfuscationResult.getObfuscatedCode(), /{ *return *'foo\\x0abar' *\+ *0x1; *}$/);
|
||||
});
|
||||
|
||||
it('variant #5: should transform es6 multiline template literal inside binary expression inside return statement', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-binary-expression-return-statement-2.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
unicodeEscapeSequence: false
|
||||
}
|
||||
);
|
||||
|
||||
assert.match(obfuscationResult.getObfuscatedCode(), /case *!!\[] *: *return *'foo\\x0abar' *\+ *0x1; *} *}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #3: simple template literal with expression only', () => {
|
||||
it('should transform es6 template literal to es5 and add empty literal node before expression node', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/expression-only.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
@@ -39,7 +106,7 @@ describe('TemplateLiteralTransformer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #3: literal node inside expression', () => {
|
||||
describe('variant #4: literal node inside expression', () => {
|
||||
it('should transform es6 template literal to es5', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/literal-inside-expression.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
@@ -54,7 +121,7 @@ describe('TemplateLiteralTransformer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #4: multiple expressions', () => {
|
||||
describe('variant #5: multiple expressions', () => {
|
||||
it('should transform es6 template literal to es5', () => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/multiple-expressions.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
function foo() {
|
||||
return `foo
|
||||
bar` + 1;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
function hi() {
|
||||
switch (true) {
|
||||
case true:
|
||||
return `foo
|
||||
bar` + 1;
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
function foo() {
|
||||
return `foo
|
||||
bar`;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
function hi() {
|
||||
switch (true) {
|
||||
case true:
|
||||
return `foo
|
||||
bar`;
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
var test = `foo
|
||||
bar`;
|
||||
+110
@@ -481,5 +481,115 @@ describe('DeadCodeInjectionTransformer', () => {
|
||||
assert.notEqual(returnIdentifierName, variableDeclarationIdentifierName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #11 - block statements with empty body', () => {
|
||||
const regExp: RegExp = new RegExp(
|
||||
`function *${variableMatch} *\\(\\) *{ *} *` +
|
||||
`${variableMatch} *\\(\\); *`,
|
||||
'g'
|
||||
);
|
||||
const expectedMatchesLength: number = 5;
|
||||
|
||||
let matchesLength: number = 0;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/block-statement-empty-body.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
deadCodeInjection: true,
|
||||
deadCodeInjectionThreshold: 1
|
||||
}
|
||||
);
|
||||
|
||||
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
|
||||
const functionMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regExp);
|
||||
|
||||
if (functionMatches) {
|
||||
matchesLength = functionMatches.length;
|
||||
}
|
||||
});
|
||||
|
||||
it('shouldn\'t add dead code conditions to the block empty block statements', () => {
|
||||
assert.isAtLeast(matchesLength, expectedMatchesLength);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #12 - block statement with scope-hoisting', () => {
|
||||
describe('variant #1: collecting of block statements', () => {
|
||||
const regExp: RegExp = new RegExp(
|
||||
`${variableMatch} *\\(\\); *` +
|
||||
`var *${variableMatch} *= *0x2; *` +
|
||||
`function *${variableMatch} *\\(\\) *{ *} *`,
|
||||
'g'
|
||||
);
|
||||
const expectedMatchesLength: number = 5;
|
||||
|
||||
let matchesLength: number = 0;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/block-statement-with-scope-hoisting-1.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
deadCodeInjection: true,
|
||||
deadCodeInjectionThreshold: 1
|
||||
}
|
||||
);
|
||||
|
||||
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
|
||||
const functionMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(regExp);
|
||||
|
||||
if (functionMatches) {
|
||||
matchesLength = functionMatches.length;
|
||||
}
|
||||
});
|
||||
|
||||
it('shouldn\'t collect block statements with scope-hoisting', () => {
|
||||
assert.equal(matchesLength, expectedMatchesLength);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #2: wrapping of block statements in dead code conditions', () => {
|
||||
const regExp: RegExp = new RegExp(
|
||||
`function *${variableMatch} *\\(\\) *{ *` +
|
||||
`var *${variableMatch} *= *0x1; *` +
|
||||
`${variableMatch} *\\(\\); *` +
|
||||
`var *${variableMatch} *= *0x2; *` +
|
||||
`function *${variableMatch} *\\(\\) *{ *} *` +
|
||||
`var *${variableMatch} *= *0x3; *` +
|
||||
`}`,
|
||||
'g'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/block-statement-with-scope-hoisting-2.js');
|
||||
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
deadCodeInjection: true,
|
||||
deadCodeInjectionThreshold: 1
|
||||
}
|
||||
);
|
||||
|
||||
obfuscatedCode = obfuscationResult.getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('shouldn\'t wrap block statements in dead code conditions', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
(function(){
|
||||
function foo () {
|
||||
function inner1 () {}
|
||||
inner1();
|
||||
}
|
||||
function bar () {
|
||||
function inner2 () {}
|
||||
inner2();
|
||||
}
|
||||
function baz () {
|
||||
function inner3 () {}
|
||||
inner3();
|
||||
}
|
||||
function bark () {
|
||||
function inner4 () {}
|
||||
inner4();
|
||||
}
|
||||
function hawk () {
|
||||
function inner5 () {}
|
||||
inner5();
|
||||
}
|
||||
})();
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
(function(){
|
||||
function foo () {
|
||||
var a = 1;
|
||||
inner1();
|
||||
var b = 2;
|
||||
function inner1 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function bar () {
|
||||
var a = 1;
|
||||
inner2();
|
||||
var b = 2;
|
||||
function inner2 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function baz () {
|
||||
var a = 1;
|
||||
inner3();
|
||||
var b = 2;
|
||||
function inner3 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function bark () {
|
||||
var a = 1;
|
||||
inner4();
|
||||
var b = 2;
|
||||
function inner4 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function hawk () {
|
||||
var a = 1;
|
||||
inner5();
|
||||
var b = 2;
|
||||
function inner5 () {}
|
||||
var c = 3;
|
||||
}
|
||||
})();
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
(function(){
|
||||
function foo () {
|
||||
var a = 1;
|
||||
inner1();
|
||||
var b = 2;
|
||||
function inner1 () {}
|
||||
var c = 3;
|
||||
}
|
||||
function bar () {
|
||||
var a = 1;
|
||||
}
|
||||
function baz () {
|
||||
var a = 1;
|
||||
}
|
||||
function bark () {
|
||||
var a = 1;
|
||||
}
|
||||
function hawk () {
|
||||
var a = 1;
|
||||
}
|
||||
function eagle () {
|
||||
var a = 1;
|
||||
}
|
||||
})();
|
||||
@@ -294,6 +294,176 @@ describe('NodeUtils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNextSiblingStatementNode (node: ESTree.Statement): TStatement | null', () => {
|
||||
describe('variant #1: block statement node as scope node', () => {
|
||||
let statementNode1: ESTree.Statement,
|
||||
statementNode2: ESTree.Statement,
|
||||
statementNode3: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode1 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('a')
|
||||
);
|
||||
statementNode2 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('b')
|
||||
);
|
||||
statementNode3 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('c')
|
||||
);
|
||||
|
||||
const blockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode([
|
||||
statementNode1,
|
||||
statementNode2,
|
||||
statementNode3
|
||||
]);
|
||||
|
||||
statementNode1.parentNode = blockStatementNode;
|
||||
statementNode2.parentNode = blockStatementNode;
|
||||
statementNode3.parentNode = blockStatementNode;
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
|
||||
});
|
||||
|
||||
it('should return `null` if given statement node is last node in the scope', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #2: switch case node as scope node', () => {
|
||||
let statementNode1: ESTree.Statement,
|
||||
statementNode2: ESTree.Statement,
|
||||
statementNode3: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode1 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('a')
|
||||
);
|
||||
statementNode2 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('b')
|
||||
);
|
||||
statementNode3 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('c')
|
||||
);
|
||||
|
||||
const switchCaseNode: ESTree.SwitchCase = Nodes.getSwitchCaseNode(
|
||||
Nodes.getLiteralNode(true),
|
||||
[
|
||||
statementNode1,
|
||||
statementNode2,
|
||||
statementNode3
|
||||
]
|
||||
);
|
||||
|
||||
statementNode1.parentNode = switchCaseNode;
|
||||
statementNode2.parentNode = switchCaseNode;
|
||||
statementNode3.parentNode = switchCaseNode;
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
|
||||
});
|
||||
|
||||
it('should return `null` if given statement node is last node in the scope', () => {
|
||||
assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPreviousSiblingStatementNode (node: ESTree.Statement): TStatement | null', () => {
|
||||
describe('variant #1: block statement node as scope node', () => {
|
||||
let statementNode1: ESTree.Statement,
|
||||
statementNode2: ESTree.Statement,
|
||||
statementNode3: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode1 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('a')
|
||||
);
|
||||
statementNode2 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('b')
|
||||
);
|
||||
statementNode3 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('c')
|
||||
);
|
||||
|
||||
const blockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode([
|
||||
statementNode1,
|
||||
statementNode2,
|
||||
statementNode3
|
||||
]);
|
||||
|
||||
statementNode1.parentNode = blockStatementNode;
|
||||
statementNode2.parentNode = blockStatementNode;
|
||||
statementNode3.parentNode = blockStatementNode;
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
|
||||
});
|
||||
|
||||
it('should return `null` if given statement node is last node in the scope', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('variant #2: switch case node as scope node', () => {
|
||||
let statementNode1: ESTree.Statement,
|
||||
statementNode2: ESTree.Statement,
|
||||
statementNode3: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode1 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('a')
|
||||
);
|
||||
statementNode2 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('b')
|
||||
);
|
||||
statementNode3 = Nodes.getExpressionStatementNode(
|
||||
Nodes.getIdentifierNode('c')
|
||||
);
|
||||
|
||||
const switchCaseNode: ESTree.SwitchCase = Nodes.getSwitchCaseNode(
|
||||
Nodes.getLiteralNode(true),
|
||||
[
|
||||
statementNode1,
|
||||
statementNode2,
|
||||
statementNode3
|
||||
]
|
||||
);
|
||||
|
||||
statementNode1.parentNode = switchCaseNode;
|
||||
statementNode2.parentNode = switchCaseNode;
|
||||
statementNode3.parentNode = switchCaseNode;
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
|
||||
});
|
||||
|
||||
it('should return next sibling statement node', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
|
||||
});
|
||||
|
||||
it('should return `null` if given statement node is last node in the scope', () => {
|
||||
assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getScopeOfNode (node: ESTree.Node): TNodeWithScope | null', () => {
|
||||
let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
|
||||
ifStatementBlockStatementNode1: ESTree.BlockStatement,
|
||||
|
||||
@@ -72,9 +72,9 @@
|
||||
version "8.0.53"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
|
||||
|
||||
"@types/node@9.4.5":
|
||||
version "9.4.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.5.tgz#d2a90c634208173d1b1a0a6ba9f1df3de62edcf5"
|
||||
"@types/node@9.4.6":
|
||||
version "9.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.6.tgz#d8176d864ee48753d053783e4e463aec86b8d82e"
|
||||
|
||||
"@types/rimraf@2.0.2":
|
||||
version "2.0.2"
|
||||
@@ -168,7 +168,7 @@ ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
|
||||
ansi-styles@^3.1.0:
|
||||
ansi-styles@^3.1.0, ansi-styles@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
|
||||
dependencies:
|
||||
@@ -969,7 +969,15 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@2.3.0, chalk@^2.1.0, chalk@^2.3.0:
|
||||
chalk@2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
|
||||
dependencies:
|
||||
ansi-styles "^3.2.0"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.2.0"
|
||||
|
||||
chalk@^2.1.0, chalk@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
|
||||
dependencies:
|
||||
@@ -1330,7 +1338,7 @@ diffie-hellman@^5.0.0:
|
||||
miller-rabin "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
|
||||
doctrine@^0.7.2:
|
||||
doctrine@0.7.2:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523"
|
||||
dependencies:
|
||||
@@ -1839,6 +1847,10 @@ has-flag@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
@@ -2575,9 +2587,9 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
mocha@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.0.tgz#cccac988b0bc5477119cba0e43de7af6d6ad8f4e"
|
||||
mocha@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.1.tgz#759b62c836b0732382a62b6b1fb245ec1bc943ac"
|
||||
dependencies:
|
||||
browser-stdout "1.3.0"
|
||||
commander "2.11.0"
|
||||
@@ -3603,6 +3615,12 @@ supports-color@^5.1.0:
|
||||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
supports-color@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
tapable@^0.2.5, tapable@^0.2.7:
|
||||
version "0.2.8"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
|
||||
@@ -3722,17 +3740,17 @@ tslib@1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
|
||||
|
||||
tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0:
|
||||
tslib@^1.7.1, tslib@^1.8.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
|
||||
|
||||
tslint-eslint-rules@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-4.1.1.tgz#7c30e7882f26bc276bff91d2384975c69daf88ba"
|
||||
tslint-eslint-rules@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.0.0.tgz#ba46e32168137b7b6f73c2121a29d57abea032a6"
|
||||
dependencies:
|
||||
doctrine "^0.7.2"
|
||||
tslib "^1.0.0"
|
||||
tsutils "^1.4.0"
|
||||
doctrine "0.7.2"
|
||||
tslib "1.9.0"
|
||||
tsutils "2.8.0"
|
||||
|
||||
tslint-language-service@0.9.8:
|
||||
version "0.9.8"
|
||||
@@ -3761,9 +3779,11 @@ tslint@5.9.1:
|
||||
tslib "^1.8.0"
|
||||
tsutils "^2.12.1"
|
||||
|
||||
tsutils@^1.4.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0"
|
||||
tsutils@2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.0.tgz#0160173729b3bf138628dd14a1537e00851d814a"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
tsutils@^2.12.1:
|
||||
version "2.12.2"
|
||||
@@ -3803,9 +3823,9 @@ typedarray@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
typescript@2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.1.tgz#bb3682c2c791ac90e7c6210b26478a8da085c359"
|
||||
typescript@2.7.2:
|
||||
version "2.7.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
|
||||
|
||||
uglify-js@^2.6, uglify-js@^2.8.29:
|
||||
version "2.8.29"
|
||||
|
||||
Reference in New Issue
Block a user