Repository: DmitrySoshnikov/regexp-tree (js)

Issue:
It should be SyntaxError if Unicode code point is greater than 0x10FFFF
This should be an invalid regexp:

```js
/\u{0x11FFFF}/u
```

The max value which should be checked is `0x10FFFF`.

Pull request description:
Throw on invalid unicode escapes
Closes #13.

Patch:
diff --git a/src/parser/generated/regexp-tree.js b/src/parser/generated/regexp-tree.js
index be14c02..e5ca8eb 100644
--- a/src/parser/generated/regexp-tree.js
+++ b/src/parser/generated/regexp-tree.js
@@ -739,7 +739,7 @@ const yyparse = {
  */
 let capturingGroupsCount = 0;
 
-yyparse.onParseBegin = (_string) => {
+yyparse.onParseBegin = () => {
   capturingGroupsCount = 0;
 };
 
@@ -771,6 +771,10 @@ function Char(value, kind, loc) {
     case 'unicode': {
       const hex = value.slice(2).replace('{', '');
       const code = parseInt(hex, 16);
+      if (code > 0x10ffff) {
+        throw new SyntaxError(`Bad character escape sequence: ${value}`);
+      }
+
       symbol = String.fromCodePoint(code);
       break;
     }
diff --git a/src/parser/regexp.bnf b/src/parser/regexp.bnf
index b524ec7..ac8b86f 100644
--- a/src/parser/regexp.bnf
+++ b/src/parser/regexp.bnf
@@ -115,7 +115,7 @@ U                       [0-9a-fA-F]
  */
 let capturingGroupsCount = 0;
 
-yyparse.onParseBegin = (_string) => {
+yyparse.onParseBegin = () => {
   capturingGroupsCount = 0;
 };
 
@@ -147,6 +147,10 @@ function Char(value, kind, loc) {
     case 'unicode': {
       const hex = value.slice(2).replace('{', '');
       const code = parseInt(hex, 16);
+      if (code > 0x10ffff) {
+        throw new SyntaxError(`Bad character escape sequence: ${value}`);
+      }
+
       symbol = String.fromCodePoint(code);
       break;
     }
diff --git a/src/transform/README.md b/src/transform/README.md
deleted file mode 100644
index 79e90ee..0000000
--- a/src/transform/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# regexp-tree: Transform module
-
-Transform module is a convenient wrapper on top of the _"parse-traverse-generate"_ tool chain. In addition to traversal, it provides useful API methods for manipulating, and actual transformation of the AST nodes.
-
-TODO
-
-Example:
-
-```js
-const regexpTree = require('regexp-tree');
-
-const re = regexpTree.transform('/[a-z]{1,}/',
-  api => ({
-    // Handle "Quantifier" node type,
-    // transforming `{1,}` quantifier to `+`.
-    onQuantifier(node) {
-      // {1,} -> +
-      if (
-        node.type === 'Range' &&
-        node.from === 1 &&
-        !node.to
-      ) {
-        api.replaceNode(node, {
-          type: 'Quantifier',
-          kind: '+',
-          loc: {
-            start: node.loc.start,
-            end: node.loc.start + 1,
-          },
-        });
-      }
-    },
-  }),
-});
-
-console.log(re.toRegExp()); // /[a-z]+/
-```
\ No newline at end of file
diff --git a/src/transform/index.js b/src/transform/index.js
deleted file mode 100644
index 222e07c..0000000
--- a/src/transform/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * The MIT License (MIT)
- * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
- */
-
-'use strict';
-
-// TODO (https://github.com/DmitrySoshnikov/regexp-tree/issues/7)
-
-const parser = require('../parser');
-const traverse = require('../traverse');
-
-/**
- * Transform result.
- */
-class TransformResult {
-  //
-}
-
-module.exports = {
-  /**
-   * Transforms a regular expression applying a set of
-   * transformation handlers.
-   *
-   * @param mixed regexp:
-   *
-   *   a regular expression in different representations: a string,
-   *   a RegExp object, or an AST.
-   *
-   * @param Object|Array<Object>:
-   *
-   *   a handler (or a list of handlers). Can be a simple plain handler object,
-   *   or a "plugin" to which different API methods are accessible. A "plugin"
-   *   is a function which receives as a parameter `TransformApi` object, and
-   *   which should return a plain handler.
-   *
-   * @return TransformResult instance.
-   *
-   * Example:
-   *
-   *   transform(/[a-z]/i, [
-   *     api => {
-   *       onChar(node) {
-   *         if (...) {
-   *           api.removeNode(node);
-   *         }
-   *       }
-   *     },
-   *   ]);
-   */
-  transform(regexp, handlers) {
-    //
-  },
-};
\ No newline at end of file
diff --git a/src/traverse/index.js b/src/traverse/index.js
index f4a4007..0fda565 100644
--- a/src/traverse/index.js
+++ b/src/traverse/index.js
@@ -49,12 +49,6 @@ module.exports = {
        */
       pre(node, parent, prop, index) {
         for (const handler of handlers) {
-          // "Catch-all" `*` handler.
-          if (typeof handler['*'] === 'function') {
-            handler['*'](node, parent, prop, index);
-          }
-
-          // Per-node handler.
           const handlerName = `on${node.type}`;
           if (typeof handler[handlerName] === 'function') {
             handler[handlerName](node, parent, prop, index);


Test patch:
diff --git a/src/parser/__tests__/parser-test262-test.js b/src/parser/__tests__/parser-test262-test.js
index fddd9cb..ac3074a 100644
--- a/src/parser/__tests__/parser-test262-test.js
+++ b/src/parser/__tests__/parser-test262-test.js
@@ -8,14 +8,10 @@
 
 const regexpTree = require('..');
 
-function re(regexp) {
-  return regexpTree.parse(regexp.toString());
-}
-
 function invalid(regexp, message) {
   try {
     regexpTree.parse(regexp);
-    expect(1).not.toBe(1); // unreachable
+    throw new Error('expected `parse` to throw');
   } catch (e) {
     expect(e).toBeInstanceOf(SyntaxError);
 
@@ -29,10 +25,8 @@ function valid(regexp) {
   expect(() => regexpTree.parse(regexp)).not.toThrow(SyntaxError);
 }
 
-const UT = 'Unexpected token:';
-
 function ut(message) {
-  return `${UT} ${message}`;
+  return `Unexpected token: ${message}`;
 }
 
 describe('test262', () => {
@@ -136,4 +130,8 @@ describe('test262', () => {
     // S15.10.1_A1_T9
     invalid('/+a/', ut(`"+" at 1:1`));
   });
+
+  it('invalid unicode escape', () => {
+    invalid('/\\u{11FFFF}/u', 'Bad character escape');
+  });
 });
\ No newline at end of file
diff --git a/src/traverse/__tests__/traverse-basic-test.js b/src/traverse/__tests__/traverse-basic-test.js
index e960438..b927afa 100644
--- a/src/traverse/__tests__/traverse-basic-test.js
+++ b/src/traverse/__tests__/traverse-basic-test.js
@@ -235,22 +235,4 @@ describe('traverse-basic', () => {
     });
   });
 
-  it('catch-all * handler', () => {
-    const ast = parser.parse('/a+/');
-    const visited = [];
-
-    traverse.traverse(ast, {
-      '*': node => {
-        visited.push(node.type);
-      },
-    });
-
-    expect(visited).toEqual([
-      'RegExp',
-      'Repetition',
-      'Char',
-      'Quantifier',
-    ]);
-  });
-
 });
\ No newline at end of file