Repository navigation
fix(define): preserve non-optional property access past undefined member - #22016
Pcmhacker-piro wants to merge 1 commit into
Conversation
When an object member defined via DefinePlugin resolves to undefined, accessing properties non-optionally past that member was unconditionally collapsed into undefined by expressionMemberChain. At runtime, reading a property off undefined must throw a TypeError. We now cut the chain at the undefined member using dropTrailingMembers when the access is not optional, emitting (undefined).a so the runtime TypeError is preserved natively. Fixes webpack#22014
|
|
|
👋 Hi there! This PR was automatically flagged and closed by our quality checks. If you believe this was a mistake, please review our contributing guidelines |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughDefinePlugin now preserves runtime errors for non-optional accesses after undefined members while retaining optional-chain short-circuiting. Tests cover dot, computed, chained, and mixed member access. ChangesDefinePlugin member access
Suggested reviewers: Change: Bug fix · Severity of issue fixed: Medium ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hi @webpack-maintainers, this PR was automatically flagged and closed by the quality checks bot. This is a valid, focused bug fix for #22014 resolving non-optional property access in Could a maintainer please review and reopen this PR? |
|
Superseded by @alexander-akait's official maintainer PR #22017 which resolves #22014. |
Summary
Follow-up to #21827. In #21827,
callMemberChainwas updated usingdropTrailingMembersso that a non-optional call past an undefined member (e.g.OBJ.MISSING.a?.()) emitsundefined.a?.()and throws at runtime as native JavaScript would.However,
expressionMemberChainwas not updated and still unconditionally replaced the entire member expression withundefined. Consequently, non-optional property accesses (such asOBJECT.SUB.UNKNOWN.a,OBJECT.SUB.UNKNOWN["a"],OBJECT.SUB.UNKNOWN.a.b, andOBJECT.SUB.UNKNOWN.a?.b) silently evaluated toundefinedinstead of throwing aTypeErrorwhen reading offundefined.This PR brings the same chain-cutting logic to
parser.hooks.expressionMemberChain:members.length - 1 === undefinedIndex) or the next link is optional (membersOptionals[undefinedIndex + 1]), the expression evaluates toundefined.dropTrailingMemberscuts the chain atundefinedIndex, emitting(undefined).aso that the non-optional property read executes againstundefinedand throws the expectedTypeError.Fixes #22014.
What kind of change does this PR introduce?
fix
Did you add tests for your changes?
Yes:
.a,["a"], deep chained.a.b, and.a?.b) throwing intest/configCases/plugins/define-plugin-optional-chaining/index.js.test/configCases/plugins/define-plugin/index.jsto assertundefined.Aand verify it throws on execution.Does this PR introduce a breaking change?
No. Affected expressions previously evaluated to
undefinedinstead of throwing the runtimeTypeErrormandated by ECMAScript semantics.If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a
Use of AI
No.
Summary by CodeRabbit
undefinedwhen an earlier member is unknown.