Skip to content

feat(events): WrappingSet.on/off with mapped values#93

Draft
jeswr wants to merge 1 commit into
rdfjs:mainfrom
jeswr:feat/wrapping-set-events
Draft

feat(events): WrappingSet.on/off with mapped values#93
jeswr wants to merge 1 commit into
rdfjs:mainfrom
jeswr:feat/wrapping-set-events

Conversation

@jeswr

@jeswr jeswr commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

What this does

Adds change subscriptions at the collection level: WrappingSet<T> gains on(listener) / off(listener), with listeners receiving the kind of mutation and the mapped JavaScript value rather than a raw quad.

  • WrappingSetListener<T>(event: "add" | "delete", value: T) => void.
  • on(listener) subscribes to the underlying dataset's "add"/"delete" quad events, filters them by this set's subject + predicate, and projects the affected quad's object through the termAs mapping the set was created with. Mutations made through any route (the dataset directly, sibling wrappers) are observed.
  • off(listener) detaches via a WeakMap<listener, Map<subject␀predicate, adapter>> registry, so it works across the fresh instances SetFrom.subjectPredicate returns on every property access (instance.prop.on(l)instance.prop.off(l) just works). Re-attaching the same listener for the same subject + predicate replaces the previous subscription, so events are never delivered twice.
  • Datasets that don't emit change events are rejected with a new typed DatasetEventsError (extends WrapperError).

Event-emitting datasets are detected structurally (a DatasetCore that is also an EventEmitter with "add"/"delete" quad events, e.g. EventfulDatasetCore from @jeswr/eventful-dataset). That package is a devDependency only (tests + a type-only import); the emitted declarations do not reference it and the package keeps zero runtime dependencies.

Relationship to other PRs

Tests

14 new tests (test/unit/wrapping_set_events.test.ts): add/delete/clear emission with mapped values (term and literal mappings), subject/predicate filtering, direct dataset mutations, no event on ineffective adds, multiple independent listeners, live re-iteration inside a listener, off across fresh instances / unknown listeners / per-(subject, predicate) detachment, re-subscription replacement, and the DatasetEventsError path. npm test (136 tests, 0 fail), npx typedoc, and npm audit --omit=dev all pass locally.

Review timing: This draft was prepared with Claude; I (@jeswr) will personally review it before it progresses. I'm currently batching a lot of work in flight, so expect active review Wednesday-Friday (8-10 July).

Adds change subscriptions at the collection level: WrappingSet.on(listener)
filters the underlying dataset's add/delete quad events by this set's
subject and predicate and projects the affected quad's object through the
set's termAs mapping before invoking the listener. off(listener) detaches
via a WeakMap<listener, Map<subject NUL predicate, adapter>> registry, so
it works across the fresh WrappingSet instances SetFrom returns on every
property access.

Datasets that do not emit change events are rejected with a typed
DatasetEventsError. @jeswr/eventful-dataset is a devDependency only
(tests + type-only import); the published declarations do not reference
it and the package keeps zero runtime dependencies.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant