Skip to content

[dasc] Use RFC 6901 JSON Pointer for field paths instead of custom dot-notation #187

@mhaack

Description

@mhaack

Summary

Adopt RFC 6901 (JSON Pointer) for the paths that identify form fields (and the corresponding JSON properties) instead of the current dot-notation (Lodash-style property path). Paths would be built, stored, and parsed as JSON Pointers (e.g. /data/items/0/name), with a small adapter so the rest of the form logic stays unchanged.


Current behavior

Form field paths are built in annotateProp() (nx/blocks/form/utils/utils.js) as dot-separated strings with bracket indices, e.g.:

  • data
  • data.title
  • data.items.[0].name

They are used as the name attribute on form controls and written back via setValueByPath(), which splits on . and handles [n]. This follows a known, widely used convention in JS app code (e.g. Lodash _.get/_.set), but there is no formal standard for it, and no defined escaping for property names containing ., [, ], or ~, so certain keys can break or be ambiguous.


Proposed change

  • Represent paths as RFC 6901 JSON Pointers (slash-separated, with ~0 / ~1 encoding where needed).
  • Build paths in annotateProp() (or a small helper) as JSON Pointers (e.g. /data, /data/items/0/name).
  • Parse paths with an RFC 6901–compliant implementation (library or small in-house module) for get/set instead of the current setValueByPath() string-splitting logic.
  • Keep the same public behavior: same form fields, same update event contract; only the internal path format and parsing change. Optionally keep accepting current dot-notation and normalize to JSON Pointer for backward compatibility during a transition.

Why RFC 6901 fits our stack

RFC 6901 (JSON Pointer) is used primarily in specs and tooling (JSON Schema, OpenAPI, JSON Patch), not in everyday app path strings. Our app already relies on JSON Schema and validation; form data is schema-driven and validated against those schemas. Using JSON Pointer for field paths aligns with that world: the same path format appears in schema references, validation errors, and patches, so one consistent notation serves forms, validation, and tooling.

Benefits

  • Standard, stable format: Paths have a single, well-defined meaning and encoding (RFC 6901).
  • Ecosystem alignment: Same format as JSON Schema $ref, JSON Patch (RFC 6902), and many API specs; easier to integrate validation, patches, or tooling—and consistent with our existing use of JSON Schema and validation.
  • Robust edge cases: Keys containing ., /, ~, [, ] are handled via the RFC’s encoding rules instead of ad‑hoc logic.
  • Less custom code: Path parsing and encoding can rely on a well-tested library (or a minimal compliant implementation) instead of maintaining custom regex/split logic.
  • Future-proof: Aligns with the broader JSON ecosystem and reduces the risk of path-related bugs as schemas and property names evolve.

Note on custom implementation vs. dependency

Even if you do not add a dependency and implement JSON Pointer yourself, following RFC 6901 is still more future-proof than the current dot-notation:

  • Learnable from a standard: Any developer can look up RFC 6901 and implement or review the behavior. The rules are fixed and documented in one place.
  • Widely known: JSON Pointer is used in JSON Schema, OpenAPI, and JSON Patch, so many developers already know it or can recognize it quickly.
  • Stable spec: A custom implementation that follows the RFC gives you a single, well-defined path format and encoding; you avoid inventing and maintaining your own path syntax and edge-case rules.

So adopting the RFC convention (with or without a library) improves long-term maintainability and reduces the risk of path-related bugs, and stays consistent with the spec/tooling side of our stack (JSON Schema, validation).


Examples

Current (Lodash-style dot-notation)

Location in JSON Current path string
Root data data
data.title data.title
First item’s name in data.items data.items.[0].name

Proposed (RFC 6901 JSON Pointer)

Location in JSON JSON Pointer
Root data /data
data.title /data/title
First item’s name in data.items /data/items/0/name

Suggested implementation steps

  1. Use an existing RFC 6901–compliant library, or implement get/set following the RFC.
    For example, use @hyperjump/json-pointer (implements RFC 6901, Node/browsers, get/set/assign/unset/pointerSegments/appendhyperjump-io/json-pointer, MIT):

    npm i @hyperjump/json-pointer

    Alternatively, implement get/set following RFC 6901 with no new dependency; the RFC is enough for a correct, future-proof path format.

  2. Introduce a thin wrapper (if using a library) around @hyperjump/json-pointer: e.g. getByPointer(obj, pointer), setByPointer(obj, pointer, value), and a helper to build pointer strings from the segments used in annotateProp() (e.g. /data, /data/items/0/name).

  3. In annotateProp(), build the path as a JSON Pointer string (e.g. /data, /data/items/0/name) and store it on each annotated node (e.g. item.path).

  4. Replace the current setValueByPath(this._json, name, value) in FormModel.updateProperty() with the library’s set (or your RFC-based implementation), using the same name (now a JSON Pointer).

  5. Keep form controls using that name and the update event payload as-is; only the internal format of name changes to a pointer.

  6. Add/update tests for pointers with special characters (e.g. ., /, ~) and array indices. If anything external still expects the old dot-notation, add a short compatibility layer (e.g. convert old → pointer once) or document the breaking change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    dascUsed by DA Structured Content

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions