From 76202f923950737ed4165a89ec711435a24afebb Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Tue, 19 Aug 2025 14:37:59 +0200 Subject: [PATCH] refactor: add possibility to register ContentCodec with scheme TODO calls for contentToValue and valueToContent need to provide schema --- packages/core/src/content-serdes.ts | 40 ++++++++++++++++++++----- packages/core/test/ContentSerdesTest.ts | 24 +++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/packages/core/src/content-serdes.ts b/packages/core/src/content-serdes.ts index c56f59830..ee928b744 100644 --- a/packages/core/src/content-serdes.ts +++ b/packages/core/src/content-serdes.ts @@ -54,6 +54,7 @@ export class ContentSerdes { public static readonly JSON_LD: string = "application/ld+json"; private codecs: Map = new Map(); + private codecsBySchemes: Map = new Map(); private offered: Set = new Set(); public static get(): ContentSerdes { @@ -107,8 +108,17 @@ export class ContentSerdes { return params; } - public addCodec(codec: ContentCodec, offered = false): void { - ContentSerdes.get().codecs.set(codec.getMediaType(), codec); + // function to create id for combining internally mediaType and scheme + private getMediaTypeScheme(mt: string, scheme: string): string { + return mt + "|" + scheme; + } + + public addCodec(codec: ContentCodec, offered = false, scheme?: string): void { + if (scheme !== undefined) { + ContentSerdes.get().codecsBySchemes.set(this.getMediaTypeScheme(codec.getMediaType(), scheme), codec); + } else { + ContentSerdes.get().codecs.set(codec.getMediaType(), codec); + } if (offered) ContentSerdes.get().offered.add(codec.getMediaType()); } @@ -125,7 +135,7 @@ export class ContentSerdes { return this.codecs.has(mt); } - public contentToValue(content: ReadContent, schema: DataSchema): DataSchemaValue | undefined { + public contentToValue(content: ReadContent, schema: DataSchema, scheme?: string): DataSchemaValue | undefined { if (content.type === undefined) { if (content.body.byteLength > 0) { // default to application/json @@ -142,9 +152,16 @@ export class ContentSerdes { // choose codec based on mediaType if (this.codecs.has(mt)) { - debug(`ContentSerdes deserializing from ${content.type}`); - - const codec = this.codecs.get(mt); + let codec: ContentCodec | undefined; + if (scheme !== undefined) { + codec = this.codecsBySchemes.get(this.getMediaTypeScheme(mt, scheme)); + } + if (codec === undefined) { + debug(`ContentSerdes deserializing from ${content.type}`); + codec = this.codecs.get(mt); + } else { + debug(`ContentSerdes deserializing from combining ${content.type} and ${mt}`); + } // use codec to deserialize // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- this.codecs.has(mt) is true @@ -160,7 +177,8 @@ export class ContentSerdes { public valueToContent( value: DataSchemaValue | ReadableStream, schema: DataSchema | undefined, - contentType = ContentSerdes.DEFAULT + contentType = ContentSerdes.DEFAULT, + scheme?: string ): Content { if (value === undefined) warn("ContentSerdes valueToContent got no value"); @@ -175,7 +193,13 @@ export class ContentSerdes { const par = ContentSerdes.getMediaTypeParameters(contentType); // choose codec based on mediaType - const codec = this.codecs.get(mt); + let codec: ContentCodec | undefined; + if (scheme !== undefined) { + codec = this.codecsBySchemes.get(this.getMediaTypeScheme(mt, scheme)); + } + if (codec === undefined) { + codec = this.codecs.get(mt); + } if (codec) { debug(`ContentSerdes serializing to ${contentType}`); bytes = codec.valueToBytes(value, schema, par); diff --git a/packages/core/test/ContentSerdesTest.ts b/packages/core/test/ContentSerdesTest.ts index d67b460a7..9c4abd468 100644 --- a/packages/core/test/ContentSerdesTest.ts +++ b/packages/core/test/ContentSerdesTest.ts @@ -91,6 +91,16 @@ class HodorCodec implements ContentCodec { } } +class HodorHttpCodec extends HodorCodec { + bytesToValue(): string { + return "HodorHttp"; + } + + valueToBytes(): Buffer { + return Buffer.from("HodorHttp"); + } +} + @suite("testing OctectStream codec") class SerdesOctetTests { @test "OctetStream to value"() { @@ -1058,6 +1068,7 @@ class CborSerdesTests { class SerdesCodecTests { static before() { ContentSerdes.addCodec(new HodorCodec()); + ContentSerdes.addCodec(new HodorHttpCodec(), false, "http"); } @test async "new codec should serialize"() { @@ -1072,4 +1083,17 @@ class SerdesCodecTests { "Hodor" ); } + + @test async "new codec based on scheme should serialize"() { + const content = ContentSerdes.valueToContent("The meaning of Life", { type: "string" }, "text/hodor", "http"); + const body = await content.toBuffer(); + body.toString().should.equal("HodorHttp"); + } + + @test "new codec based on scheme should deserialize"() { + const buffer = Buffer.from("Some actual meaningful stuff"); + expect( + ContentSerdes.contentToValue({ type: "text/hodor", body: buffer }, { type: "string" }, "http") + ).to.be.deep.equal("HodorHttp"); + } }