Skip to content

Commit

Permalink
Add @babel/plugin-transform-named-capturing-groups-regex
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Dec 7, 2018
1 parent 3581583 commit c0014fe
Show file tree
Hide file tree
Showing 31 changed files with 261 additions and 0 deletions.
71 changes: 71 additions & 0 deletions packages/babel-helpers/src/helpers.js
Expand Up @@ -1754,3 +1754,74 @@ helpers.classPrivateMethodSet = helper("7.1.6")`
throw new TypeError("attempted to reassign private method");
}
`;

helpers.wrapRegExp = helper("7.2.2")`
import wrapNativeSuper from "wrapNativeSuper";
import getPrototypeOf from "getPrototypeOf";
import possibleConstructorReturn from "possibleConstructorReturn";
import inherits from "inherits";
export default function _wrapRegExp(re, groups) {
_wrapRegExp = function(re, groups) {
return new BabelRegExp(re, groups);
};
var _RegExp = wrapNativeSuper(RegExp);
var _super = RegExp.prototype;
var _groups = new WeakMap();
function BabelRegExp(re, groups) {
var _this = _RegExp.call(this, re);
_groups.set(_this, groups);
return _this;
}
inherits(BabelRegExp, _RegExp);
BabelRegExp.prototype.exec = function(str) {
var result = _super.exec.call(this, str);
if (result) result.groups = buildGroups(result, this);
return result;
};
BabelRegExp.prototype[Symbol.replace] = function(str, substitution) {
if (typeof substitution === "string") {
var groups = _groups.get(this);
return _super[Symbol.replace].call(
this,
str,
substitution.replace(/\\$<([^>]+)>/g, function(_, name) {
return "$" + groups[name];
})
);
} else if (typeof substitution === "function") {
var _this = this;
return _super[Symbol.replace].call(
this,
str,
function() {
var args = [];
args.push.apply(args, arguments);
if (typeof args[args.length - 1] !== "object") {
// Modern engines already pass result.groups as the last arg.
args.push(buildGroups(args, _this));
}
return substitution.apply(this, args);
}
);
} else {
return _super[Symbol.replace].call(this, str, substitution);
}
}
function buildGroups(result, re) {
// NOTE: This function should return undefined if there are no groups,
// but in that case Babel doesn't add the wrapper anyway.
var g = _groups.get(re);
return Object.keys(groups).reduce(function(groups, name) {
groups[name] = result[g[name]];
return groups;
}, Object.create(null));
}
return _wrapRegExp.apply(this, arguments);
`;
@@ -0,0 +1,3 @@
src
test
*.log
@@ -0,0 +1,19 @@
# @babel/plugin-transform-named-capturing-groups-regex

> Compile regular expressions using named groups to ES5.
See our website [@babel/plugin-transform-named-capturing-groups-regex](https://babeljs.io/docs/en/next/babel-plugin-transform-named-capturing-groups-regex.html) for more information.

## Install

Using npm:

```sh
npm install --save-dev @babel/plugin-transform-named-capturing-groups-regex
```

or using yarn:

```sh
yarn add @babel/plugin-transform-named-capturing-groups-regex --dev
```
@@ -0,0 +1,26 @@
{
"name": "@babel/plugin-transform-named-capturing-groups-regex",
"version": "7.1.0",
"description": "Compile regular expressions using named groups to ES5.",
"homepage": "https://babeljs.io/",
"license": "MIT",
"main": "lib/index.js",
"keywords": [
"babel-plugin",
"regex",
"regexp",
"regular expressions"
],
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-named-capturing-groups-regex",
"bugs": "https://github.com/babel/babel/issues",
"dependencies": {
"regexp-tree": "^0.0.78"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/helper-plugin-test-runner": "^7.0.0"
}
}
@@ -0,0 +1,54 @@
import regexpTree from "regexp-tree";

export default function({ types: t }, options) {
const { runtime = true } = options;
if (typeof runtime !== "boolean") {
throw new Error(".runtime must be boolean");
}

return {
name: "transform-named-capturing-groups-regex",

visitor: {
RegExpLiteral(path) {
const node = path.node;
if (node.pattern.indexOf("(?<") === -1) {
// Return early if there are no named groups.
// The .indexOf check may have false positives (e.g. /\(?</); in
// this case we parse the regex and regexp-tree won't transform it.
return;
}

const result = regexpTree.compatTranspile(node.extra.raw, [
"namedCapturingGroups",
]);
const { namedCapturingGroups } = result.getExtra();

if (
namedCapturingGroups &&
Object.keys(namedCapturingGroups).length > 0
) {
node.pattern = result.getSource();

if (runtime && !isRegExpTest(path)) {
path.replaceWith(
t.callExpression(this.addHelper("wrapRegExp"), [
node,
t.valueToNode(namedCapturingGroups),
]),
);
}
}
},
},
};
}

function isRegExpTest(path) {
return (
path.parentPath.isMemberExpression({
object: path.node,
computed: false,
}) && path.parentPath.get("property").isIdentifier({ name: "test" })
);
}
@@ -0,0 +1,15 @@
var re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

var result = re.exec("2017-12-23");

expect(result.groups).toEqual({
year: "2017",
month: "12",
day: "23",
});

expect(result.groups).toEqual({
year: result[1],
month: result[2],
day: result[3],
});
@@ -0,0 +1,3 @@
var re = /(?<group>)/;

expect(re instanceof RegExp).toBeTruthy();
@@ -0,0 +1,15 @@
var re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

var result = "1999-09-29".match(re);

expect(result.groups).toEqual({
year: "1999",
month: "09",
day: "29",
});

expect(result.groups).toEqual({
year: result[1],
month: result[2],
day: result[3],
});
@@ -0,0 +1,4 @@
var re = /no-groups-\(?<looks-like-a-group>looks\)/;
var result = re.exec("no-groups-(<looks-like-a-group>looks)")

expect(result.groups).toBeUndefined();
@@ -0,0 +1,3 @@
{
"plugins": ["transform-named-capturing-groups-regex"]
}
@@ -0,0 +1,5 @@
var re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

var result = "2015-10-31".replace(re, "$<day>/$<month>/$<year>")

expect(result).toBe("31/10/2015");
@@ -0,0 +1 @@
/(?<name>)\k<name>/;
@@ -0,0 +1,6 @@
{
"plugins": [
"external-helpers",
["transform-named-capturing-groups-regex", { "runtime": false }]
]
}
@@ -0,0 +1 @@
/()\1/;
@@ -0,0 +1 @@
/(?<\u{41}>)\k<\u{41}>/;
@@ -0,0 +1,3 @@
{
"throws": "invalid group Unicode name \"\\u{41}\", use `u` flag."
}
@@ -0,0 +1 @@
/(?<\u{41}>)\k<\u{41}>/u;
@@ -0,0 +1 @@
/()\1/u;
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.1000.0" }],
["transform-named-capturing-groups-regex", { "runtime": false }]
]
}
@@ -0,0 +1 @@
"foo".match(/(?<double>.)\k<double>/);
@@ -0,0 +1,3 @@
"foo".match(babelHelpers.wrapRegExp(/(.)\1/, {
double: 1
}));
@@ -0,0 +1 @@
/no-groups-\(?<looks-like-a-group>looks\)/;
@@ -0,0 +1 @@
/no-groups-\(?<looks-like-a-group>looks\)/;
@@ -0,0 +1 @@
"foo".match(/(.)\1/);
@@ -0,0 +1 @@
"foo".match(/(.)\1/);
@@ -0,0 +1,6 @@
{
"plugins": [
["external-helpers", { "helperVersion": "7.1000.0" }],
"transform-named-capturing-groups-regex"
]
}
@@ -0,0 +1 @@
"abba".match(/(.)(?<n>.)\k<n>\1/);
@@ -0,0 +1,3 @@
"abba".match(babelHelpers.wrapRegExp(/(.)(.)\2\1/, {
n: 2
}));
@@ -0,0 +1 @@
/^(?<x>.)\k<x>$/.test("aa");
@@ -0,0 +1 @@
/^(.)\1$/.test("aa");
@@ -0,0 +1,3 @@
import runner from "@babel/helper-plugin-test-runner";

runner(__dirname);

0 comments on commit c0014fe

Please sign in to comment.