Skip to content

Commit

Permalink
Implemented transform-regexp-constructors plugin.
Browse files Browse the repository at this point in the history
Changes RegExp constructors into literals.
  • Loading branch information
Shine Wang committed Oct 18, 2016
1 parent a7a890a commit 5d82d65
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
src
__tests__
node_modules
*.log
52 changes: 52 additions & 0 deletions packages/babel-plugin-transform-regexp-constructors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# babel-plugin-transform-regexp-constructors

This changes RegExp constructors into literals if and only if the RegExp
arguments are string literals.

## Example

**In**

```javascript
const foo = 'ab+';
var a = new RegExp(foo+'c', 'i');
```

**Out**

```javascript
const foo = 'ab+';
var a = /ab+c/i;
```

## Installation

```sh
$ npm install babel-plugin-transform-regexp-constructors
```

## Usage

### Via `.babelrc` (Recommended)

**.babelrc**

```json
{
"plugins": ["transform-regexp-constructors"]
}
```

### Via CLI

```sh
$ babel --plugins transform-regexp-constructors script.js
```

### Via Node API

```javascript
require("babel-core").transform("code", {
plugins: ["transform-regexp-constructors"]
});
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
jest.autoMockOff();

const babel = require("babel-core");
const plugin = require("../src/index");

function transform(code) {
return babel.transform(code, {
plugins: [plugin],
}).code;
}

describe("transform-regexp-constructors-plugin", () => {
it("should transform RegExp constructors with string literals", () => {
const source = "var x = new RegExp('ab+c');";
const expected = "var x = /ab+c/;";
expect(transform(source)).toBe(expected);
});

it("should transform RegExp constructors with flags", () => {
const source = "var x = new RegExp('ab+c', 'gimuy');";
const expected = "var x = /ab+c/gimuy;";
expect(transform(source)).toBe(expected);
});

it("should transform RegExp escapes", () => {
const source = String.raw`var x = new RegExp('\\w+\\s');`;
const expected = String.raw`var x = /\w+\s/;`;
expect(transform(source)).toBe(expected);
});

it("should not transform RegExp constructors with expressions", () => {
const source = "var x = new RegExp(foo(), 'g');";
const expected = source;
expect(transform(source)).toBe(expected);
});

it("should transform empty RegExp constructor", () => {
const source = "var x = new RegExp();";
const expected = "var x = /(?:)/;";
expect(transform(source)).toBe(expected);
});

it("should transform RegExp constructor with empty string", () => {
const source = "var x = new RegExp('');";
const expected = "var x = /(?:)/;";
expect(transform(source)).toBe(expected);
});

it("should resolve expressions and const references", () => {
const source = `
const foo = "ab+";
const bar = "c\\\\w";
const flags = "g";
const ret = new RegExp(foo + bar + "d", flags);`;
const expected = `
const foo = "ab+";
const bar = "c\\\\w";
const flags = "g";
const ret = /ab+c\\wd/g;`;
expect(transform(source)).toBe(expected);
});
});
28 changes: 28 additions & 0 deletions packages/babel-plugin-transform-regexp-constructors/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";

module.exports = function({ types: t }) {
return {
name: "transform-regexp-constructors",
visitor: {
NewExpression(path) {
if (!t.isIdentifier(path.node.callee, {name: "RegExp"})) {
return;
}
const evaluatedArgs = path.get("arguments")
.map((a) => a.evaluate());
if (!evaluatedArgs.every((a) => a.confident === true &&
typeof a.value === "string")) {
return;
}
const pattern = (evaluatedArgs.length >= 1 &&
evaluatedArgs[0].value !== "") ?
evaluatedArgs[0].value :
"(?:)";
const flags = evaluatedArgs.length >= 2 ?
evaluatedArgs[1].value :
"";
path.replaceWith(t.regExpLiteral(pattern, flags));
}
},
};
};

0 comments on commit 5d82d65

Please sign in to comment.