Repository: DmitrySoshnikov/regexp-tree (js)

Issue:
Optimizer: Don't unescape space and # when x flag is set
Currently, an error is thrown when trying to optimize `/\ \#/x` because it unescapes those chars.
I guess the optimizer should handle the `x` flag better to prevent this.

Pull request:
Optimizer: Don't unescape space and # when x flag is set
Fix #137

Patch:
diff --git a/src/optimizer/transforms/char-escape-unescape-transform.js b/src/optimizer/transforms/char-escape-unescape-transform.js
index 33d3d0f..62b3aa2 100644
--- a/src/optimizer/transforms/char-escape-unescape-transform.js
+++ b/src/optimizer/transforms/char-escape-unescape-transform.js
@@ -13,6 +13,10 @@
  * [\(] -> [(]
  */
 module.exports = {
+  _hasXFlag: false,
+  init(ast) {
+    this._hasXFlag = ast.flags.includes('x');
+  },
   Char(path) {
     const {node} = path;
 
@@ -20,18 +24,18 @@ module.exports = {
       return;
     }
 
-    if (shouldUnescape(path)) {
+    if (shouldUnescape(path, this._hasXFlag)) {
       delete node.escaped;
     }
   }
 };
 
-function shouldUnescape(path) {
+function shouldUnescape(path, hasXFlag) {
   const {node: {value}, index, parent} = path;
 
   // In char class (, etc are allowed.
   if (parent.type !== 'CharacterClass' && parent.type !== 'ClassRange') {
-    return !preservesEscape(value, index, parent);
+    return !preservesEscape(value, index, parent, hasXFlag);
   }
 
   return !preservesInCharClass(value, index, parent);
@@ -52,7 +56,7 @@ function preservesInCharClass(value, index, parent) {
   return /[\]\\]/.test(value);
 }
 
-function preservesEscape(value, index, parent) {
+function preservesEscape(value, index, parent, hasXFlag) {
   if (value === '{') {
     return preservesOpeningCurlyBraceEscape(index, parent);
   }
@@ -61,6 +65,10 @@ function preservesEscape(value, index, parent) {
     return preservesClosingCurlyBraceEscape(index, parent);
   }
 
+  if (hasXFlag && /[ #]/.test(value)) {
+    return true;
+  }
+
   return /[*[()+?^$./\\|]/.test(value);
 }
 


Test patch:
diff --git a/src/optimizer/transforms/__tests__/char-escape-unescape-transform-test.js b/src/optimizer/transforms/__tests__/char-escape-unescape-transform-test.js
index 0512552..8c844a8 100644
--- a/src/optimizer/transforms/__tests__/char-escape-unescape-transform-test.js
+++ b/src/optimizer/transforms/__tests__/char-escape-unescape-transform-test.js
@@ -88,4 +88,11 @@ describe('\e -> e', () => {
     expect(re.toString()).toBe(/[a\-z]/.toString());
   });
 
+  it('does not unescape space and # when x flag is set', () => {
+    const re = transform('/\\ \\#[\\ \\#]/x', [
+      charUnescape
+    ]);
+    expect(re.toString()).toBe('/\\ \\#[ #]/x');
+  });
+
 });
\ No newline at end of file