Skip to content

Commit

Permalink
Remove ordering constraints for static-blocks plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed May 11, 2021
1 parent 9e241fc commit 8294b8c
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 60 deletions.
13 changes: 4 additions & 9 deletions packages/babel-helper-create-class-features-plugin/src/index.js
Expand Up @@ -154,15 +154,10 @@ export function createClassFeaturePlugin({
if (!isDecorated) isDecorated = hasOwnDecorators(path.node);

if (path.isStaticBlock?.()) {
throw path.buildCodeFrameError(`Incorrect plugin order, \`@babel/plugin-proposal-class-static-block\` should be placed before class features plugins
{
"plugins": [
"@babel/plugin-proposal-class-static-block",
"@babel/plugin-proposal-private-property-in-object",
"@babel/plugin-proposal-private-methods",
"@babel/plugin-proposal-class-properties",
]
}`);
throw path.buildCodeFrameError(
"Compiling class fields and private methods requires compiling class static blocks." +
" Please add `@babel/plugin-proposal-class-static-block` to your Babel configuration.",
);
}
}

Expand Down
@@ -0,0 +1,4 @@
class A {
#x;
static {}
}
@@ -0,0 +1,4 @@
{
"plugins": ["proposal-class-properties", "syntax-class-static-block"],
"throws": "Compiling class fields and private methods requires compiling class static blocks. Please add `@babel/plugin-proposal-class-static-block` to your Babel configuration."
}
59 changes: 33 additions & 26 deletions packages/babel-plugin-proposal-class-static-block/src/index.js
Expand Up @@ -26,32 +26,39 @@ export default declare(({ types: t, template, assertVersion }) => {
name: "proposal-class-static-block",
inherits: syntaxClassStaticBlock,
visitor: {
Class(path: NodePath<Class>) {
const { scope } = path;
const classBody = path.get("body");
const privateNames = new Set();
const body = classBody.get("body");
for (const path of body) {
if (path.isPrivate()) {
privateNames.add(path.get("key.id").node.name);
}
}
for (const path of body) {
if (!path.isStaticBlock()) continue;
const staticBlockPrivateId = generateUid(scope, privateNames);
privateNames.add(staticBlockPrivateId);
const staticBlockRef = t.privateName(
t.identifier(staticBlockPrivateId),
);
path.replaceWith(
t.classPrivateProperty(
staticBlockRef,
template.expression.ast`(() => { ${path.node.body} })()`,
[],
/* static */ true,
),
);
}
Program(path) {
// We run this from the program visitor, so that when transforming private elements
// we are sure that static blocks have already been transformed regarless of the
// plugins order in the user config.
path.traverse({
Class(path: NodePath<Class>) {
const { scope } = path;
const classBody = path.get("body");
const privateNames = new Set();
const body = classBody.get("body");
for (const path of body) {
if (path.isPrivate()) {
privateNames.add(path.get("key.id").node.name);
}
}
for (const path of body) {
if (!path.isStaticBlock()) continue;
const staticBlockPrivateId = generateUid(scope, privateNames);
privateNames.add(staticBlockPrivateId);
const staticBlockRef = t.privateName(
t.identifier(staticBlockPrivateId),
);
path.replaceWith(
t.classPrivateProperty(
staticBlockRef,
template.expression.ast`(() => { ${path.node.body} })()`,
[],
/* static */ true,
),
);
}
},
});
},
},
};
Expand Down
Expand Up @@ -2,15 +2,15 @@ import * as babel from "@babel/core";
import proposalClassStaticBlock from "..";

describe("plugin ordering", () => {
it("should throw when @babel/plugin-proposal-class-static-block is after class features plugin", () => {
it("should work when @babel/plugin-proposal-class-static-block is after class features plugin", () => {
const source = `class Foo {
static {
this.foo = Foo.bar;
}
static bar = 42;
}
`;
expect(() => {
static {
this.foo = Foo.bar;
}
static bar = 42;
}
`;
expect(
babel.transform(source, {
filename: "example.js",
highlightCode: false,
Expand All @@ -20,22 +20,117 @@ describe("plugin ordering", () => {
"@babel/plugin-proposal-class-properties",
proposalClassStaticBlock,
],
});
})
.toThrow(`Incorrect plugin order, \`@babel/plugin-proposal-class-static-block\` should be placed before class features plugins
{
"plugins": [
"@babel/plugin-proposal-class-static-block",
"@babel/plugin-proposal-private-property-in-object",
"@babel/plugin-proposal-private-methods",
"@babel/plugin-proposal-class-properties",
]
}
1 | class Foo {
> 2 | static {
| ^
3 | this.foo = Foo.bar;
4 | }
5 | static bar = 42;`);
}),
).toMatchInlineSnapshot(`
Object {
"ast": null,
"code": "function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class Foo {}
var _ = {
writable: true,
value: (() => {
Foo.foo = Foo.bar;
})()
};
_defineProperty(Foo, \\"bar\\", 42);",
"map": null,
"metadata": Object {},
"options": Object {
"assumptions": Object {},
"babelrc": false,
"browserslistConfigFile": false,
"cloneInputAst": true,
"configFile": false,
"cwd": "/home/nicolo/Documenti/dev/babel/babel",
"envName": "test",
"filename": "/home/nicolo/Documenti/dev/babel/babel/example.js",
"generatorOpts": Object {
"auxiliaryCommentAfter": undefined,
"auxiliaryCommentBefore": undefined,
"comments": true,
"compact": "auto",
"filename": "/home/nicolo/Documenti/dev/babel/babel/example.js",
"minified": undefined,
"retainLines": undefined,
"shouldPrintComment": undefined,
"sourceFileName": "example.js",
"sourceMaps": false,
"sourceRoot": undefined,
},
"highlightCode": false,
"parserOpts": Object {
"plugins": Array [
"classProperties",
"classPrivateProperties",
"classStaticBlock",
],
"sourceFileName": "/home/nicolo/Documenti/dev/babel/babel/example.js",
"sourceType": "module",
},
"passPerPreset": false,
"plugins": Array [
Plugin {
"generatorOverride": undefined,
"key": "proposal-class-properties",
"manipulateOptions": [Function],
"options": Object {},
"parserOverride": undefined,
"post": undefined,
"pre": [Function],
"visitor": Object {
"ClassDeclaration": Object {
"enter": Array [
[Function],
],
},
"ClassExpression": Object {
"enter": Array [
[Function],
],
},
"ExportDefaultDeclaration": Object {
"enter": Array [
[Function],
],
},
"PrivateName": Object {
"enter": Array [
[Function],
],
},
"_exploded": true,
"_verified": true,
},
},
Plugin {
"generatorOverride": undefined,
"key": "proposal-class-static-block",
"manipulateOptions": [Function],
"options": Object {},
"parserOverride": undefined,
"post": undefined,
"pre": undefined,
"visitor": Object {
"Program": Object {
"enter": Array [
[Function],
],
},
"_exploded": Object {},
"_verified": Object {},
},
},
],
"presets": Array [],
"root": "/home/nicolo/Documenti/dev/babel/babel",
"rootMode": "root",
"targets": Object {},
},
"sourceType": "module",
}
`);
});
});

0 comments on commit 8294b8c

Please sign in to comment.