Conversation
A merge (`<<`) brings keys into the target mapping and records them as overridable, so a later explicit pair may override them without a "duplicated mapping key" error. For the default object-based map that tracking failed on non-string keys: `keys()` returns `Object.keys()` (strings), so the overridable set held "10", but the explicit override key is the resolved scalar `10`, and `Set.has(10)` does not find "10". The override was therefore rejected as a duplicate. Object-based maps already normalize keys to their string form in `addPair`/`has`/`get`; give a mapping tag a `normalizeKey` so the overridable set is keyed the same way (identity for the real `Map`/`Set` tags, whose keys are lossless). Genuine duplicate keys without a merge still raise, and string-key overrides are unchanged.
|
I understand the problem, but not sure about implementation. The enforced key stringification for JS objects is language-specific behavior, not a "normal" one. So:
IMHO, worth discussing alternatives in the issue first. Also, note about the topic name - it's about scalar keys only. Non-scalar keys (complex objects) are usually not supported at all (PyYAML, Go) or are potentially vulnerable to DoS attacks. |
|
Yeah, that's fair. And you're right it's only scalar keys — the map's The reason it ends up in the constructor is that the I don't think there's a version that needs zero tag support: either a small opt-in method on the map tags (identity elsewhere), or tracking |
|
Yes, create an issue with your vision on "how
IMHO, globally, the question is not "how to make this work", but "how much the user agrees to pay for extra features" (performance, convenience, and so on). I don't think package features should be code-driven instead of user needs. But IMHO, continuing to hack objects may be not the best/optimal approach of available. Personally, I'd mark Object-based maps as "restricted". But that depends on use cases; I don't know the user needs for YAML. |
|
Let's close this; changes to merge "as is" are low. This is referred to from an open issue, so any info will not be lost. |
Problem
A merge key (
<<) folds another mapping's keys into the target and records themas overridable, so a later explicit pair may override a merged key without a
duplicated mapping keyerror (the canonical YAML merge "Override" behavior).For the default object-based map, that tracking breaks on non-string keys:
A string key in the same position works fine (
ten:→{ten: 'y'}). Non-stringmap keys are ordinary in YAML (
on/off/yes/no, port numbers, numeric enum keys).Root cause
The overridable set is populated from
keys(), which for the object map isObject.keys()— always strings ("10"). The duplicate check then queriesthat set with the resolved key (the number
10):frame.tag.hascoerces (String(key)) so it correctly sees the duplicate, butSet.hasuses SameValueZero, so"10" !== 10— the override exemption missesand the pair is rejected.
realMapTag/setTagstore keys losslessly, so theywere never affected, which pinpoints the object-map string coercion as the cause.
Fix
Object-based maps already normalize keys to their string form in
addPair/has/get. Give a mapping tag anormalizeKey(defaulting toidentity, so
Map/Settags are unchanged) and key the overridable set throughit, so both sides use the same key identity.
{10: x, 10: y}throws).Test
Added a
tags/mergecase where a merged10:/true:is overridden by a localpair. Fails on
main(duplicated mapping key), passes with the fix. Fulltest/coresuite green (284 pass / 0 fail),type-checkandlintclean.