Skip to content

Commit b2cfc5b

Browse files
Skip class fields transform when not necessary for priv methods (#14169)
Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>
1 parent 478a970 commit b2cfc5b

File tree

180 files changed

+387
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+387
-237
lines changed

packages/babel-helper-create-class-features-plugin/src/features.ts

Lines changed: 82 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { File } from "@babel/core";
1+
import type { File, types as t } from "@babel/core";
22
import type { NodePath } from "@babel/traverse";
33
import { hasOwnDecorators } from "./decorators";
44

@@ -126,62 +126,99 @@ function canIgnoreLoose(file: File, feature: number) {
126126
return !!(file.get(looseLowPriorityKey) & feature);
127127
}
128128

129-
export function verifyUsedFeatures(path: NodePath, file: File) {
129+
export function shouldTransform(path: NodePath<t.Class>, file: File): boolean {
130+
let decoratorPath: NodePath<t.Decorator> | null = null;
131+
let publicFieldPath: NodePath<t.ClassProperty> | null = null;
132+
let privateFieldPath: NodePath<t.ClassPrivateProperty> | null = null;
133+
let privateMethodPath: NodePath<t.ClassPrivateMethod> | null = null;
134+
let staticBlockPath: NodePath<t.StaticBlock> | null = null;
135+
130136
if (hasOwnDecorators(path.node)) {
131-
if (!hasFeature(file, FEATURES.decorators)) {
132-
throw path.buildCodeFrameError(
133-
"Decorators are not enabled." +
134-
"\nIf you are using " +
135-
'["@babel/plugin-proposal-decorators", { "legacy": true }], ' +
136-
'make sure it comes *before* "@babel/plugin-proposal-class-properties" ' +
137-
"and enable loose mode, like so:\n" +
138-
'\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n' +
139-
'\t["@babel/plugin-proposal-class-properties", { "loose": true }]',
140-
);
137+
decoratorPath = path.get("decorators.0");
138+
}
139+
for (const el of path.get("body.body")) {
140+
if (!decoratorPath && hasOwnDecorators(el.node)) {
141+
decoratorPath = el.get("decorators.0");
141142
}
142-
143-
if (path.isPrivate()) {
144-
throw path.buildCodeFrameError(
145-
`Private ${
146-
path.isClassMethod() ? "methods" : "fields"
147-
} in decorated classes are not supported yet.`,
148-
);
143+
if (!publicFieldPath && el.isClassProperty()) {
144+
publicFieldPath = el;
145+
}
146+
if (!privateFieldPath && el.isClassPrivateProperty()) {
147+
privateFieldPath = el;
148+
}
149+
// NOTE: path.isClassPrivateMethod() it isn't supported in <7.2.0
150+
if (!privateMethodPath && el.isClassPrivateMethod?.()) {
151+
privateMethodPath = el;
152+
}
153+
if (!staticBlockPath && el.isStaticBlock?.()) {
154+
staticBlockPath = el;
149155
}
150156
}
151157

152-
// NOTE: path.isClassPrivateMethod() it isn't supported in <7.2.0
153-
if (path.isClassPrivateMethod?.()) {
154-
if (!hasFeature(file, FEATURES.privateMethods)) {
155-
throw path.buildCodeFrameError("Class private methods are not enabled.");
156-
}
158+
if (decoratorPath && privateFieldPath) {
159+
throw privateFieldPath.buildCodeFrameError(
160+
"Private fields in decorated classes are not supported yet.",
161+
);
162+
}
163+
if (decoratorPath && privateMethodPath) {
164+
throw privateMethodPath.buildCodeFrameError(
165+
"Private methods in decorated classes are not supported yet.",
166+
);
167+
}
168+
169+
if (decoratorPath && !hasFeature(file, FEATURES.decorators)) {
170+
throw path.buildCodeFrameError(
171+
"Decorators are not enabled." +
172+
"\nIf you are using " +
173+
'["@babel/plugin-proposal-decorators", { "legacy": true }], ' +
174+
'make sure it comes *before* "@babel/plugin-proposal-class-properties" ' +
175+
"and enable loose mode, like so:\n" +
176+
'\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n' +
177+
'\t["@babel/plugin-proposal-class-properties", { "loose": true }]',
178+
);
179+
}
180+
181+
if (privateMethodPath && !hasFeature(file, FEATURES.privateMethods)) {
182+
throw privateMethodPath.buildCodeFrameError(
183+
"Class private methods are not enabled. " +
184+
"Please add `@babel/plugin-proposal-private-method` to your configuration.",
185+
);
157186
}
158187

159188
if (
160-
path.isPrivateName() &&
161-
path.parentPath.isBinaryExpression({
162-
operator: "in",
163-
left: path.node,
164-
})
189+
(publicFieldPath || privateFieldPath) &&
190+
!hasFeature(file, FEATURES.fields) &&
191+
// We want to allow enabling the private-methods plugin even without enabling
192+
// the class-properties plugin. Class fields will still be compiled in classes
193+
// that contain private methods.
194+
// This is already allowed with the other various class features plugins, but
195+
// it's because they can fallback to a transform separated from this helper.
196+
!hasFeature(file, FEATURES.privateMethods)
165197
) {
166-
if (!hasFeature(file, FEATURES.privateIn)) {
167-
throw path.buildCodeFrameError(
168-
"Private property in checks are not enabled.",
169-
);
170-
}
198+
throw path.buildCodeFrameError(
199+
"Class fields are not enabled. " +
200+
"Please add `@babel/plugin-proposal-class-properties` to your configuration.",
201+
);
171202
}
172203

173-
if (path.isProperty()) {
174-
if (!hasFeature(file, FEATURES.fields)) {
175-
throw path.buildCodeFrameError("Class fields are not enabled.");
176-
}
204+
if (staticBlockPath && !hasFeature(file, FEATURES.staticBlocks)) {
205+
throw path.buildCodeFrameError(
206+
"Static class blocks are not enabled. " +
207+
"Please add `@babel/plugin-proposal-class-static-block` to your configuration.",
208+
);
177209
}
178210

179-
if (path.isStaticBlock?.()) {
180-
if (!hasFeature(file, FEATURES.staticBlocks)) {
181-
throw path.buildCodeFrameError(
182-
"Static class blocks are not enabled. " +
183-
"Please add `@babel/plugin-proposal-class-static-block` to your configuration.",
184-
);
185-
}
211+
if (decoratorPath || privateMethodPath || staticBlockPath) {
212+
// If one of those feature is used we know that its transform is
213+
// enabled, otherwise the previous checks throw.
214+
return true;
186215
}
216+
if (
217+
(publicFieldPath || privateFieldPath) &&
218+
hasFeature(file, FEATURES.fields)
219+
) {
220+
return true;
221+
}
222+
223+
return false;
187224
}

packages/babel-helper-create-class-features-plugin/src/index.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,7 @@ import {
1212
import type { PropPath } from "./fields";
1313
import { buildDecoratedClass, hasDecorators } from "./decorators";
1414
import { injectInitialization, extractComputedKeys } from "./misc";
15-
import {
16-
enableFeature,
17-
verifyUsedFeatures,
18-
FEATURES,
19-
isLoose,
20-
} from "./features";
15+
import { enableFeature, FEATURES, isLoose, shouldTransform } from "./features";
2116
import { assertFieldTransformed } from "./typescript";
2217
import type { ParserOptions } from "@babel/parser";
2318

@@ -98,7 +93,7 @@ export function createClassFeaturePlugin({
9893
Class(path: NodePath<t.Class>, state: File) {
9994
if (this.file.get(versionKey) !== version) return;
10095

101-
verifyUsedFeatures(path, this.file);
96+
if (!shouldTransform(path, this.file)) return;
10297

10398
if (path.isClassDeclaration()) assertFieldTransformed(path);
10499

@@ -113,8 +108,6 @@ export function createClassFeaturePlugin({
113108
const body = path.get("body");
114109

115110
for (const path of body.get("body")) {
116-
verifyUsedFeatures(path, this.file);
117-
118111
if (
119112
// check path.node.computed is enough, but ts will complain
120113
(path.isClassProperty() || path.isClassMethod()) &&
@@ -266,17 +259,6 @@ export function createClassFeaturePlugin({
266259
}
267260
},
268261

269-
PrivateName(path: NodePath<t.PrivateName>) {
270-
if (
271-
this.file.get(versionKey) !== version ||
272-
path.parentPath.isPrivate({ key: path.node })
273-
) {
274-
return;
275-
}
276-
277-
throw path.buildCodeFrameError(`Unknown PrivateName "${path}"`);
278-
},
279-
280262
ExportDefaultDeclaration(path: NodePath<t.ExportDefaultDeclaration>) {
281263
if (this.file.get(versionKey) !== version) return;
282264

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"presets": [["env", { "shippedProposals": true }]],
33
"targets": {
4-
"chrome": "75"
4+
"chrome": "70"
55
}
66
}

packages/babel-preset-env/src/plugins-compat-data.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,4 @@ for (const plugin of Object.keys(bugfixPlugins)) {
1717
}
1818
}
1919

20-
pluginsFiltered["proposal-class-properties"] =
21-
pluginsFiltered["proposal-private-methods"];
22-
2320
export { pluginsFiltered as plugins, bugfixPluginsFiltered as pluginsBugfixes };

packages/babel-preset-env/test/fixtures/bugfixes/_esmodules-no-bugfixes/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Using modules transform: auto
1818
Using plugins:
1919
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
2020
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
21-
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
21+
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
2222
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
2323
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
2424
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }

packages/babel-preset-env/test/fixtures/bugfixes/_esmodules/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Using modules transform: auto
1818
Using plugins:
1919
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
2020
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
21-
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
21+
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
2222
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
2323
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
2424
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }

packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-40/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Using modules transform: auto
1010
Using plugins:
1111
proposal-class-static-block { chrome < 94 }
1212
proposal-private-property-in-object { chrome < 91 }
13-
proposal-class-properties { chrome < 84 }
13+
proposal-class-properties { chrome < 74 }
1414
proposal-private-methods { chrome < 84 }
1515
proposal-numeric-separator { chrome < 75 }
1616
proposal-logical-assignment-operators { chrome < 85 }

packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-chrome-70/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Using modules transform: auto
1010
Using plugins:
1111
proposal-class-static-block { chrome < 94 }
1212
proposal-private-property-in-object { chrome < 91 }
13-
proposal-class-properties { chrome < 84 }
13+
proposal-class-properties { chrome < 74 }
1414
proposal-private-methods { chrome < 84 }
1515
proposal-numeric-separator { chrome < 75 }
1616
proposal-logical-assignment-operators { chrome < 85 }

packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-14/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Using modules transform: auto
1010
Using plugins:
1111
proposal-class-static-block { edge < 94 }
1212
proposal-private-property-in-object { edge < 91 }
13-
proposal-class-properties { edge < 84 }
13+
proposal-class-properties { edge < 79 }
1414
proposal-private-methods { edge < 84 }
1515
proposal-numeric-separator { edge < 79 }
1616
proposal-logical-assignment-operators { edge < 85 }

packages/babel-preset-env/test/fixtures/bugfixes/edge-default-params-edge-15/stdout.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Using modules transform: auto
1010
Using plugins:
1111
proposal-class-static-block { edge < 94 }
1212
proposal-private-property-in-object { edge < 91 }
13-
proposal-class-properties { edge < 84 }
13+
proposal-class-properties { edge < 79 }
1414
proposal-private-methods { edge < 84 }
1515
proposal-numeric-separator { edge < 79 }
1616
proposal-logical-assignment-operators { edge < 85 }

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy