Skip to content

Commit 99d542e

Browse files
authored
fix(js): support private methods and static blocks in babel preset (#36218)
## Current Behavior The `@nx/js/babel` preset loads `@babel/plugin-transform-class-properties` on its own. That plugin runs babel's shared class-features transform, which hard-errors on `#private` methods and `static {}` blocks unless their companion transforms are also loaded. When babel-jest transforms an ESM-only dependency that uses this syntax (un-ignored through `transformIgnorePatterns`, the documented way to consume ESM-only packages), the transform fails: ``` SyntaxError: Class private methods are not enabled. Please add `@babel/plugin-transform-private-methods` to your configuration. ``` ## Expected Behavior The preset transforms private methods, `#private in obj` checks, and static blocks instead of erroring. It now loads the companion class-features transforms next to `class-properties`: `private-methods` and `private-property-in-object` with the same `loose` setting (babel requires `loose` to match across the three), plus `class-static-block`. This clears the whole family of "not enabled" hard-errors, not just private methods. A regression test covering the affected syntax is added. ## Related Issue(s) Fixes #36205 <!-- polygraph-session-start --> --- [View session information ↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/gh-36205-21561609) <!-- polygraph-session-end -->
1 parent 9ba1c01 commit 99d542e

4 files changed

Lines changed: 59 additions & 0 deletions

File tree

packages/js/babel.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { transformSync } from '@babel/core';
2+
3+
describe('@nx/js/babel preset', () => {
4+
// Regression for https://github.com/nrwl/nx/issues/36205: the class-properties
5+
// plugin shares @babel/helper-create-class-features-plugin, which hard-errors on
6+
// private methods and static blocks unless their transforms are also loaded. This
7+
// surfaces when an ESM-only dep using that syntax is transformed via a
8+
// transformIgnorePatterns exception.
9+
it('does not error on private methods, static blocks, or "#private in obj" checks', () => {
10+
const code = [
11+
'class Container {',
12+
' static registry = new Map<string, boolean>();',
13+
' static {',
14+
" Container.registry.set('init', true);",
15+
' }',
16+
' #buildAutobindOptions(autobind: boolean, defaultScope: string) {',
17+
' return autobind ? { scope: defaultScope } : undefined;',
18+
' }',
19+
' has() {',
20+
' return #buildAutobindOptions in this;',
21+
' }',
22+
'}',
23+
].join('\n');
24+
25+
const result = transformSync(code, {
26+
babelrc: false,
27+
configFile: false,
28+
filename: 'container.ts',
29+
presets: [require.resolve('./babel')],
30+
});
31+
32+
expect(result?.code).toBeTruthy();
33+
// Private members are transformed away rather than left to error.
34+
expect(result?.code).not.toContain('#buildAutobindOptions');
35+
});
36+
});

packages/js/babel.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ module.exports = function (api: any, options: NxWebBabelPresetOptions = {}) {
7070
options.decorators ?? { legacy: true },
7171
],
7272
[require.resolve('@babel/plugin-transform-class-properties'), { loose }],
73+
// class-properties runs babel's shared class-features plugin, which hard-errors
74+
// on private methods and static blocks unless their transforms are loaded too.
75+
// This bites when an ESM-only dep using that syntax is transformed (un-ignored
76+
// via transformIgnorePatterns). private-property-in-object completes babel's
77+
// loose-consistency trio so `loose` stays uniform across the class-features transforms.
78+
[require.resolve('@babel/plugin-transform-private-methods'), { loose }],
79+
[
80+
require.resolve('@babel/plugin-transform-private-property-in-object'),
81+
{ loose },
82+
],
83+
require.resolve('@babel/plugin-transform-class-static-block'),
7384
].filter(Boolean);
7485

7586
return {

packages/js/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@
123123
"@babel/core": "catalog:",
124124
"@babel/plugin-proposal-decorators": "^7.22.7",
125125
"@babel/plugin-transform-class-properties": "^7.22.5",
126+
"@babel/plugin-transform-class-static-block": "^7.22.5",
127+
"@babel/plugin-transform-private-methods": "^7.22.5",
128+
"@babel/plugin-transform-private-property-in-object": "^7.22.5",
126129
"@babel/plugin-transform-runtime": "^7.23.2",
127130
"@babel/preset-env": "^7.23.2",
128131
"@babel/preset-typescript": "^7.22.5",

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)