Skip to content

Commit 4780dfe

Browse files
authored
Merge pull request #345 from knockout/fix/nullish-coalescing-earlyout
Fix ?? (nullish coalescing) earlyOut to not short-circuit on falsy values
2 parents 9baee6b + c547a64 commit 4780dfe

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

packages/utils.parser/spec/nodeBehaviors.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ describe('Operators', function () {
5252
test([null, op['??'], false], false)
5353
})
5454

55+
it('?? evaluates rhs iff lhs is null/undefined', () => {
56+
let rhsCalls = 0
57+
const rhs = () => {
58+
rhsCalls++
59+
return 'right'
60+
}
61+
const parser = new Parser()
62+
const args = new Arguments(null, [])
63+
64+
for (const [lhs, expected, expectedCalls] of [
65+
[0, 0, 0],
66+
['', '', 0],
67+
[false, false, 0],
68+
[null, 'right', 1],
69+
[undefined, 'right', 1]
70+
] as const) {
71+
rhsCalls = 0
72+
const context = ctxStub({ a: lhs, rhs })
73+
const root = nodes_to_tree([new Identifier(parser, 'a'), op['??'], new Identifier(parser, 'rhs', [args])])
74+
assert.strictEqual(root.get_value(null, context), expected, `${String(lhs)} ?? rhs() value`)
75+
assert.strictEqual(rhsCalls, expectedCalls, `${String(lhs)} ?? rhs() calls`)
76+
}
77+
})
78+
5579
it('performs ?. optional chaining', () => {
5680
test([{}, op['?.'], 'a'], undefined)
5781
test([null, op['?.'], 'a'], undefined)

packages/utils.parser/src/operators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ operators['??'].precedence = 3
216216

217217
operators['&&'].earlyOut = a => !a
218218
operators['||'].earlyOut = a => a
219-
operators['??'].earlyOut = a => a
219+
operators['??'].earlyOut = a => a !== null && a !== undefined
220220

221221
// Assignment and miscellaneous (lamda)
222222
operators['=>'].precedence = 2

0 commit comments

Comments
 (0)