1 | 'use strict';
|
---|
2 |
|
---|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
---|
4 |
|
---|
5 | var core = require('@babel/core');
|
---|
6 | var helperPluginUtils = require('@babel/helper-plugin-utils');
|
---|
7 |
|
---|
8 | function isNameOrLength(key) {
|
---|
9 | if (core.types.isIdentifier(key)) {
|
---|
10 | return key.name === "name" || key.name === "length";
|
---|
11 | }
|
---|
12 | if (core.types.isStringLiteral(key)) {
|
---|
13 | return key.value === "name" || key.value === "length";
|
---|
14 | }
|
---|
15 | return false;
|
---|
16 | }
|
---|
17 | function isStaticFieldWithValue(node) {
|
---|
18 | return (core.types.isClassProperty(node) || core.types.isClassPrivateProperty(node)) && node.static && !!node.value;
|
---|
19 | }
|
---|
20 | const hasReferenceVisitor = {
|
---|
21 | ReferencedIdentifier(path, state) {
|
---|
22 | if (path.node.name === state.name) {
|
---|
23 | state.ref();
|
---|
24 | path.stop();
|
---|
25 | }
|
---|
26 | },
|
---|
27 | Scope(path, {
|
---|
28 | name
|
---|
29 | }) {
|
---|
30 | if (path.scope.hasOwnBinding(name)) {
|
---|
31 | path.skip();
|
---|
32 | }
|
---|
33 | }
|
---|
34 | };
|
---|
35 | function isReferenceOrThis(node, name) {
|
---|
36 | return core.types.isThisExpression(node) || name && core.types.isIdentifier(node, {
|
---|
37 | name
|
---|
38 | });
|
---|
39 | }
|
---|
40 | const hasReferenceOrThisVisitor = {
|
---|
41 | "ThisExpression|ReferencedIdentifier"(path, state) {
|
---|
42 | if (isReferenceOrThis(path.node, state.name)) {
|
---|
43 | state.ref();
|
---|
44 | path.stop();
|
---|
45 | }
|
---|
46 | },
|
---|
47 | FunctionParent(path, state) {
|
---|
48 | if (path.isArrowFunctionExpression()) return;
|
---|
49 | if (state.name && !path.scope.hasOwnBinding(state.name)) {
|
---|
50 | path.traverse(hasReferenceVisitor, state);
|
---|
51 | }
|
---|
52 | path.skip();
|
---|
53 | if (path.isMethod()) {
|
---|
54 | if (path.requeueComputedKeyAndDecorators) {
|
---|
55 | path.requeueComputedKeyAndDecorators();
|
---|
56 | } else {
|
---|
57 | require("@babel/traverse").NodePath.prototype.requeueComputedKeyAndDecorators.call(path);
|
---|
58 | }
|
---|
59 | }
|
---|
60 | }
|
---|
61 | };
|
---|
62 | function getPotentiallyBuggyFieldsIndexes(path) {
|
---|
63 | var _path$node$id;
|
---|
64 | const buggyPublicStaticFieldsIndexes = [];
|
---|
65 | let classReferenced = false;
|
---|
66 | const className = (_path$node$id = path.node.id) == null ? void 0 : _path$node$id.name;
|
---|
67 | const hasReferenceState = {
|
---|
68 | name: className,
|
---|
69 | ref: () => classReferenced = true
|
---|
70 | };
|
---|
71 | if (className) {
|
---|
72 | for (const el of path.get("body.body")) {
|
---|
73 | if (el.node.computed) {
|
---|
74 | el.get("key").traverse(hasReferenceVisitor, hasReferenceState);
|
---|
75 | if (classReferenced) break;
|
---|
76 | }
|
---|
77 | }
|
---|
78 | }
|
---|
79 | let nextPotentiallyBuggy = false;
|
---|
80 | const {
|
---|
81 | body
|
---|
82 | } = path.node.body;
|
---|
83 | for (let i = 0; i < body.length; i++) {
|
---|
84 | const node = body[i];
|
---|
85 | if (!nextPotentiallyBuggy) {
|
---|
86 | if (core.types.isStaticBlock(node)) {
|
---|
87 | classReferenced = true;
|
---|
88 | nextPotentiallyBuggy = true;
|
---|
89 | } else if (isStaticFieldWithValue(node)) {
|
---|
90 | if (!classReferenced) {
|
---|
91 | if (isReferenceOrThis(node.value, className)) {
|
---|
92 | classReferenced = true;
|
---|
93 | } else {
|
---|
94 | path.get(`body.body.${i}.value`).traverse(hasReferenceOrThisVisitor, hasReferenceState);
|
---|
95 | }
|
---|
96 | }
|
---|
97 | if (classReferenced) {
|
---|
98 | nextPotentiallyBuggy = !path.scope.isPure(node.value);
|
---|
99 | }
|
---|
100 | }
|
---|
101 | }
|
---|
102 | if (core.types.isClassProperty(node, {
|
---|
103 | static: true
|
---|
104 | }) && (nextPotentiallyBuggy || node.computed || isNameOrLength(node.key))) {
|
---|
105 | buggyPublicStaticFieldsIndexes.push(i);
|
---|
106 | }
|
---|
107 | }
|
---|
108 | return buggyPublicStaticFieldsIndexes;
|
---|
109 | }
|
---|
110 | function getNameOrLengthStaticFieldsIndexes(path) {
|
---|
111 | const indexes = [];
|
---|
112 | const {
|
---|
113 | body
|
---|
114 | } = path.node.body;
|
---|
115 | for (let i = 0; i < body.length; i++) {
|
---|
116 | const node = body[i];
|
---|
117 | if (core.types.isClassProperty(node, {
|
---|
118 | static: true,
|
---|
119 | computed: false
|
---|
120 | }) && isNameOrLength(node.key)) {
|
---|
121 | indexes.push(i);
|
---|
122 | }
|
---|
123 | }
|
---|
124 | return indexes;
|
---|
125 | }
|
---|
126 | function toRanges(nums) {
|
---|
127 | const ranges = [];
|
---|
128 | if (nums.length === 0) return ranges;
|
---|
129 | let start = nums[0];
|
---|
130 | let end = start + 1;
|
---|
131 | for (let i = 1; i < nums.length; i++) {
|
---|
132 | if (nums[i] <= nums[i - 1]) {
|
---|
133 | throw new Error("Internal Babel error: nums must be in ascending order");
|
---|
134 | }
|
---|
135 | if (nums[i] === end) {
|
---|
136 | end++;
|
---|
137 | } else {
|
---|
138 | ranges.push([start, end]);
|
---|
139 | start = nums[i];
|
---|
140 | end = start + 1;
|
---|
141 | }
|
---|
142 | }
|
---|
143 | ranges.push([start, end]);
|
---|
144 | return ranges;
|
---|
145 | }
|
---|
146 |
|
---|
147 | function buildFieldsReplacement(fields, scope, file) {
|
---|
148 | return core.types.staticBlock(fields.map(field => {
|
---|
149 | const key = field.computed || !core.types.isIdentifier(field.key) ? field.key : core.types.stringLiteral(field.key.name);
|
---|
150 | return core.types.expressionStatement(core.types.callExpression(file.addHelper("defineProperty"), [core.types.thisExpression(), key, field.value || scope.buildUndefinedNode()]));
|
---|
151 | }));
|
---|
152 | }
|
---|
153 | var index = helperPluginUtils.declare(api => {
|
---|
154 | api.assertVersion("^7.0.0-0 || >8.0.0-alpha <8.0.0-beta");
|
---|
155 | const setPublicClassFields = api.assumption("setPublicClassFields");
|
---|
156 | return {
|
---|
157 | name: "bugfix-v8-static-class-fields-redefine-readonly",
|
---|
158 | visitor: {
|
---|
159 | Class(path) {
|
---|
160 | const ranges = toRanges(setPublicClassFields ? getNameOrLengthStaticFieldsIndexes(path) : getPotentiallyBuggyFieldsIndexes(path));
|
---|
161 | for (let i = ranges.length - 1; i >= 0; i--) {
|
---|
162 | const [start, end] = ranges[i];
|
---|
163 | const startPath = path.get("body.body")[start];
|
---|
164 | startPath.replaceWith(buildFieldsReplacement(path.node.body.body.slice(start, end), path.scope, this.file));
|
---|
165 | for (let j = end - 1; j > start; j--) {
|
---|
166 | path.get("body.body")[j].remove();
|
---|
167 | }
|
---|
168 | }
|
---|
169 | }
|
---|
170 | }
|
---|
171 | };
|
---|
172 | });
|
---|
173 |
|
---|
174 | exports.default = index;
|
---|
175 | //# sourceMappingURL=index.js.map
|
---|