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

@niscorp/prism

v0.2.2

Published

Pure JSON transformation DSL with compilation and zero code execution

Readme

@niscorp/prism

Pure JSON data transformation DSL with compilation, caching, and zero code execution risk.

Transformations are JSON objects — no code strings, no eval, no security risks. Designed so LLMs can generate transformation configs that are safe to execute.

Install

pnpm add @niscorp/prism @niscorp/strata zod

@niscorp/strata and zod are required peers. @niscorp/cortex and @niscorp/signal are optional — only the mapping agent at @niscorp/prism/agent (mappingAgent) needs them.

Quick Example

import { evaluate } from '@niscorp/prism';

const result = evaluate(
  {
    fullName: {
      $join: {
        parts: [{ $ref: '$.user.firstName' }, { $ref: '$.user.lastName' }],
        sep: ' ',
      },
    },
    itemCount: { $length: { $ref: '$.items' } },
    total: { $sum: { over: { $pluck: { over: { $ref: '$.items' }, key: 'price' } } } },
  },
  {
    user: { firstName: 'Alice', lastName: 'Smith' },
    items: [
      { name: 'Widget', price: 9.99 },
      { name: 'Gadget', price: 24.99 },
    ],
  },
);
// → { fullName: 'Alice Smith', itemCount: 2, total: 34.98 }

Documentation

  • DOCS.md — Full reference for every operation, with examples
  • DESIGN.md — Architecture, design decisions, and trade-offs

API

// One-shot evaluation
evaluate(config, source, limits?) → JsonValue
evaluateSafe(config, source, limits?) → { ok: true, data } | { ok: false, error }

// The same, in the shape a host's transform seam takes
prismTransform(config: unknown, source: unknown) → unknown

// Compile once, execute many (2-5x faster for repeated configs)
compile(config, options?) → Promise<CompiledIr>
execute(ir, source, limits?) → JsonValue

// Validation
validate(config) → { ok: true, data } | { ok: false, issues }

// JSON Schema for LLM consumption
getNodeJsonSchema(target?) → object
getConfigJsonSchema(target?) → object

As a host's transform

nova's shell, tide's engine and strata's upgrader each run a config through a transform they are handed, (config, source) => unknown, and know nothing of Prism. prismTransform is Prism in that shape:

import { prismTransform } from '@niscorp/prism';

createTide({ store, transform: prismTransform, effects });   // @niscorp/tide
createUpgrader(grammars, { transform: prismTransform });     // @niscorp/strata

Both sides arrive untyped, so both are checked: the config is parsed against ConfigSchema (once for each config object), and the source must be plain JSON — a source holding undefined, a function or a non-finite number is refused. evaluate is typed for a JsonValue and checks no source, which is why it cannot be handed to a seam as it is. A host that adds values of its own to the source first (the app's "today", the session's principal) wraps it.

Examples

@niscorp/prism/examples is the reference as data: one example for each operator, named by the operator — a config, the source it is given, and what comes out — then a few configs of several operators working together.

import { evaluate } from '@niscorp/prism';
import { PRISM_EXAMPLES, PRISM_EXAMPLE_GROUPS } from '@niscorp/prism/examples';

const map = PRISM_EXAMPLES.find((example) => example.op === '$map');
// → { id: 'map', group: 'arrays', title: '$map', description, op: '$map', source, config, expected }
evaluate(map.config, map.source); // → map.expected

// PRISM_EXAMPLE_GROUPS → [{ id: 'arrays', title: 'Arrays', description }, …]
// the groups the reference puts the operators in, in the same order

They are tested with the package (test/examples.test.ts): each one evaluates to its expected, and every operator in OP_KEYS has exactly one example of its own. So whatever shows them — a documentation page, an agent reading node_modules — is showing what the installed version does.

Profiles

getProfileJsonSchema(ops, target?) is the config JSON Schema documenting only the ops you name — derived from the full schema, never restated. MAPPING_OPS is the set a mapping uses (rows into a shape), about 28% less prompt than the whole grammar; the mapping agent is documented with it. A profile narrows what a prompt teaches, never what Prism accepts: validation is always the full ConfigSchema, and a config using an op outside the profile is still valid.

Transform ops and the grammar

Besides deriving values, a config can rewrite a document: $has, $renameKeys, $update, $assert and $walk (every node of a tree, by rules) — see DOCS.md § Transform Operations. They are what strata's document migrations are written in.

@niscorp/prism/migrations publishes Prism's own grammar — PRISM_SEQUENCE (nisc.prism, kind nisc.prism/config), PRISM_SCHEMAS — and exports prismTransform as well, the evaluator a migration runs through (strata injects it): the same function as the main entry's.

The op set only ever grows. Configs are stored — endpoint requests, vex mappings, migrations — and a migration cannot be migrated by the language it is written in: an op is never removed or reshaped; an old form stays as sugar. test/transform.test.ts keeps the record; a grammar change is a migration on nisc.prism, gated by pnpm check:grammars.

License

Apache-2.0