@unrdf/kgn 5.0.1 → 26.4.3
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 +18 -14
- 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
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unrdf/kgn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "26.4.3",
|
|
4
4
|
"description": "Deterministic Nunjucks template system with custom filters and frontmatter support",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
6
|
+
"main": "dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
|
-
"import": "./
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
10
12
|
},
|
|
11
13
|
"./engine": {
|
|
12
14
|
"import": "./src/engine/index.js"
|
|
@@ -23,26 +25,27 @@
|
|
|
23
25
|
"./templates/*": "./src/templates/*"
|
|
24
26
|
},
|
|
25
27
|
"dependencies": {
|
|
28
|
+
"@unrdf/core": "26.4.3",
|
|
26
29
|
"fs-extra": "^11.3.1",
|
|
27
30
|
"gray-matter": "^4.0.3",
|
|
28
31
|
"nunjucks": "^3.2.4",
|
|
29
32
|
"yaml": "^2.8.1",
|
|
30
|
-
"
|
|
31
|
-
"@unrdf/test-utils": "5.0.1"
|
|
33
|
+
"zod": "^3.25.76"
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
|
-
"@amiceli/vitest-cucumber": "^
|
|
36
|
+
"@amiceli/vitest-cucumber": "^6.2.0",
|
|
35
37
|
"@babel/parser": "^7.28.5",
|
|
36
38
|
"@babel/traverse": "^7.28.5",
|
|
37
39
|
"comment-parser": "^1.4.1",
|
|
38
40
|
"eslint": "^8.56.0",
|
|
39
41
|
"nodemon": "^3.0.1",
|
|
40
|
-
"vitest": "^
|
|
42
|
+
"vitest": "^4.0.16"
|
|
41
43
|
},
|
|
42
44
|
"engines": {
|
|
43
45
|
"node": ">=18.0.0",
|
|
44
|
-
"pnpm": ">=
|
|
46
|
+
"pnpm": ">=7.0.0"
|
|
45
47
|
},
|
|
48
|
+
"sideEffects": false,
|
|
46
49
|
"keywords": [
|
|
47
50
|
"unrdf",
|
|
48
51
|
"kgn",
|
|
@@ -57,13 +60,13 @@
|
|
|
57
60
|
"license": "MIT",
|
|
58
61
|
"repository": {
|
|
59
62
|
"type": "git",
|
|
60
|
-
"url": "https://github.com/
|
|
63
|
+
"url": "https://github.com/unrdf/unrdf.git",
|
|
61
64
|
"directory": "packages/kgn"
|
|
62
65
|
},
|
|
63
66
|
"bugs": {
|
|
64
|
-
"url": "https://github.com/
|
|
67
|
+
"url": "https://github.com/unrdf/unrdf/issues"
|
|
65
68
|
},
|
|
66
|
-
"homepage": "https://github.com/
|
|
69
|
+
"homepage": "https://github.com/unrdf/unrdf#readme",
|
|
67
70
|
"files": [
|
|
68
71
|
"src/",
|
|
69
72
|
"README.md"
|
|
@@ -72,7 +75,8 @@
|
|
|
72
75
|
"access": "public"
|
|
73
76
|
},
|
|
74
77
|
"scripts": {
|
|
75
|
-
"build": "
|
|
78
|
+
"build": "unbuild && tsc --emitDeclarationOnly || true",
|
|
79
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
76
80
|
"build:watch": "nodemon --watch src --exec 'npm run build'",
|
|
77
81
|
"test": "vitest run",
|
|
78
82
|
"test:watch": "vitest",
|
|
@@ -80,8 +84,8 @@
|
|
|
80
84
|
"test:cucumber:watch": "vitest --config vitest.cucumber.config.js --watch",
|
|
81
85
|
"test:all": "npm run test && npm run test:cucumber",
|
|
82
86
|
"test:coverage": "vitest run --coverage",
|
|
83
|
-
"lint": "eslint src/
|
|
84
|
-
"lint:fix": "eslint src/ --
|
|
87
|
+
"lint": "eslint src/",
|
|
88
|
+
"lint:fix": "eslint src/ --fix",
|
|
85
89
|
"dev": "nodemon --watch src --exec 'echo @unrdf/kgn dev mode - watching for changes'",
|
|
86
90
|
"typecheck": "echo '@unrdf/kgn - JavaScript validation not configured'",
|
|
87
91
|
"clean": "rm -rf coverage .nyc_output dist build",
|
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
* All filter templates are designed to be composable and reusable
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import _crypto from 'crypto';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
10
13
|
export class KGenFilterTemplates {
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
11
17
|
constructor(options = {}) {
|
|
12
18
|
this.options = {
|
|
13
19
|
deterministicMode: options.deterministicMode !== false,
|
package/src/base/index.js
CHANGED
|
@@ -1,31 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KGEN Base Templates - Foundation template system
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Exports all base template classes and utilities for building
|
|
5
5
|
* deterministic, reusable template components
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
|
|
8
|
+
// Import classes for local use
|
|
9
|
+
import { KGenTemplateBase } from './template-base.js';
|
|
10
|
+
import { KGenMacroTemplates } from './macro-templates.js';
|
|
11
|
+
import { KGenFilterTemplates } from './filter-templates.js';
|
|
12
|
+
import { KGenSHACLTemplates } from './shacl-templates.js';
|
|
13
|
+
import { KGenInjectionTargets } from './injection-targets.js';
|
|
10
14
|
|
|
11
|
-
//
|
|
15
|
+
// Re-export for external use
|
|
16
|
+
export { KGenTemplateBase } from './template-base.js';
|
|
12
17
|
export { KGenMacroTemplates } from './macro-templates.js';
|
|
13
|
-
|
|
14
|
-
// Filter system for deterministic data processing
|
|
15
18
|
export { KGenFilterTemplates } from './filter-templates.js';
|
|
16
|
-
|
|
17
|
-
// SHACL validation templates for RDF knowledge graphs
|
|
18
19
|
export { KGenSHACLTemplates } from './shacl-templates.js';
|
|
19
|
-
|
|
20
|
-
// Injection targets for code modification
|
|
21
20
|
export { KGenInjectionTargets } from './injection-targets.js';
|
|
22
21
|
|
|
23
22
|
// Convenience factory function
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
24
26
|
export function createBaseTemplate(options = {}) {
|
|
25
27
|
return new KGenTemplateBase(options);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
// Template system factory
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
29
34
|
export function createTemplateSystem(options = {}) {
|
|
30
35
|
const base = new KGenTemplateBase(options);
|
|
31
36
|
const macros = new KGenMacroTemplates(options);
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* Supports marker-based, semantic-based, and position-based injection strategies
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
8
11
|
export class KGenInjectionTargets {
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
9
15
|
constructor(options = {}) {
|
|
10
16
|
this.options = {
|
|
11
17
|
deterministicMode: options.deterministicMode !== false,
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* All macros are deterministic and compatible with KGEN template engine
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
8
11
|
export class KGenMacroTemplates {
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
9
15
|
constructor(options = {}) {
|
|
10
16
|
this.options = {
|
|
11
17
|
deterministicMode: options.deterministicMode !== false,
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* for validating RDF knowledge graphs used in KGEN template generation
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
8
11
|
export class KGenSHACLTemplates {
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
9
15
|
constructor(options = {}) {
|
|
10
16
|
this.options = {
|
|
11
17
|
deterministicMode: options.deterministicMode !== false,
|
|
@@ -9,7 +9,13 @@ import crypto from 'crypto';
|
|
|
9
9
|
import { KGenTemplateEngine } from '../core/kgen-engine.js';
|
|
10
10
|
import { TemplateInheritanceEngine } from '../inheritance/index.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
12
15
|
export class KGenTemplateBase {
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
13
19
|
constructor(options = {}) {
|
|
14
20
|
this.options = {
|
|
15
21
|
strictMode: options.strictMode !== false,
|
|
@@ -231,7 +237,7 @@ export default {{ moduleName }};
|
|
|
231
237
|
/**
|
|
232
238
|
* Generate template from registered template
|
|
233
239
|
*/
|
|
234
|
-
async generateFromTemplate(templateName, context = {},
|
|
240
|
+
async generateFromTemplate(templateName, context = {}, _options = {}) {
|
|
235
241
|
if (!this.templates.has(templateName)) {
|
|
236
242
|
throw new Error(`Template '${templateName}' not found`);
|
|
237
243
|
}
|
package/src/core/attestor.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KGEN Attestor - Generate cryptographic attestations for deterministic output
|
|
2
|
+
* @file KGEN Attestor - Generate cryptographic attestations for deterministic output
|
|
3
|
+
* @module @unrdf/kgn/core/attestor
|
|
3
4
|
*
|
|
5
|
+
* @description
|
|
4
6
|
* Provides:
|
|
5
7
|
* - Content integrity verification
|
|
6
8
|
* - Deterministic output attestation
|
|
@@ -10,7 +12,21 @@
|
|
|
10
12
|
|
|
11
13
|
import crypto from 'crypto';
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* KGEN Attestor class - Cryptographic attestation system
|
|
17
|
+
*/
|
|
13
18
|
export class KGenAttestor {
|
|
19
|
+
/**
|
|
20
|
+
* Create a new KGenAttestor instance
|
|
21
|
+
* @param {Object} [options={}] - Attestor configuration options
|
|
22
|
+
* @param {boolean} [options.enableAttestation=true] - Enable attestation generation
|
|
23
|
+
* @param {string} [options.algorithm='sha256'] - Hash algorithm to use
|
|
24
|
+
* @param {string} [options.attestorId='kgen-templates'] - Attestor identifier
|
|
25
|
+
* @param {string} [options.version='2.0.0'] - Attestor version
|
|
26
|
+
* @param {string} [options.staticBuildTime] - Static timestamp for deterministic mode
|
|
27
|
+
* @param {boolean} [options.deterministicMode=true] - Enable deterministic mode
|
|
28
|
+
* @param {boolean} [options.includeMetadata=true] - Include additional metadata
|
|
29
|
+
*/
|
|
14
30
|
constructor(options = {}) {
|
|
15
31
|
this.options = {
|
|
16
32
|
enableAttestation: options.enableAttestation !== false,
|
|
@@ -26,6 +42,9 @@ export class KGenAttestor {
|
|
|
26
42
|
|
|
27
43
|
/**
|
|
28
44
|
* Generate attestation for rendered content
|
|
45
|
+
* @param {string} content - Content to attest
|
|
46
|
+
* @param {Object} [context={}] - Context data for attestation
|
|
47
|
+
* @returns {Promise<Object>} Attestation result
|
|
29
48
|
*/
|
|
30
49
|
async attest(content, context = {}) {
|
|
31
50
|
if (!this.options.enableAttestation) {
|
|
@@ -61,6 +80,9 @@ export class KGenAttestor {
|
|
|
61
80
|
|
|
62
81
|
/**
|
|
63
82
|
* Create complete attestation record
|
|
83
|
+
* @param {string} content - Content to attest
|
|
84
|
+
* @param {Object} [context={}] - Context data
|
|
85
|
+
* @returns {Promise<Object>} Complete attestation record
|
|
64
86
|
*/
|
|
65
87
|
async createAttestation(content, context = {}) {
|
|
66
88
|
const contentHash = this.createContentHash(content);
|
|
@@ -104,6 +126,9 @@ export class KGenAttestor {
|
|
|
104
126
|
|
|
105
127
|
/**
|
|
106
128
|
* Verify attestation integrity
|
|
129
|
+
* @param {string} content - Content to verify
|
|
130
|
+
* @param {Object} attestation - Attestation to verify against
|
|
131
|
+
* @returns {Promise<Object>} Verification result
|
|
107
132
|
*/
|
|
108
133
|
async verify(content, attestation) {
|
|
109
134
|
try {
|
|
@@ -159,6 +184,10 @@ export class KGenAttestor {
|
|
|
159
184
|
|
|
160
185
|
/**
|
|
161
186
|
* Create reproducibility proof
|
|
187
|
+
* @param {string} content - Content to test reproducibility
|
|
188
|
+
* @param {Object} context - Context data
|
|
189
|
+
* @param {number} [iterations=3] - Number of iterations to test
|
|
190
|
+
* @returns {Promise<Object>} Reproducibility proof
|
|
162
191
|
*/
|
|
163
192
|
async createReproducibilityProof(content, context, iterations = 3) {
|
|
164
193
|
const proofs = [];
|
|
@@ -194,6 +223,8 @@ export class KGenAttestor {
|
|
|
194
223
|
|
|
195
224
|
/**
|
|
196
225
|
* Create audit trail for template execution
|
|
226
|
+
* @param {Array<Object>} [steps=[]] - Execution steps to audit
|
|
227
|
+
* @returns {Object} Audit trail record
|
|
197
228
|
*/
|
|
198
229
|
createAuditTrail(steps = []) {
|
|
199
230
|
return {
|
|
@@ -214,6 +245,9 @@ export class KGenAttestor {
|
|
|
214
245
|
|
|
215
246
|
/**
|
|
216
247
|
* Compare two attestations
|
|
248
|
+
* @param {Object} attestation1 - First attestation
|
|
249
|
+
* @param {Object} attestation2 - Second attestation
|
|
250
|
+
* @returns {Object} Comparison result
|
|
217
251
|
*/
|
|
218
252
|
compareAttestations(attestation1, attestation2) {
|
|
219
253
|
const differences = [];
|
|
@@ -264,6 +298,8 @@ export class KGenAttestor {
|
|
|
264
298
|
|
|
265
299
|
/**
|
|
266
300
|
* Create content hash using specified algorithm
|
|
301
|
+
* @param {string} content - Content to hash
|
|
302
|
+
* @returns {string} Content hash as hex string
|
|
267
303
|
*/
|
|
268
304
|
createContentHash(content) {
|
|
269
305
|
return crypto.createHash(this.options.algorithm)
|
|
@@ -273,6 +309,8 @@ export class KGenAttestor {
|
|
|
273
309
|
|
|
274
310
|
/**
|
|
275
311
|
* Create signature for attestation data
|
|
312
|
+
* @param {Object} data - Data to sign
|
|
313
|
+
* @returns {string} Signature as hex string
|
|
276
314
|
*/
|
|
277
315
|
createSignature(data) {
|
|
278
316
|
// Simple signature using hash of data + attestor ID
|
|
@@ -284,6 +322,9 @@ export class KGenAttestor {
|
|
|
284
322
|
|
|
285
323
|
/**
|
|
286
324
|
* Get additional metadata if enabled
|
|
325
|
+
* @param {string} content - Content being attested
|
|
326
|
+
* @param {Object} context - Context data
|
|
327
|
+
* @returns {Object} Additional metadata
|
|
287
328
|
*/
|
|
288
329
|
getAdditionalMetadata(content, context) {
|
|
289
330
|
return {
|
|
@@ -306,6 +347,7 @@ export class KGenAttestor {
|
|
|
306
347
|
|
|
307
348
|
/**
|
|
308
349
|
* Get deterministic or real timestamp
|
|
350
|
+
* @returns {string} ISO 8601 timestamp
|
|
309
351
|
*/
|
|
310
352
|
getTimestamp() {
|
|
311
353
|
return this.options.deterministicMode ?
|
|
@@ -315,6 +357,9 @@ export class KGenAttestor {
|
|
|
315
357
|
|
|
316
358
|
/**
|
|
317
359
|
* Export attestation in standard format
|
|
360
|
+
* @param {Object} attestation - Attestation to export
|
|
361
|
+
* @param {string} [format='json'] - Export format (json, compact, yaml, base64)
|
|
362
|
+
* @returns {string} Exported attestation
|
|
318
363
|
*/
|
|
319
364
|
exportAttestation(attestation, format = 'json') {
|
|
320
365
|
switch (format.toLowerCase()) {
|
|
@@ -340,6 +385,9 @@ export class KGenAttestor {
|
|
|
340
385
|
|
|
341
386
|
/**
|
|
342
387
|
* Import attestation from standard format
|
|
388
|
+
* @param {string} data - Attestation data to import
|
|
389
|
+
* @param {string} [format='json'] - Import format (json, compact, base64)
|
|
390
|
+
* @returns {Object} Imported attestation object
|
|
343
391
|
*/
|
|
344
392
|
importAttestation(data, format = 'json') {
|
|
345
393
|
try {
|
|
@@ -362,6 +410,7 @@ export class KGenAttestor {
|
|
|
362
410
|
|
|
363
411
|
/**
|
|
364
412
|
* Get attestor statistics
|
|
413
|
+
* @returns {Object} Attestor configuration and capabilities
|
|
365
414
|
*/
|
|
366
415
|
getStats() {
|
|
367
416
|
return {
|
package/src/core/filters.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KGEN Filter System - Deterministic template filters
|
|
2
|
+
* @file KGEN Filter System - Deterministic template filters
|
|
3
|
+
* @module @unrdf/kgn/core/filters
|
|
3
4
|
*
|
|
5
|
+
* @description
|
|
4
6
|
* Implements all v1 Lock specification filters:
|
|
5
7
|
* - Text: upper, lower, trim, replace, split, join, slice
|
|
6
8
|
* - Data: default, unique, sort, groupby, map, sum, count
|
|
@@ -12,7 +14,16 @@
|
|
|
12
14
|
|
|
13
15
|
import crypto from 'crypto';
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* KGEN Filters class - Template filter system
|
|
19
|
+
*/
|
|
15
20
|
export class KGenFilters {
|
|
21
|
+
/**
|
|
22
|
+
* Create a new KGenFilters instance
|
|
23
|
+
* @param {Object} [options={}] - Filter configuration options
|
|
24
|
+
* @param {boolean} [options.deterministicMode=true] - Enable deterministic mode
|
|
25
|
+
* @param {boolean} [options.strictMode=true] - Enable strict error handling
|
|
26
|
+
*/
|
|
16
27
|
constructor(options = {}) {
|
|
17
28
|
this.options = {
|
|
18
29
|
deterministicMode: options.deterministicMode !== false,
|
|
@@ -26,6 +37,12 @@ export class KGenFilters {
|
|
|
26
37
|
|
|
27
38
|
/**
|
|
28
39
|
* Register a filter function
|
|
40
|
+
* @param {string} name - Filter name
|
|
41
|
+
* @param {Function} filterFunction - Filter implementation
|
|
42
|
+
* @param {Object} [options={}] - Filter options
|
|
43
|
+
* @param {boolean} [options.deterministic=true] - Whether filter is deterministic
|
|
44
|
+
* @param {string} [options.description=''] - Filter description
|
|
45
|
+
* @param {string} [options.category='custom'] - Filter category
|
|
29
46
|
*/
|
|
30
47
|
register(name, filterFunction, options = {}) {
|
|
31
48
|
if (typeof filterFunction !== 'function') {
|
|
@@ -42,6 +59,10 @@ export class KGenFilters {
|
|
|
42
59
|
|
|
43
60
|
/**
|
|
44
61
|
* Apply filter to value
|
|
62
|
+
* @param {string} filterName - Name of filter to apply
|
|
63
|
+
* @param {*} value - Value to filter
|
|
64
|
+
* @param {...*} args - Additional filter arguments
|
|
65
|
+
* @returns {*} Filtered value
|
|
45
66
|
*/
|
|
46
67
|
apply(filterName, value, ...args) {
|
|
47
68
|
const filter = this.filters.get(filterName);
|
|
@@ -70,6 +91,8 @@ export class KGenFilters {
|
|
|
70
91
|
|
|
71
92
|
/**
|
|
72
93
|
* Check if filter exists
|
|
94
|
+
* @param {string} filterName - Filter name to check
|
|
95
|
+
* @returns {boolean} True if filter exists
|
|
73
96
|
*/
|
|
74
97
|
has(filterName) {
|
|
75
98
|
return this.filters.has(filterName);
|
|
@@ -77,6 +100,7 @@ export class KGenFilters {
|
|
|
77
100
|
|
|
78
101
|
/**
|
|
79
102
|
* Get filter count
|
|
103
|
+
* @returns {number} Number of registered filters
|
|
80
104
|
*/
|
|
81
105
|
getFilterCount() {
|
|
82
106
|
return this.filters.size;
|
|
@@ -84,6 +108,7 @@ export class KGenFilters {
|
|
|
84
108
|
|
|
85
109
|
/**
|
|
86
110
|
* Register all core filters
|
|
111
|
+
* Registers text, data, format, RDF, validation, CAS, and utility filters
|
|
87
112
|
*/
|
|
88
113
|
registerCoreFilters() {
|
|
89
114
|
this.registerTextFilters();
|
|
@@ -97,6 +122,7 @@ export class KGenFilters {
|
|
|
97
122
|
|
|
98
123
|
/**
|
|
99
124
|
* Text processing filters
|
|
125
|
+
* Registers upper, lower, trim, replace, split, join, slice filters
|
|
100
126
|
*/
|
|
101
127
|
registerTextFilters() {
|
|
102
128
|
this.register('upper', (str) => String(str || '').toUpperCase(), {
|
|
@@ -146,10 +172,27 @@ export class KGenFilters {
|
|
|
146
172
|
category: 'text',
|
|
147
173
|
description: 'Extract substring by position'
|
|
148
174
|
});
|
|
175
|
+
|
|
176
|
+
this.register('truncate', (str, length = 10, suffix = '...') => {
|
|
177
|
+
const s = String(str || '');
|
|
178
|
+
if (s.length <= length) return s;
|
|
179
|
+
return s.slice(0, length) + suffix;
|
|
180
|
+
}, {
|
|
181
|
+
category: 'text',
|
|
182
|
+
description: 'Truncate string to specified length'
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
this.register('reverse', (str) => {
|
|
186
|
+
return String(str || '').split('').reverse().join('');
|
|
187
|
+
}, {
|
|
188
|
+
category: 'text',
|
|
189
|
+
description: 'Reverse string'
|
|
190
|
+
});
|
|
149
191
|
}
|
|
150
192
|
|
|
151
193
|
/**
|
|
152
194
|
* Data processing filters
|
|
195
|
+
* Registers default, unique, sort, groupby, map, sum, count filters
|
|
153
196
|
*/
|
|
154
197
|
registerDataFilters() {
|
|
155
198
|
this.register('default', (value, defaultValue = '') => {
|
|
@@ -356,6 +399,7 @@ export class KGenFilters {
|
|
|
356
399
|
|
|
357
400
|
/**
|
|
358
401
|
* Validation filters
|
|
402
|
+
* Registers shaclReport, validate filters
|
|
359
403
|
*/
|
|
360
404
|
registerValidationFilters() {
|
|
361
405
|
this.register('shaclReport', (data, shaclShapes = {}) => {
|
|
@@ -425,6 +469,7 @@ export class KGenFilters {
|
|
|
425
469
|
|
|
426
470
|
/**
|
|
427
471
|
* Utility filters
|
|
472
|
+
* Registers typeof, length, keys, values, entries, formatDate filters
|
|
428
473
|
*/
|
|
429
474
|
registerUtilityFilters() {
|
|
430
475
|
// Non-deterministic filters that throw in deterministic mode
|
|
@@ -460,6 +505,93 @@ export class KGenFilters {
|
|
|
460
505
|
deterministic: false,
|
|
461
506
|
description: 'Generate UUID (non-deterministic)'
|
|
462
507
|
});
|
|
508
|
+
|
|
509
|
+
// Date arithmetic filters
|
|
510
|
+
this.register('dateAdd', (dateStr, amount, unit = 'day') => {
|
|
511
|
+
const date = new Date(dateStr);
|
|
512
|
+
switch (unit) {
|
|
513
|
+
case 'day':
|
|
514
|
+
date.setDate(date.getDate() + amount);
|
|
515
|
+
break;
|
|
516
|
+
case 'month':
|
|
517
|
+
date.setMonth(date.getMonth() + amount);
|
|
518
|
+
break;
|
|
519
|
+
case 'year':
|
|
520
|
+
date.setFullYear(date.getFullYear() + amount);
|
|
521
|
+
break;
|
|
522
|
+
default:
|
|
523
|
+
throw new Error(`Unknown unit: ${unit}`);
|
|
524
|
+
}
|
|
525
|
+
return date.toISOString();
|
|
526
|
+
}, {
|
|
527
|
+
category: 'utility',
|
|
528
|
+
description: 'Add time to date'
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
this.register('dateSub', (dateStr, amount, unit = 'day') => {
|
|
532
|
+
const date = new Date(dateStr);
|
|
533
|
+
switch (unit) {
|
|
534
|
+
case 'day':
|
|
535
|
+
date.setDate(date.getDate() - amount);
|
|
536
|
+
break;
|
|
537
|
+
case 'month':
|
|
538
|
+
date.setMonth(date.getMonth() - amount);
|
|
539
|
+
break;
|
|
540
|
+
case 'year':
|
|
541
|
+
date.setFullYear(date.getFullYear() - amount);
|
|
542
|
+
break;
|
|
543
|
+
default:
|
|
544
|
+
throw new Error(`Unknown unit: ${unit}`);
|
|
545
|
+
}
|
|
546
|
+
return date.toISOString();
|
|
547
|
+
}, {
|
|
548
|
+
category: 'utility',
|
|
549
|
+
description: 'Subtract time from date'
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
// Path utility filters
|
|
553
|
+
this.register('resolve', (base, relative) => {
|
|
554
|
+
// Simple path resolution (normalize and join)
|
|
555
|
+
const baseParts = base.split('/').filter(p => p);
|
|
556
|
+
const relativeParts = relative.split('/').filter(p => p);
|
|
557
|
+
|
|
558
|
+
for (const part of relativeParts) {
|
|
559
|
+
if (part === '..') {
|
|
560
|
+
baseParts.pop();
|
|
561
|
+
} else if (part !== '.') {
|
|
562
|
+
baseParts.push(part);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return '/' + baseParts.join('/');
|
|
567
|
+
}, {
|
|
568
|
+
category: 'utility',
|
|
569
|
+
description: 'Resolve path'
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
this.register('relative', (from, to) => {
|
|
573
|
+
// Simple relative path calculation
|
|
574
|
+
const fromParts = from.split('/').filter(p => p);
|
|
575
|
+
const toParts = to.split('/').filter(p => p);
|
|
576
|
+
|
|
577
|
+
// Find common base
|
|
578
|
+
let i = 0;
|
|
579
|
+
while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {
|
|
580
|
+
i++;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Go up from 'from' directory
|
|
584
|
+
const upCount = fromParts.length - i;
|
|
585
|
+
const upParts = Array(upCount).fill('..');
|
|
586
|
+
|
|
587
|
+
// Then append remaining 'to' parts
|
|
588
|
+
const remainingParts = toParts.slice(i);
|
|
589
|
+
|
|
590
|
+
return [...upParts, ...remainingParts].join('/');
|
|
591
|
+
}, {
|
|
592
|
+
category: 'utility',
|
|
593
|
+
description: 'Calculate relative path'
|
|
594
|
+
});
|
|
463
595
|
}
|
|
464
596
|
|
|
465
597
|
/**
|
|
@@ -489,6 +621,7 @@ export class KGenFilters {
|
|
|
489
621
|
|
|
490
622
|
/**
|
|
491
623
|
* Get filter statistics
|
|
624
|
+
* @returns {Object} Filter system statistics
|
|
492
625
|
*/
|
|
493
626
|
getStats() {
|
|
494
627
|
const categories = {};
|
package/src/core/index.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Features: Deterministic rendering, custom filters, attestation support
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Import class first so it can be used in factory function
|
|
9
|
+
import { KGenTemplateEngine } from './kgen-engine.js';
|
|
10
|
+
|
|
11
|
+
// Export all classes
|
|
8
12
|
export { KGenTemplateEngine } from './kgen-engine.js';
|
|
9
13
|
export { KGenParser } from './parser.js';
|
|
10
14
|
export { KGenFilters } from './filters.js';
|
|
@@ -13,9 +17,12 @@ export { KGenPostProcessor } from './post-processor.js';
|
|
|
13
17
|
export { KGenAttestor } from './attestor.js';
|
|
14
18
|
|
|
15
19
|
// Convenience factory function
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
16
23
|
export function createKGenEngine(options = {}) {
|
|
17
24
|
return new KGenTemplateEngine(options);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
// Default export
|
|
21
|
-
export
|
|
28
|
+
export default KGenTemplateEngine;
|