@@ -9,25 +9,41 @@ import {
99import type { Typekit } from "@typespec/compiler/typekit" ;
1010import { isHeader } from "@typespec/http" ;
1111
12+ /** The codec selected for a source type and the two type-graph projections it produces. */
1213export interface EncodingInfo {
14+ /** First codec in the registry that accepted the source and its reference context. */
1315 codec : Codec ;
16+ /** Type exposed to generated language code; may be the unmodified source type. */
1417 languageType : Type ;
18+ /** Type describing the serialized representation, not an encoded runtime value. */
1519 wireType : Type ;
1620}
1721
22+ /**
23+ * Selects a codec by registration order. A registry starts empty; register an
24+ * {@link IdentityCodec} last when unrecognized types should pass through.
25+ */
1826export class CodecRegistry {
27+ /** Typekit supplied to every codec when selecting a representation. */
1928 $ : Typekit ;
2029 #codecs: Codec [ ] ;
2130
31+ /** Creates an empty registry bound to the typekit's program. */
2232 constructor ( $ : Typekit ) {
2333 this . $ = $ ;
2434 this . #codecs = [ ] ;
2535 }
2636
37+ /** Appends a codec; previously registered codecs retain priority. */
2738 addCodec ( codec : Codec ) {
2839 this . #codecs. push ( codec ) ;
2940 }
3041
42+ /**
43+ * Returns the first non-null codec result, together with the selected codec.
44+ * Reference members let codecs honor use-site metadata before type metadata.
45+ * @throws Error when every registered codec declines the source type.
46+ */
3147 encode ( sourceType : Type , referenceTypes : MemberType [ ] ) : EncodingInfo {
3248 for ( const codec of this . #codecs) {
3349 const result = codec . encode ( this . $ , sourceType , referenceTypes ) ;
@@ -40,15 +56,34 @@ export class CodecRegistry {
4056 }
4157}
4258
59+ /**
60+ * Chooses language and wire types for a source type in its use-site context.
61+ * Codecs describe representations; they do not serialize or deserialize values.
62+ */
4363export abstract class Codec {
64+ /** Stable selection identifier, also used in scalar canonicalization cache keys. */
4465 abstract id : string ;
4566
67+ /**
68+ * Selects type representations, or returns `null` to let the next codec try.
69+ * @param referenceTypes Members referencing the source, in metadata lookup order.
70+ */
4671 abstract encode (
4772 $ : Typekit ,
4873 sourceType : Type ,
4974 referenceTypes : MemberType [ ] ,
50- ) : { languageType : Type ; wireType : Type } | null ;
51-
75+ ) : {
76+ /** Type to use in the generated language's type graph. */
77+ languageType : Type ;
78+ /** Type to use in the serialized payload's type graph. */
79+ wireType : Type ;
80+ } | null ;
81+
82+ /**
83+ * Finds the first truthy metadata value on applicable reference members, then
84+ * falls back to the source type. The source getter's result is returned as-is;
85+ * without a source or a matching member value, returns `undefined`.
86+ */
5287 static getMetadata <
5388 TTypeSource extends Type ,
5489 TMemberSource extends MemberType ,
@@ -84,9 +119,12 @@ export abstract class Codec {
84119 }
85120}
86121
122+ /** Fallback codec that accepts every type and preserves both representations. */
87123export class IdentityCodec extends Codec {
124+ /** Marks the result as unchanged for identity-codec predicates. */
88125 readonly id = "identity" ;
89126
127+ /** Returns the source object itself for both language and wire types. */
90128 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
91129 return {
92130 wireType : sourceType ,
@@ -95,9 +133,15 @@ export class IdentityCodec extends Codec {
95133 }
96134}
97135
136+ /**
137+ * Recognizes UTC date-time scalars encoded as `"unix-timestamp"` with `int64`.
138+ * Use-site encoding metadata takes precedence over scalar metadata.
139+ */
98140export class UnixTimestamp64Codec extends Codec {
141+ /** Distinguishes this timestamp selection in scalar cache keys. */
99142 readonly id = "unix-timestamp-64" ;
100143
144+ /** Uses builtin `utcDateTime` and `float64`, or declines nonmatching encodings. */
101145 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
102146 if ( ! $ . scalar . is ( sourceType ) || ! $ . type . isAssignableTo ( sourceType , $ . builtin . utcDateTime ) ) {
103147 return null ;
@@ -126,9 +170,15 @@ export class UnixTimestamp64Codec extends Codec {
126170 }
127171}
128172
173+ /**
174+ * Recognizes UTC date-time scalars encoded as `"unixTimestamp"` with `int32`.
175+ * Use-site encoding metadata takes precedence over scalar metadata.
176+ */
129177export class UnixTimestamp32Codec extends Codec {
178+ /** Distinguishes this timestamp selection in scalar cache keys. */
130179 readonly id = "unix-timestamp-32" ;
131180
181+ /** Uses builtin `utcDateTime` and `float64`, or declines nonmatching encodings. */
132182 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
133183 if ( ! $ . scalar . is ( sourceType ) || ! $ . type . isAssignableTo ( sourceType , $ . builtin . utcDateTime ) ) {
134184 return null ;
@@ -157,9 +207,15 @@ export class UnixTimestamp32Codec extends Codec {
157207 }
158208}
159209
210+ /**
211+ * Fallback string representation for scalars assignable to `utcDateTime`.
212+ * Does not inspect encoding metadata; register more specific date codecs first.
213+ */
160214export class Rfc3339Codec extends Codec {
215+ /** Distinguishes the RFC 3339 selection in scalar cache keys. */
161216 readonly id = "rfc3339" ;
162217
218+ /** Preserves the date-time language type and uses `string` on the wire, or declines. */
163219 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
164220 if ( ! $ . scalar . is ( sourceType ) || ! $ . type . isAssignableTo ( sourceType , $ . builtin . utcDateTime ) ) {
165221 return null ;
@@ -172,9 +228,15 @@ export class Rfc3339Codec extends Codec {
172228 }
173229}
174230
231+ /**
232+ * Selects the HTTP-date string representation for UTC date-time scalars.
233+ * Accepts explicit `rfc7231` encoding, or a header use site with no encoding.
234+ */
175235export class Rfc7231Codec extends Codec {
236+ /** Distinguishes the HTTP-date selection in scalar cache keys. */
176237 readonly id = "rfc7231" ;
177238
239+ /** Preserves the source date-time type and uses `string` on the wire, or declines. */
178240 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
179241 if ( ! $ . scalar . is ( sourceType ) || ! $ . type . isAssignableTo ( sourceType , $ . builtin . utcDateTime ) ) {
180242 return null ;
@@ -209,9 +271,15 @@ export class Rfc7231Codec extends Codec {
209271 }
210272}
211273
274+ /**
275+ * Selects a string wire representation for types assignable to `bytes`.
276+ * This selection does not inspect an explicit encoding decorator.
277+ */
212278export class Base64Codec extends Codec {
279+ /** Identifies the byte-to-string representation. */
213280 readonly id = "base64" ;
214281
282+ /** Preserves the byte language type and uses `string` on the wire, or declines. */
215283 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
216284 if ( ! $ . type . isAssignableTo ( sourceType , $ . builtin . bytes ) ) {
217285 return null ;
@@ -224,19 +292,30 @@ export class Base64Codec extends Codec {
224292 }
225293}
226294
295+ /**
296+ * Optional category filters for numeric codec selection. Neither flag bypasses
297+ * the final requirement to extend `float`, `int32`, or `uint32`.
298+ */
227299export interface CoerceToFloat64CodecOptions {
300+ /** When true, additionally requires an integer or float scalar; defaults to false. */
228301 lossyInteger ?: boolean ;
302+ /** When true, additionally requires a decimal or float scalar; defaults to false. */
229303 lossyDecimal ?: boolean ;
230304}
231305
306+ /** Uses `float64` on the wire for scalars extending `float`, `int32`, or `uint32`. */
232307export class CoerceToFloat64Codec extends Codec {
308+ /** Identifies numeric wire coercion without a language-type replacement. */
233309 readonly id = "coerce-to-float64" ;
310+ /** Category filters consulted on each call; the supplied object is retained. */
234311 options : CoerceToFloat64CodecOptions ;
312+ /** Creates a numeric codec with no additional category filters by default. */
235313 constructor ( options : CoerceToFloat64CodecOptions = { } ) {
236314 super ( ) ;
237315 this . options = options ;
238316 }
239317
318+ /** Preserves an accepted numeric language type and uses `float64`, or returns `null`. */
240319 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
241320 if (
242321 this . options . lossyInteger &&
@@ -271,9 +350,15 @@ export class CoerceToFloat64Codec extends Codec {
271350 }
272351}
273352
353+ /**
354+ * Selects a string wire representation for any array type, regardless of HTTP
355+ * location. The codec does not choose a delimiter or perform the join itself.
356+ */
274357export class ArrayJoinCodec extends Codec {
358+ /** Identifies an array represented as a string on the wire. */
275359 readonly id = "array-join" ;
276360
361+ /** Preserves the array language type and uses `string` on the wire, or declines. */
277362 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
278363 if ( ! $ . array . is ( sourceType ) ) {
279364 return null ;
@@ -288,22 +373,32 @@ export class ArrayJoinCodec extends Codec {
288373 }
289374}
290375
376+ /** Naming hook used after checking a property's `@friendlyName`. */
291377interface RenameCodecOptions {
378+ /** Returns a language-side property name, or `undefined` to leave it unchanged. */
292379 namer ?( type : Type ) : string | undefined ;
293380}
294381/**
295382 * Renames the language type according to the language's name policy and
296383 * friendly name decorator.
297384 */
298385export class RenameCodec extends Codec {
386+ /** Identifies a language-only model property rename. */
299387 readonly id = "model-property-rename" ;
388+ /** Naming configuration retained by reference and consulted for each property. */
300389 options : RenameCodecOptions ;
301390
391+ /** Creates a codec that only uses `@friendlyName` unless a naming hook is supplied. */
302392 constructor ( options : RenameCodecOptions = { } ) {
303393 super ( ) ;
304394 this . options = options ;
305395 }
306396
397+ /**
398+ * Clones a model property with a changed language name and preserves its wire
399+ * type. A different, nonempty friendly name wins over the naming hook.
400+ * Returns `null` for other types or when neither source supplies a changed name.
401+ */
307402 encode ( $ : Typekit , sourceType : Type , referenceTypes : MemberType [ ] ) {
308403 if ( ! $ . modelProperty . is ( sourceType ) ) {
309404 return null ;
@@ -341,6 +436,12 @@ export class RenameCodec extends Codec {
341436}
342437
343438const jsonCodecRegistryCache = new WeakMap < Program , CodecRegistry > ( ) ;
439+ /**
440+ * Gets the mutable default registry cached per program. Specific numeric and
441+ * date-time codecs precede byte, array, and rename codecs, with identity last.
442+ * Appending a codec to this registry cannot override its identity fallback;
443+ * supply a separate registry to customize selection priority.
444+ */
344445export const getJsonCodecRegistry = ( $ : Typekit ) => {
345446 if ( jsonCodecRegistryCache . has ( $ . program ) ) {
346447 return jsonCodecRegistryCache . get ( $ . program ) ! ;
0 commit comments