Skip to content

Commit

Permalink
feat: allow computed properties in @wire if they are constants or pri…
Browse files Browse the repository at this point in the history
…mitives @W-14785085 (#3955)

* refactor(@wire): split parameter validation into individual methods

* chore(tests): remove duplicate tests

duplicate of decorator-accepts-a-member-expression

* test(@wire): add tests for spreads, methods, and numbers

* test(@wire): update test for computed identifiers and primitives

* feat: allow computed properties that are constants or primitive literals

* refactor: less nesting

* test(@wire): add test for template literal computed prop

* test(@wire): add test for let variable computed prop

* test(@wire): add test for expression in computed prop

* test(@wire): add test for regexp literal computed prop

* test(@wire): add test for bigint literal computed prop

* chore: add github issues to TODOs
  • Loading branch information
wjhsf authored Jan 22, 2024
1 parent 69a6766 commit 8e90e92
Show file tree
Hide file tree
Showing 20 changed files with 281 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { wire, LightningElement } from "lwc";
import { Foo } from "data-service";
import { getFoo } from "data-service";
export default class Test extends LightningElement {
@wire(Foo.Bar, {}) wiredProp;
@wire(getFoo, {
method() {}
})
wiredProp;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { registerDecorators as _registerDecorators, registerComponent as _registerComponent, LightningElement } from "lwc";
import _tmpl from "./test.html";
import { Foo } from "data-service";
import { getFoo } from "data-service";
class Test extends LightningElement {
wiredProp;
/*LWC compiler vX.X.X*/
}
_registerDecorators(Test, {
wire: {
wiredProp: {
adapter: Foo.Bar,
adapter: getFoo,
dynamic: [],
config: function ($cmp) {
return {};
return {
method() {}
};
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
const spreadMe = {
key1: "$prop2"
}
export default class Test extends LightningElement {
@wire(getFoo, {
...spreadMe,
...({key2: "$prop2"})
})
wiredProp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { registerDecorators as _registerDecorators, registerComponent as _registerComponent, LightningElement } from "lwc";
import _tmpl from "./test.html";
import { getFoo } from "data-service";
const spreadMe = {
key1: "$prop2"
};
class Test extends LightningElement {
wiredProp;
/*LWC compiler vX.X.X*/
}
_registerDecorators(Test, {
wire: {
wiredProp: {
adapter: getFoo,
dynamic: [],
config: function ($cmp) {
return {
...spreadMe,
...{
key2: "$prop2"
}
};
}
}
}
});
export default _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
const symbol = Symbol.for("key");
export default class Test extends LightningElement {
// accidentally an array expression = oops!
@wire(getFoo, { [[symbol]]: "$prop1", key2: ["fixed", "array"] })
wiredFoo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1200: Computed property in @wire config must be a constant or primitive literal.",
"loc": {
"line": 6,
"column": 19,
"start": 237,
"length": 8
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
let key1 = 'key1'
export default class Test extends LightningElement {
@wire(getFoo, { [key1]: "$prop1", key2: ["fixed", "array"] })
wiredFoo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1200: Computed property in @wire config must be a constant or primitive literal.",
"loc": {
"line": 5,
"column": 19,
"start": 175,
"length": 4
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
export default class Test extends LightningElement {
@wire(getFoo, { [/key1/]: "$prop1", key2: ["fixed", "array"] })
wiredFoo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1200: Computed property in @wire config must be a constant or primitive literal.",
"loc": {
"line": 4,
"column": 19,
"start": 157,
"length": 6
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
export default class Test extends LightningElement {
@wire(getFoo, { [`key1`]: "$prop1", key2: ["fixed", "array"] })
wiredFoo;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"message": "LWC1199: Cannot use a template literal as a computed property key. Instead, use a string or extract the value to a constant.",
"loc": {
"line": 4,
"column": 19,
"start": 157,
"length": 6
},
"filename": "test.js"
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { wire, LightningElement } from "lwc";
import { getFoo, getBar } from "data-service";
const key1 = Symbol.for("key");
export default class Test extends LightningElement {
@wire(getBar, { [key1]: "$prop1", key2: ["fixed", "array"] })
wiredBar;

// eslint-disable-next-line no-useless-computed-key
@wire(getFoo, { ["key1"]: "$prop1", key2: ["fixed", "array"] })
wiredFoo;
const symbol = Symbol.for("key");
export default class Test extends LightningElement {
@wire(getFoo, {
[symbol]: '$prop'
})
wiredIdentifier;

@wire(getBar, {
['computedStringLiteral']: '$prop',
[123n]: '$prop',
[321]: '$prop',
[null]: '$prop',
[undefined]: '$prop'
})
wiredPrimitives;
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import { registerDecorators as _registerDecorators, registerComponent as _registerComponent, LightningElement } from "lwc";
import _tmpl from "./test.html";
import { getFoo, getBar } from "data-service";
const key1 = Symbol.for("key");
const symbol = Symbol.for("key");
class Test extends LightningElement {
wiredBar;

// eslint-disable-next-line no-useless-computed-key
wiredFoo;
wiredIdentifier;
wiredPrimitives;
/*LWC compiler vX.X.X*/
}
_registerDecorators(Test, {
wire: {
wiredBar: {
adapter: getBar,
dynamic: [key1],
wiredIdentifier: {
adapter: getFoo,
dynamic: [symbol],
config: function ($cmp) {
return {
key2: ["fixed", "array"],
[key1]: $cmp.prop1
[symbol]: $cmp.prop
};
}
},
wiredFoo: {
adapter: getFoo,
dynamic: ["key1"],
wiredPrimitives: {
adapter: getBar,
dynamic: ["computedStringLiteral", "123", "321", "null", undefined],
config: function ($cmp) {
return {
key2: ["fixed", "array"],
["key1"]: $cmp.prop1
['computedStringLiteral']: $cmp.prop,
[123n]: $cmp.prop,
[321]: $cmp.prop,
[null]: $cmp.prop,
[undefined]: $cmp.prop
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { wire, LightningElement } from "lwc";
import { getFoo } from "data-service";
export default class Test extends LightningElement {
// Did you know numeric literals can be used as property keys? This becomes "123"!
@wire(getFoo, { 1.2_3e2: "$prop" })
wiredProp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { registerDecorators as _registerDecorators, registerComponent as _registerComponent, LightningElement } from "lwc";
import _tmpl from "./test.html";
import { getFoo } from "data-service";
class Test extends LightningElement {
// Did you know numeric literals can be used as property keys? This becomes "123"!
wiredProp;
/*LWC compiler vX.X.X*/
}
_registerDecorators(Test, {
wire: {
wiredProp: {
adapter: getFoo,
dynamic: ["123"],
config: function ($cmp) {
return {
1.2_3e2: $cmp.prop
};
}
}
}
});
export default _registerComponent(Test, {
tmpl: _tmpl,
sel: "lwc-test",
apiVersion: 9999999
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* Copyright (c) 2024, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
Expand Down Expand Up @@ -175,12 +175,22 @@ function buildWireConfigValue(t: BabelTypes, wiredValues: WiredValue[]) {

if (wiredValue.params) {
const dynamicParamNames = wiredValue.params.map((p) => {
const value = t.isIdentifier(p.key)
? p.key.name
: (p.key as types.StringLiteral).value;
return p.computed && t.isIdentifier(p.key)
? t.identifier(value)
: t.stringLiteral(value);
if (t.isIdentifier(p.key)) {
return p.computed ? t.identifier(p.key.name) : t.stringLiteral(p.key.name);
} else if (
t.isLiteral(p.key) &&
// Template literals may contain expressions, so they are not allowed
!t.isTemplateLiteral(p.key) &&
// RegExp are not primitives, so they are not allowed
!t.isRegExpLiteral(p.key)
) {
const value = t.isNullLiteral(p.key) ? null : p.key.value;
return t.stringLiteral(String(value));
}
// If it's not an identifier or primitive literal then it's a computed expression
throw new TypeError(
`Expected object property key to be an identifier or a literal, but instead saw "${p.key.type}".`
);
});
wireConfig.push(
t.objectProperty(t.identifier('dynamic'), t.arrayExpression(dynamicParamNames))
Expand Down
Loading

0 comments on commit 8e90e92

Please sign in to comment.