Add @babel/plugin-transform-named-capturing-groups-regex (#7105)
When the `runtime` flag is on (by default), this plugin adds a new helper which wraps the native `RegExp` class to provide groups support. People nees to use a polyfill (I implemented it in core-js) for browsers that don't support ES6 regexps.
This commit is contained in:
parent
aaec2cd51d
commit
a27b9b4299
@ -1783,3 +1783,75 @@ helpers.classPrivateMethodSet = helper("7.1.6")`
|
|||||||
throw new TypeError("attempted to reassign private method");
|
throw new TypeError("attempted to reassign private method");
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
helpers.wrapRegExp = helper("7.2.6")`
|
||||||
|
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.2.5",
|
||||||
|
"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.1.0"
|
||||||
|
},
|
||||||
|
"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("The 'runtime' option 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" })
|
||||||
|
);
|
||||||
|
}
|
||||||
15
packages/babel-plugin-transform-named-capturing-groups-regex/test/fixtures/runtime/exec.js
vendored
Normal file
15
packages/babel-plugin-transform-named-capturing-groups-regex/test/fixtures/runtime/exec.js
vendored
Normal file
@ -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();
|
||||||
15
packages/babel-plugin-transform-named-capturing-groups-regex/test/fixtures/runtime/match.js
vendored
Normal file
15
packages/babel-plugin-transform-named-capturing-groups-regex/test/fixtures/runtime/match.js
vendored
Normal file
@ -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);
|
||||||
Loading…
x
Reference in New Issue
Block a user