Skip to content

Commit

Permalink
Skip class fields transform when not necessary for priv methods (#14169)
Browse files Browse the repository at this point in the history
Co-authored-by: Hu谩ng J霉nli脿ng <jlhwung@gmail.com>
  • Loading branch information
nicolo-ribaudo and JLHwung committed Jan 18, 2022
1 parent 478a970 commit b2cfc5b
Show file tree
Hide file tree
Showing 180 changed files with 387 additions and 237 deletions.
127 changes: 82 additions & 45 deletions packages/babel-helper-create-class-features-plugin/src/features.ts
@@ -1,4 +1,4 @@
import type { File } from "@babel/core";
import type { File, types as t } from "@babel/core";
import type { NodePath } from "@babel/traverse";
import { hasOwnDecorators } from "./decorators";

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

export function verifyUsedFeatures(path: NodePath, file: File) {
export function shouldTransform(path: NodePath<t.Class>, file: File): boolean {
let decoratorPath: NodePath<t.Decorator> | null = null;
let publicFieldPath: NodePath<t.ClassProperty> | null = null;
let privateFieldPath: NodePath<t.ClassPrivateProperty> | null = null;
let privateMethodPath: NodePath<t.ClassPrivateMethod> | null = null;
let staticBlockPath: NodePath<t.StaticBlock> | null = null;

if (hasOwnDecorators(path.node)) {
if (!hasFeature(file, FEATURES.decorators)) {
throw path.buildCodeFrameError(
"Decorators are not enabled." +
"\nIf you are using " +
'["@babel/plugin-proposal-decorators", { "legacy": true }], ' +
'make sure it comes *before* "@babel/plugin-proposal-class-properties" ' +
"and enable loose mode, like so:\n" +
'\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n' +
'\t["@babel/plugin-proposal-class-properties", { "loose": true }]',
);
decoratorPath = path.get("decorators.0");
}
for (const el of path.get("body.body")) {
if (!decoratorPath && hasOwnDecorators(el.node)) {
decoratorPath = el.get("decorators.0");
}

if (path.isPrivate()) {
throw path.buildCodeFrameError(
`Private ${
path.isClassMethod() ? "methods" : "fields"
} in decorated classes are not supported yet.`,
);
if (!publicFieldPath && el.isClassProperty()) {
publicFieldPath = el;
}
if (!privateFieldPath && el.isClassPrivateProperty()) {
privateFieldPath = el;
}
// NOTE: path.isClassPrivateMethod() it isn't supported in <7.2.0
if (!privateMethodPath && el.isClassPrivateMethod?.()) {
privateMethodPath = el;
}
if (!staticBlockPath && el.isStaticBlock?.()) {
staticBlockPath = el;
}
}

// NOTE: path.isClassPrivateMethod() it isn't supported in <7.2.0
if (path.isClassPrivateMethod?.()) {
if (!hasFeature(file, FEATURES.privateMethods)) {
throw path.buildCodeFrameError("Class private methods are not enabled.");
}
if (decoratorPath && privateFieldPath) {
throw privateFieldPath.buildCodeFrameError(
"Private fields in decorated classes are not supported yet.",
);
}
if (decoratorPath && privateMethodPath) {
throw privateMethodPath.buildCodeFrameError(
"Private methods in decorated classes are not supported yet.",
);
}

if (decoratorPath && !hasFeature(file, FEATURES.decorators)) {
throw path.buildCodeFrameError(
"Decorators are not enabled." +
"\nIf you are using " +
'["@babel/plugin-proposal-decorators", { "legacy": true }], ' +
'make sure it comes *before* "@babel/plugin-proposal-class-properties" ' +
"and enable loose mode, like so:\n" +
'\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n' +
'\t["@babel/plugin-proposal-class-properties", { "loose": true }]',
);
}

if (privateMethodPath && !hasFeature(file, FEATURES.privateMethods)) {
throw privateMethodPath.buildCodeFrameError(
"Class private methods are not enabled. " +
"Please add `@babel/plugin-proposal-private-method` to your configuration.",
);
}

if (
path.isPrivateName() &&
path.parentPath.isBinaryExpression({
operator: "in",
left: path.node,
})
(publicFieldPath || privateFieldPath) &&
!hasFeature(file, FEATURES.fields) &&
// We want to allow enabling the private-methods plugin even without enabling
// the class-properties plugin. Class fields will still be compiled in classes
// that contain private methods.
// This is already allowed with the other various class features plugins, but
// it's because they can fallback to a transform separated from this helper.
!hasFeature(file, FEATURES.privateMethods)
) {
if (!hasFeature(file, FEATURES.privateIn)) {
throw path.buildCodeFrameError(
"Private property in checks are not enabled.",
);
}
throw path.buildCodeFrameError(
"Class fields are not enabled. " +
"Please add `@babel/plugin-proposal-class-properties` to your configuration.",
);
}

if (path.isProperty()) {
if (!hasFeature(file, FEATURES.fields)) {
throw path.buildCodeFrameError("Class fields are not enabled.");
}
if (staticBlockPath && !hasFeature(file, FEATURES.staticBlocks)) {
throw path.buildCodeFrameError(
"Static class blocks are not enabled. " +
"Please add `@babel/plugin-proposal-class-static-block` to your configuration.",
);
}

if (path.isStaticBlock?.()) {
if (!hasFeature(file, FEATURES.staticBlocks)) {
throw path.buildCodeFrameError(
"Static class blocks are not enabled. " +
"Please add `@babel/plugin-proposal-class-static-block` to your configuration.",
);
}
if (decoratorPath || privateMethodPath || staticBlockPath) {
// If one of those feature is used we know that its transform is
// enabled, otherwise the previous checks throw.
return true;
}
if (
(publicFieldPath || privateFieldPath) &&
hasFeature(file, FEATURES.fields)
) {
return true;
}

return false;
}
22 changes: 2 additions & 20 deletions packages/babel-helper-create-class-features-plugin/src/index.ts
Expand Up @@ -12,12 +12,7 @@ import {
import type { PropPath } from "./fields";
import { buildDecoratedClass, hasDecorators } from "./decorators";
import { injectInitialization, extractComputedKeys } from "./misc";
import {
enableFeature,
verifyUsedFeatures,
FEATURES,
isLoose,
} from "./features";
import { enableFeature, FEATURES, isLoose, shouldTransform } from "./features";
import { assertFieldTransformed } from "./typescript";
import type { ParserOptions } from "@babel/parser";

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

verifyUsedFeatures(path, this.file);
if (!shouldTransform(path, this.file)) return;

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

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

for (const path of body.get("body")) {
verifyUsedFeatures(path, this.file);

if (
// check path.node.computed is enough, but ts will complain
(path.isClassProperty() || path.isClassMethod()) &&
Expand Down Expand Up @@ -266,17 +259,6 @@ export function createClassFeaturePlugin({
}
},

PrivateName(path: NodePath<t.PrivateName>) {
if (
this.file.get(versionKey) !== version ||
path.parentPath.isPrivate({ key: path.node })
) {
return;
}

throw path.buildCodeFrameError(`Unknown PrivateName "${path}"`);
},

ExportDefaultDeclaration(path: NodePath<t.ExportDefaultDeclaration>) {
if (this.file.get(versionKey) !== version) return;

Expand Down
@@ -1,6 +1,6 @@
{
"presets": [["env", { "shippedProposals": true }]],
"targets": {
"chrome": "75"
"chrome": "70"
}
}
3 changes: 0 additions & 3 deletions packages/babel-preset-env/src/plugins-compat-data.ts
Expand Up @@ -17,7 +17,4 @@ for (const plugin of Object.keys(bugfixPlugins)) {
}
}

pluginsFiltered["proposal-class-properties"] =
pluginsFiltered["proposal-private-methods"];

export { pluginsFiltered as plugins, bugfixPluginsFiltered as pluginsBugfixes };
Expand Up @@ -18,7 +18,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down
Expand Up @@ -18,7 +18,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { chrome < 94 }
proposal-private-property-in-object { chrome < 91 }
proposal-class-properties { chrome < 84 }
proposal-class-properties { chrome < 74 }
proposal-private-methods { chrome < 84 }
proposal-numeric-separator { chrome < 75 }
proposal-logical-assignment-operators { chrome < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { chrome < 94 }
proposal-private-property-in-object { chrome < 91 }
proposal-class-properties { chrome < 84 }
proposal-class-properties { chrome < 74 }
proposal-private-methods { chrome < 84 }
proposal-numeric-separator { chrome < 75 }
proposal-logical-assignment-operators { chrome < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { edge < 94 }
proposal-private-property-in-object { edge < 91 }
proposal-class-properties { edge < 84 }
proposal-class-properties { edge < 79 }
proposal-private-methods { edge < 84 }
proposal-numeric-separator { edge < 79 }
proposal-logical-assignment-operators { edge < 85 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { safari }
proposal-private-property-in-object { safari < 15 }
proposal-class-properties { safari < 15 }
proposal-class-properties { safari < 14.1 }
proposal-private-methods { safari < 15 }
proposal-numeric-separator { safari < 13 }
proposal-logical-assignment-operators { safari < 14 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { safari }
proposal-private-property-in-object { safari < 15 }
proposal-class-properties { safari < 15 }
proposal-class-properties { safari < 14.1 }
proposal-private-methods { safari < 15 }
proposal-numeric-separator { safari < 13 }
proposal-logical-assignment-operators { safari < 14 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { safari }
proposal-private-property-in-object { safari < 15 }
proposal-class-properties { safari < 15 }
proposal-class-properties { safari < 14.1 }
proposal-private-methods { safari < 15 }
proposal-numeric-separator { safari < 13 }
proposal-logical-assignment-operators { safari < 14 }
Expand Down
Expand Up @@ -10,7 +10,7 @@ Using modules transform: auto
Using plugins:
proposal-class-static-block { safari }
proposal-private-property-in-object { safari < 15 }
proposal-class-properties { safari < 15 }
proposal-class-properties { safari < 14.1 }
proposal-private-methods { safari < 15 }
proposal-numeric-separator { safari < 13 }
proposal-logical-assignment-operators { safari < 14 }
Expand Down
Expand Up @@ -18,7 +18,7 @@ Using modules transform: false
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down
Expand Up @@ -18,7 +18,7 @@ Using modules transform: false
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down
Expand Up @@ -18,7 +18,7 @@ Using modules transform: false
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down
Expand Up @@ -18,7 +18,7 @@ Using modules transform: false
Using plugins:
proposal-class-static-block { android, chrome < 94, edge < 94, firefox < 93, ios, node < 16.11, opera < 80, safari, samsung }
proposal-private-property-in-object { android, chrome < 91, edge < 91, firefox < 90, ios < 15, node < 16.9, opera < 77, safari < 15, samsung }
proposal-class-properties { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-class-properties { android, chrome < 74, edge < 79, firefox < 90, ios < 15, opera < 62, safari < 14.1, samsung < 11 }
proposal-private-methods { android, chrome < 84, edge < 84, firefox < 90, ios < 15, node < 14.6, opera < 70, safari < 15, samsung < 14 }
proposal-numeric-separator { android, chrome < 75, edge < 79, firefox < 70, ios < 13, opera < 62, safari < 13, samsung < 11 }
proposal-logical-assignment-operators { android, chrome < 85, edge < 85, firefox < 79, ios < 14, node < 15, opera < 71, safari < 14, samsung < 14 }
Expand Down

0 comments on commit b2cfc5b

Please sign in to comment.