🔍 fix: correct the last three findings from the page review
Of 26 findings raised across five auditors, 23 were refuted on a second
pass. These three survived.
**A renamed property's old key is still writable.** The README, the landing
page and two doc comments all said that once a property carries
@JsonProperty its original name "is no longer accepted on input". It is no
longer *mapped* — but it is not rejected either. Unlike @JsonReadOnly,
whose JSON name goes into the blocked set, the old key falls through to the
unknown-key policy, and the default `allow` copies it onto the instance
untouched. Reproduced against dist:
@JsonProperty('home_address') @JsonType(() => Addr) @ValidateNested()
address!: Addr;
toInstanceSync(Order, { address: { city: 'Paris' } })
-> address is a plain object, instanceof Addr === false
-> validateSync() returns [] <- nothing complains
-> round-trips out as home_address <- silently accepted
Blocking the old key would fix it, but would also swallow the
`unknownKeys: 'error'` report a strict caller gets today, which is arguably
the more useful signal. That is a judgement call the library has not made,
so this commit states the behaviour accurately everywhere it was stated
wrongly and pins it with five tests covering the default, `strip`, `error`
and the @JsonAlias fix — so it cannot drift either way while the question
is open.
**@IsNotEmpty and @IsEmpty are not complements.** `[]` and `{}` pass BOTH:
isNotEmpty checks only null/undefined/'' while isEmpty also treats empty
arrays and objects as empty. Listed one line apart as "must not be empty" /
"must be empty", they invited exactly the wrong inference.
**unknownKeys is deserialization-only**, in a group whose blurb says these
apply per call or via configure().
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAcqrz3FcadkYr3xG32CjK
This commit is contained in:
@@ -114,6 +114,25 @@ Also corrected in the same pass: the toolchain table is described as executed by
|
||||
the oxc row — the only ✗ — cannot be, because oxc ships inside a native binary with no
|
||||
standalone transform API. The claim now covers the three rows it actually covers.
|
||||
|
||||
### A sharp edge, now documented and pinned
|
||||
|
||||
The README, the landing page and two doc comments all said that once a property carries
|
||||
`@JsonProperty`, its original name "is no longer accepted on input". It is no longer
|
||||
*mapped* — but it is not rejected either. Unlike `@JsonReadOnly`, whose JSON name goes into
|
||||
the blocked set, a renamed property's old key falls through to the unknown-key policy, and
|
||||
the default `allow` copies it onto the instance untouched. The value lands on a declared
|
||||
property having skipped everything declared for it: no `@JsonType` conversion, so
|
||||
`@ValidateNested` then inspects a plain object with no model and reports nothing.
|
||||
|
||||
Blocking the old key would fix that, but it would also swallow the `unknownKeys: 'error'`
|
||||
report a strict caller gets today, which is arguably the more useful signal. That decision
|
||||
has not been made, so the behaviour is stated accurately everywhere it was previously stated
|
||||
wrongly, and five tests in `mapping.test.ts` pin it — including the `strip` and `error`
|
||||
policies and the `@JsonAlias` fix — so it cannot change by accident either way.
|
||||
|
||||
Two reference entries were also imprecise: `@IsNotEmpty()` and `@IsEmpty()` read as
|
||||
complements but are not (`[]` and `{}` pass both), and `unknownKeys` is deserialization-only.
|
||||
|
||||
### Positioning
|
||||
|
||||
`zod-alternative` is out of the keywords, and the README leads with the comparison that
|
||||
|
||||
Reference in New Issue
Block a user