@lde/docgen 0.6.13 → 0.6.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -2
- package/dist/cli.js +1 -4
- package/dist/frame.d.ts +2 -2
- package/dist/frame.d.ts.map +1 -1
- package/dist/frame.js +35 -2
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,3 +1,127 @@
|
|
|
1
|
-
# docgen
|
|
1
|
+
# @lde/docgen
|
|
2
2
|
|
|
3
|
-
Generate documentation
|
|
3
|
+
Generate human-readable documentation from [SHACL](https://www.w3.org/TR/shacl/) shapes using [Liquid](https://liquidjs.com) templates.
|
|
4
|
+
|
|
5
|
+
- **Template-driven:** you control the output format (Markdown, HTML, plain text) with Liquid templates.
|
|
6
|
+
- **Standards-based:** reads any RDF serialization (Turtle, JSON-LD, N-Triples, etc.) via [rdf-dereference](https://github.com/rubensworks/rdf-dereference.js).
|
|
7
|
+
- **Structured output:** SHACL shapes are framed into a clean JSON-LD tree before rendering, so templates work with predictable, nested objects.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
graph LR
|
|
13
|
+
A[SHACL file] --> B[Parse to JSON-LD] --> C[Frame by NodeShape] --> D[Render with Liquid template] --> E[Output]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
1. **Parse** — the SHACL file is dereferenced and converted to JSON-LD.
|
|
17
|
+
2. **Frame** — the JSON-LD is [framed](https://www.w3.org/TR/json-ld11-framing/) using a JSON-LD Frame that selects `sh:NodeShape` resources and nests their property shapes. A default frame is included; you can supply your own.
|
|
18
|
+
3. **Render** — the framed data is passed to a Liquid template as `nodeShapes`, an array of node shape objects.
|
|
19
|
+
|
|
20
|
+
## CLI usage
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npx @lde/docgen@latest from-shacl <shacl-file> <template-file> [options]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Arguments
|
|
27
|
+
|
|
28
|
+
| Argument | Description |
|
|
29
|
+
| ----------------- | --------------------------------------------------- |
|
|
30
|
+
| `<shacl-file>` | Path to a SHACL shapes file (any RDF serialization) |
|
|
31
|
+
| `<template-file>` | Path to a Liquid template file |
|
|
32
|
+
|
|
33
|
+
### Options
|
|
34
|
+
|
|
35
|
+
| Option | Description | Default |
|
|
36
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
37
|
+
| `-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` |
|
|
38
|
+
|
|
39
|
+
### Example
|
|
40
|
+
|
|
41
|
+
Given a SHACL file `shapes.ttl`:
|
|
42
|
+
|
|
43
|
+
```turtle
|
|
44
|
+
@prefix dcat: <http://www.w3.org/ns/dcat#> .
|
|
45
|
+
@prefix dct: <http://purl.org/dc/terms/> .
|
|
46
|
+
@prefix sh: <http://www.w3.org/ns/shacl#> .
|
|
47
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
48
|
+
|
|
49
|
+
[] a sh:NodeShape ;
|
|
50
|
+
sh:targetClass dcat:Dataset ;
|
|
51
|
+
sh:property [
|
|
52
|
+
sh:path dct:title ;
|
|
53
|
+
sh:minCount 1 ;
|
|
54
|
+
] ,
|
|
55
|
+
[
|
|
56
|
+
sh:path dct:description ;
|
|
57
|
+
sh:minCount 1 ;
|
|
58
|
+
sh:datatype xsd:string ;
|
|
59
|
+
sh:description "A description of the dataset"@en ;
|
|
60
|
+
] .
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
And a template `spec.md.liquid`:
|
|
64
|
+
|
|
65
|
+
```liquid
|
|
66
|
+
{% for nodeShape in nodeShapes -%}
|
|
67
|
+
## {{ nodeShape.targetClass }}
|
|
68
|
+
|
|
69
|
+
| Property | Required | Type | Description |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
{% assign mergedProperties = nodeShape.property | mergePropertiesByPath -%}
|
|
72
|
+
{% for property in mergedProperties -%}
|
|
73
|
+
| `{{ property.path }}` | {{ property.minCount | default: "no" }} | {{ property.datatype }} | {{ property.description | lang: "en" }} |
|
|
74
|
+
{% endfor %}
|
|
75
|
+
{% endfor %}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Run:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npx @lde/docgen@latest from-shacl shapes.ttl spec.md.liquid > spec.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Programmatic usage
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { generateDocumentation } from '@lde/docgen';
|
|
88
|
+
|
|
89
|
+
const output = await generateDocumentation(
|
|
90
|
+
'shapes.ttl',
|
|
91
|
+
'spec.md.liquid',
|
|
92
|
+
'frames/shacl.frame.jsonld', // optional: path to custom frame
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Template data
|
|
97
|
+
|
|
98
|
+
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.
|
|
99
|
+
|
|
100
|
+
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.
|
|
101
|
+
|
|
102
|
+
### Custom filters
|
|
103
|
+
|
|
104
|
+
| Filter | Description | Example |
|
|
105
|
+
| ----------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
|
|
106
|
+
| `lang` | Select a value by language tag | `{{ property.description \| lang: "en" }}` |
|
|
107
|
+
| `mergePropertiesByPath` | Merge property shapes that share the same `sh:path` | `{% assign merged = nodeShape.property \| mergePropertiesByPath %}` |
|
|
108
|
+
|
|
109
|
+
## Custom frames
|
|
110
|
+
|
|
111
|
+
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](https://www.w3.org/TR/json-ld11-framing/) – it is **deep-merged** on top of the default, so you only need to specify your additions:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"@context": {
|
|
116
|
+
"nde": "https://def.nde.nl#",
|
|
117
|
+
"nde:futureChange": {},
|
|
118
|
+
"nde:version": {}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
npx @lde/docgen@latest from-shacl shapes.ttl template.liquid -f my-frame.jsonld
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Plain 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`.
|
package/dist/cli.js
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { generateDocumentation } from './index.js';
|
|
4
4
|
import packageJson from '../package.json' with { type: 'json' };
|
|
5
|
-
import { dirname } from 'path';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
5
|
const program = new Command();
|
|
9
6
|
program
|
|
10
7
|
.name('docgen')
|
|
@@ -15,7 +12,7 @@ program
|
|
|
15
12
|
.description('Generate documentation from a SHACL shapes file')
|
|
16
13
|
.argument('<shacl-file>', 'Path to SHACL shapes file (in any RDF serialization format)')
|
|
17
14
|
.argument('<template-file>', 'Path to Liquid template file')
|
|
18
|
-
.option('-f --frame <json-ld-frame-file>', 'Path to a JSON-LD Frame file
|
|
15
|
+
.option('-f --frame <json-ld-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.')
|
|
19
16
|
.addHelpText('after', `
|
|
20
17
|
Example:
|
|
21
18
|
$ npx @lde/docgen@latest from-shacl shacl.ttl template.liquid
|
package/dist/frame.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { JsonLdArray } from 'jsonld/jsonld-spec.js';
|
|
2
|
-
import
|
|
3
|
-
export declare function frame(document: JsonLdArray,
|
|
2
|
+
import type { NodeObject } from 'jsonld';
|
|
3
|
+
export declare function frame(document: JsonLdArray, userFramePath?: string): Promise<NodeObject>;
|
|
4
4
|
//# sourceMappingURL=frame.d.ts.map
|
package/dist/frame.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../src/frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../src/frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAUzC,wBAAsB,KAAK,CACzB,QAAQ,EAAE,WAAW,EACrB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,UAAU,CAAC,CAUrB"}
|
package/dist/frame.js
CHANGED
|
@@ -1,8 +1,41 @@
|
|
|
1
1
|
import jsonld from 'jsonld';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const defaultFramePath = join(__dirname, '../frames/shacl.frame.jsonld');
|
|
7
|
+
export async function frame(document, userFramePath) {
|
|
8
|
+
const defaultFrame = await readFrame(defaultFramePath);
|
|
9
|
+
const mergedFrame = userFramePath
|
|
10
|
+
? deepMerge(defaultFrame, await readFrame(userFramePath))
|
|
11
|
+
: defaultFrame;
|
|
12
|
+
return await jsonld.frame(document, mergedFrame, {
|
|
5
13
|
omitGraph: false,
|
|
6
14
|
embed: '@always',
|
|
7
15
|
});
|
|
8
16
|
}
|
|
17
|
+
async function readFrame(path) {
|
|
18
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Recursively merges `source` into `target`, returning a new object. Plain
|
|
22
|
+
* objects are merged key-by-key; arrays and primitives in `source` replace
|
|
23
|
+
* those in `target`. Used to compose a user-supplied JSON-LD frame on top of
|
|
24
|
+
* docgen’s built-in default so consumers only need to specify their additions.
|
|
25
|
+
*/
|
|
26
|
+
function deepMerge(target, source) {
|
|
27
|
+
const result = { ...target };
|
|
28
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
29
|
+
const targetValue = result[key];
|
|
30
|
+
if (isPlainObject(targetValue) && isPlainObject(sourceValue)) {
|
|
31
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
result[key] = sourceValue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function isPlainObject(value) {
|
|
40
|
+
return (typeof value === 'object' && value !== null && !Array.isArray(value));
|
|
41
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Generate documentation from a SHACL shapes file using a Liquid template.
|
|
3
|
+
*
|
|
4
|
+
* @param rdfPath Path to a SHACL shapes file in any RDF serialization.
|
|
5
|
+
* @param templatePath Path to a Liquid template.
|
|
6
|
+
* @param framePath Optional path to a JSON-LD frame. When provided, it is
|
|
7
|
+
* deep-merged on top of docgen’s built-in default frame, so consumers only
|
|
8
|
+
* need to specify their additions (e.g. extra `@context` entries).
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateDocumentation(rdfPath: string, templatePath: string, framePath?: string): Promise<string>;
|
|
2
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAKjB"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { parseRdfToJsonLd } from './parse.js';
|
|
2
2
|
import { frame } from './frame.js';
|
|
3
3
|
import { render } from './render.js';
|
|
4
|
+
/**
|
|
5
|
+
* Generate documentation from a SHACL shapes file using a Liquid template.
|
|
6
|
+
*
|
|
7
|
+
* @param rdfPath Path to a SHACL shapes file in any RDF serialization.
|
|
8
|
+
* @param templatePath Path to a Liquid template.
|
|
9
|
+
* @param framePath Optional path to a JSON-LD frame. When provided, it is
|
|
10
|
+
* deep-merged on top of docgen’s built-in default frame, so consumers only
|
|
11
|
+
* need to specify their additions (e.g. extra `@context` entries).
|
|
12
|
+
*/
|
|
4
13
|
export async function generateDocumentation(rdfPath, templatePath, framePath) {
|
|
5
14
|
const jsonld = await parseRdfToJsonLd(rdfPath);
|
|
6
15
|
const framed = await frame(jsonld, framePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/docgen",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.15",
|
|
4
4
|
"description": "Generate documentation from SHACL shapes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shacl",
|
|
@@ -9,15 +9,16 @@
|
|
|
9
9
|
"generator"
|
|
10
10
|
],
|
|
11
11
|
"repository": {
|
|
12
|
-
"url": "https://github.com/
|
|
12
|
+
"url": "git+https://github.com/ldelements/lde.git",
|
|
13
13
|
"directory": "packages/docgen"
|
|
14
14
|
},
|
|
15
|
+
"license": "MIT",
|
|
15
16
|
"type": "module",
|
|
16
17
|
"exports": {
|
|
17
18
|
"./package.json": "./package.json",
|
|
18
19
|
".": {
|
|
19
|
-
"development": "./src/index.ts",
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
|
+
"development": "./src/index.ts",
|
|
21
22
|
"import": "./dist/index.js",
|
|
22
23
|
"default": "./dist/index.js"
|
|
23
24
|
}
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
"module": "./dist/index.js",
|
|
27
28
|
"types": "./dist/index.d.ts",
|
|
28
29
|
"bin": {
|
|
29
|
-
"docgen": "
|
|
30
|
+
"docgen": "dist/cli.js"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"dist",
|
|
@@ -35,9 +36,9 @@
|
|
|
35
36
|
],
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"commander": "^14.0.3",
|
|
38
|
-
"jsonld": "^
|
|
39
|
-
"liquidjs": "^10.
|
|
40
|
-
"rdf-dereference": "^
|
|
39
|
+
"jsonld": "^9.0.0",
|
|
40
|
+
"liquidjs": "^10.25.5",
|
|
41
|
+
"rdf-dereference": "^5.0.0",
|
|
41
42
|
"rdf-serialize": "^5.1.0",
|
|
42
43
|
"stream-to-string": "^1.2.1",
|
|
43
44
|
"tslib": "^2.3.0"
|