Graph reconstitution pipeline; classifies JSON records and squashes them into deterministic RDF.
Upstream: Ripperoni produces the JSON records Squashage consumes. Pair them to go from raw web pages to structured RDF.
Documentation · Architecture · Classifier engines · Demo · Releases
- Node 24+
- TypeScript 5.7+
git clone https://github.com/Studnicky/Squashage.git
cd Squashage
npm install
npm run build# Run the full Pathfinder/AONPRD demo (pipeline + cytoscape render)
npm run viz:demo
# Build from a config
squashage build \
--target aonprd \
--config squashage.config.json \
--in ./output/aonprd
# Override output path/format for a one-off run
squashage build --target aonprd --out ./graphs/aonprd.jsonld
# Render any squashage JSON-LD output as an offline HTML graph
squashage viz --in ./graphs/aonprd.jsonld --out aonprd.html --title "My Graph"Copy squashage.config.example.json to squashage.config.json and edit. The unprefixed file is gitignored.
npm run build # compile TypeScript
npm run typecheck # tsc --noEmit
npm run lint # eslint src/
npm run check # typecheck + lint + unit tests
npm run docs:build # build VitePress docs
npm run viz:demo # rebuild the Pathfinder/AONPRD demo- Consume structured JSON input records from one file, a directory tree, or JSONL.
- Classify each input record into an ontology type with deterministic evidence.
- Normalize source-specific records into stable graph entities.
- Project records into RDF/JS quads using a thin wrapper over
@rdfjs/*,n3,jsonld. - Serialize the canonical dataset to a single RDF file per build run (v0.x: Turtle, TriG, N-Triples, N-Quads, JSON-LD; v1.x adds RDF/XML and N3).
- Run a deterministic, declaratively configured classifier cascade.
- Squashage does not scrape web pages.
- Squashage does not run probabilistic models in the build path.
- Squashage does not load graph stores. Hand the file to your loader of choice.
- Squashage does not fan out across multiple outputs. One build, one file.
See the full config reference for all options.
Custom squash tasks register themselves with TaskRegistry:
import { TaskRegistry } from 'squashage/registry/TaskRegistry';
TaskRegistry.register('aonprd:squash', async (next, state) => {
if (state.classification?.type !== 'feat') { await next(); return; }
const ctx = state.context!;
const prefixes = ctx.prefixes;
const subject = ctx.factory.namedNode(
`${prefixes.instances.base}${String(state.input['url'] ?? 'unknown')}`
);
ctx.dataset.add(ctx.factory.quad(
subject,
ctx.factory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
ctx.factory.namedNode(`${prefixes.vocabulary.base}Feat`),
ctx.factory.namedNode(`${prefixes.graphs.base}feat`),
));
await next();
});Open docs/public/examples/aonprd/aonprd.html in
any browser to see the package's JSON-LD output rendered as an interactive graph.
Nodes are coloured by RDF class, edges show object-property links, and clicking
a node reveals its properties in the sidebar. The file runs entirely offline ,
no network access, no Node.js, no node_modules required at display time.
To rebuild the demo from the fixture data:
npm run viz:demoUNLICENSED

{ "targets": { "aonprd": { "input": "./output/aonprd", "pipeline": [ "json:read", "classify:source", "classify:structural", "classify:rules", "classify:ontology", "classify:conflict", "aonprd:squash", "rdfjs:finalize" ], "output": { "kind": "file", "path": "./graphs/aonprd.jsonld" } } } }