Skip to content

Add support for serializer presets #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
zsilbi opened this issue Mar 27, 2025 · 0 comments
Open
1 task done

Add support for serializer presets #157

zsilbi opened this issue Mar 27, 2025 · 0 comments
Labels
enhancement New feature or request

Comments

@zsilbi
Copy link
Collaborator

zsilbi commented Mar 27, 2025

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?
@zsilbi zsilbi added the enhancement New feature or request label Mar 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant