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/core

v0.3.1

Published

JSON-LD 1.1 processor and validator that reports what your documents silently lose, with a JSON Pointer from every result back to the line that produced it.

Readme


Looking for the tool rather than the library? Install the CLI — @json-ld-modeler/ldm — or the VS Code extension, JSON-LD Modeler. This package is the engine both of them are built on.

Why this exists

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 involved reports success.

Every JSON-LD library will hand you the expanded document. None of them will tell you what fell out on the way, or which line of your file it fell out of. This one does, because that is the only reason it was written: every value, every node and every dropped key carries a JSON Pointer back to the input, and the pointer resolves to a line and column in the file a person edited.

Install

npm install @json-ld-modeler/core

Node 20+, ESM, TypeScript types included, zero runtime dependencies beyond a YAML parser. It never imports vscode — enforced by lint and by a test that scans the source — so the conformance suite and every emitter run in plain Node.

Expand a document and see what it lost

import { readFileSync } from 'node:fs'
import {
  activeContextForModel,
  bareExpanded,
  expandDocument,
  resolveModelText,
} from '@json-ld-modeler/core'

const path = 'vocabulary.jsonld.yaml'
const { ir } = resolveModelText(readFileSync(path, 'utf8'), path)

const active = activeContextForModel(ir!)
const document = JSON.parse(readFileSync('documents/order.json', 'utf8'))
const result = expandDocument(document, active)

for (const o of result.observations) {
  if (o.kind === 'key-dropped') {
    console.log(`"${o.key}" at ${o.pointer} expands to nothing`)
  }
}

// The plain JSON-LD a conformant processor returns, provenance stripped:
const expanded = bareExpanded(result)

observations is the interesting half. Beyond key-dropped it reports key-only-via-vocab (the key matched no term and only became an IRI because @vocab applied — not a drop, and worse, because nothing else reports it), relative-iri, blank-node-minted, coercion-did-not-fire and term-used.

Validate a model

import { validateModelText } from '@json-ld-modeler/core'

const report = validateModelText(readFileSync(path, 'utf8'), path)

for (const f of report.findings) {
  console.log(`${f.file}:${f.loc.line}:${f.loc.column}  ${f.severity}  ${f.ruleId}`)
  console.log(`  ${f.message}`)
}

process.exit(report.failed ? 1 : 0)

The ladder runs L0 well-formedness, L1 context errors located at the term in your model rather than in a generated artifact, and L2 lossiness. Each Finding carries a stable ruleId, a pointer, a file and a loc — the wording is not an interface, the rule id is.

Trace an expansion

import { expandTraced, formatTrace } from '@json-ld-modeler/core'

const traced = expandTraced(document, active)
console.log(formatTrace(traced.trace).join('\n'))

Every term lookup, every IRI resolution, every change to the active context and every key dropped, in order. A traced run and an untraced run produce identical output — asserted, not assumed. It is the only honest way to explain a scoped context, whose whole behaviour is a sequence of active-context changes.

Emit a @context

import { emit, SourceIndex } from '@json-ld-modeler/core'

const source = SourceIndex.parse(readFileSync(path, 'utf8'), { path })
const { text, findings, downgrades } = emit(ir!, { target: 'context', source })

context references the contexts a model uses; context-inline flattens them and reports the fork rather than performing it quietly. Generated artifacts carry a header saying they are generated.

What is in the box

| Area | Some of what it exports | | --- | --- | | Processor | expand, compact, expandTraced, processContext, expandIri, activeContextForModel | | Provenance | SourceIndex, resolvePointer, pointersIn, strip, bareExpanded | | Model | resolveModel, resolveModelText, serializeIr, backfillElementIds, type Ir | | Validation | validateModel, validateModelText, RULES, type Finding, type Level | | Emitters | emit, buildContextDocument, capabilitiesFor | | Import | importContext — an existing @context becomes a model | | Vendoring | VendorStore, vendorCheck, vendorRefresh, integrityOf, resolverFor | | Projects | loadProject, checkProject, projectScaffold, modelScaffold | | Versions | VersionStore, createVersionFromModel, sealManifest, AliasStore | | Diff | compareVersions, CHANGE_CLASSES — additive, compatible, breaking, semantic, illegal | | Publishing | publish, verifyTree, adapterFor — plain, GitHub Pages, S3 | | Search | buildIndex, search — offline, across every model in a project | | Skills | loadSkills, render, FORMATS — authoring guidance, in three agent formats |

Everything is a named export from the package root, and every public type ships with it.

The JSON Schema for model files is exported as @json-ld-modeler/core/schema and published at its own $id, with every field documented.

loadSkills() returns the authoring guidance the CLI installs. It is prose: it produces no finding, no edit and no exit code, and nothing in validation, emission or the processor reads it.

Offline by design

There is no network code in this package outside a single explicit resolver (fetchContext, used only by vendorRefresh). Everything else takes a resolveContext callback that reads from the vendored, hash-checked copy on disk.

That is a security boundary, not a preference: a model file names the URLs to fetch, so a routine that fetches what a model tells it to — running in CI against an outside pull request — is a request-forgery primitive.

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 two outputs compared — every disagreement becomes a question with a recorded answer. Cases that do not pass are listed with a reason; frame, toRdf, fromRdf, flatten and html are out of scope for this release.

Framing, URDNA2015 canonicalization and N-Quads serialization are delegated to existing libraries. The line is drawn at provenance: expansion and compaction sit between what you wrote and what is reported, so they must carry pointers. Canonicalization is a pure function over an already-expanded graph and gains nothing from being reimplemented.

Learn JSON-LD while you are here

Links

MIT licensed.