-
Notifications
You must be signed in to change notification settings - Fork 403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow computed properties in @wire if they are constants or primitives @W-14785085 #3955
Conversation
duplicate of decorator-accepts-a-member-expression
Writing up a follow up ticket, I had a better idea that could solve this issue more robustly. #3956 (comment) |
validateWireId(id, path, state); | ||
if (config) validateWireConfig(config, path, state); | ||
} else { | ||
// Single argument: should just be id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this never actually occurs (the code prior to this change doesn't handle this case and would have thrown). I don't actually know whether it's true that a single argument would be the ID here, but it seems a reasonable guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs are not clear, but it does seem that the config
is optional. A quick search for @wire
in SourceGraph reveals several instances of @wire
being used with just the single argument. We should probably add a test for this.
Also you are correct, this line is not hit per code coverage.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fall through will probably never occur, because it should already be covered by the validation, but we should still play it safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add this as a comment here? You can also add /* istanbul ignore next */
to drive home the point that this code should never get hit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This diff is git being silly. I deleted the old file because it was a duplicate of another test, and the new file is unrelated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall. Nicely done!
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add this as a comment here? You can also add /* istanbul ignore next */
to drive home the point that this code should never get hit.
|
||
for (const prop of config.get('properties')) { | ||
// Only validate {[computed]: true} object properties; {static: true} props are all valid | ||
// and we ignore {...spreads} and {methods(){}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tested, and you're correct that the existing compiler ignores spreads and methods. This is an oversight in our validation logic.
Could you please open a follow-up GH issue for this? This is the kind of thing that may need to be handled with API versioning, since it may already be "exploited" in the wild (spreads in particular).
for (const prop of config.get('properties')) { | ||
// Only validate {[computed]: true} object properties; {static: true} props are all valid | ||
// and we ignore {...spreads} and {methods(){}} | ||
if (!prop.isObjectProperty() || !prop.node.computed) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not actually enforced in our ESLint rules, but I think by convention we always use curly brackets for cases like this.
if (!prop.isObjectProperty() || !prop.node.computed) continue; | |
if (!prop.isObjectProperty() || !prop.node.computed) { | |
continue; | |
} |
Ditto for other cases below.
|
||
COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL: { | ||
code: 1200, | ||
message: 'Computed property in @wire config must be a constant or primitive literal.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message: 'Computed property in @wire config must be a constant or primitive literal.', | |
message: 'Computed property in @wire config must be a constant or primitive literal, such as a string or Symbol.', |
Most developers probably don't know what the words "constant or primitive literal" mean – this gives a bit of a hint. 🙂
validateWireId(id, path, state); | ||
if (config) validateWireConfig(config, path, state); | ||
} else { | ||
// Single argument: should just be id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs are not clear, but it does seem that the config
is optional. A quick search for @wire
in SourceGraph reveals several instances of @wire
being used with just the single argument. We should probably add a test for this.
Also you are correct, this line is not hit per code coverage.
I agree, but to be clear I don't think this merits a major version bump. We only recently allowed computed properties in |
Details
We currently allow computed properties in the
@wire
config object, in order to allow symbols as property keys. The current code, as written, assumes that a property key is an identifier or a string literal. However, that is not necessarily always the case (e.g.{ 123: 'NumericLiteral' }
,{ [true]: 'BooleanLiteral' }
). This PR loosens that restriction to also allow numeric, null, boolean, and bigint literals. Regular expression literals are excluded because they are not primitives, and template literals are excluded because they may contain expressions, meaning they are not guaranteed to always result in the same value (e.g.`${Math.random()}`
).Additionally, this PR restricts variables used in computed properties to only allow constants. This helps prevent accidentally using a computed value that changes, which would prevent reactivity from functioning appropriately.
Fixes #3910.
Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
GUS work item
W-14785085