-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Describe the feature
I think it is almost time we think about supporting extended serializers (like a preset addon for supporting HTML serialization), even though bundle addition is few bytes still is not needed for many (I imagine most of) users.
Originally posted by @pi0 in #155 (comment)
I thought about two ways to approach this:
[A] Handle presets within the Serializer
instance
Depending on how many hooks we use this would add some overhead because it checks for possible presets and their handlers before each serialization.
interface SerializerPreset {
/**
* Runs before the default serialization.
*
* @param input - input value to serialize
* @param serialize - to use for inner structures
* @param context - to serialization context
* @returns The serialized string or undefined if not handled
*/
serializeBefore?: (
input: unknown,
serializer: {
serialize: (input: unknown) => string;
context: Map<object, string>;
},
) => string | undefined;
/**
* Runs after the default serialization before the `object.entries` check in `serailizeBuiltInType()`
*
* @param input- input value to serialize
* @param type - type of the input object (for example: "HTMLCollection")
* @param serialize - to use for inner structures
* @param context - to serialization context
* @returns The serialized string or undefined if not handled
*/
serializeAfter?: (
input: object,
type: string,
serializer: {
serialize: (input: unknown) => string;
context: Map<object, string>;
},
) => string | undefined;
}
import { serialize } from "ohash";
import customPreset from "ohash/presets/custom";
serialize("hello world", { presets: [customPreset] });
[B] Create customized Serializer
prototypes using the presets
This would be a bit faster as prototype creation could be optimized to add hooks only when handlers for that specific hook are provided from the presets.
The extend()
helper would allow extending the protoype with custom type handlers directly.
This would eliminate the necessity to use hooks at all in some presets.
interface SerializerPreset {
/**
* Allows extending the serializer with custom types.
*
* @param serializer - serializer to extend
* @example
* ```ts
* setup(serializer) {
* serializer.extend(
* "HTMLCollection",
* (collection: HTMLCollection, type, { serialize, context }) =>
* `${type}${serialize(Array.from(collection))}`
* );
* }
* ```
*/
setup?: <const T extends string | string[], V>(serializer: {
extend: (
types: T,
handler: (
input: V,
type: T extends string ? T : T[number],
serializer: {
serialize: (input: unknown) => string;
context: Map<object, string>;
},
) => string,
) => void;
}) => void;
// ...serializeBefore
// ...serializeAfter
}
import { ohash, createSerializer } from "ohash";
import customPreset from "ohash/presets/custom";
const { serialize, isEqual, hash } = ohash({ presets: [customPreset] });
serialize("hello world");
const customSerialize = createSerializer({ presets: [customPreset] });
customSerialize("hello world");
Creating a custom prototype on each serialize()
call would be much slower, so createSerializer()
creates the custom Serializer
prototype and provides a serialize
function to use it with.
Additional information
- Would you be willing to help implement this feature?