diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/error.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/expected.html
new file mode 100644
index 0000000000..4b6d956f1a
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/expected.html
@@ -0,0 +1,14 @@
+
+
+
+
+ const setter getter api value
+
+
+
+
+ setter getter api value
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/index.js
new file mode 100644
index 0000000000..d5a55ceefa
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/index.js
@@ -0,0 +1,3 @@
+export const tagName = 'x-parent';
+export { default } from 'x/parent';
+export * from 'x/parent';
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.html
new file mode 100755
index 0000000000..9a178c0e77
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.html
@@ -0,0 +1,3 @@
+
+ {setterGetterApi}
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.js
new file mode 100755
index 0000000000..7c97dd51ea
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/child/child.js
@@ -0,0 +1,12 @@
+import { LightningElement, api } from 'lwc';
+
+export default class Child extends LightningElement {
+ set setterGetterApi(value) {
+ this._someApi = value;
+ }
+
+ @api
+ get setterGetterApi() {
+ return this._someApi;
+ }
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.html
new file mode 100755
index 0000000000..f096b285f5
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.js
new file mode 100755
index 0000000000..e1d0ea7f96
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-getter/modules/x/parent/parent.js
@@ -0,0 +1,5 @@
+import { LightningElement } from 'lwc';
+
+export default class Parent extends LightningElement {
+ setterGetterApiValue = 'setter getter api value';
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/error.txt
new file mode 100644
index 0000000000..ab90d18fb4
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/error.txt
@@ -0,0 +1 @@
+LWC1112: @api get setterGetterApi and @api set setterGetterApi detected in class declaration. Only one of the two needs to be decorated with @api.
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/expected.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/index.js
new file mode 100644
index 0000000000..d5a55ceefa
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/index.js
@@ -0,0 +1,3 @@
+export const tagName = 'x-parent';
+export { default } from 'x/parent';
+export * from 'x/parent';
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.html
new file mode 100755
index 0000000000..9a178c0e77
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.html
@@ -0,0 +1,3 @@
+
+ {setterGetterApi}
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.js
new file mode 100755
index 0000000000..608d8f4639
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/child/child.js
@@ -0,0 +1,13 @@
+import { LightningElement, api } from 'lwc';
+
+export default class Child extends LightningElement {
+ @api
+ set setterGetterApi(value) {
+ this._someApi = value;
+ }
+
+ @api
+ get setterGetterApi() {
+ return this._someApi;
+ }
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.html
new file mode 100755
index 0000000000..f096b285f5
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.js
new file mode 100755
index 0000000000..e1d0ea7f96
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter-getter/modules/x/parent/parent.js
@@ -0,0 +1,5 @@
+import { LightningElement } from 'lwc';
+
+export default class Parent extends LightningElement {
+ setterGetterApiValue = 'setter getter api value';
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/error.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/expected.html
new file mode 100644
index 0000000000..4b6d956f1a
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/expected.html
@@ -0,0 +1,14 @@
+
+
+
+
+ const setter getter api value
+
+
+
+
+ setter getter api value
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/index.js
new file mode 100644
index 0000000000..d5a55ceefa
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/index.js
@@ -0,0 +1,3 @@
+export const tagName = 'x-parent';
+export { default } from 'x/parent';
+export * from 'x/parent';
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.html
new file mode 100755
index 0000000000..9a178c0e77
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.html
@@ -0,0 +1,3 @@
+
+ {setterGetterApi}
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.js
new file mode 100755
index 0000000000..bb1cabad15
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/child/child.js
@@ -0,0 +1,12 @@
+import { LightningElement, api } from 'lwc';
+
+export default class Child extends LightningElement {
+ @api
+ set setterGetterApi(value) {
+ this._someApi = value;
+ }
+
+ get setterGetterApi() {
+ return this._someApi;
+ }
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.html
new file mode 100755
index 0000000000..f096b285f5
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.js
new file mode 100755
index 0000000000..e1d0ea7f96
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/decorated-setter/modules/x/parent/parent.js
@@ -0,0 +1,5 @@
+import { LightningElement } from 'lwc';
+
+export default class Parent extends LightningElement {
+ setterGetterApiValue = 'setter getter api value';
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/error.txt b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/error.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/expected.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/expected.html
new file mode 100644
index 0000000000..73ad529907
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/expected.html
@@ -0,0 +1,14 @@
+
+
+
+
+ const field api value
+
+
+
+
+ field api value
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/index.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/index.js
new file mode 100644
index 0000000000..d5a55ceefa
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/index.js
@@ -0,0 +1,3 @@
+export const tagName = 'x-parent';
+export { default } from 'x/parent';
+export * from 'x/parent';
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.html
new file mode 100755
index 0000000000..c7953f5407
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.html
@@ -0,0 +1,3 @@
+
+ {fieldApi}
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.js
new file mode 100755
index 0000000000..26d125ff03
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/child/child.js
@@ -0,0 +1,5 @@
+import { LightningElement, api } from 'lwc';
+
+export default class Child extends LightningElement {
+ @api fieldApi;
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.html b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.html
new file mode 100755
index 0000000000..2a68acdb59
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.js b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.js
new file mode 100755
index 0000000000..2594cd2bed
--- /dev/null
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/api/property/modules/x/parent/parent.js
@@ -0,0 +1,5 @@
+import { LightningElement } from 'lwc';
+
+export default class Parent extends LightningElement {
+ fieldApiValue = 'field api value';
+}
diff --git a/packages/@lwc/engine-server/src/__tests__/fixtures/reserved-keywords/modules/x/cmp/cmp.js b/packages/@lwc/engine-server/src/__tests__/fixtures/reserved-keywords/modules/x/cmp/cmp.js
index 738e5d8707..80e30c3485 100644
--- a/packages/@lwc/engine-server/src/__tests__/fixtures/reserved-keywords/modules/x/cmp/cmp.js
+++ b/packages/@lwc/engine-server/src/__tests__/fixtures/reserved-keywords/modules/x/cmp/cmp.js
@@ -1,7 +1,7 @@
import { LightningElement } from 'lwc';
-const privateFields = undefined;
-const publicFields = undefined;
+const privateProperties = undefined;
+const publicProperties = undefined;
const stylesheetScopeToken = undefined;
const hasScopedStylesheets = undefined;
const defaultScopedStylesheets = undefined;
@@ -12,8 +12,8 @@ export default class extends LightningElement {
Object.assign(
{},
{
- privateFields,
- publicFields,
+ privateProperties,
+ publicProperties,
stylesheetScopeToken,
hasScopedStylesheets,
defaultScopedStylesheets,
diff --git a/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts b/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts
index ce1fd11d7b..bddee319c5 100644
--- a/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts
+++ b/packages/@lwc/ssr-compiler/src/compile-js/generate-markup.ts
@@ -16,8 +16,8 @@ import type { ComponentMetaState } from './types';
const bGenerateMarkup = esTemplate`
// These variables may mix with component-authored variables, so should be reasonably unique
- const __lwcPublicFields__ = new Set(${/*public fields*/ is.arrayExpression});
- const __lwcPrivateFields__ = new Set(${/*private fields*/ is.arrayExpression});
+ const __lwcPublicProperties__ = new Set(${/*api*/ is.arrayExpression});
+ const __lwcPrivateProperties__ = new Set(${/*private fields*/ is.arrayExpression});
async function* generateMarkup(
tagName,
@@ -43,8 +43,8 @@ const bGenerateMarkup = esTemplate`
instance[__SYMBOL__SET_INTERNALS](
props,
attrs,
- __lwcPublicFields__,
- __lwcPrivateFields__,
+ __lwcPublicProperties__,
+ __lwcPrivateProperties__,
);
instance.isConnected = true;
if (instance.connectedCallback) {
@@ -101,7 +101,7 @@ export function addGenerateMarkupFunction(
tagName: string,
filename: string
) {
- const { privateFields, publicFields, tmplExplicitImports } = state;
+ const { privateProperties, publicProperties, tmplExplicitImports } = state;
// The default tag name represents the component name that's passed to the transformer.
// This is needed to generate markup for dynamic components which are invoked through
@@ -141,8 +141,8 @@ export function addGenerateMarkupFunction(
);
program.body.push(
...bGenerateMarkup(
- b.arrayExpression(publicFields.map(b.literal)),
- b.arrayExpression(privateFields.map(b.literal)),
+ b.arrayExpression(publicProperties.map(b.literal)),
+ b.arrayExpression(privateProperties.map(b.literal)),
defaultTagName,
classIdentifier,
connectWireAdapterCode
diff --git a/packages/@lwc/ssr-compiler/src/compile-js/index.ts b/packages/@lwc/ssr-compiler/src/compile-js/index.ts
index a6386dcadf..34a8e50c31 100644
--- a/packages/@lwc/ssr-compiler/src/compile-js/index.ts
+++ b/packages/@lwc/ssr-compiler/src/compile-js/index.ts
@@ -101,16 +101,16 @@ const visitors: Visitors = {
validateUniqueDecorator(decorators);
const decoratedExpression = decorators?.[0]?.expression;
if (is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
- state.publicFields.push(node.key.name);
+ state.publicProperties.push(node.key.name);
} else if (
is.callExpression(decoratedExpression) &&
is.identifier(decoratedExpression.callee) &&
decoratedExpression.callee.name === 'wire'
) {
catalogWireAdapters(path, state);
- state.privateFields.push(node.key.name);
+ state.privateProperties.push(node.key.name);
} else {
- state.privateFields.push(node.key.name);
+ state.privateProperties.push(node.key.name);
}
if (
@@ -164,6 +164,14 @@ const visitors: Visitors = {
} else {
catalogWireAdapters(path, state);
}
+ } else if (is.identifier(decoratedExpression) && decoratedExpression.name === 'api') {
+ if (state.publicProperties.includes(node.key.name)) {
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
+ throw new Error(
+ `LWC1112: @api get ${node.key.name} and @api set ${node.key.name} detected in class declaration. Only one of the two needs to be decorated with @api.`
+ );
+ }
+ state.publicProperties.push(node.key.name);
}
switch (node.key.name) {
@@ -269,8 +277,8 @@ export default function compileJS(
tmplExplicitImports: null,
cssExplicitImports: null,
staticStylesheetIds: null,
- publicFields: [],
- privateFields: [],
+ publicProperties: [],
+ privateProperties: [],
wireAdapters: [],
experimentalDynamicComponent: options.experimentalDynamicComponent,
importManager: new ImportManager(),
diff --git a/packages/@lwc/ssr-compiler/src/compile-js/types.ts b/packages/@lwc/ssr-compiler/src/compile-js/types.ts
index 6ff7723f08..3690338a52 100644
--- a/packages/@lwc/ssr-compiler/src/compile-js/types.ts
+++ b/packages/@lwc/ssr-compiler/src/compile-js/types.ts
@@ -48,10 +48,10 @@ export interface ComponentMetaState {
cssExplicitImports: Map | null;
// the set of variable names associated with explicitly imported CSS files
staticStylesheetIds: Set | null;
- // the public (`@api`-annotated) fields of the component class
- publicFields: Array;
- // the private fields of the component class
- privateFields: Array;
+ // the public (`@api`-annotated) properties of the component class
+ publicProperties: Array;
+ // the private properties of the component class
+ privateProperties: Array;
// indicates whether the LightningElement has any wired props
wireAdapters: WireAdapter[];
// dynamic imports configuration
diff --git a/packages/@lwc/ssr-runtime/src/lightning-element.ts b/packages/@lwc/ssr-runtime/src/lightning-element.ts
index 2c78d199a4..464830d247 100644
--- a/packages/@lwc/ssr-runtime/src/lightning-element.ts
+++ b/packages/@lwc/ssr-runtime/src/lightning-element.ts
@@ -78,8 +78,8 @@ export class LightningElement implements PropsAvailableAtConstruction {
[SYMBOL__SET_INTERNALS](
props: Properties,
attrs: Attributes,
- publicFields: Set,
- privateFields: Set
+ publicProperties: Set,
+ privateProperties: Set
) {
this.#props = props;
this.#attrs = attrs;
@@ -91,9 +91,9 @@ export class LightningElement implements PropsAvailableAtConstruction {
for (const propName of keys(props)) {
const attrName = htmlPropertyToAttribute(propName);
if (
- publicFields.has(propName) ||
+ publicProperties.has(propName) ||
((REFLECTIVE_GLOBAL_PROPERTY_SET.has(propName) || isAriaAttribute(attrName)) &&
- !privateFields.has(propName))
+ !privateProperties.has(propName))
) {
// For props passed from parents to children, they are intended to be read-only
// to avoid a child mutating its parent's state