Skip to content

fix: compare own enumerable properties on Date, RegExp, and boxed primitives#111

Open
spokodev wants to merge 1 commit into
chaijs:mainfrom
spokodev:fix/own-props-on-date-regexp-boxed
Open

fix: compare own enumerable properties on Date, RegExp, and boxed primitives#111
spokodev wants to merge 1 commit into
chaijs:mainfrom
spokodev:fix/own-props-on-date-regexp-boxed

Conversation

@spokodev

Copy link
Copy Markdown

Problem

deep-eql ignores own enumerable properties on Date, RegExp, and boxed-primitive (String/Number/Boolean) instances. Two such objects are reported deeply equal even when they carry differing own enumerable data properties.

import eql from 'deep-eql';
import util from 'node:util';

const a = new Date(0); a.foo = 1;
const b = new Date(0); b.foo = 2;

eql(a, b);                      // true  (wrong)
util.isDeepStrictEqual(a, b);   // false (oracle)

Same for RegExp (const r = /x/; r.foo = ...) and boxed new Number(1) / new String(...) / new Boolean(...).

This contradicts the documented contract in the README "Rules" section:

All own and inherited enumerable properties are considered.

Only Error is documented as an exception. The control case is already correct (eql({foo:1}, {foo:2}) === false), which shows that only the special-cased types bypass the rule.

Root cause

In extensiveDeepEqualByType(), the String/Number/Boolean/Date branch returns only the valueOf() comparison, and the RegExp branch returns only the toString() comparison. Both return before the objectEqual() default branch, so own enumerable properties are never compared.

Fix

AND the type-specific value check with the existing objectEqual() own-enumerable-key comparison for those branches. objectEqual() already returns true when both sides have zero own enumerable keys, so plain instances are unaffected. valueOf / -0 / NaN semantics and the documented Error special-case are untouched.

Verification

Red -> green: 5 new tests (one per affected type) assert that instances with differing own enumerable properties are not equal. They fail before the fix and pass after.

Each new case was cross-checked against node:util.isDeepStrictEqual as an oracle, including the cases that must stay equal (same prop value, no extra props, new Number(NaN), new Date(NaN)) and the Error special-case (extra own props still ignored, as documented).

Full suite green: 179 passing, 0 failing. Lint clean.

…mitives

Date, RegExp, and boxed-primitive (String/Number/Boolean) instances were
compared only by their internal value (valueOf/toString), so two such
objects with differing own enumerable data properties were reported as
deeply equal. This contradicts the documented rule that all own and
inherited enumerable properties are considered (only Error is exempt) and
diverges from node's util.isDeepStrictEqual.

AND the type-specific value check with the existing objectEqual own-key
comparison so extra own properties are taken into account while valueOf,
-0/NaN, and the Error special-case semantics are preserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant