Package Exports
- @lde/docgen
- @lde/docgen/package.json
Readme
@lde/docgen
Generate human-readable documentation from SHACL shapes using Liquid templates.
- Template-driven: you control the output format (Markdown, HTML, plain text) with Liquid templates.
- Standards-based: reads any RDF serialization (Turtle, JSON-LD, N-Triples, etc.) via rdf-dereference.
- Structured output: SHACL shapes are framed into a clean JSON-LD tree before rendering, so templates work with predictable, nested objects.
How it works
graph LR
A[SHACL file] --> B[Parse to JSON-LD] --> C[Frame by NodeShape] --> D[Render with Liquid template] --> E[Output]- Parse — the SHACL file is dereferenced and converted to JSON-LD.
- Frame — the JSON-LD is framed using a JSON-LD Frame that selects
sh:NodeShaperesources and nests their property shapes. A default frame is included; you can supply your own. - Render — the framed data is passed to a Liquid template as
nodeShapes, an array of node shape objects.
CLI usage
npx @lde/docgen@latest from-shacl <shacl-file> <template-file> [options]Arguments
| Argument | Description |
|---|---|
<shacl-file> |
Path to a SHACL shapes file (any RDF serialization) |
<template-file> |
Path to a Liquid template file |
Options
| Option | Description | Default |
|---|---|---|
-f, --frame <file> |
Path to a JSON-LD Frame file. Deep-merged on top of the built-in default frame, so it only needs to contain your additions (e.g. extra @context entries). |
Built-in frames/shacl.frame.jsonld |
Example
Given a SHACL file shapes.ttl:
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
[] a sh:NodeShape ;
sh:targetClass dcat:Dataset ;
sh:property [
sh:path dct:title ;
sh:minCount 1 ;
] ,
[
sh:path dct:description ;
sh:minCount 1 ;
sh:datatype xsd:string ;
sh:description "A description of the dataset"@en ;
] .And a template spec.md.liquid:
{% for nodeShape in nodeShapes -%}
## {{ nodeShape.targetClass }}
| Property | Required | Type | Description |
|---|---|---|---|
{% assign mergedProperties = nodeShape.property | mergePropertiesByPath -%}
{% for property in mergedProperties -%}
| `{{ property.path }}` | {{ property.minCount | default: "no" }} | {{ property.datatype }} | {{ property.description | lang: "en" }} |
{% endfor %}
{% endfor %}Run:
npx @lde/docgen@latest from-shacl shapes.ttl spec.md.liquid > spec.mdProgrammatic usage
import { generateDocumentation } from '@lde/docgen';
const output = await generateDocumentation(
'shapes.ttl',
'spec.md.liquid',
'frames/shacl.frame.jsonld', // optional: path to custom frame
);Template data
The Liquid template receives a nodeShapes array. Each node shape object has the structure produced by the JSON-LD Frame — keys are SHACL term names (targetClass, property, name, etc.) with IRIs as values.
Property shapes with the same sh:path are common in SHACL (e.g. one for cardinality, another for datatype). The mergePropertiesByPath filter combines them into a single object per path.
Custom filters
| Filter | Description | Example |
|---|---|---|
lang |
Select a value by language tag | {{ property.description | lang: "en" }} |
mergePropertiesByPath |
Merge property shapes that share the same sh:path |
{% assign merged = nodeShape.property | mergePropertiesByPath %} |
Custom frames
The default frame selects all sh:NodeShape resources and provides type coercions for common SHACL terms (targetClass, path, severity, etc.). To extend it, pass a partial JSON-LD Frame – it is deep-merged on top of the default, so you only need to specify your additions:
{
"@context": {
"nde": "https://def.nde.nl#",
"nde:futureChange": {},
"nde:version": {}
}
}npx @lde/docgen@latest from-shacl shapes.ttl template.liquid -f my-frame.jsonldPlain objects are merged key-by-key, with user values winning; arrays and primitives in your frame replace the default. To override a built-in coercion (e.g. change severity from @vocab to @id), redefine the same key in your @context.