Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bea64c5
feat: first attempt
a-chabot Feb 13, 2026
f443394
fix: linter fix
a-chabot Feb 13, 2026
2d9ad36
fix: update note
a-chabot Feb 13, 2026
999c686
fix: cleaning up lint errors to be able to run tests
a-chabot Feb 23, 2026
6b1f599
fix: bump "Next error code" comment to 1213
a-chabot Feb 23, 2026
4b1e630
feat: add round-trip validation for private method transforms
a-chabot Feb 26, 2026
8dcb515
test: add full-cycle and intermediate disruption tests for private me…
a-chabot Feb 26, 2026
9b1e109
refactor: make PRIVATE_METHOD_NAME_COLLISION error message mention re…
a-chabot Mar 2, 2026
61ad8b5
chore: revert playground counter.js to master
a-chabot Mar 2, 2026
76da7ac
refactor: hoist methodKind constant to module scope
a-chabot Mar 2, 2026
fcf9c25
refactor: extract shared copyMethodMetadata helper for private method…
a-chabot Mar 2, 2026
c409872
refactor: make forward and reverse private method transforms independ…
a-chabot Mar 2, 2026
591bc67
refactor: move non-null assertion to transformSync helpers in tests
a-chabot Mar 2, 2026
a2d3e4b
refactor: consolidate fragmented toContain assertions in tests
a-chabot Mar 2, 2026
7e51945
test: add test cases for private fields passing through unchanged
a-chabot Mar 2, 2026
d4f93e4
test: add test cases for rogue #privateNames not sneaking through
a-chabot Mar 2, 2026
f284247
feat: add unsupported private member errors and fixture e2e tests
a-chabot Mar 2, 2026
380c24d
chore: retrigger CI
a-chabot Mar 2, 2026
f18b317
feat: transform private method invocations in forward and reverse passes
a-chabot Mar 4, 2026
3461010
feat: gate private method transform behind enablePrivateMethods compi…
a-chabot Mar 4, 2026
2ba8959
feat: thread enablePrivateMethods through rollup plugin and enable in…
a-chabot Mar 4, 2026
d38ae20
chore: revert playground counter and rollup config changes
a-chabot Mar 4, 2026
c59f08a
Merge pull request #1 from a-chabot/a-chabot/private-methods-compiler…
a-chabot Mar 4, 2026
446b34a
test: move private-methods fixture tests to dedicated branch
a-chabot Mar 4, 2026
197d2ff
test: remove inline tests now covered by fixture tests
a-chabot Mar 4, 2026
f024518
test: remove inline tests now covered by fixture tests
a-chabot Mar 4, 2026
4d60549
test: replace per-test comments with top-of-file blurb
a-chabot Mar 4, 2026
500c3b3
test: add cross-class private method access inline tests
a-chabot Mar 4, 2026
e49f1b3
docs: add enablePrivateMethods to rollup plugin README
a-chabot Mar 4, 2026
2820b37
docs: add enablePrivateMethods to compiler README
a-chabot Mar 5, 2026
cb1870d
test: skip empty private-methods fixtures suite until tests are merged
a-chabot Mar 5, 2026
c2a8c07
Merge remote-tracking branch 'origin/master' into a-chabot/private-me…
a-chabot Mar 6, 2026
5adb1be
fix: enable flag
a-chabot Mar 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { LightningElement } from 'lwc';
export default class Test extends LightningElement {
#validate(input) {
return input != null;
}
#transform(input) {
return String(input).trim();
}
#process(input) {
if (this.#validate(input)) {
return this.#transform(input);
}
return null;
}
connectedCallback() {
this.#process('hello');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import _tmpl from "./test.html";
import { LightningElement, registerComponent as _registerComponent } from 'lwc';
class Test extends LightningElement {
#validate(input) {
return input != null;
}
#transform(input) {
return String(input).trim();
}
#process(input) {
if (this.#validate(input)) {
return this.#transform(input);
}
return null;
}
connectedCallback() {
this.#process('hello');
}
/*LWC compiler vX.X.X*/
}
const __lwc_component_class_internal = _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
export default __lwc_component_class_internal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { LightningElement, api } from 'lwc';
export default class Test extends LightningElement {
@api label = 'default';
count = 0;

#increment() {
this.count++;
}

handleClick() {
this.#increment();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { registerDecorators as _registerDecorators } from "lwc";
import _tmpl from "./test.html";
import { LightningElement, registerComponent as _registerComponent } from 'lwc';
class Test extends LightningElement {
constructor(...args) {
super(...args);
this.label = 'default';
this.count = 0;
}
#increment() {
this.count++;
}
handleClick() {
this.#increment();
}
/*LWC compiler vX.X.X*/
}
_registerDecorators(Test, {
publicProps: {
label: {
config: 0
}
},
fields: ["count"]
});
const __lwc_component_class_internal = _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
export default __lwc_component_class_internal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LightningElement } from 'lwc';
export default class Test extends LightningElement {
#privateHelper() {
return 42;
}
connectedCallback() {
const val = this.#privateHelper();
console.log(val);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import _tmpl from "./test.html";
import { LightningElement, registerComponent as _registerComponent } from 'lwc';
class Test extends LightningElement {
#privateHelper() {
return 42;
}
connectedCallback() {
const val = this.#privateHelper();
console.log(val);
}
/*LWC compiler vX.X.X*/
}
const __lwc_component_class_internal = _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
export default __lwc_component_class_internal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LightningElement } from 'lwc';
export default class Test extends LightningElement {
static async #fetchData(url) {
const response = await fetch(url);
return response.json();
}
async connectedCallback() {
const data = await Test.#fetchData('/api/data');
console.log(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import _tmpl from "./test.html";
import { LightningElement, registerComponent as _registerComponent } from 'lwc';
class Test extends LightningElement {
static async #fetchData(url) {
const response = await fetch(url);
return response.json();
}
async connectedCallback() {
const data = await Test.#fetchData('/api/data');
console.log(data);
}
/*LWC compiler vX.X.X*/
}
const __lwc_component_class_internal = _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
export default __lwc_component_class_internal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { LightningElement } from 'lwc';
export default class Test extends LightningElement {
#count = 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1214: Private fields are not currently supported. Only private methods are supported.",
"loc": {
"line": 3,
"column": 4,
"start": 97,
"length": 11
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { LightningElement } from 'lwc';
export default class Test extends LightningElement {
get #value() {
return this._val;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1214: Private accessor methods are not currently supported. Only private methods are supported.",
"loc": {
"line": 3,
"column": 4,
"start": 97,
"length": 46
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
import path from 'node:path';
import { describe } from 'vitest';
import { transformSync } from '@babel/core';
import babelClassPropertiesPlugin from '@babel/plugin-transform-class-properties';
import { LWC_VERSION, HIGHEST_API_VERSION } from '@lwc/shared';
import { testFixtureDir } from '@lwc/test-utils-lwc-internals';
import plugin, { type LwcBabelPluginOptions } from '../index';
import plugin, {
LwcPrivateMethodTransform,
LwcReversePrivateMethodTransform,
type LwcBabelPluginOptions,
} from '../index';

interface TestConfig extends LwcBabelPluginOptions {
experimentalErrorRecoveryMode?: boolean;
Expand Down Expand Up @@ -82,7 +87,7 @@ describe('fixtures', () => {
testFixtureDir<TestConfig>(
{
root: path.resolve(import.meta.dirname, 'fixtures'),
pattern: '**/actual.js',
pattern: '!(private-methods)/**/actual.js',
ssrVersion: 2,
},
({ src, config }) => {
Expand Down Expand Up @@ -110,3 +115,55 @@ describe('fixtures', () => {
}
);
});

function transformWithPrivateMethodPipeline(source: string, opts = {}) {
const testConfig = {
...BASE_CONFIG,
parserOpts: (opts as any).parserOpts ?? {},
plugins: [
LwcPrivateMethodTransform,
[plugin, { ...BASE_OPTS, ...opts }],
[babelClassPropertiesPlugin, { loose: true }],
LwcReversePrivateMethodTransform,
],
};

const result = transformSync(source, testConfig)!;

let { code } = result;

code = code!.replace(new RegExp(LWC_VERSION.replace(/\./g, '\\.'), 'g'), 'X.X.X');

code = code.replace(
new RegExp(`apiVersion: ${HIGHEST_API_VERSION}`, 'g'),
`apiVersion: 9999999`
);

return { code };
}

describe('private-methods fixtures', () => {
testFixtureDir(
{
root: path.resolve(import.meta.dirname, 'fixtures', 'private-methods'),
pattern: '**/actual.js',
ssrVersion: 2,
},
({ src, config }) => {
let code;
let error;

try {
const result = transformWithPrivateMethodPipeline(src, config);
code = result.code;
} catch (err) {
error = JSON.stringify(normalizeError(err), null, 4);
}

return {
'expected.js': code,
'error.json': error,
};
}
);
});
Loading
Loading