npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@json-ld-modeler/ldm

v0.3.1

Published

ldm — author a JSON-LD @context as a reviewable YAML model, validate what your documents lose, and gate it in CI. Runs with the network off.

Readme


The most expensive JSON-LD bug is not an error.

Expansion is total. It does not fail on a key it cannot resolve — it drops it. A document can lose most of its content while every processor in your pipeline reports success, and nothing in your test suite goes red.

ldm is the command that catches that, in CI, on the data you actually ship.

$ ldm check vocabulary.jsonld.yaml
Checked vocabulary.jsonld.yaml at L2.
documents/order.json:3:3  warning L2.key-dropped  "writtenBy" matched no term and expands to nothing. Expansion still succeeded; this content is simply gone.
documents/order.json:7:3  warning L2.coercion-did-not-fire  "https://example.org/people/ada" reads as an IRI but "author" has no `@type: @id`, so it expanded as a literal rather than a reference. The term is not declared by this model.
vocabulary.jsonld.yaml:59:3  info    L2.term-unused  No example document uses "byType".
3 findings.

Every finding carries a stable rule id, a JSON Pointer, and a line and column in a file you wrote — never a position in a generated artifact.

Install

npm install -g @json-ld-modeler/ldm    # the command it installs is `ldm`

Or without installing anything:

npx @json-ld-modeler/ldm check vocabulary.jsonld.yaml

Node 20 or newer. No native dependencies, no service to run.

Sixty seconds

Start from nothing:

ldm init --prefix cat --base https://example.org/catalogue#
ldm check                         # every model in the project, one report

Or start from a @context you already have:

ldm import schema-subset.jsonld --out vocabulary.jsonld.yaml
ldm vendor vocabulary.jsonld.yaml       # the one command that touches the network
ldm check  vocabulary.jsonld.yaml       # what your examples lose
ldm emit   vocabulary.jsonld.yaml --out build
ldm explain vocabulary.jsonld.yaml doc.json --trace

ldm explain --trace is the one to reach for when a document does not mean what you think it means: it prints every term lookup, every IRI resolution, every change to the active context and every key dropped, in order, for your document rather than for an example in a specification.

Commands

One model

| | | | --- | --- | | ldm check <model> | Run the validation ladder — --level L0\|L1\|L2, --json | | ldm emit <model> | Generate the @context--target context\|context-inline, --out <dir> | | ldm import <context> | Turn an existing @context into a model — --out <model> | | ldm vendor <model> | Fetch referenced contexts once and hash them — --check | | ldm explain <model> <doc> | Why the document means that — --trace | | ldm ids <model> | Backfill stable element ids |

A project — found by searching upward, or named with --project

| | | | --- | --- | | ldm check --project | Every model, one report | | ldm version new [<model>] | Freeze a model as a content-addressed version — --alias <name> | | ldm alias set \| rename \| rm \| list | Move the human-readable labels | | ldm clone <version-or-alias> | Start a new draft from a frozen version | | ldm publish | Write the static tree you commit and serve | | ldm diff <a> <b> | What changed and what kind of change — --fail-on breaking | | ldm search <query> | What already exists, offline |

Authoring skills — guidance for a coding agent working on a model

| | | | --- | --- | | ldm skill list | What this build carries | | ldm skill install --project\|--user | Write them — --format agent-skill,agents,chatmode, --force |

There is no default install target. --project writes beneath the current directory and --user beneath your home directory, and the two are not interchangeable enough to guess between. A skill you have edited is never overwritten; --force takes the new version.

A skill is prose and produces nothing — no finding, no edit, no exit code. Anything about your model comes from the commands the skill names. Installing them changes no output ldm check produces, which is asserted rather than promised.

Run ldm with no arguments for the full usage text.

There is no command that renames a version — a version's name is its content hash, so there is nothing to rename. ldm alias rename moves the label instead, and both leave every published version byte-identical.

In continuous integration

Exit codes are the interface: 0 clean, 1 findings at error severity, 2 usage.

- run: npm install -g @json-ld-modeler/ldm
- run: ldm vendor models/catalogue.jsonld.yaml --check   # hashes still match
- run: ldm check --project                               # nothing is being lost
- run: ldm diff stable next --fail-on breaking            # no silent break

Everything except ldm vendor runs with the network off. That is not a convenience setting. A model file names the URLs to fetch, so a command that fetches what a model tells it to — running in CI against a pull request from outside — is a request-forgery primitive. Exactly one command can reach the network, and a person invokes it.

ldm vendor writes each referenced context into a committed directory and records its integrity hash in the model. An upstream publisher editing their context then becomes a reviewable diff instead of a silent change of meaning.

What a model looks like

Point any editor at the published schema and it checks the file as you type:

# yaml-language-server: $schema=https://volland.github.io/dr-json-ld/schemas/model/1/model.schema.json

Every field is documented at the schema reference. The VS Code extension contributes the same schema automatically.

jsonld: "1"

namespace:
  prefix: cat
  base: https://example.org/catalogue#

mode: "1.1"

uses:
  - iri: https://example.org/vocab/core.jsonld
    integrity: sha256-…

terms:
  # `@set` is the closest thing JSON-LD has to future-proofing: always an
  # array, so a property that becomes multi-valued later does not change the
  # shape of every document that already exists.
  tags:
    id: tag001
    "@id": cat:tag
    "@container": "@set"

examples:
  - id: exa001
    path: documents/ok.json
    expect: { ok: true }

  # A negative example names the rule ids it must raise. One that merely fails
  # passes even when it fails for the wrong reason.
  - id: exa002
    path: documents/empties.json
    expect:
      rules: [L2.key-dropped]

The YAML model is canonical and holds semantics only. The @context is generated from it and says so in its header — run ldm emit in CI and compare, so a hand edit to a generated artifact is caught in review.

Authoring: the VS Code extension

ldm is what your pull request runs. For writing the model in the first place, install JSON-LD Modeler (pavlyshyn.jsonld-modeler):

  • Two coordinated panes — the JSON shape a developer will type beside the RDF graph it denotes, sharing one selection. A @container that restructures the JSON and changes no triple is drawn as exactly that.
  • Findings in the Problems panel, at the line in your model, not in a generated file.
  • Schema-driven completion from the JSON Schema the extension contributes — no language server to install.
  • Edits that do not reformat your file: every canvas action is a targeted splice, so comments and key order survive.

Same engine underneath — both this CLI and the extension are thin wrappers over @json-ld-modeler/core.

Conformance

Observed, not claimed. The W3C JSON-LD 1.1 test suite is vendored and run with the network off, and every in-scope case is additionally run through jsonld.js with the outputs compared. Cases that do not pass are listed with a reason; frame, toRdf, fromRdf, flatten and html are out of scope for this release and are reported as such rather than skipped silently.

Expansion and compaction are implemented here rather than delegated, because the lossiness reporting needs a JSON Pointer from every output back to the input that produced it — and no library exposes that.

Learn JSON-LD while you are here

Links

Not in this release

The shapes layer and everything that consumes it — SHACL, framing, JSON Schema, the vocabulary document, generated types. Validation L3 and L4. RDF to JSON-LD conversion. Uploading to a host, or signing anything: a checksum detects accident and casual tampering; it is not a signature, and nothing here implies otherwise.

Deferred is not cancelled — each is reachable from the current design, and the design record in lat.md/ says how.

MIT licensed.