Repository navigation
feat(generator): an optional special number keeps its named literals through the tri-state wrapper - #459
Merged
Conversation
…through the tri-state wrapper
…ects, and the literal refusal names itself
2 of 4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The generator now emits a working tri-state member for an optional-and-nullable request property whose number admits
NaNand the infinities. Until now,OptionalConverterNamePolicythrew "No optional converter name exists for plan 'SpecialNumberTypeReferencePlan'". Generated output at the 2.0.29 pin is byte-identical: no pinned member has this shape. The 2.0.32 pin needs it forVoiceWebRTCTransportInput.dcid(Schema.optional(Schema.Number)inpackages/protocol/src/groups/voice.ts:8).Part of #462. This is REFRESH-232 PR A, the generator half of the 2.0.29 → 2.0.32 pin refresh. PR B, the refresh itself, follows on a base that contains this one.
What changes
OptionalConverterNamePolicy: a top-level special-number instantiation is namedOptionalOfSpecialNumberJsonConverter. A special number inside a list or dictionary still throws the existing message, because a container's converter would go through the plaindoublemetadata and lose the named literals.OptionalConverterEmitter:double?, so a format-only key would merge them into one converter. With the pair key, two different types that share a converter name still reachSourceEmitter's duplicate-path refusal.NaN,Infinityor-Infinityas that value, and refuses any other string with aJsonException. It writes those three values back as the same strings. Null and number handling are as before.ModelEmitter: a wrapped member no longer carries[JsonNumberHandling]. On anOptional<double?>member, System.Text.Json throws at metadata time: "'JsonNumberHandlingAttribute' is only valid on a number or a collection of numbers". So the converter carries the named literals instead. Required and non-wrapped optional special numbers keep the attribute unchanged.docs/architecture/protocol-and-generation.md, in the tri-state converter bullet.The converter matches what System.Text.Json's
AllowNamedFloatingPointLiteralsdoes on a required member. Measured on net10.0 with a source-generated context: it writesNaNas"NaN", and it refuses"nan","1.5"and"+Infinity".Tests
Red first:
double?and a wrapped special number give exactly two converters, in order;SourceEmitterTests);[JsonNumberHandling], and the wrapped one doesn't (inModelEmitterTests);patchSpecialNumbermember in the materialization matrix's request schema covers absent, explicit null,4.5, and each named literal (exact JSON text)."nan","+Infinity"and"1.5"each throwJsonException.Mutation: seven compiling mutants, all killed, each production file restored and compared byte-for-byte:
GetDoubleWriteNumberValue[JsonNumberHandling]kept on the wrapper"nan")Existing-test edits: only additions. In the materialization matrix:
patchSpecialNumber;Every existing assertion is unchanged.
Budget (against the merge-base)
Local check and review
verify-clonespassing;--help;generate --verifycurrent; the whole Tools.Tests project at 2086/0, Packaging included. CI is the full gate.verify-clones,generate --verifyand the whitespace pass.JsonExceptionnow carries a message;Provenance: Generator lane / opencode dispatch harness (openai/gpt-6.1-sol-1m), coordinated, reviewed and finished in Claude Code.