@unrdf/kgn 5.0.1 → 26.4.2
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/dist/index.mjs +9207 -0
- package/package.json +33 -28
- package/src/base/filter-templates.js +7 -1
- package/src/base/index.js +15 -10
- package/src/base/injection-targets.js +6 -0
- package/src/base/macro-templates.js +6 -0
- package/src/base/shacl-templates.js +6 -0
- package/src/base/template-base.js +7 -1
- package/src/core/attestor.js +50 -1
- package/src/core/filters.js +134 -1
- package/src/core/index.js +8 -1
- package/src/core/kgen-engine.js +49 -1
- package/src/core/parser.js +52 -1
- package/src/core/post-processor.js +7 -1
- package/src/core/renderer.js +67 -1
- package/src/doc-generator/mdx-generator.mjs +1 -1
- package/src/doc-generator/nav-generator.mjs +1 -1
- package/src/doc-generator/rdf-builder.mjs +2 -2
- package/src/engine/index.js +9 -0
- package/src/engine/pipeline.js +7 -1
- package/src/engine/renderer.js +18 -3
- package/src/engine/template-engine.js +12 -3
- package/src/filters/array.js +14 -6
- package/src/filters/index.js +165 -17
- package/src/filters/rdf.js +3 -3
- package/src/{index.js → index.mjs} +46 -0
- package/src/index.test.mjs +40 -0
- package/src/inheritance/index.js +19 -1
- package/src/injection/atomic-writer.js +22 -1
- package/src/injection/idempotency-manager.js +33 -0
- package/src/injection/injection-engine.js +46 -1
- package/src/injection/integration.js +3 -3
- package/src/injection/modes/index.js +30 -0
- package/src/injection/rollback-manager.js +26 -2
- package/src/injection/target-resolver.js +48 -3
- package/src/injection/tests/injection-engine.test.js +3 -3
- package/src/injection/tests/integration.test.js +2 -1
- package/src/injection/tests/run-tests.js +3 -0
- package/src/injection/validation-engine.js +71 -5
- package/src/linter/determinism-linter.js +20 -5
- package/src/linter/determinism.js +8 -2
- package/src/linter/index.js +3 -1
- package/src/linter/test-doubles.js +151 -4
- package/src/parser/frontmatter.js +6 -0
- package/src/parser/variables.js +7 -1
- package/src/rdf/filters.js +393 -0
- package/src/rdf/index.js +444 -0
- package/src/renderer/deterministic.js +6 -0
- package/src/renderer/index.js +3 -1
- package/src/templates/rdf/DELIVERY-SUMMARY.md +266 -0
- package/src/templates/rdf/README.md +595 -0
- package/src/templates/rdf/dataset.njk +83 -0
- package/src/templates/rdf/index.js +106 -0
- package/src/templates/rdf/jsonld-context.njk +63 -0
- package/src/templates/rdf/ontology.njk +107 -0
- package/src/templates/rdf/schema.njk +79 -0
- package/src/templates/rdf/shapes.njk +89 -0
- package/src/templates/rdf/sparql-queries.njk +70 -0
- package/src/templates/rdf/vocabulary.njk +79 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
# RDF Templates for @unrdf/kgn
|
|
2
|
+
|
|
3
|
+
Comprehensive Nunjucks templates for generating RDF/Semantic Web content with frontmatter-driven configuration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This template library provides production-ready templates for common RDF formats and vocabularies:
|
|
8
|
+
|
|
9
|
+
- **ontology.njk** - OWL ontologies with classes and properties
|
|
10
|
+
- **schema.njk** - RDFS vocabularies and schemas
|
|
11
|
+
- **dataset.njk** - DCAT dataset metadata
|
|
12
|
+
- **vocabulary.njk** - SKOS concept schemes and taxonomies
|
|
13
|
+
- **shapes.njk** - SHACL validation shapes
|
|
14
|
+
- **sparql-queries.njk** - SPARQL query collections
|
|
15
|
+
- **jsonld-context.njk** - JSON-LD context mappings
|
|
16
|
+
|
|
17
|
+
All templates:
|
|
18
|
+
- Accept structured data via YAML frontmatter
|
|
19
|
+
- Generate valid RDF/Turtle or JSON-LD output
|
|
20
|
+
- Include comprehensive prefix declarations
|
|
21
|
+
- Support customization through variables
|
|
22
|
+
- Include inline documentation and examples
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Pattern
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
import { createEngine } from '@unrdf/kgn';
|
|
30
|
+
|
|
31
|
+
const engine = createEngine({
|
|
32
|
+
templatePaths: ['./node_modules/@unrdf/kgn/src/templates/rdf']
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const output = await engine.render('ontology.njk', {
|
|
36
|
+
ontologyIRI: 'http://example.org/myonto',
|
|
37
|
+
title: 'My Ontology',
|
|
38
|
+
classes: [
|
|
39
|
+
{
|
|
40
|
+
iri: 'http://example.org/myonto#Person',
|
|
41
|
+
label: 'Person',
|
|
42
|
+
comment: 'Represents a person'
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### With Frontmatter Files
|
|
49
|
+
|
|
50
|
+
Create a `.njk` file with frontmatter:
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
---
|
|
54
|
+
ontologyIRI: http://example.org/ontology/library
|
|
55
|
+
version: 1.0.0
|
|
56
|
+
title: Library Ontology
|
|
57
|
+
description: An ontology for library systems
|
|
58
|
+
creator: http://example.org/people/librarian
|
|
59
|
+
created: 2026-01-11
|
|
60
|
+
classes:
|
|
61
|
+
- iri: http://example.org/ontology/library#Book
|
|
62
|
+
label: Book
|
|
63
|
+
comment: Represents a book in the library
|
|
64
|
+
- iri: http://example.org/ontology/library#Author
|
|
65
|
+
label: Author
|
|
66
|
+
comment: Represents an author
|
|
67
|
+
objectProperties:
|
|
68
|
+
- iri: http://example.org/ontology/library#writtenBy
|
|
69
|
+
label: written by
|
|
70
|
+
comment: Links a book to its author
|
|
71
|
+
domain: http://example.org/ontology/library#Book
|
|
72
|
+
range: http://example.org/ontology/library#Author
|
|
73
|
+
---
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then render:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const output = await engine.renderFile('my-ontology.njk');
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Template Reference
|
|
83
|
+
|
|
84
|
+
### 1. ontology.njk - OWL Ontology
|
|
85
|
+
|
|
86
|
+
Generates complete OWL ontologies with metadata, classes, object properties, and datatype properties.
|
|
87
|
+
|
|
88
|
+
**Required Variables:**
|
|
89
|
+
- `ontologyIRI` (string) - The IRI of the ontology
|
|
90
|
+
- `title` (string) - Ontology title
|
|
91
|
+
|
|
92
|
+
**Optional Variables:**
|
|
93
|
+
- `version` (string) - Version string (e.g., "1.0.0")
|
|
94
|
+
- `description` (string) - Ontology description
|
|
95
|
+
- `creator` (string) - Creator IRI
|
|
96
|
+
- `created` (string) - Creation date (ISO format)
|
|
97
|
+
- `license` (string) - License IRI
|
|
98
|
+
- `prefix` (string) - Short prefix for the ontology namespace
|
|
99
|
+
- `classes` (array) - Class definitions
|
|
100
|
+
- `iri` - Class IRI
|
|
101
|
+
- `label` - rdfs:label
|
|
102
|
+
- `comment` - rdfs:comment (optional)
|
|
103
|
+
- `subClassOf` - Parent class IRI (optional)
|
|
104
|
+
- `objectProperties` (array) - Object property definitions
|
|
105
|
+
- `iri` - Property IRI
|
|
106
|
+
- `label` - rdfs:label
|
|
107
|
+
- `comment` - rdfs:comment (optional)
|
|
108
|
+
- `domain` - Domain class IRI (optional)
|
|
109
|
+
- `range` - Range class IRI (optional)
|
|
110
|
+
- `datatypeProperties` (array) - Datatype property definitions
|
|
111
|
+
- `iri` - Property IRI
|
|
112
|
+
- `label` - rdfs:label
|
|
113
|
+
- `comment` - rdfs:comment (optional)
|
|
114
|
+
- `domain` - Domain class IRI (optional)
|
|
115
|
+
- `range` - XSD datatype IRI (optional)
|
|
116
|
+
|
|
117
|
+
**Example Output:**
|
|
118
|
+
|
|
119
|
+
```turtle
|
|
120
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
121
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
122
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
123
|
+
|
|
124
|
+
<http://example.org/ontology/myonto> a owl:Ontology ;
|
|
125
|
+
dc:title "My Example Ontology"@en ;
|
|
126
|
+
owl:versionInfo "1.0.0" .
|
|
127
|
+
|
|
128
|
+
<http://example.org/ontology/myonto#Person> a owl:Class ;
|
|
129
|
+
rdfs:label "Person"@en ;
|
|
130
|
+
rdfs:isDefinedBy <http://example.org/ontology/myonto> .
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 2. schema.njk - RDFS Schema
|
|
134
|
+
|
|
135
|
+
Generates RDFS vocabularies with classes and properties.
|
|
136
|
+
|
|
137
|
+
**Required Variables:**
|
|
138
|
+
- `schemaIRI` (string) - The IRI of the schema
|
|
139
|
+
- `title` (string) - Schema title
|
|
140
|
+
|
|
141
|
+
**Optional Variables:**
|
|
142
|
+
- `description` (string) - Schema description
|
|
143
|
+
- `version` (string) - Version string
|
|
144
|
+
- `prefix` (string) - Short prefix
|
|
145
|
+
- `classes` (array) - RDFS class definitions
|
|
146
|
+
- `iri` - Class IRI
|
|
147
|
+
- `label` - rdfs:label
|
|
148
|
+
- `comment` - rdfs:comment (optional)
|
|
149
|
+
- `subClassOf` - Parent class IRI (optional)
|
|
150
|
+
- `properties` (array) - RDF property definitions
|
|
151
|
+
- `iri` - Property IRI
|
|
152
|
+
- `label` - rdfs:label
|
|
153
|
+
- `comment` - rdfs:comment (optional)
|
|
154
|
+
- `domain` - Domain class IRI (optional)
|
|
155
|
+
- `range` - Range class/datatype IRI (optional)
|
|
156
|
+
- `subPropertyOf` - Parent property IRI (optional)
|
|
157
|
+
|
|
158
|
+
**Example:**
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
const schema = await engine.render('schema.njk', {
|
|
162
|
+
schemaIRI: 'http://example.org/schema/vocab',
|
|
163
|
+
title: 'Document Vocabulary',
|
|
164
|
+
classes: [
|
|
165
|
+
{
|
|
166
|
+
iri: 'http://example.org/schema/vocab#Document',
|
|
167
|
+
label: 'Document',
|
|
168
|
+
comment: 'A textual document'
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
properties: [
|
|
172
|
+
{
|
|
173
|
+
iri: 'http://example.org/schema/vocab#title',
|
|
174
|
+
label: 'title',
|
|
175
|
+
domain: 'http://example.org/schema/vocab#Document',
|
|
176
|
+
range: 'http://www.w3.org/2001/XMLSchema#string'
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. dataset.njk - DCAT Dataset
|
|
183
|
+
|
|
184
|
+
Generates DCAT dataset descriptions for data catalogs.
|
|
185
|
+
|
|
186
|
+
**Required Variables:**
|
|
187
|
+
- `datasetIRI` (string) - The IRI of the dataset
|
|
188
|
+
- `title` (string) - Dataset title
|
|
189
|
+
- `description` (string) - Dataset description
|
|
190
|
+
|
|
191
|
+
**Optional Variables:**
|
|
192
|
+
- `publisher` (string) - Publisher IRI
|
|
193
|
+
- `creator` (string) - Creator IRI
|
|
194
|
+
- `issued` (string) - Issue date (ISO format)
|
|
195
|
+
- `modified` (string) - Modification date (ISO format)
|
|
196
|
+
- `license` (string) - License IRI
|
|
197
|
+
- `keywords` (array of strings) - Keywords
|
|
198
|
+
- `theme` (array of strings) - Theme IRIs
|
|
199
|
+
- `spatial` (string) - Spatial coverage IRI
|
|
200
|
+
- `temporal` (string) - Temporal coverage description
|
|
201
|
+
- `distributions` (array) - Distribution objects
|
|
202
|
+
- `iri` - Distribution IRI
|
|
203
|
+
- `title` - Distribution title
|
|
204
|
+
- `format` - Media type (e.g., "text/turtle")
|
|
205
|
+
- `accessURL` - Access URL
|
|
206
|
+
- `downloadURL` - Download URL (optional)
|
|
207
|
+
|
|
208
|
+
**Example:**
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
const dataset = await engine.render('dataset.njk', {
|
|
212
|
+
datasetIRI: 'http://example.org/datasets/census-2020',
|
|
213
|
+
title: 'Census Data 2020',
|
|
214
|
+
description: 'Population census data for 2020',
|
|
215
|
+
license: 'http://creativecommons.org/licenses/by/4.0/',
|
|
216
|
+
keywords: ['census', 'population', 'statistics'],
|
|
217
|
+
distributions: [
|
|
218
|
+
{
|
|
219
|
+
iri: 'http://example.org/datasets/census-2020/csv',
|
|
220
|
+
title: 'CSV Distribution',
|
|
221
|
+
format: 'text/csv',
|
|
222
|
+
accessURL: 'http://example.org/data/census-2020.csv'
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 4. vocabulary.njk - SKOS Vocabulary
|
|
229
|
+
|
|
230
|
+
Generates SKOS concept schemes for taxonomies and controlled vocabularies.
|
|
231
|
+
|
|
232
|
+
**Required Variables:**
|
|
233
|
+
- `schemeIRI` (string) - The IRI of the concept scheme
|
|
234
|
+
- `title` (string) - Scheme title
|
|
235
|
+
|
|
236
|
+
**Optional Variables:**
|
|
237
|
+
- `description` (string) - Scheme description
|
|
238
|
+
- `creator` (string) - Creator IRI
|
|
239
|
+
- `created` (string) - Creation date (ISO format)
|
|
240
|
+
- `prefix` (string) - Short prefix
|
|
241
|
+
- `concepts` (array) - Concept definitions
|
|
242
|
+
- `iri` - Concept IRI
|
|
243
|
+
- `prefLabel` - Preferred label
|
|
244
|
+
- `altLabel` (array of strings) - Alternative labels (optional)
|
|
245
|
+
- `definition` - Definition text (optional)
|
|
246
|
+
- `notation` - Notation string (optional)
|
|
247
|
+
- `broader` - Broader concept IRI (optional)
|
|
248
|
+
- `narrower` (array of strings) - Narrower concept IRIs (optional)
|
|
249
|
+
- `related` (array of strings) - Related concept IRIs (optional)
|
|
250
|
+
|
|
251
|
+
**Example:**
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
const vocab = await engine.render('vocabulary.njk', {
|
|
255
|
+
schemeIRI: 'http://example.org/vocab/topics',
|
|
256
|
+
title: 'Topic Vocabulary',
|
|
257
|
+
concepts: [
|
|
258
|
+
{
|
|
259
|
+
iri: 'http://example.org/vocab/topics#Science',
|
|
260
|
+
prefLabel: 'Science',
|
|
261
|
+
definition: 'Natural and formal sciences',
|
|
262
|
+
narrower: [
|
|
263
|
+
'http://example.org/vocab/topics#Physics',
|
|
264
|
+
'http://example.org/vocab/topics#Biology'
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 5. shapes.njk - SHACL Shapes
|
|
272
|
+
|
|
273
|
+
Generates SHACL shapes for RDF data validation.
|
|
274
|
+
|
|
275
|
+
**Required Variables:**
|
|
276
|
+
- `shapesGraphIRI` (string) - The IRI of the shapes graph
|
|
277
|
+
- `shapes` (array) - Shape definitions
|
|
278
|
+
|
|
279
|
+
**Optional Variables:**
|
|
280
|
+
- `title` (string) - Shapes graph title
|
|
281
|
+
- `description` (string) - Description
|
|
282
|
+
- `prefix` (string) - Short prefix
|
|
283
|
+
|
|
284
|
+
**Shape Object:**
|
|
285
|
+
- `iri` - Shape IRI
|
|
286
|
+
- `targetClass` - Target class IRI (optional)
|
|
287
|
+
- `targetNode` - Target node IRI (optional)
|
|
288
|
+
- `label` - Shape label (optional)
|
|
289
|
+
- `description` - Shape description (optional)
|
|
290
|
+
- `closed` (boolean) - Whether shape is closed (optional)
|
|
291
|
+
- `properties` (array) - Property constraints
|
|
292
|
+
- `path` - Property path IRI
|
|
293
|
+
- `minCount` (number) - Minimum cardinality (optional)
|
|
294
|
+
- `maxCount` (number) - Maximum cardinality (optional)
|
|
295
|
+
- `datatype` - Datatype IRI (optional)
|
|
296
|
+
- `class` - Class IRI (optional)
|
|
297
|
+
- `pattern` - Regex pattern (optional)
|
|
298
|
+
- `minLength` (number) - Min string length (optional)
|
|
299
|
+
- `maxLength` (number) - Max string length (optional)
|
|
300
|
+
- `minInclusive` (number) - Min numeric value (optional)
|
|
301
|
+
- `maxInclusive` (number) - Max numeric value (optional)
|
|
302
|
+
|
|
303
|
+
**Example:**
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const shapes = await engine.render('shapes.njk', {
|
|
307
|
+
shapesGraphIRI: 'http://example.org/shapes/person',
|
|
308
|
+
title: 'Person Shapes',
|
|
309
|
+
shapes: [
|
|
310
|
+
{
|
|
311
|
+
iri: 'http://example.org/shapes/person#PersonShape',
|
|
312
|
+
targetClass: 'http://xmlns.com/foaf/0.1/Person',
|
|
313
|
+
properties: [
|
|
314
|
+
{
|
|
315
|
+
path: 'http://xmlns.com/foaf/0.1/name',
|
|
316
|
+
minCount: 1,
|
|
317
|
+
maxCount: 1,
|
|
318
|
+
datatype: 'http://www.w3.org/2001/XMLSchema#string'
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
]
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### 6. sparql-queries.njk - SPARQL Queries
|
|
327
|
+
|
|
328
|
+
Generates collections of SPARQL queries with metadata and comments.
|
|
329
|
+
|
|
330
|
+
**Required Variables:**
|
|
331
|
+
- `title` (string) - Query collection title
|
|
332
|
+
- `queries` (array) - Query definitions
|
|
333
|
+
|
|
334
|
+
**Optional Variables:**
|
|
335
|
+
- `description` (string) - Collection description
|
|
336
|
+
|
|
337
|
+
**Query Object:**
|
|
338
|
+
- `name` - Query name/identifier
|
|
339
|
+
- `description` - Query description
|
|
340
|
+
- `type` - Query type: "SELECT", "CONSTRUCT", "ASK", "DESCRIBE"
|
|
341
|
+
- `prefixes` (object) - Prefix mappings (e.g., `{foaf: 'http://xmlns.com/foaf/0.1/'}`)
|
|
342
|
+
- `variables` (array of strings) - Variable names for SELECT (optional)
|
|
343
|
+
- `where` (array of strings) - WHERE clause patterns
|
|
344
|
+
- `construct` (array of strings) - CONSTRUCT patterns (for CONSTRUCT queries)
|
|
345
|
+
- `resources` (array of strings) - Resources for DESCRIBE (optional)
|
|
346
|
+
- `orderBy` (array of strings) - ORDER BY variables (optional)
|
|
347
|
+
- `limit` (number) - LIMIT value (optional)
|
|
348
|
+
- `offset` (number) - OFFSET value (optional)
|
|
349
|
+
|
|
350
|
+
**Example:**
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
const queries = await engine.render('sparql-queries.njk', {
|
|
354
|
+
title: 'Person Queries',
|
|
355
|
+
queries: [
|
|
356
|
+
{
|
|
357
|
+
name: 'getAllPersons',
|
|
358
|
+
description: 'Get all persons with names',
|
|
359
|
+
type: 'SELECT',
|
|
360
|
+
prefixes: {
|
|
361
|
+
foaf: 'http://xmlns.com/foaf/0.1/'
|
|
362
|
+
},
|
|
363
|
+
variables: ['person', 'name'],
|
|
364
|
+
where: [
|
|
365
|
+
'?person a foaf:Person',
|
|
366
|
+
'?person foaf:name ?name'
|
|
367
|
+
],
|
|
368
|
+
orderBy: ['name'],
|
|
369
|
+
limit: 100
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### 7. jsonld-context.njk - JSON-LD Context
|
|
376
|
+
|
|
377
|
+
Generates JSON-LD context files for mapping JSON to RDF.
|
|
378
|
+
|
|
379
|
+
**Required Variables:**
|
|
380
|
+
- `terms` (object) - Term mappings
|
|
381
|
+
|
|
382
|
+
**Optional Variables:**
|
|
383
|
+
- `contextIRI` (string) - Context IRI (for @id)
|
|
384
|
+
- `vocab` (string) - Default vocabulary IRI (for @vocab)
|
|
385
|
+
- `base` (string) - Base IRI (for @base)
|
|
386
|
+
- `prefixes` (object) - Prefix mappings
|
|
387
|
+
|
|
388
|
+
**Terms Object:**
|
|
389
|
+
- Simple mapping: `termName: "iri"`
|
|
390
|
+
- Complex mapping: `termName: { id: "iri", type: "@id|@vocab|xsd:type", container: "@list|@set", ... }`
|
|
391
|
+
|
|
392
|
+
**Example:**
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
const context = await engine.render('jsonld-context.njk', {
|
|
396
|
+
contextIRI: 'http://example.org/contexts/person',
|
|
397
|
+
vocab: 'http://schema.org/',
|
|
398
|
+
prefixes: {
|
|
399
|
+
foaf: 'http://xmlns.com/foaf/0.1/',
|
|
400
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#'
|
|
401
|
+
},
|
|
402
|
+
terms: {
|
|
403
|
+
Person: 'foaf:Person',
|
|
404
|
+
name: 'foaf:name',
|
|
405
|
+
email: {
|
|
406
|
+
id: 'foaf:mbox',
|
|
407
|
+
type: '@id'
|
|
408
|
+
},
|
|
409
|
+
age: {
|
|
410
|
+
id: 'foaf:age',
|
|
411
|
+
type: 'xsd:integer'
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Best Practices
|
|
418
|
+
|
|
419
|
+
### 1. Use Consistent IRI Patterns
|
|
420
|
+
|
|
421
|
+
```yaml
|
|
422
|
+
# Good - consistent namespace
|
|
423
|
+
ontologyIRI: http://example.org/ontology/library
|
|
424
|
+
classes:
|
|
425
|
+
- iri: http://example.org/ontology/library#Book
|
|
426
|
+
- iri: http://example.org/ontology/library#Author
|
|
427
|
+
|
|
428
|
+
# Avoid - mixed namespaces without justification
|
|
429
|
+
classes:
|
|
430
|
+
- iri: http://example.org/Book
|
|
431
|
+
- iri: http://another.org/Author
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 2. Provide Comprehensive Metadata
|
|
435
|
+
|
|
436
|
+
```yaml
|
|
437
|
+
# Good - complete metadata
|
|
438
|
+
ontologyIRI: http://example.org/onto
|
|
439
|
+
version: 1.0.0
|
|
440
|
+
title: Example Ontology
|
|
441
|
+
description: Comprehensive description of the ontology purpose
|
|
442
|
+
creator: http://example.org/people/john-doe
|
|
443
|
+
created: 2026-01-11
|
|
444
|
+
license: http://creativecommons.org/licenses/by/4.0/
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### 3. Use Labels and Comments
|
|
448
|
+
|
|
449
|
+
```yaml
|
|
450
|
+
# Good - human-readable annotations
|
|
451
|
+
classes:
|
|
452
|
+
- iri: http://example.org/onto#Person
|
|
453
|
+
label: Person
|
|
454
|
+
comment: Represents a human being with social and legal rights
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### 4. Leverage Template Inheritance
|
|
458
|
+
|
|
459
|
+
For complex ontologies, compose from multiple templates:
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
// Generate base classes
|
|
463
|
+
const baseClasses = await engine.render('ontology.njk', baseClassesData);
|
|
464
|
+
|
|
465
|
+
// Generate specialized properties
|
|
466
|
+
const properties = await engine.render('ontology.njk', propertiesData);
|
|
467
|
+
|
|
468
|
+
// Combine outputs
|
|
469
|
+
const combined = baseClasses + '\n\n' + properties;
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### 5. Validate Generated RDF
|
|
473
|
+
|
|
474
|
+
```javascript
|
|
475
|
+
import { Parser } from 'n3';
|
|
476
|
+
|
|
477
|
+
const parser = new Parser({ format: 'text/turtle' });
|
|
478
|
+
const quads = parser.parse(generatedTurtle);
|
|
479
|
+
|
|
480
|
+
// Validates syntax and structure
|
|
481
|
+
if (quads.length > 0) {
|
|
482
|
+
console.log('Valid RDF generated:', quads.length, 'triples');
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### 6. Use Prefixes for Readability
|
|
487
|
+
|
|
488
|
+
```yaml
|
|
489
|
+
# Define reusable prefix
|
|
490
|
+
prefix: lib
|
|
491
|
+
|
|
492
|
+
# Results in cleaner output:
|
|
493
|
+
# @prefix lib: <http://example.org/ontology/library#> .
|
|
494
|
+
# lib:Book a owl:Class .
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Integration Examples
|
|
498
|
+
|
|
499
|
+
### With @unrdf/core
|
|
500
|
+
|
|
501
|
+
```javascript
|
|
502
|
+
import { createEngine } from '@unrdf/kgn';
|
|
503
|
+
import { createStore, loadTurtle } from '@unrdf/core';
|
|
504
|
+
|
|
505
|
+
const engine = createEngine({
|
|
506
|
+
templatePaths: ['./node_modules/@unrdf/kgn/src/templates/rdf']
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Generate ontology
|
|
510
|
+
const turtle = await engine.render('ontology.njk', ontologyData);
|
|
511
|
+
|
|
512
|
+
// Load into RDF store
|
|
513
|
+
const store = createStore();
|
|
514
|
+
await loadTurtle(store, turtle);
|
|
515
|
+
|
|
516
|
+
// Query the generated ontology
|
|
517
|
+
const classes = store.getQuads(null, RDF.type, OWL.Class);
|
|
518
|
+
console.log('Generated classes:', classes.length);
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Batch Generation
|
|
522
|
+
|
|
523
|
+
```javascript
|
|
524
|
+
const templates = [
|
|
525
|
+
{ template: 'ontology.njk', data: ontologyData, output: 'onto.ttl' },
|
|
526
|
+
{ template: 'shapes.njk', data: shapesData, output: 'shapes.ttl' },
|
|
527
|
+
{ template: 'dataset.njk', data: datasetData, output: 'metadata.ttl' }
|
|
528
|
+
];
|
|
529
|
+
|
|
530
|
+
for (const { template, data, output } of templates) {
|
|
531
|
+
const result = await engine.render(template, data);
|
|
532
|
+
await fs.writeFile(output, result, 'utf-8');
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Dynamic Frontmatter
|
|
537
|
+
|
|
538
|
+
```javascript
|
|
539
|
+
import matter from 'gray-matter';
|
|
540
|
+
|
|
541
|
+
// Load template with frontmatter
|
|
542
|
+
const templateContent = await fs.readFile('my-ontology.njk', 'utf-8');
|
|
543
|
+
const { data, content } = matter(templateContent);
|
|
544
|
+
|
|
545
|
+
// Modify frontmatter programmatically
|
|
546
|
+
data.version = '2.0.0';
|
|
547
|
+
data.modified = new Date().toISOString().split('T')[0];
|
|
548
|
+
|
|
549
|
+
// Render with updated data
|
|
550
|
+
const result = await engine.render('ontology.njk', data);
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
## Troubleshooting
|
|
554
|
+
|
|
555
|
+
### Common Issues
|
|
556
|
+
|
|
557
|
+
**Empty output:**
|
|
558
|
+
- Check that all required variables are provided
|
|
559
|
+
- Verify frontmatter YAML is valid
|
|
560
|
+
- Ensure template path is correct
|
|
561
|
+
|
|
562
|
+
**Invalid RDF:**
|
|
563
|
+
- Validate IRIs are absolute (http://, https://)
|
|
564
|
+
- Check for proper string escaping in labels/comments
|
|
565
|
+
- Ensure array variables are actual arrays, not strings
|
|
566
|
+
|
|
567
|
+
**Missing prefixes:**
|
|
568
|
+
- Add prefixes to `prefixes` object or template header
|
|
569
|
+
- Verify namespace IRIs end with # or /
|
|
570
|
+
|
|
571
|
+
### Debugging
|
|
572
|
+
|
|
573
|
+
Enable template debugging:
|
|
574
|
+
|
|
575
|
+
```javascript
|
|
576
|
+
const engine = createEngine({
|
|
577
|
+
templatePaths: ['./node_modules/@unrdf/kgn/src/templates/rdf'],
|
|
578
|
+
debug: true
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Validate template syntax:
|
|
583
|
+
|
|
584
|
+
```javascript
|
|
585
|
+
import { lintTemplate } from '@unrdf/kgn';
|
|
586
|
+
|
|
587
|
+
const issues = await lintTemplate('ontology.njk');
|
|
588
|
+
if (issues.length > 0) {
|
|
589
|
+
console.error('Template issues:', issues);
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
## License
|
|
594
|
+
|
|
595
|
+
MIT License - see @unrdf/kgn package for details.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{#
|
|
2
|
+
DCAT Dataset Template
|
|
3
|
+
|
|
4
|
+
Generates a DCAT (Data Catalog Vocabulary) dataset description.
|
|
5
|
+
|
|
6
|
+
Expected frontmatter variables:
|
|
7
|
+
- datasetIRI: The IRI of the dataset (required)
|
|
8
|
+
- title: Dataset title (required)
|
|
9
|
+
- description: Dataset description (required)
|
|
10
|
+
- publisher: Publisher name/IRI (optional)
|
|
11
|
+
- creator: Creator name/IRI (optional)
|
|
12
|
+
- issued: Issue date (ISO format) (optional)
|
|
13
|
+
- modified: Modification date (ISO format) (optional)
|
|
14
|
+
- license: License IRI (optional)
|
|
15
|
+
- keywords: Array of keyword strings (optional)
|
|
16
|
+
- theme: Array of theme IRIs (optional)
|
|
17
|
+
- distributions: Array of distribution objects (optional)
|
|
18
|
+
- iri: Distribution IRI
|
|
19
|
+
- title: Distribution title
|
|
20
|
+
- format: Format (e.g., "text/turtle", "application/json")
|
|
21
|
+
- accessURL: Access URL
|
|
22
|
+
- downloadURL: Download URL (optional)
|
|
23
|
+
- spatial: Spatial coverage IRI (optional)
|
|
24
|
+
- temporal: Temporal coverage description (optional)
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
---
|
|
28
|
+
datasetIRI: http://example.org/datasets/sample-data
|
|
29
|
+
title: Sample Dataset
|
|
30
|
+
description: A comprehensive sample dataset for testing
|
|
31
|
+
publisher: http://example.org/organizations/acme
|
|
32
|
+
issued: 2026-01-11
|
|
33
|
+
license: http://creativecommons.org/licenses/by/4.0/
|
|
34
|
+
keywords:
|
|
35
|
+
- sample
|
|
36
|
+
- test
|
|
37
|
+
- rdf
|
|
38
|
+
distributions:
|
|
39
|
+
- iri: http://example.org/datasets/sample-data/dist/turtle
|
|
40
|
+
title: Turtle Distribution
|
|
41
|
+
format: text/turtle
|
|
42
|
+
accessURL: http://example.org/datasets/sample-data.ttl
|
|
43
|
+
---
|
|
44
|
+
#}
|
|
45
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
46
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
47
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
48
|
+
@prefix dcat: <http://www.w3.org/ns/dcat#> .
|
|
49
|
+
@prefix dcterms: <http://purl.org/dc/terms/> .
|
|
50
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
|
51
|
+
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .
|
|
52
|
+
|
|
53
|
+
# Dataset Description
|
|
54
|
+
<{{ datasetIRI }}> a dcat:Dataset ;
|
|
55
|
+
dcterms:title "{{ title }}"@en ;
|
|
56
|
+
dcterms:description "{{ description }}"@en ;
|
|
57
|
+
{% if publisher %} dcterms:publisher <{{ publisher }}> ;{% endif %}
|
|
58
|
+
{% if creator %} dcterms:creator <{{ creator }}> ;{% endif %}
|
|
59
|
+
{% if issued %} dcterms:issued "{{ issued }}"^^xsd:date ;{% endif %}
|
|
60
|
+
{% if modified %} dcterms:modified "{{ modified }}"^^xsd:date ;{% else %} dcterms:modified "{{ now | date('YYYY-MM-DD') }}"^^xsd:date ;{% endif %}
|
|
61
|
+
{% if license %} dcterms:license <{{ license }}> ;{% endif %}
|
|
62
|
+
{% if spatial %} dcterms:spatial <{{ spatial }}> ;{% endif %}
|
|
63
|
+
{% if temporal %} dcterms:temporal "{{ temporal }}"@en ;{% endif %}
|
|
64
|
+
{% if keywords and keywords.length > 0 %}{% for keyword in keywords %} dcat:keyword "{{ keyword }}"@en ;
|
|
65
|
+
{% endfor %}{% endif %}
|
|
66
|
+
{% if theme and theme.length > 0 %}{% for t in theme %} dcat:theme <{{ t }}> ;
|
|
67
|
+
{% endfor %}{% endif %}
|
|
68
|
+
{% if distributions and distributions.length > 0 %}{% for dist in distributions %} dcat:distribution <{{ dist.iri }}> ;
|
|
69
|
+
{% endfor %}{% endif %}
|
|
70
|
+
.
|
|
71
|
+
|
|
72
|
+
{% if distributions and distributions.length > 0 %}
|
|
73
|
+
# Distributions
|
|
74
|
+
{% for dist in distributions %}
|
|
75
|
+
<{{ dist.iri }}> a dcat:Distribution ;
|
|
76
|
+
dcterms:title "{{ dist.title }}"@en ;
|
|
77
|
+
{% if dist.format %} dcat:mediaType "{{ dist.format }}" ;{% endif %}
|
|
78
|
+
{% if dist.accessURL %} dcat:accessURL <{{ dist.accessURL }}> ;{% endif %}
|
|
79
|
+
{% if dist.downloadURL %} dcat:downloadURL <{{ dist.downloadURL }}> ;{% endif %}
|
|
80
|
+
dcterms:format "{{ dist.format }}" .
|
|
81
|
+
|
|
82
|
+
{% endfor %}
|
|
83
|
+
{% endif %}
|