forked from babel/babel
/
index.ts
100 lines (83 loc) 路 2.95 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import rewritePattern from "regexpu-core";
import { featuresKey, FEATURES, enableFeature, runtimeKey } from "./features";
import { generateRegexpuOptions, canSkipRegexpu, transformFlags } from "./util";
import { types as t } from "@babel/core";
import type { PluginObject } from "@babel/core";
import annotateAsPure from "@babel/helper-annotate-as-pure";
declare const PACKAGE_JSON: { name: string; version: string };
// Note: Versions are represented as an integer. e.g. 7.1.5 is represented
// as 70000100005. This method is easier than using a semver-parsing
// package, but it breaks if we release x.y.z where x, y or z are
// greater than 99_999.
const version = PACKAGE_JSON.version
.split(".")
.reduce((v, x) => v * 1e5 + +x, 0);
const versionKey = "@babel/plugin-regexp-features/version";
export function createRegExpFeaturePlugin({
name,
feature,
options = {} as any,
manipulateOptions = (() => {}) as PluginObject["manipulateOptions"],
}): PluginObject {
return {
name,
manipulateOptions,
pre() {
const { file } = this;
const features = file.get(featuresKey) ?? 0;
let newFeatures = enableFeature(features, FEATURES[feature]);
const { useUnicodeFlag, runtime = true } = options;
if (useUnicodeFlag === false) {
newFeatures = enableFeature(newFeatures, FEATURES.unicodeFlag);
}
if (newFeatures !== features) {
file.set(featuresKey, newFeatures);
}
if (!runtime) {
file.set(runtimeKey, false);
}
if (!file.has(versionKey) || file.get(versionKey) < version) {
file.set(versionKey, version);
}
},
visitor: {
RegExpLiteral(path) {
const { node } = path;
const { file } = this;
const features = file.get(featuresKey);
const runtime = file.get(runtimeKey) ?? true;
const regexpuOptions = generateRegexpuOptions(features);
if (canSkipRegexpu(node, regexpuOptions)) return;
const namedCaptureGroups = {};
if (regexpuOptions.namedGroups === "transform") {
regexpuOptions.onNamedGroup = (name, index) => {
namedCaptureGroups[name] = index;
};
}
node.pattern = rewritePattern(node.pattern, node.flags, regexpuOptions);
if (
regexpuOptions.namedGroups === "transform" &&
Object.keys(namedCaptureGroups).length > 0 &&
runtime &&
!isRegExpTest(path)
) {
const call = t.callExpression(this.addHelper("wrapRegExp"), [
node,
t.valueToNode(namedCaptureGroups),
]);
annotateAsPure(call);
path.replaceWith(call);
}
node.flags = transformFlags(regexpuOptions, node.flags);
},
},
};
}
function isRegExpTest(path) {
return (
path.parentPath.isMemberExpression({
object: path.node,
computed: false,
}) && path.parentPath.get("property").isIdentifier({ name: "test" })
);
}