FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Extract JSON pointer primitives from vc-query. by applesnort · Pull Request #1 · digitalbazaar/json-pointer-primitives · GitHub

Extract JSON pointer primitives from vc-query. - #1

Merged
davidlehn merged 13 commits into
mainfrom
jmangin/extract-pointer-primitives
Aug 27, 2026
Merged

Extract JSON pointer primitives from vc-query.#1
davidlehn merged 13 commits into
mainfrom
jmangin/extract-pointer-primitives

Conversation

applesnort commented Aug 21, 2026
edited
Loading

Copy link
Copy Markdown
Collaborator

Extracts the JSON pointer matcher into its own package so it can be shared rather than copied.

What it is

matches({object, map}) — does an object satisfy a Map of JSON pointer to expected value. Every entry must match, a Set value means any member may match, plus wildcards, array inclusion and optional number coercion. Ships alongside toJsonPointerMap, fromJsonPointerMap and resolvePointer.

Changes from the original

  • credentialMatches({credential, map}) is now matches({object, map}). It never inspected a credential, only an object and a map.
  • MDOC_MDL is not carried over; it is credential-specific.
  • jsonpath-plus stays behind. One runtime dependency here, json-pointer.

Verified

Tests and lint green. The suite matches a render method as well as a credential, since the claim is that the matcher does not know what it is matching.

A small kit that higher libraries build on: convert a nested object to a
map of JSON pointers, convert one back, resolve a single pointer, and test
whether an object satisfies a map.

`matches({object, map})` takes the object and the map only. It does not
know what it is matching, which is the whole point -- a credential, a
render method and a hand-written object are all the same to it.

One runtime dependency, `json-pointer`. Presentation-Exchange path
handling and credential-specific constants are deliberately not here.
`matches` had every test; the six utilities this package also exports had
none. That left the pointer behaviour inherited from the dependency
unpinned, so a bump could have changed any of it silently.

Covers the RFC 6901 rules that are easy to get wrong: `-` names the
element after the last one and must not resolve on a read, `~1` decodes
before `~0`, and an array index may not carry a leading zero.

Also pins two deliberate departures, so they read as decisions rather
than drift. `/` means the whole document here rather than the value
under the empty-string key. And `fromJsonPointerMap` infers a container
from the next token's shape, which is what lets a caller compile "any
array index" to the literal token `0` and get an array back.

Every assertion is mutation-verified. Three drafts of these tests could
not fail and were rewritten: the missing-segment fixture needed a value
at the root for a re-rooting resolver to find, the empty-container tests
read presence rather than emptiness, and the `assert` case never called
the four-argument form it was named for.
Five defects. Two are reachable from a pointer map an outside party
authors, which in a query flow means whoever wrote the query:

`matches` did not check that `map` was a `Map`, and `_isWildcard` tested
a bare `size`. Anything carrying `size: 0` -- a `''`, or a `{"size": 0}`
parsed out of JSON -- turned every constraint into "match anything", so
a selection predicate answered `true` for every candidate. It now
asserts the type and tests the wildcard by class.

`resolvePointer` gated each hop on `in`, which walks the prototype
chain: `/toString` and `/constructor` resolved on every plain object,
and a wildcard entry naming one matched a document that has no such
field. It now walks the tokens itself against own properties and refuses
`__proto__`, `constructor` and `prototype` outright.

The other three are correctness:

`fromJsonPointerMap` assigned through `__proto__` as a final token,
replacing the prototype of the object it was rebuilding -- the result
stringified as `{}` while its properties still read back. The same three
tokens are now refused on the write path.

`toJsonPointerMap` returned the walk cursor instead of the map, so three
inputs its own `assert` allowed came back as `undefined`, `null` or a
`Set`, and the caller's next `.get` failed somewhere else entirely.

`fromJsonPointerMap` returned from inside its loop on a root pointer,
silently discarding every other entry in either key order.

`assert` also now enforces presence when `optional` is false. Without
that the first two fixes are decorative, since `undefined` passed every
check.
Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated
@@ -0,0 +1,48 @@
# @digitalbazaar/json-pointer-primitives ChangeLog

## 0.1.0 - TBD

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Always target 1.0.0 as the first version. Sub-v1 versions generally just cause headaches -- treat "v1" as nothing special wrt. any other major version.

Comment thread lib/match.js
`@context` is the one ordered array in a credential -- later entries
override earlier ones -- so expressing it as a `Set` discards the thing
that makes it mean anything.

A non-flat map now keeps `@context` as an array, and matching compares
element by index, allowing the object to carry more entries than the
query names. Every other array stays an unordered `Set`.

Also fixes a consequence of the ordered container: `_fromPointers`
rebuilt maps nested inside a `Set` but not inside an array, so an inline
context object came back as a raw `Map`. That stringifies to `{}`, so
nothing that logged the result would show the loss.

Note for any caller converting a pointer map to Presentation Exchange:
the array now has to be recognised alongside `Set`, or a `@context`
constraint silently becomes an object filter instead of an array one.

Changelog reduced to what a first release states, and the version
targets 1.0.0 rather than 0.1.0.
All three empty forms already mean "any value at this pointer". This
records which to reach for: an empty `Map`, which is what `{}` in an
example becomes, and what JSON-LD Framing already uses.

The empty string keeps working. It is the written QueryByExample
convention, and a conversion elsewhere special-cases it. But it is a
value standing in for a wildcard: type-specific, it reads as "the name
is blank", and it makes "this property is the empty string"
inexpressible. A test now pins that ambiguity so it is a known cost
rather than a surprise.

No behaviour change.
applesnort requested a review from dlongley August 24, 2026 15:34
Comments now explain the code in front of them and nothing else. No
repository names, issue numbers or links to other work.
applesnort force-pushed the jmangin/extract-pointer-primitives branch from 5f4c2d8 to eab4505 Compare August 24, 2026 18:03
applesnort requested a review from davidlehn August 24, 2026 18:11
Nothing in `lib/` touches a node builtin, so the package should work in a
browser -- but nothing had ever run there, which made that an assertion
rather than a fact. Two vitest projects now run the identical spec files
in both places, so a spec that passes in one and fails in the other is a
real portability bug rather than something nobody sees.

All 99 tests pass in chromium as well as node. The runtime dependency is
CommonJS and vite bundles it without complaint, so no build change was
needed to get there.

Note for anyone copying this config: vitest 4 takes a provider factory,
`provider: playwright()`, where 3 took the string `'playwright'`.

davidlehn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Also needs workflow for lint/tests/coverage. Take a look at the work-in-progress vitest setup in http-client for inspiration. Does caching and such. Can use the c8 coverage plugin here. (The http-client code needed to use istanbul for cross-browser reasons.)
digitalbazaar/http-client#56

Comment thread lib/index.js Outdated
@@ -0,0 +1,8 @@
/*!
* Copyright (c) 2026 Digital Bazaar, Inc. All rights reserved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Need similar removal of "All rights reserved." in every file.

Suggested change
* Copyright (c) 2026 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2026 Digital Bazaar, Inc.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@djscruggs I thought the harness was taking care of this one? If not, we should get that added.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@BigBlueHat it was merged into ai-harness two weeks ago. @applesnort are you running the latest?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Removed it from every source file, but left LICENSE.md alone since a licence file conventionally keeps its full copyright line. Did you mean that one too?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I removed it from license file too.

Comment thread package.json Outdated
Comment thread eslint.config.js Outdated
Comment thread package.json Outdated
Comment thread README.md Outdated
Comment thread .gitignore
Comment thread README.md
applesnort and others added 6 commits August 26, 2026 13:01
Drops "All rights reserved." from every file header. LICENSE.md keeps it,
since that is the licence's own text rather than a header.

Switches eslint to the universal config, which is the honest one for a
package that runs in both places, and sets the licence to the SPDX id.
Adds the editor cruft other repos ignore.

The readme loses the section explaining why shared libraries exist, and
the semantics table becomes worked examples -- the table said what the
rules were without showing any of them, so the tests were the only place
to see one. Every example is checked against the real code.
Runs eslint, node tests across 22/24/26, browser tests, and a coverage
report uploaded to Codecov. Bumps eslint-config to ^9 and eslint to ^10
to match, and adds the v8 coverage provider; coverage is configured at
the vitest root because it is process-wide and cannot be set per project.

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

davidlehn merged commit 194971f into main Aug 27, 2026
6 checks passed
davidlehn deleted the jmangin/extract-pointer-primitives branch August 27, 2026 02:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.

6 participants


Back | FazBrowse Home | New Git URL