소스 검색

Added the facade over esprima to improve error messages

sanex3339 7 년 전
부모
커밋
8e7423a852
9개의 변경된 파일124개의 추가작업 그리고 34개의 파일을 삭제
  1. 0 0
      dist/index.js
  2. 4 4
      package.json
  3. 70 0
      src/EsprimaFacade.ts
  4. 2 2
      src/JavaScriptObfuscator.ts
  5. 1 1
      src/cli/utils/CLIUtils.ts
  6. 11 0
      src/declarations/esprima.d.ts
  7. 6 0
      test/declarations/index.d.ts
  8. 1 3
      test/dev/dev.ts
  9. 29 24
      yarn.lock

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.js


+ 4 - 4
package.json

@@ -22,7 +22,7 @@
     "chalk": "2.3.0",
     "chance": "1.0.13",
     "class-validator": "0.8.1",
-    "commander": "2.14.0",
+    "commander": "2.14.1",
     "escodegen-wallaby": "1.6.17",
     "esprima": "4.0.0",
     "estraverse": "4.2.0",
@@ -47,7 +47,7 @@
     "@types/md5": "2.1.32",
     "@types/mkdirp": "0.5.2",
     "@types/mocha": "2.2.48",
-    "@types/node": "9.4.1",
+    "@types/node": "9.4.5",
     "@types/rimraf": "2.0.2",
     "@types/sinon": "4.1.3",
     "@types/string-template": "1.0.2",
@@ -63,7 +63,7 @@
     "mocha": "5.0.0",
     "pre-commit": "1.2.2",
     "rimraf": "2.6.2",
-    "sinon": "4.2.2",
+    "sinon": "4.3.0",
     "threads": "0.10.1",
     "ts-node": "4.1.0",
     "tslint": "5.9.1",
@@ -71,7 +71,7 @@
     "tslint-language-service": "0.9.8",
     "tslint-webpack-plugin": "1.1.1",
     "typescript": "2.7.1",
-    "webpack": "3.10.0",
+    "webpack": "3.11.0",
     "webpack-node-externals": "1.6.0"
   },
   "repository": {

+ 70 - 0
src/EsprimaFacade.ts

@@ -0,0 +1,70 @@
+import * as esprima from 'esprima';
+import * as ESTree from 'estree';
+
+import chalk, { Chalk } from 'chalk';
+
+/**
+ * Facade over `esprima` to handle parsing errors and provide more detailed error messages
+ */
+export class EsprimaFacade {
+    /**
+     * @type {Chalk}
+     */
+    private static readonly colorError: Chalk = chalk.red;
+
+    /**
+     * @type {number}
+     */
+    private static readonly nearestSymbolsCount: number = 10;
+
+    /**
+     * @param {string} input
+     * @param {ParseOptions} config
+     * @returns {Program}
+     */
+    public static parseScript (input: string, config: esprima.ParseOptions): ESTree.Program {
+        let lastMeta: esprima.NodeMeta | null = null;
+
+        try {
+            return esprima.parseScript(input, config, (node: ESTree.Node, meta: any) => lastMeta = meta);
+        } catch (error) {
+            return this.processParsingError(input, error.message, lastMeta);
+        }
+    }
+
+    /**
+     * @param {string} sourceCode
+     * @param {string} errorMessage
+     * @param {"esprima".NodeMeta | null} meta
+     * @returns {never}
+     */
+    private static processParsingError (sourceCode: string, errorMessage: string, meta: esprima.NodeMeta | null): never {
+        if (!meta || !meta.start || !meta.end || !meta.start.column || !meta.end.column) {
+            throw new Error(errorMessage);
+        }
+
+        const lineNumberMatch: RegExpMatchArray | null = errorMessage.match(/Line *(\d)/);
+
+        if (!lineNumberMatch) {
+            throw new Error(errorMessage);
+        }
+
+        const lineNumber: number = parseInt(lineNumberMatch[1], 10);
+        const sourceCodeLines: string[] = sourceCode.split(/\r?\n/);
+        const errorLine: string | undefined = sourceCodeLines[lineNumber - 1];
+
+        if (!errorLine) {
+            throw new Error(errorMessage);
+        }
+
+        const startErrorIndex: number = Math.max(0, meta.start.column - EsprimaFacade.nearestSymbolsCount);
+        const endErrorIndex: number = Math.min(errorLine.length, meta.end.column + EsprimaFacade.nearestSymbolsCount);
+
+        const formattedPointer: string = EsprimaFacade.colorError('>');
+        const formattedCodeSlice: string = `...${
+            errorLine.substring(startErrorIndex, endErrorIndex).replace(/^\s+/, '')
+        }...`;
+
+        throw new Error(`${errorMessage}\n${formattedPointer} ${formattedCodeSlice}`);
+    }
+}

+ 2 - 2
src/JavaScriptObfuscator.ts

@@ -1,7 +1,6 @@
 import { inject, injectable, } from 'inversify';
 import { ServiceIdentifiers } from './container/ServiceIdentifiers';
 
-import * as esprima from 'esprima';
 import * as escodegen from 'escodegen-wallaby';
 import * as ESTree from 'estree';
 import * as packageJson from 'pjson';
@@ -19,6 +18,7 @@ import { LoggingMessage } from './enums/logger/LoggingMessage';
 import { NodeTransformer } from './enums/node-transformers/NodeTransformer';
 import { TransformationStage } from './enums/node-transformers/TransformationStage';
 
+import { EsprimaFacade } from './EsprimaFacade';
 import { NodeGuards } from './node/NodeGuards';
 
 @injectable()
@@ -134,7 +134,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
      * @returns {Program}
      */
     private parseCode (sourceCode: string): ESTree.Program {
-        return esprima.parseScript(sourceCode, {
+        return EsprimaFacade.parseScript(sourceCode, {
             attachComment: true,
             loc: this.options.sourceMap
         });

+ 1 - 1
src/cli/utils/CLIUtils.ts

@@ -55,7 +55,7 @@ export class CLIUtils {
             try {
                 config = __non_webpack_require__(configPath);
             } catch (e) {
-                throw new ReferenceError('Given config path must be a valid file path');
+                throw new ReferenceError('Given config path must be a valid path of `.js` or `.json` file');
             }
         }
 

+ 11 - 0
src/declarations/esprima.d.ts

@@ -3,6 +3,17 @@
 import * as esprima from 'esprima';
 
 declare module 'esprima' {
+    export interface LineMeta {
+        line?: number;
+        column?: number;
+        offset?: number;
+    }
+
+    export interface NodeMeta {
+        start?: LineMeta;
+        end?: LineMeta;
+    }
+
     export interface ParseOptions {
         attachComment?: boolean;
     }

+ 6 - 0
test/declarations/index.d.ts

@@ -0,0 +1,6 @@
+/// <reference path="../../src/declarations/escodegen.d.ts" />
+/// <reference path="../../src/declarations/escodegen-wallaby.d.ts" />
+/// <reference path="../../src/declarations/esprima.d.ts" />
+/// <reference path="../../src/declarations/ESTree.d.ts" />
+/// <reference path="../../src/declarations/js-string-escape.d.ts" />
+/// <reference path="../../src/declarations/threads.d.ts" />

+ 1 - 3
test/dev/dev.ts

@@ -6,10 +6,8 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-        var bar = 1;
-        var baz = 2;
         (function(){
-            var bark = bar + baz;
+            var foo = 'foo'; var bar = 'bar'; var bark = foo + bar,; var baz = 'baz';
         })();
         `,
         {

+ 29 - 24
yarn.lock

@@ -2,6 +2,12 @@
 # yarn lockfile v1
 
 
+"@sinonjs/formatio@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-2.0.0.tgz#84db7e9eb5531df18a8c5e0bfb6e449e55e654b2"
+  dependencies:
+    samsam "1.3.0"
+
 "@types/[email protected]":
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
@@ -66,9 +72,9 @@
   version "8.0.53"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
 
-"@types/[email protected].1":
-  version "9.4.1"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.1.tgz#0f636f7837e15d2d73a7f6f3ea0e322eb2a5ab65"
+"@types/[email protected].5":
+  version "9.4.5"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.5.tgz#d2a90c634208173d1b1a0a6ba9f1df3de62edcf5"
 
 "@types/[email protected]":
   version "2.0.2"
@@ -115,9 +121,9 @@ acorn@^5.0.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7"
 
-ajv-keywords@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
+ajv-keywords@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be"
 
 ajv@^4.9.1:
   version "4.11.8"
@@ -126,11 +132,10 @@ ajv@^4.9.1:
     co "^4.6.0"
     json-stable-stringify "^1.0.1"
 
-ajv@^5.1.5:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda"
+ajv@^6.1.0:
+  version "6.1.1"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e"
   dependencies:
-    co "^4.6.0"
     fast-deep-equal "^1.0.0"
     fast-json-stable-stringify "^2.0.0"
     json-schema-traverse "^0.3.0"
@@ -1087,9 +1092,9 @@ [email protected]:
   version "2.11.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
 
[email protected].0:
-  version "2.14.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.0.tgz#7b25325963e6aace20d3a9285b09379b0c2208b5"
[email protected].1:
+  version "2.14.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
 
 commander@^2.11.0:
   version "2.12.2"
@@ -1684,7 +1689,7 @@ form-data@~2.1.1:
     combined-stream "^1.0.5"
     mime-types "^2.1.12"
 
-[email protected], formatio@^1.2.0:
+formatio@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
   dependencies:
@@ -3268,7 +3273,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0,
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
 
[email protected]:
+[email protected], [email protected]:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
 
@@ -3333,12 +3338,12 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
 
-sinon@4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.2.2.tgz#e039ab27bdb426fc61363c380726e996a2e2c620"
+sinon@4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.3.0.tgz#cec9b27d5f4e2c63c1a79c9dc1c05d34bb088234"
   dependencies:
+    "@sinonjs/formatio" "^2.0.0"
     diff "^3.1.0"
-    formatio "1.2.0"
     lodash.get "^4.4.2"
     lolex "^2.2.0"
     nise "^1.2.0"
@@ -3936,14 +3941,14 @@ webpack-sources@^1.0.1:
     source-list-map "^2.0.0"
     source-map "~0.5.3"
 
[email protected]0.0:
-  version "3.10.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725"
[email protected]1.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894"
   dependencies:
     acorn "^5.0.0"
     acorn-dynamic-import "^2.0.0"
-    ajv "^5.1.5"
-    ajv-keywords "^2.0.0"
+    ajv "^6.1.0"
+    ajv-keywords "^3.1.0"
     async "^2.1.2"
     enhanced-resolve "^3.4.0"
     escope "^3.6.0"

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.