Skip to content

Feature Request: reviver / replacer hooks for stringify and parse #2

@codemeasandwich

Description

@codemeasandwich

Add optional reviver and replacer callback parameters to jss.stringify() and jss.parse(), mirroring the native JSON.stringify(value, replacer) and JSON.parse(text, reviver) signatures.

Motivation

Sometimes users need lightweight, one-off transformations without registering a full custom type via jss.custom(). Common use cases:

  • Redacting sensitive fields before serialization (e.g. stripping tokens or passwords)
  • Transforming values on the fly during parsing (e.g. clamping numbers, normalising strings)
  • Filtering keys from the output without mutating the original object
  • Migration / versioning — reshaping legacy data during deserialization

The native JSON API already establishes this pattern, so supporting it keeps JsonSuperSet a true drop-in replacement.

Proposed API

// replacer — called during stringify, before type encoding
jss.stringify(data, {
  replacer(key, value) {
    if (key === 'password') return undefined  // omit field
    return value
  }
})

// reviver — called during parse, after type decoding
jss.parse(json, {
  reviver(key, value) {
    if (key === 'count') return Math.max(0, value)  // clamp
    return value
  }
})

Design Considerations

  • Execution order: replacer should run before the JSS type encoding so users see the original JS values. reviver should run after type decoding so users receive fully restored objects (Dates, Maps, etc.) rather than raw tagged values.
  • Signature compatibility: Ideally the callbacks receive (key, value) just like the native JSON equivalents to minimise surprise.
  • Options object vs positional args: An options object ({ replacer }) is more extensible than a positional second argument, but positional would be closer to native JSON. Worth deciding which style fits the library better.
  • Interaction with custom(): Hooks should compose cleanly with registered custom types — the hook runs in addition to, not instead of, custom encoders/decoders.

Alternatives

  • Users can always wrap jss.stringify / jss.parse themselves, but built-in support is cleaner and avoids double-parsing.
  • jss.custom() covers the "new type" case but is heavier than needed for simple field-level transforms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions