@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.
Files changed (59) hide show
  1. package/dist/index.mjs +9207 -0
  2. package/package.json +33 -28
  3. package/src/base/filter-templates.js +7 -1
  4. package/src/base/index.js +15 -10
  5. package/src/base/injection-targets.js +6 -0
  6. package/src/base/macro-templates.js +6 -0
  7. package/src/base/shacl-templates.js +6 -0
  8. package/src/base/template-base.js +7 -1
  9. package/src/core/attestor.js +50 -1
  10. package/src/core/filters.js +134 -1
  11. package/src/core/index.js +8 -1
  12. package/src/core/kgen-engine.js +49 -1
  13. package/src/core/parser.js +52 -1
  14. package/src/core/post-processor.js +7 -1
  15. package/src/core/renderer.js +67 -1
  16. package/src/doc-generator/mdx-generator.mjs +1 -1
  17. package/src/doc-generator/nav-generator.mjs +1 -1
  18. package/src/doc-generator/rdf-builder.mjs +2 -2
  19. package/src/engine/index.js +9 -0
  20. package/src/engine/pipeline.js +7 -1
  21. package/src/engine/renderer.js +18 -3
  22. package/src/engine/template-engine.js +12 -3
  23. package/src/filters/array.js +14 -6
  24. package/src/filters/index.js +165 -17
  25. package/src/filters/rdf.js +3 -3
  26. package/src/{index.js → index.mjs} +46 -0
  27. package/src/index.test.mjs +40 -0
  28. package/src/inheritance/index.js +19 -1
  29. package/src/injection/atomic-writer.js +22 -1
  30. package/src/injection/idempotency-manager.js +33 -0
  31. package/src/injection/injection-engine.js +46 -1
  32. package/src/injection/integration.js +3 -3
  33. package/src/injection/modes/index.js +30 -0
  34. package/src/injection/rollback-manager.js +26 -2
  35. package/src/injection/target-resolver.js +48 -3
  36. package/src/injection/tests/injection-engine.test.js +3 -3
  37. package/src/injection/tests/integration.test.js +2 -1
  38. package/src/injection/tests/run-tests.js +3 -0
  39. package/src/injection/validation-engine.js +71 -5
  40. package/src/linter/determinism-linter.js +20 -5
  41. package/src/linter/determinism.js +8 -2
  42. package/src/linter/index.js +3 -1
  43. package/src/linter/test-doubles.js +151 -4
  44. package/src/parser/frontmatter.js +6 -0
  45. package/src/parser/variables.js +7 -1
  46. package/src/rdf/filters.js +393 -0
  47. package/src/rdf/index.js +444 -0
  48. package/src/renderer/deterministic.js +6 -0
  49. package/src/renderer/index.js +3 -1
  50. package/src/templates/rdf/DELIVERY-SUMMARY.md +266 -0
  51. package/src/templates/rdf/README.md +595 -0
  52. package/src/templates/rdf/dataset.njk +83 -0
  53. package/src/templates/rdf/index.js +106 -0
  54. package/src/templates/rdf/jsonld-context.njk +63 -0
  55. package/src/templates/rdf/ontology.njk +107 -0
  56. package/src/templates/rdf/schema.njk +79 -0
  57. package/src/templates/rdf/shapes.njk +89 -0
  58. package/src/templates/rdf/sparql-queries.njk +70 -0
  59. package/src/templates/rdf/vocabulary.njk +79 -0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @file RDF Templates Index
3
+ * @description Exports all RDF template paths for programmatic use
4
+ */
5
+
6
+ import { fileURLToPath } from 'url';
7
+ import { dirname, join } from 'path';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+
12
+ /**
13
+ * RDF template definitions
14
+ */
15
+ export const RDF_TEMPLATES = {
16
+ ontology: {
17
+ name: 'ontology.njk',
18
+ path: join(__dirname, 'ontology.njk'),
19
+ description: 'OWL ontology template with classes and properties',
20
+ requiredVars: ['ontologyIRI', 'title']
21
+ },
22
+ schema: {
23
+ name: 'schema.njk',
24
+ path: join(__dirname, 'schema.njk'),
25
+ description: 'RDFS vocabulary schema template',
26
+ requiredVars: ['schemaIRI', 'title']
27
+ },
28
+ dataset: {
29
+ name: 'dataset.njk',
30
+ path: join(__dirname, 'dataset.njk'),
31
+ description: 'DCAT dataset metadata template',
32
+ requiredVars: ['datasetIRI', 'title', 'description']
33
+ },
34
+ vocabulary: {
35
+ name: 'vocabulary.njk',
36
+ path: join(__dirname, 'vocabulary.njk'),
37
+ description: 'SKOS concept scheme template',
38
+ requiredVars: ['schemeIRI', 'title']
39
+ },
40
+ shapes: {
41
+ name: 'shapes.njk',
42
+ path: join(__dirname, 'shapes.njk'),
43
+ description: 'SHACL validation shapes template',
44
+ requiredVars: ['shapesGraphIRI', 'shapes']
45
+ },
46
+ sparqlQueries: {
47
+ name: 'sparql-queries.njk',
48
+ path: join(__dirname, 'sparql-queries.njk'),
49
+ description: 'SPARQL query collection template',
50
+ requiredVars: ['title', 'queries']
51
+ },
52
+ jsonldContext: {
53
+ name: 'jsonld-context.njk',
54
+ path: join(__dirname, 'jsonld-context.njk'),
55
+ description: 'JSON-LD context mapping template',
56
+ requiredVars: ['terms']
57
+ }
58
+ };
59
+
60
+ /**
61
+ * Get template path by name
62
+ * @param {string} name - Template name (e.g., 'ontology', 'schema')
63
+ * @returns {string} Full path to template file
64
+ */
65
+ export function getTemplatePath(name) {
66
+ const template = RDF_TEMPLATES[name];
67
+ if (!template) {
68
+ throw new Error(`Unknown RDF template: ${name}`);
69
+ }
70
+ return template.path;
71
+ }
72
+
73
+ /**
74
+ * List all available RDF templates
75
+ * @returns {Array<{name: string, description: string, requiredVars: string[]}>}
76
+ */
77
+ export function listTemplates() {
78
+ return Object.entries(RDF_TEMPLATES).map(([key, value]) => ({
79
+ key,
80
+ name: value.name,
81
+ description: value.description,
82
+ requiredVars: value.requiredVars
83
+ }));
84
+ }
85
+
86
+ /**
87
+ * Validate data against template requirements
88
+ * @param {string} templateName - Template name
89
+ * @param {Object} data - Data to validate
90
+ * @returns {{valid: boolean, missing: string[]}}
91
+ */
92
+ export function validateTemplateData(templateName, data) {
93
+ const template = RDF_TEMPLATES[templateName];
94
+ if (!template) {
95
+ return { valid: false, missing: ['Unknown template'] };
96
+ }
97
+
98
+ const missing = template.requiredVars.filter(varName => !data[varName]);
99
+
100
+ return {
101
+ valid: missing.length === 0,
102
+ missing
103
+ };
104
+ }
105
+
106
+ export default RDF_TEMPLATES;
@@ -0,0 +1,63 @@
1
+ {#
2
+ JSON-LD Context Template
3
+
4
+ Generates a JSON-LD context file for mapping JSON to RDF.
5
+
6
+ Expected frontmatter variables:
7
+ - contextIRI: The IRI of the context (optional, for @id)
8
+ - vocab: Default vocabulary IRI (optional, for @vocab)
9
+ - base: Base IRI for relative IRIs (optional, for @base)
10
+ - prefixes: Object mapping prefixes to namespace IRIs (optional)
11
+ - terms: Object mapping terms to IRIs or term definitions (required)
12
+ Simple mapping: termName: iri
13
+ Complex mapping:
14
+ termName:
15
+ id: IRI
16
+ type: @id, @vocab, or XSD datatype
17
+ container: @list, @set, @language, etc. (optional)
18
+ language: Language tag (optional)
19
+ reverse: Boolean (optional)
20
+
21
+ Example:
22
+ ---
23
+ contextIRI: http://example.org/contexts/person
24
+ vocab: http://schema.org/
25
+ prefixes:
26
+ foaf: http://xmlns.com/foaf/0.1/
27
+ xsd: http://www.w3.org/2001/XMLSchema#
28
+ terms:
29
+ Person: foaf:Person
30
+ name: foaf:name
31
+ email:
32
+ id: foaf:mbox
33
+ type: @id
34
+ age:
35
+ id: foaf:age
36
+ type: xsd:integer
37
+ knows:
38
+ id: foaf:knows
39
+ type: @id
40
+ container: @set
41
+ ---
42
+ #}{
43
+ "@context": {
44
+ {% if contextIRI %} "@id": "{{ contextIRI }}",
45
+ {% endif %}
46
+ {% if vocab %} "@vocab": "{{ vocab }}",
47
+ {% endif %}
48
+ {% if base %} "@base": "{{ base }}",
49
+ {% endif %}
50
+ {% if prefixes %}{% for prefix, uri in prefixes %} "{{ prefix }}": "{{ uri }}",
51
+ {% endfor %}{% endif %}
52
+ {% if terms %}{% for term, def in terms %}{% if def.id %} "{{ term }}": {
53
+ "@id": "{{ def.id }}"{% if def.type %},
54
+ "@type": "{{ def.type }}"{% endif %}{% if def.container %},
55
+ "@container": "{{ def.container }}"{% endif %}{% if def.language %},
56
+ "@language": "{{ def.language }}"{% endif %}{% if def.reverse %},
57
+ "@reverse": "{{ def.reverse }}"{% endif %}
58
+ }{% if not loop.last %},{% endif %}
59
+ {% else %} "{{ term }}": "{{ def }}"{% if not loop.last %},{% endif %}
60
+ {% endif %}
61
+ {% endfor %}{% endif %}
62
+ }
63
+ }
@@ -0,0 +1,107 @@
1
+ {#
2
+ OWL Ontology Template
3
+
4
+ Generates a complete OWL ontology with classes, properties, and metadata.
5
+
6
+ Expected frontmatter variables:
7
+ - ontologyIRI: The IRI of the ontology (required)
8
+ - version: Version string (optional)
9
+ - title: Ontology title (required)
10
+ - description: Ontology description (optional)
11
+ - creator: Creator name/IRI (optional)
12
+ - created: Creation date (ISO format) (optional)
13
+ - license: License IRI (optional)
14
+ - classes: Array of class definitions (optional)
15
+ - iri: Class IRI
16
+ - label: rdfs:label
17
+ - comment: rdfs:comment
18
+ - subClassOf: Parent class IRI (optional)
19
+ - objectProperties: Array of object properties (optional)
20
+ - iri: Property IRI
21
+ - label: rdfs:label
22
+ - comment: rdfs:comment
23
+ - domain: Domain class IRI
24
+ - range: Range class IRI
25
+ - datatypeProperties: Array of datatype properties (optional)
26
+ - iri: Property IRI
27
+ - label: rdfs:label
28
+ - comment: rdfs:comment
29
+ - domain: Domain class IRI
30
+ - range: XSD datatype IRI
31
+
32
+ Example:
33
+ ---
34
+ ontologyIRI: http://example.org/ontology/myonto
35
+ version: 1.0.0
36
+ title: My Example Ontology
37
+ description: An example OWL ontology
38
+ creator: http://example.org/people/john-doe
39
+ created: 2026-01-11
40
+ classes:
41
+ - iri: http://example.org/ontology/myonto#Person
42
+ label: Person
43
+ comment: Represents a person
44
+ - iri: http://example.org/ontology/myonto#Organization
45
+ label: Organization
46
+ comment: Represents an organization
47
+ objectProperties:
48
+ - iri: http://example.org/ontology/myonto#worksFor
49
+ label: works for
50
+ comment: Relates a person to their employer
51
+ domain: http://example.org/ontology/myonto#Person
52
+ range: http://example.org/ontology/myonto#Organization
53
+ ---
54
+ #}
55
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
56
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
57
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
58
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
59
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
60
+ @prefix dcterms: <http://purl.org/dc/terms/> .
61
+ {% if prefix %}@prefix {{ prefix }}: <{{ ontologyIRI }}#> .{% endif %}
62
+
63
+ # Ontology Declaration
64
+ <{{ ontologyIRI }}> a owl:Ontology ;
65
+ dc:title "{{ title }}"@en ;
66
+ {% if description %} dc:description "{{ description }}"@en ;{% endif %}
67
+ {% if version %} owl:versionInfo "{{ version }}" ;{% endif %}
68
+ {% if creator %} dcterms:creator <{{ creator }}> ;{% endif %}
69
+ {% if created %} dcterms:created "{{ created }}"^^xsd:date ;{% endif %}
70
+ {% if license %} dcterms:license <{{ license }}> ;{% endif %}
71
+ dcterms:modified "{{ now | date('YYYY-MM-DD') }}"^^xsd:date .
72
+
73
+ {% if classes and classes.length > 0 %}
74
+ # Classes
75
+ {% for class in classes %}
76
+ <{{ class.iri }}> a owl:Class ;
77
+ rdfs:label "{{ class.label }}"@en ;
78
+ {% if class.comment %} rdfs:comment "{{ class.comment }}"@en ;{% endif %}
79
+ {% if class.subClassOf %} rdfs:subClassOf <{{ class.subClassOf }}> ;{% endif %}
80
+ rdfs:isDefinedBy <{{ ontologyIRI }}> .
81
+
82
+ {% endfor %}
83
+ {% endif %}
84
+ {% if objectProperties and objectProperties.length > 0 %}
85
+ # Object Properties
86
+ {% for prop in objectProperties %}
87
+ <{{ prop.iri }}> a owl:ObjectProperty ;
88
+ rdfs:label "{{ prop.label }}"@en ;
89
+ {% if prop.comment %} rdfs:comment "{{ prop.comment }}"@en ;{% endif %}
90
+ {% if prop.domain %} rdfs:domain <{{ prop.domain }}> ;{% endif %}
91
+ {% if prop.range %} rdfs:range <{{ prop.range }}> ;{% endif %}
92
+ rdfs:isDefinedBy <{{ ontologyIRI }}> .
93
+
94
+ {% endfor %}
95
+ {% endif %}
96
+ {% if datatypeProperties and datatypeProperties.length > 0 %}
97
+ # Datatype Properties
98
+ {% for prop in datatypeProperties %}
99
+ <{{ prop.iri }}> a owl:DatatypeProperty ;
100
+ rdfs:label "{{ prop.label }}"@en ;
101
+ {% if prop.comment %} rdfs:comment "{{ prop.comment }}"@en ;{% endif %}
102
+ {% if prop.domain %} rdfs:domain <{{ prop.domain }}> ;{% endif %}
103
+ {% if prop.range %} rdfs:range <{{ prop.range }}> ;{% endif %}
104
+ rdfs:isDefinedBy <{{ ontologyIRI }}> .
105
+
106
+ {% endfor %}
107
+ {% endif %}
@@ -0,0 +1,79 @@
1
+ {#
2
+ RDFS Schema Template
3
+
4
+ Generates an RDFS vocabulary with classes and properties.
5
+
6
+ Expected frontmatter variables:
7
+ - schemaIRI: The IRI of the schema (required)
8
+ - title: Schema title (required)
9
+ - description: Schema description (optional)
10
+ - version: Version string (optional)
11
+ - classes: Array of RDFS class definitions (optional)
12
+ - iri: Class IRI
13
+ - label: rdfs:label
14
+ - comment: rdfs:comment
15
+ - subClassOf: Parent class IRI (optional)
16
+ - properties: Array of RDF properties (optional)
17
+ - iri: Property IRI
18
+ - label: rdfs:label
19
+ - comment: rdfs:comment
20
+ - domain: Domain class IRI (optional)
21
+ - range: Range class/datatype IRI (optional)
22
+ - subPropertyOf: Parent property IRI (optional)
23
+
24
+ Example:
25
+ ---
26
+ schemaIRI: http://example.org/schema/vocab
27
+ title: Example Vocabulary
28
+ description: A simple RDFS vocabulary
29
+ version: 1.0.0
30
+ classes:
31
+ - iri: http://example.org/schema/vocab#Document
32
+ label: Document
33
+ comment: A textual document
34
+ properties:
35
+ - iri: http://example.org/schema/vocab#title
36
+ label: title
37
+ comment: The title of a document
38
+ domain: http://example.org/schema/vocab#Document
39
+ range: http://www.w3.org/2001/XMLSchema#string
40
+ ---
41
+ #}
42
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
43
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
44
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
45
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
46
+ @prefix dcterms: <http://purl.org/dc/terms/> .
47
+ {% if prefix %}@prefix {{ prefix }}: <{{ schemaIRI }}#> .{% endif %}
48
+
49
+ # Schema Metadata
50
+ <{{ schemaIRI }}> a rdfs:Resource ;
51
+ rdfs:label "{{ title }}"@en ;
52
+ {% if description %} rdfs:comment "{{ description }}"@en ;{% endif %}
53
+ {% if version %} dc:version "{{ version }}" ;{% endif %}
54
+ dcterms:modified "{{ now | date('YYYY-MM-DD') }}"^^xsd:date .
55
+
56
+ {% if classes and classes.length > 0 %}
57
+ # Class Definitions
58
+ {% for class in classes %}
59
+ <{{ class.iri }}> a rdfs:Class ;
60
+ rdfs:label "{{ class.label }}"@en ;
61
+ {% if class.comment %} rdfs:comment "{{ class.comment }}"@en ;{% endif %}
62
+ {% if class.subClassOf %} rdfs:subClassOf <{{ class.subClassOf }}> ;{% endif %}
63
+ rdfs:isDefinedBy <{{ schemaIRI }}> .
64
+
65
+ {% endfor %}
66
+ {% endif %}
67
+ {% if properties and properties.length > 0 %}
68
+ # Property Definitions
69
+ {% for prop in properties %}
70
+ <{{ prop.iri }}> a rdf:Property ;
71
+ rdfs:label "{{ prop.label }}"@en ;
72
+ {% if prop.comment %} rdfs:comment "{{ prop.comment }}"@en ;{% endif %}
73
+ {% if prop.domain %} rdfs:domain <{{ prop.domain }}> ;{% endif %}
74
+ {% if prop.range %} rdfs:range <{{ prop.range }}> ;{% endif %}
75
+ {% if prop.subPropertyOf %} rdfs:subPropertyOf <{{ prop.subPropertyOf }}> ;{% endif %}
76
+ rdfs:isDefinedBy <{{ schemaIRI }}> .
77
+
78
+ {% endfor %}
79
+ {% endif %}
@@ -0,0 +1,89 @@
1
+ {#
2
+ SHACL Shapes Template
3
+
4
+ Generates SHACL (Shapes Constraint Language) shapes for RDF validation.
5
+
6
+ Expected frontmatter variables:
7
+ - shapesGraphIRI: The IRI of the shapes graph (required)
8
+ - title: Shapes graph title (optional)
9
+ - description: Description of the shapes (optional)
10
+ - shapes: Array of shape definitions (required)
11
+ - iri: Shape IRI
12
+ - targetClass: Target class IRI (optional)
13
+ - targetNode: Target node IRI (optional)
14
+ - label: Shape label (optional)
15
+ - description: Shape description (optional)
16
+ - closed: Boolean - whether shape is closed (optional)
17
+ - properties: Array of property constraints
18
+ - path: Property path IRI
19
+ - minCount: Minimum cardinality (optional)
20
+ - maxCount: Maximum cardinality (optional)
21
+ - datatype: Datatype IRI for datatype properties (optional)
22
+ - class: Class IRI for object properties (optional)
23
+ - pattern: Regex pattern for string validation (optional)
24
+ - minLength: Minimum string length (optional)
25
+ - maxLength: Maximum string length (optional)
26
+ - minInclusive: Minimum numeric value (optional)
27
+ - maxInclusive: Maximum numeric value (optional)
28
+
29
+ Example:
30
+ ---
31
+ shapesGraphIRI: http://example.org/shapes/person
32
+ title: Person Shapes
33
+ description: Validation shapes for Person data
34
+ shapes:
35
+ - iri: http://example.org/shapes/person#PersonShape
36
+ targetClass: http://example.org/ontology/Person
37
+ label: Person Shape
38
+ description: Validates Person instances
39
+ closed: false
40
+ properties:
41
+ - path: http://xmlns.com/foaf/0.1/name
42
+ minCount: 1
43
+ maxCount: 1
44
+ datatype: http://www.w3.org/2001/XMLSchema#string
45
+ - path: http://xmlns.com/foaf/0.1/mbox
46
+ minCount: 0
47
+ datatype: http://www.w3.org/2001/XMLSchema#string
48
+ pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
49
+ ---
50
+ #}
51
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
52
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
53
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
54
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
55
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
56
+ {% if prefix %}@prefix {{ prefix }}: <{{ shapesGraphIRI }}#> .{% endif %}
57
+
58
+ # Shapes Graph Metadata
59
+ <{{ shapesGraphIRI }}> a sh:ShapesGraph ;
60
+ {% if title %} dc:title "{{ title }}"@en ;{% endif %}
61
+ {% if description %} dc:description "{{ description }}"@en ;{% endif %}
62
+ .
63
+
64
+ {% if shapes and shapes.length > 0 %}
65
+ # Shape Definitions
66
+ {% for shape in shapes %}
67
+ <{{ shape.iri }}> a sh:NodeShape ;
68
+ {% if shape.targetClass %} sh:targetClass <{{ shape.targetClass }}> ;{% endif %}
69
+ {% if shape.targetNode %} sh:targetNode <{{ shape.targetNode }}> ;{% endif %}
70
+ {% if shape.label %} rdfs:label "{{ shape.label }}"@en ;{% endif %}
71
+ {% if shape.description %} rdfs:comment "{{ shape.description }}"@en ;{% endif %}
72
+ {% if shape.closed %} sh:closed {{ shape.closed }} ;{% endif %}
73
+ {% if shape.properties and shape.properties.length > 0 %}{% for prop in shape.properties %} sh:property [
74
+ sh:path <{{ prop.path }}> ;
75
+ {% if prop.minCount !== undefined %} sh:minCount {{ prop.minCount }} ;{% endif %}
76
+ {% if prop.maxCount !== undefined %} sh:maxCount {{ prop.maxCount }} ;{% endif %}
77
+ {% if prop.datatype %} sh:datatype <{{ prop.datatype }}> ;{% endif %}
78
+ {% if prop.class %} sh:class <{{ prop.class }}> ;{% endif %}
79
+ {% if prop.pattern %} sh:pattern "{{ prop.pattern }}" ;{% endif %}
80
+ {% if prop.minLength !== undefined %} sh:minLength {{ prop.minLength }} ;{% endif %}
81
+ {% if prop.maxLength !== undefined %} sh:maxLength {{ prop.maxLength }} ;{% endif %}
82
+ {% if prop.minInclusive !== undefined %} sh:minInclusive {{ prop.minInclusive }} ;{% endif %}
83
+ {% if prop.maxInclusive !== undefined %} sh:maxInclusive {{ prop.maxInclusive }} ;{% endif %}
84
+ ] ;
85
+ {% endfor %}{% endif %}
86
+ .
87
+
88
+ {% endfor %}
89
+ {% endif %}
@@ -0,0 +1,70 @@
1
+ {#
2
+ SPARQL Queries Template
3
+
4
+ Generates a collection of SPARQL queries with metadata.
5
+
6
+ Expected frontmatter variables:
7
+ - title: Query collection title (required)
8
+ - description: Collection description (optional)
9
+ - queries: Array of query definitions (required)
10
+ - name: Query name/identifier
11
+ - description: Query description
12
+ - type: Query type (SELECT, CONSTRUCT, ASK, DESCRIBE)
13
+ - prefixes: Object with prefix mappings (optional)
14
+ - variables: Array of variable names for SELECT (optional)
15
+ - where: Array of WHERE clause patterns
16
+ - orderBy: Array of ORDER BY variables (optional)
17
+ - limit: LIMIT value (optional)
18
+ - offset: OFFSET value (optional)
19
+
20
+ Example:
21
+ ---
22
+ title: Common SPARQL Queries
23
+ description: Frequently used SPARQL queries
24
+ queries:
25
+ - name: getAllPersons
26
+ description: Retrieve all persons with their names
27
+ type: SELECT
28
+ prefixes:
29
+ foaf: http://xmlns.com/foaf/0.1/
30
+ rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
31
+ variables:
32
+ - person
33
+ - name
34
+ where:
35
+ - "?person a foaf:Person"
36
+ - "?person foaf:name ?name"
37
+ orderBy:
38
+ - name
39
+ limit: 100
40
+ ---
41
+ #}
42
+ {# Query Collection: {{ title }} #}
43
+ {% if description %}{# {{ description }} #}{% endif %}
44
+
45
+ {% for query in queries %}
46
+ {# Query: {{ query.name }} #}
47
+ {% if query.description %}{# Description: {{ query.description }} #}{% endif %}
48
+
49
+ {% if query.type === 'SELECT' %}SELECT {% if query.variables %}{% for v in query.variables %}?{{ v }}{% if not loop.last %} {% endif %}{% endfor %}{% else %}*{% endif %}
50
+ {% elif query.type === 'CONSTRUCT' %}CONSTRUCT {
51
+ {% for pattern in query.construct %} {{ pattern }} .
52
+ {% endfor %}}
53
+ {% elif query.type === 'ASK' %}ASK
54
+ {% elif query.type === 'DESCRIBE' %}DESCRIBE {% if query.resources %}{{ query.resources | join(' ') }}{% else %}?resource{% endif %}
55
+ {% endif %}
56
+ {% if query.prefixes %}{% for prefix, uri in query.prefixes %}PREFIX {{ prefix }}: <{{ uri }}>
57
+ {% endfor %}{% endif %}
58
+ WHERE {
59
+ {% for pattern in query.where %} {{ pattern }} .
60
+ {% endfor %}}
61
+ {% if query.orderBy %}ORDER BY {% for v in query.orderBy %}?{{ v }} {% endfor %}{% endif %}
62
+ {% if query.limit %}LIMIT {{ query.limit }}{% endif %}
63
+ {% if query.offset %}
64
+ OFFSET {{ query.offset }}{% endif %}
65
+
66
+ {% if not loop.last %}
67
+ ---
68
+
69
+ {% endif %}
70
+ {% endfor %}
@@ -0,0 +1,79 @@
1
+ {#
2
+ SKOS Vocabulary Template
3
+
4
+ Generates a SKOS (Simple Knowledge Organization System) concept scheme.
5
+
6
+ Expected frontmatter variables:
7
+ - schemeIRI: The IRI of the concept scheme (required)
8
+ - title: Scheme title (required)
9
+ - description: Scheme description (optional)
10
+ - creator: Creator name/IRI (optional)
11
+ - created: Creation date (ISO format) (optional)
12
+ - concepts: Array of concept definitions (optional)
13
+ - iri: Concept IRI
14
+ - prefLabel: Preferred label
15
+ - altLabel: Alternative labels (array, optional)
16
+ - definition: Definition text (optional)
17
+ - broader: Broader concept IRI (optional)
18
+ - narrower: Array of narrower concept IRIs (optional)
19
+ - related: Array of related concept IRIs (optional)
20
+ - notation: Notation string (optional)
21
+
22
+ Example:
23
+ ---
24
+ schemeIRI: http://example.org/vocabularies/topics
25
+ title: Topic Vocabulary
26
+ description: A controlled vocabulary of topics
27
+ creator: http://example.org/people/jane-doe
28
+ created: 2026-01-11
29
+ concepts:
30
+ - iri: http://example.org/vocabularies/topics#Science
31
+ prefLabel: Science
32
+ definition: Natural and formal sciences
33
+ narrower:
34
+ - http://example.org/vocabularies/topics#Physics
35
+ - http://example.org/vocabularies/topics#Biology
36
+ - iri: http://example.org/vocabularies/topics#Physics
37
+ prefLabel: Physics
38
+ definition: The study of matter and energy
39
+ broader: http://example.org/vocabularies/topics#Science
40
+ ---
41
+ #}
42
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
43
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
44
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
45
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
46
+ @prefix dc: <http://purl.org/dc/elements/1.1/> .
47
+ @prefix dcterms: <http://purl.org/dc/terms/> .
48
+ {% if prefix %}@prefix {{ prefix }}: <{{ schemeIRI }}#> .{% endif %}
49
+
50
+ # Concept Scheme
51
+ <{{ schemeIRI }}> a skos:ConceptScheme ;
52
+ dc:title "{{ title }}"@en ;
53
+ {% if description %} dc:description "{{ description }}"@en ;{% endif %}
54
+ {% if creator %} dcterms:creator <{{ creator }}> ;{% endif %}
55
+ {% if created %} dcterms:created "{{ created }}"^^xsd:date ;{% endif %}
56
+ dcterms:modified "{{ now | date('YYYY-MM-DD') }}"^^xsd:date ;
57
+ {% if concepts and concepts.length > 0 %}{% for concept in concepts %} skos:hasTopConcept <{{ concept.iri }}> ;
58
+ {% endfor %}{% endif %}
59
+ .
60
+
61
+ {% if concepts and concepts.length > 0 %}
62
+ # Concepts
63
+ {% for concept in concepts %}
64
+ <{{ concept.iri }}> a skos:Concept ;
65
+ skos:inScheme <{{ schemeIRI }}> ;
66
+ skos:prefLabel "{{ concept.prefLabel }}"@en ;
67
+ {% if concept.altLabel and concept.altLabel.length > 0 %}{% for alt in concept.altLabel %} skos:altLabel "{{ alt }}"@en ;
68
+ {% endfor %}{% endif %}
69
+ {% if concept.definition %} skos:definition "{{ concept.definition }}"@en ;{% endif %}
70
+ {% if concept.notation %} skos:notation "{{ concept.notation }}" ;{% endif %}
71
+ {% if concept.broader %} skos:broader <{{ concept.broader }}> ;{% endif %}
72
+ {% if concept.narrower and concept.narrower.length > 0 %}{% for narrow in concept.narrower %} skos:narrower <{{ narrow }}> ;
73
+ {% endfor %}{% endif %}
74
+ {% if concept.related and concept.related.length > 0 %}{% for rel in concept.related %} skos:related <{{ rel }}> ;
75
+ {% endfor %}{% endif %}
76
+ .
77
+
78
+ {% endfor %}
79
+ {% endif %}