@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
package/src/core/kgen-engine.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KGEN Native Template Engine - Deterministic template processing without nunjucks
|
|
2
|
+
* @file KGEN Native Template Engine - Deterministic template processing without nunjucks
|
|
3
|
+
* @module @unrdf/kgn/core/kgen-engine
|
|
3
4
|
*
|
|
5
|
+
* @description
|
|
4
6
|
* Pipeline: plan → render → post → attest
|
|
5
7
|
* Supports: Variables {{ var }}, conditionals {% if %}, loops {% for %}, filters {{ var | filter }}
|
|
6
8
|
* Deterministic: All operations produce stable, reproducible output
|
|
@@ -13,7 +15,20 @@ import { KGenRenderer } from './renderer.js';
|
|
|
13
15
|
import { KGenPostProcessor } from './post-processor.js';
|
|
14
16
|
import { KGenAttestor } from './attestor.js';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* KGEN Template Engine - Main entry point for template processing
|
|
20
|
+
*/
|
|
16
21
|
export class KGenTemplateEngine {
|
|
22
|
+
/**
|
|
23
|
+
* Create a new KGenTemplateEngine instance
|
|
24
|
+
* @param {Object} [options={}] - Engine configuration options
|
|
25
|
+
* @param {boolean} [options.strictMode=true] - Enable strict mode validation
|
|
26
|
+
* @param {boolean} [options.deterministicMode=true] - Enable deterministic mode
|
|
27
|
+
* @param {string} [options.staticBuildTime='2024-01-01T00:00:00.000Z'] - Static timestamp for deterministic builds
|
|
28
|
+
* @param {number} [options.maxDepth=10] - Maximum template nesting depth
|
|
29
|
+
* @param {boolean} [options.enableIncludes=true] - Enable include statements
|
|
30
|
+
* @param {boolean} [options.enableAttestation=true] - Enable cryptographic attestation
|
|
31
|
+
*/
|
|
17
32
|
constructor(options = {}) {
|
|
18
33
|
this.options = {
|
|
19
34
|
strictMode: options.strictMode !== false,
|
|
@@ -38,6 +53,9 @@ export class KGenTemplateEngine {
|
|
|
38
53
|
|
|
39
54
|
/**
|
|
40
55
|
* PHASE 1: PLAN - Parse and analyze template
|
|
56
|
+
* @param {string} template - Template content to plan
|
|
57
|
+
* @param {Object} [context={}] - Context data for validation
|
|
58
|
+
* @returns {Promise<Object>} Plan result with parsed template, frontmatter, variables, expressions, includes, complexity, hash
|
|
41
59
|
*/
|
|
42
60
|
async plan(template, context = {}) {
|
|
43
61
|
try {
|
|
@@ -74,6 +92,9 @@ export class KGenTemplateEngine {
|
|
|
74
92
|
|
|
75
93
|
/**
|
|
76
94
|
* PHASE 2: RENDER - Execute template with context
|
|
95
|
+
* @param {Object} plan - Plan result from plan() phase
|
|
96
|
+
* @param {Object} [context={}] - Context data for rendering
|
|
97
|
+
* @returns {Promise<Object>} Render result with success, content, context, metadata
|
|
77
98
|
*/
|
|
78
99
|
async render(plan, context = {}) {
|
|
79
100
|
if (!plan.success) {
|
|
@@ -122,6 +143,8 @@ export class KGenTemplateEngine {
|
|
|
122
143
|
|
|
123
144
|
/**
|
|
124
145
|
* PHASE 3: POST - Post-process rendered content
|
|
146
|
+
* @param {Object} renderResult - Render result from render() phase
|
|
147
|
+
* @returns {Promise<Object>} Post-processed result with normalized content
|
|
125
148
|
*/
|
|
126
149
|
async post(renderResult) {
|
|
127
150
|
if (!renderResult.success) {
|
|
@@ -157,6 +180,8 @@ export class KGenTemplateEngine {
|
|
|
157
180
|
|
|
158
181
|
/**
|
|
159
182
|
* PHASE 4: ATTEST - Generate attestation of deterministic output
|
|
183
|
+
* @param {Object} postResult - Post-processed result from post() phase
|
|
184
|
+
* @returns {Promise<Object>} Attested result with cryptographic attestation
|
|
160
185
|
*/
|
|
161
186
|
async attest(postResult) {
|
|
162
187
|
if (!postResult.success || !this.options.enableAttestation) {
|
|
@@ -193,6 +218,9 @@ export class KGenTemplateEngine {
|
|
|
193
218
|
|
|
194
219
|
/**
|
|
195
220
|
* Complete pipeline: plan → render → post → attest
|
|
221
|
+
* @param {string} template - Template content to execute
|
|
222
|
+
* @param {Object} [context={}] - Context data for rendering
|
|
223
|
+
* @returns {Promise<Object>} Final result with all pipeline phases complete
|
|
196
224
|
*/
|
|
197
225
|
async execute(template, context = {}) {
|
|
198
226
|
const plan = await this.plan(template, context);
|
|
@@ -205,6 +233,9 @@ export class KGenTemplateEngine {
|
|
|
205
233
|
|
|
206
234
|
/**
|
|
207
235
|
* Simple render method for basic use cases
|
|
236
|
+
* @param {string} template - Template content to render
|
|
237
|
+
* @param {Object} [context={}] - Context data for rendering
|
|
238
|
+
* @returns {Promise<string>} Rendered content as string
|
|
208
239
|
*/
|
|
209
240
|
async renderTemplate(template, context = {}) {
|
|
210
241
|
// Use a simplified pipeline without post-processing for simple rendering
|
|
@@ -220,6 +251,7 @@ export class KGenTemplateEngine {
|
|
|
220
251
|
|
|
221
252
|
/**
|
|
222
253
|
* Register core filters
|
|
254
|
+
* Registers text, data, and format filters for template use
|
|
223
255
|
*/
|
|
224
256
|
registerCoreFilters() {
|
|
225
257
|
// Text filters
|
|
@@ -292,6 +324,11 @@ export class KGenTemplateEngine {
|
|
|
292
324
|
|
|
293
325
|
/**
|
|
294
326
|
* Calculate template complexity score
|
|
327
|
+
* @param {Object} parseResult - Parse result from parser
|
|
328
|
+
* @param {Array} [parseResult.variables=[]] - Variables in template
|
|
329
|
+
* @param {Array} [parseResult.expressions=[]] - Expressions in template
|
|
330
|
+
* @param {Array} [parseResult.includes=[]] - Includes in template
|
|
331
|
+
* @returns {number} Complexity score
|
|
295
332
|
*/
|
|
296
333
|
calculateComplexity(parseResult) {
|
|
297
334
|
const { variables = [], expressions = [], includes = [] } = parseResult;
|
|
@@ -300,6 +337,10 @@ export class KGenTemplateEngine {
|
|
|
300
337
|
|
|
301
338
|
/**
|
|
302
339
|
* Validate context has required variables
|
|
340
|
+
* @param {Array<string>} variables - Required variable names
|
|
341
|
+
* @param {Object} context - Context object to validate
|
|
342
|
+
* @param {Object} frontmatter - Frontmatter data
|
|
343
|
+
* @throws {Error} When required variables are missing
|
|
303
344
|
*/
|
|
304
345
|
validateContext(variables, context, frontmatter) {
|
|
305
346
|
const missing = [];
|
|
@@ -325,6 +366,8 @@ export class KGenTemplateEngine {
|
|
|
325
366
|
|
|
326
367
|
/**
|
|
327
368
|
* Generate deterministic content hash
|
|
369
|
+
* @param {string} content - Content to hash
|
|
370
|
+
* @returns {string} SHA-256 hash as hex string
|
|
328
371
|
*/
|
|
329
372
|
hashContent(content) {
|
|
330
373
|
return crypto.createHash('sha256').update(String(content || ''), 'utf8').digest('hex');
|
|
@@ -332,6 +375,7 @@ export class KGenTemplateEngine {
|
|
|
332
375
|
|
|
333
376
|
/**
|
|
334
377
|
* Get engine statistics
|
|
378
|
+
* @returns {Object} Engine configuration and statistics
|
|
335
379
|
*/
|
|
336
380
|
getStats() {
|
|
337
381
|
return {
|
|
@@ -343,6 +387,10 @@ export class KGenTemplateEngine {
|
|
|
343
387
|
|
|
344
388
|
/**
|
|
345
389
|
* Verify deterministic behavior across multiple runs
|
|
390
|
+
* @param {string} template - Template to verify
|
|
391
|
+
* @param {Object} context - Context for rendering
|
|
392
|
+
* @param {number} [iterations=3] - Number of iterations to test
|
|
393
|
+
* @returns {Promise<Object>} Verification result with isDeterministic, iterations, successfulRuns, uniqueOutputs, results
|
|
346
394
|
*/
|
|
347
395
|
async verifyDeterminism(template, context, iterations = 3) {
|
|
348
396
|
const results = [];
|
package/src/core/parser.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KGEN Template Parser - Parse template syntax without nunjucks
|
|
2
|
+
* @file KGEN Template Parser - Parse template syntax without nunjucks
|
|
3
|
+
* @module @unrdf/kgn/core/parser
|
|
3
4
|
*
|
|
5
|
+
* @description
|
|
4
6
|
* Supports:
|
|
5
7
|
* - Variables: {{ variable }}
|
|
6
8
|
* - Filters: {{ variable | filter }}
|
|
@@ -12,7 +14,17 @@
|
|
|
12
14
|
|
|
13
15
|
// Use existing frontmatter parser if available, fallback to basic parsing
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* KGEN Template Parser class
|
|
19
|
+
*/
|
|
15
20
|
export class KGenParser {
|
|
21
|
+
/**
|
|
22
|
+
* Create a new KGenParser instance
|
|
23
|
+
* @param {Object} [options={}] - Parser configuration options
|
|
24
|
+
* @param {number} [options.maxDepth=10] - Maximum nesting depth for templates
|
|
25
|
+
* @param {boolean} [options.enableIncludes=true] - Enable include statement processing
|
|
26
|
+
* @param {boolean} [options.strictMode=true] - Enable strict syntax validation
|
|
27
|
+
*/
|
|
16
28
|
constructor(options = {}) {
|
|
17
29
|
this.options = {
|
|
18
30
|
maxDepth: options.maxDepth || 10,
|
|
@@ -32,6 +44,16 @@ export class KGenParser {
|
|
|
32
44
|
|
|
33
45
|
/**
|
|
34
46
|
* Parse template content into structured format
|
|
47
|
+
* @param {string} template - Template content to parse
|
|
48
|
+
* @returns {Promise<Object>} Parse result with template structure
|
|
49
|
+
* @returns {string} return.template - Parsed template content
|
|
50
|
+
* @returns {Object} return.frontmatter - Extracted frontmatter data
|
|
51
|
+
* @returns {Array<string>} return.variables - Extracted variable names
|
|
52
|
+
* @returns {Array<Object>} return.expressions - Extracted expressions
|
|
53
|
+
* @returns {Array<Object>} return.includes - Include statements
|
|
54
|
+
* @returns {Array<Object>} return.comments - Template comments
|
|
55
|
+
* @returns {Object} return.structure - Structural analysis
|
|
56
|
+
* @throws {Error} When parse error occurs
|
|
35
57
|
*/
|
|
36
58
|
async parse(template) {
|
|
37
59
|
try {
|
|
@@ -62,6 +84,10 @@ export class KGenParser {
|
|
|
62
84
|
|
|
63
85
|
/**
|
|
64
86
|
* Parse frontmatter from template
|
|
87
|
+
* @param {string} template - Template content with optional frontmatter
|
|
88
|
+
* @returns {Object} Frontmatter parse result
|
|
89
|
+
* @returns {Object} return.frontmatter - Parsed frontmatter data
|
|
90
|
+
* @returns {string} return.content - Template content without frontmatter
|
|
65
91
|
*/
|
|
66
92
|
parseFrontmatter(template) {
|
|
67
93
|
const match = template.match(this.patterns.frontmatter);
|
|
@@ -96,6 +122,8 @@ export class KGenParser {
|
|
|
96
122
|
|
|
97
123
|
/**
|
|
98
124
|
* Basic YAML parser for frontmatter (simplified)
|
|
125
|
+
* @param {string} yamlContent - YAML content to parse
|
|
126
|
+
* @returns {Object} Parsed YAML data as JavaScript object
|
|
99
127
|
*/
|
|
100
128
|
parseBasicYAML(yamlContent) {
|
|
101
129
|
const result = {};
|
|
@@ -134,6 +162,8 @@ export class KGenParser {
|
|
|
134
162
|
|
|
135
163
|
/**
|
|
136
164
|
* Extract variables from template content
|
|
165
|
+
* @param {string} content - Template content to analyze
|
|
166
|
+
* @returns {Array<string>} Array of required variable names
|
|
137
167
|
*/
|
|
138
168
|
extractVariables(content) {
|
|
139
169
|
const variables = new Set();
|
|
@@ -175,6 +205,8 @@ export class KGenParser {
|
|
|
175
205
|
|
|
176
206
|
/**
|
|
177
207
|
* Extract expressions (conditionals, loops, etc.)
|
|
208
|
+
* @param {string} content - Template content to analyze
|
|
209
|
+
* @returns {Array<Object>} Array of expression objects with type, expression, position, raw
|
|
178
210
|
*/
|
|
179
211
|
extractExpressions(content) {
|
|
180
212
|
const expressions = [];
|
|
@@ -200,6 +232,8 @@ export class KGenParser {
|
|
|
200
232
|
|
|
201
233
|
/**
|
|
202
234
|
* Extract include statements
|
|
235
|
+
* @param {string} content - Template content to analyze
|
|
236
|
+
* @returns {Array<Object>} Array of include objects with path, position, raw
|
|
203
237
|
*/
|
|
204
238
|
extractIncludes(content) {
|
|
205
239
|
const includes = [];
|
|
@@ -223,6 +257,8 @@ export class KGenParser {
|
|
|
223
257
|
|
|
224
258
|
/**
|
|
225
259
|
* Extract comments
|
|
260
|
+
* @param {string} content - Template content to analyze
|
|
261
|
+
* @returns {Array<Object>} Array of comment objects with text, position, raw
|
|
226
262
|
*/
|
|
227
263
|
extractComments(content) {
|
|
228
264
|
const comments = [];
|
|
@@ -244,6 +280,8 @@ export class KGenParser {
|
|
|
244
280
|
|
|
245
281
|
/**
|
|
246
282
|
* Analyze template structure
|
|
283
|
+
* @param {string} content - Template content to analyze
|
|
284
|
+
* @returns {Object} Structure analysis with conditionals, loops, includes, blocks, macros, depth counts
|
|
247
285
|
*/
|
|
248
286
|
analyzeStructure(content) {
|
|
249
287
|
const expressions = this.extractExpressions(content);
|
|
@@ -309,6 +347,8 @@ export class KGenParser {
|
|
|
309
347
|
|
|
310
348
|
/**
|
|
311
349
|
* Get expression type from expression string
|
|
350
|
+
* @param {string} expr - Expression string to classify
|
|
351
|
+
* @returns {string} Expression type (if, else, elif, endif, for, endfor, include, block, endblock, macro, endmacro, set, unknown)
|
|
312
352
|
*/
|
|
313
353
|
getExpressionType(expr) {
|
|
314
354
|
const trimmed = expr.trim().toLowerCase();
|
|
@@ -331,6 +371,8 @@ export class KGenParser {
|
|
|
331
371
|
|
|
332
372
|
/**
|
|
333
373
|
* Check if variable is a built-in
|
|
374
|
+
* @param {string} name - Variable name to check
|
|
375
|
+
* @returns {boolean} True if variable is a built-in
|
|
334
376
|
*/
|
|
335
377
|
isBuiltinVariable(name) {
|
|
336
378
|
const builtins = new Set([
|
|
@@ -342,6 +384,10 @@ export class KGenParser {
|
|
|
342
384
|
|
|
343
385
|
/**
|
|
344
386
|
* Validate template syntax
|
|
387
|
+
* @param {Object} parseResult - Parse result to validate
|
|
388
|
+
* @param {Array<Object>} parseResult.expressions - Expressions to validate
|
|
389
|
+
* @param {Object} parseResult.structure - Structure to validate
|
|
390
|
+
* @throws {Error} When syntax validation fails
|
|
345
391
|
*/
|
|
346
392
|
validateSyntax(parseResult) {
|
|
347
393
|
const { expressions } = parseResult;
|
|
@@ -402,6 +448,10 @@ export class KGenParser {
|
|
|
402
448
|
|
|
403
449
|
/**
|
|
404
450
|
* Check if template is deterministic
|
|
451
|
+
* @param {Object} parseResult - Parse result to check
|
|
452
|
+
* @param {Array<string>} parseResult.variables - Variables to check
|
|
453
|
+
* @param {Array<Object>} parseResult.expressions - Expressions to check
|
|
454
|
+
* @returns {Object} Result with deterministic boolean and reasons array
|
|
405
455
|
*/
|
|
406
456
|
isDeterministic(parseResult) {
|
|
407
457
|
const { variables, expressions } = parseResult;
|
|
@@ -435,6 +485,7 @@ export class KGenParser {
|
|
|
435
485
|
|
|
436
486
|
/**
|
|
437
487
|
* Get parser statistics
|
|
488
|
+
* @returns {Object} Parser configuration and supported patterns
|
|
438
489
|
*/
|
|
439
490
|
getStats() {
|
|
440
491
|
return {
|
|
@@ -9,7 +9,13 @@
|
|
|
9
9
|
* - Deterministic formatting
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
12
15
|
export class KGenPostProcessor {
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
13
19
|
constructor(options = {}) {
|
|
14
20
|
this.options = {
|
|
15
21
|
normalizeWhitespace: options.normalizeWhitespace !== false,
|
|
@@ -183,7 +189,7 @@ export class KGenPostProcessor {
|
|
|
183
189
|
let hasSpaces = false;
|
|
184
190
|
let hasTabs = false;
|
|
185
191
|
|
|
186
|
-
lines.forEach((line,
|
|
192
|
+
lines.forEach((line, _index) => {
|
|
187
193
|
const indentMatch = line.match(/^(\s*)/);
|
|
188
194
|
if (indentMatch && indentMatch[1]) {
|
|
189
195
|
if (indentMatch[1].includes(' ')) hasSpaces = true;
|
package/src/core/renderer.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* KGEN Template Renderer - Execute template logic without nunjucks
|
|
2
|
+
* @file KGEN Template Renderer - Execute template logic without nunjucks
|
|
3
|
+
* @module @unrdf/kgn/core/renderer
|
|
3
4
|
*
|
|
5
|
+
* @description
|
|
4
6
|
* Handles:
|
|
5
7
|
* - Variable interpolation: {{ variable }}
|
|
6
8
|
* - Filter application: {{ variable | filter }}
|
|
@@ -9,7 +11,18 @@
|
|
|
9
11
|
* - Include processing: {% include %}
|
|
10
12
|
*/
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* KGEN Template Renderer class
|
|
16
|
+
*/
|
|
12
17
|
export class KGenRenderer {
|
|
18
|
+
/**
|
|
19
|
+
* Create a new KGenRenderer instance
|
|
20
|
+
* @param {Object} [options={}] - Renderer configuration options
|
|
21
|
+
* @param {number} [options.maxDepth=10] - Maximum rendering depth
|
|
22
|
+
* @param {boolean} [options.enableIncludes=true] - Enable include processing
|
|
23
|
+
* @param {boolean} [options.strictMode=true] - Enable strict error handling
|
|
24
|
+
* @param {boolean} [options.deterministicMode=true] - Enable deterministic mode
|
|
25
|
+
*/
|
|
13
26
|
constructor(options = {}) {
|
|
14
27
|
this.options = {
|
|
15
28
|
maxDepth: options.maxDepth || 10,
|
|
@@ -31,6 +44,11 @@ export class KGenRenderer {
|
|
|
31
44
|
|
|
32
45
|
/**
|
|
33
46
|
* Render template with context
|
|
47
|
+
* @param {string} template - Template content to render
|
|
48
|
+
* @param {Object} context - Context data for template variables
|
|
49
|
+
* @param {Object} [options={}] - Rendering options
|
|
50
|
+
* @param {Object} options.filters - Filter instance (required)
|
|
51
|
+
* @returns {Promise<Object>} Render result with content and metadata
|
|
34
52
|
*/
|
|
35
53
|
async render(template, context, options = {}) {
|
|
36
54
|
this.renderDepth = 0;
|
|
@@ -59,6 +77,11 @@ export class KGenRenderer {
|
|
|
59
77
|
|
|
60
78
|
/**
|
|
61
79
|
* Process template content recursively
|
|
80
|
+
* @param {string} template - Template content
|
|
81
|
+
* @param {Object} context - Context data
|
|
82
|
+
* @param {Object} filters - Filter instance
|
|
83
|
+
* @param {number} [depth=0] - Current recursion depth
|
|
84
|
+
* @returns {Promise<string>} Processed template content
|
|
62
85
|
*/
|
|
63
86
|
async processTemplate(template, context, filters, depth = 0) {
|
|
64
87
|
if (depth > this.options.maxDepth) {
|
|
@@ -83,6 +106,8 @@ export class KGenRenderer {
|
|
|
83
106
|
|
|
84
107
|
/**
|
|
85
108
|
* Remove template comments
|
|
109
|
+
* @param {string} template - Template content
|
|
110
|
+
* @returns {string} Template without comments
|
|
86
111
|
*/
|
|
87
112
|
removeComments(template) {
|
|
88
113
|
return template.replace(this.patterns.comment, '');
|
|
@@ -90,6 +115,11 @@ export class KGenRenderer {
|
|
|
90
115
|
|
|
91
116
|
/**
|
|
92
117
|
* Process template expressions (if, for, etc.)
|
|
118
|
+
* @param {string} template - Template content
|
|
119
|
+
* @param {Object} context - Context data
|
|
120
|
+
* @param {Object} filters - Filter instance
|
|
121
|
+
* @param {number} depth - Current recursion depth
|
|
122
|
+
* @returns {Promise<string>} Processed template
|
|
93
123
|
*/
|
|
94
124
|
async processExpressions(template, context, filters, depth) {
|
|
95
125
|
let processed = template;
|
|
@@ -110,6 +140,11 @@ export class KGenRenderer {
|
|
|
110
140
|
|
|
111
141
|
/**
|
|
112
142
|
* Process conditional expressions
|
|
143
|
+
* @param {string} template - Template content
|
|
144
|
+
* @param {Object} context - Context data
|
|
145
|
+
* @param {Object} filters - Filter instance
|
|
146
|
+
* @param {number} depth - Current recursion depth
|
|
147
|
+
* @returns {Promise<string>} Processed template with conditionals resolved
|
|
113
148
|
*/
|
|
114
149
|
async processConditionals(template, context, filters, depth) {
|
|
115
150
|
const ifPattern = /\{\%\s*if\s+([^%]+)\s*\%\}([\s\S]*?)(\{\%\s*else\s*\%\}([\s\S]*?))?\{\%\s*endif\s*\%\}/g;
|
|
@@ -155,6 +190,11 @@ export class KGenRenderer {
|
|
|
155
190
|
|
|
156
191
|
/**
|
|
157
192
|
* Process loop expressions
|
|
193
|
+
* @param {string} template - Template content
|
|
194
|
+
* @param {Object} context - Context data
|
|
195
|
+
* @param {Object} filters - Filter instance
|
|
196
|
+
* @param {number} depth - Current recursion depth
|
|
197
|
+
* @returns {Promise<string>} Processed template with loops expanded
|
|
158
198
|
*/
|
|
159
199
|
async processLoops(template, context, filters, depth) {
|
|
160
200
|
const forPattern = /\{\%\s*for\s+(\w+)\s+in\s+([^%]+)\s*\%\}([\s\S]*?)\{\%\s*endfor\s*\%\}/g;
|
|
@@ -235,6 +275,11 @@ export class KGenRenderer {
|
|
|
235
275
|
|
|
236
276
|
/**
|
|
237
277
|
* Process include expressions
|
|
278
|
+
* @param {string} template - Template content
|
|
279
|
+
* @param {Object} context - Context data
|
|
280
|
+
* @param {Object} filters - Filter instance
|
|
281
|
+
* @param {number} depth - Current recursion depth
|
|
282
|
+
* @returns {Promise<string>} Processed template with includes resolved
|
|
238
283
|
*/
|
|
239
284
|
async processIncludes(template, context, filters, depth) {
|
|
240
285
|
const includePattern = /\{\%\s*include\s+['"]([^'"]+)['"]\s*\%\}/g;
|
|
@@ -260,6 +305,10 @@ export class KGenRenderer {
|
|
|
260
305
|
|
|
261
306
|
/**
|
|
262
307
|
* Process variable interpolations and filters
|
|
308
|
+
* @param {string} template - Template content
|
|
309
|
+
* @param {Object} context - Context data
|
|
310
|
+
* @param {Object} filters - Filter instance
|
|
311
|
+
* @returns {string} Template with variables interpolated
|
|
263
312
|
*/
|
|
264
313
|
processVariables(template, context, filters) {
|
|
265
314
|
return template.replace(this.patterns.variable, (match, expression) => {
|
|
@@ -315,6 +364,9 @@ export class KGenRenderer {
|
|
|
315
364
|
|
|
316
365
|
/**
|
|
317
366
|
* Evaluate condition expression
|
|
367
|
+
* @param {string} condition - Condition expression to evaluate
|
|
368
|
+
* @param {Object} context - Context data
|
|
369
|
+
* @returns {boolean} Evaluation result
|
|
318
370
|
*/
|
|
319
371
|
evaluateCondition(condition, context) {
|
|
320
372
|
// Simple condition evaluation
|
|
@@ -341,6 +393,9 @@ export class KGenRenderer {
|
|
|
341
393
|
|
|
342
394
|
/**
|
|
343
395
|
* Evaluate expression to get value from context
|
|
396
|
+
* @param {string} expr - Expression to evaluate
|
|
397
|
+
* @param {Object} context - Context data
|
|
398
|
+
* @returns {*} Evaluated value
|
|
344
399
|
*/
|
|
345
400
|
evaluateExpression(expr, context) {
|
|
346
401
|
if (!expr) return '';
|
|
@@ -377,6 +432,8 @@ export class KGenRenderer {
|
|
|
377
432
|
|
|
378
433
|
/**
|
|
379
434
|
* Parse filter arguments from a comma-separated string, respecting quotes
|
|
435
|
+
* @param {string} argsStr - Arguments string
|
|
436
|
+
* @returns {Array<string>} Parsed arguments
|
|
380
437
|
*/
|
|
381
438
|
parseFilterArguments(argsStr) {
|
|
382
439
|
const args = [];
|
|
@@ -412,6 +469,9 @@ export class KGenRenderer {
|
|
|
412
469
|
|
|
413
470
|
/**
|
|
414
471
|
* Parse argument value (string, number, or variable reference)
|
|
472
|
+
* @param {string} arg - Argument to parse
|
|
473
|
+
* @param {Object} context - Context data
|
|
474
|
+
* @returns {*} Parsed value
|
|
415
475
|
*/
|
|
416
476
|
parseArgument(arg, context) {
|
|
417
477
|
// Handle quoted strings
|
|
@@ -435,6 +495,9 @@ export class KGenRenderer {
|
|
|
435
495
|
|
|
436
496
|
/**
|
|
437
497
|
* Parse value with context substitution
|
|
498
|
+
* @param {string} value - Value to parse
|
|
499
|
+
* @param {Object} context - Context data
|
|
500
|
+
* @returns {*} Parsed value
|
|
438
501
|
*/
|
|
439
502
|
parseValue(value, context) {
|
|
440
503
|
return this.parseArgument(value, context);
|
|
@@ -442,6 +505,8 @@ export class KGenRenderer {
|
|
|
442
505
|
|
|
443
506
|
/**
|
|
444
507
|
* Check if value is truthy in template context
|
|
508
|
+
* @param {*} value - Value to check
|
|
509
|
+
* @returns {boolean} True if value is truthy
|
|
445
510
|
*/
|
|
446
511
|
isTruthy(value) {
|
|
447
512
|
if (value === null || value === undefined) return false;
|
|
@@ -456,6 +521,7 @@ export class KGenRenderer {
|
|
|
456
521
|
|
|
457
522
|
/**
|
|
458
523
|
* Get renderer statistics
|
|
524
|
+
* @returns {Object} Renderer configuration and statistics
|
|
459
525
|
*/
|
|
460
526
|
getStats() {
|
|
461
527
|
return {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import nunjucks from 'nunjucks';
|
|
7
7
|
import { dirname, join } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { readFileSync } from 'fs';
|
|
9
|
+
import { readFileSync as _readFileSync } from 'fs';
|
|
10
10
|
|
|
11
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
12
|
const __dirname = dirname(__filename);
|
|
@@ -76,7 +76,7 @@ export function buildRDFGraph(parsedFile) {
|
|
|
76
76
|
triples.push('');
|
|
77
77
|
|
|
78
78
|
// Exports
|
|
79
|
-
parsedFile.exports.forEach((exp,
|
|
79
|
+
parsedFile.exports.forEach((exp, _idx) => {
|
|
80
80
|
const exportURI = `${fileURI}#${exp.name}`;
|
|
81
81
|
|
|
82
82
|
triples.push(`# Export: ${exp.name}`);
|
|
@@ -131,7 +131,7 @@ export function buildRDFGraph(parsedFile) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
// Examples
|
|
134
|
-
exp.examples?.forEach((example,
|
|
134
|
+
exp.examples?.forEach((example, _exIdx) => {
|
|
135
135
|
triples.push(` doc:example ${escapeLiteral(example)} ;`);
|
|
136
136
|
});
|
|
137
137
|
|
package/src/engine/index.js
CHANGED
|
@@ -5,11 +5,20 @@
|
|
|
5
5
|
* 100% Deterministic guarantees with cryptographic attestation
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// Import classes for local use
|
|
9
|
+
import { TemplateEngine } from './template-engine.js';
|
|
10
|
+
import { DeterministicRenderer } from './renderer.js';
|
|
11
|
+
import { DeterministicPipeline } from './pipeline.js';
|
|
12
|
+
|
|
13
|
+
// Re-export for external use
|
|
8
14
|
export { TemplateEngine } from './template-engine.js';
|
|
9
15
|
export { DeterministicRenderer } from './renderer.js';
|
|
10
16
|
export { DeterministicPipeline } from './pipeline.js';
|
|
11
17
|
|
|
12
18
|
// Factory for deterministic engine with complete pipeline
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
13
22
|
export function createDeterministicEngine(options = {}) {
|
|
14
23
|
const pipeline = new DeterministicPipeline(options);
|
|
15
24
|
|
package/src/engine/pipeline.js
CHANGED
|
@@ -17,7 +17,13 @@
|
|
|
17
17
|
|
|
18
18
|
import { DeterministicRenderer } from './renderer.js';
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
20
23
|
export class DeterministicPipeline {
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
21
27
|
constructor(options = {}) {
|
|
22
28
|
this.renderer = new DeterministicRenderer(options);
|
|
23
29
|
this.enableValidation = options.enableValidation !== false;
|
|
@@ -348,7 +354,7 @@ export class DeterministicPipeline {
|
|
|
348
354
|
/**
|
|
349
355
|
* Verify pipeline result integrity
|
|
350
356
|
*/
|
|
351
|
-
async _verifyPipelineResult(attestResult,
|
|
357
|
+
async _verifyPipelineResult(attestResult, _template, _data) {
|
|
352
358
|
const expectedHash = this.renderer._hashContent(attestResult.content);
|
|
353
359
|
const actualHash = attestResult.contentHash;
|
|
354
360
|
|
package/src/engine/renderer.js
CHANGED
|
@@ -17,7 +17,13 @@
|
|
|
17
17
|
import crypto from 'crypto';
|
|
18
18
|
import path from 'path';
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
20
23
|
export class DeterministicRenderer {
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
21
27
|
constructor(options = {}) {
|
|
22
28
|
// Core configuration
|
|
23
29
|
this.staticBuildTime = options.staticBuildTime || '2024-01-01T00:00:00.000Z';
|
|
@@ -388,7 +394,7 @@ export class DeterministicRenderer {
|
|
|
388
394
|
/**
|
|
389
395
|
* Validate data context against template requirements
|
|
390
396
|
*/
|
|
391
|
-
_validateDataContext(data,
|
|
397
|
+
_validateDataContext(data, _variables) {
|
|
392
398
|
const validated = { ...data };
|
|
393
399
|
|
|
394
400
|
// Add deterministic metadata
|
|
@@ -479,7 +485,7 @@ export class DeterministicRenderer {
|
|
|
479
485
|
/**
|
|
480
486
|
* Execute main template rendering
|
|
481
487
|
*/
|
|
482
|
-
async _executeRender(plan,
|
|
488
|
+
async _executeRender(plan, _context, _includes) {
|
|
483
489
|
// This would integrate with the template engine
|
|
484
490
|
// For now, return processed template content
|
|
485
491
|
return `${plan.structure.template}\n<!-- Rendered deterministically at ${this.staticBuildTime} -->`;
|
|
@@ -547,6 +553,9 @@ export class DeterministicRenderer {
|
|
|
547
553
|
|
|
548
554
|
// DEFAULT DEPENDENCY IMPLEMENTATIONS (for production use)
|
|
549
555
|
|
|
556
|
+
/**
|
|
557
|
+
*
|
|
558
|
+
*/
|
|
550
559
|
_createDefaultLoader() {
|
|
551
560
|
return {
|
|
552
561
|
async load(templatePath) {
|
|
@@ -556,6 +565,9 @@ export class DeterministicRenderer {
|
|
|
556
565
|
};
|
|
557
566
|
}
|
|
558
567
|
|
|
568
|
+
/**
|
|
569
|
+
*
|
|
570
|
+
*/
|
|
559
571
|
_createDefaultResolver() {
|
|
560
572
|
return {
|
|
561
573
|
resolve(includePath, basePath) {
|
|
@@ -564,9 +576,12 @@ export class DeterministicRenderer {
|
|
|
564
576
|
};
|
|
565
577
|
}
|
|
566
578
|
|
|
579
|
+
/**
|
|
580
|
+
*
|
|
581
|
+
*/
|
|
567
582
|
_createDefaultProvider() {
|
|
568
583
|
return {
|
|
569
|
-
async query(
|
|
584
|
+
async query(_sparqlQuery) {
|
|
570
585
|
// Default implementation - could integrate with RDF stores
|
|
571
586
|
return [];
|
|
572
587
|
}
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
import nunjucks from 'nunjucks';
|
|
24
24
|
import crypto from 'crypto';
|
|
25
25
|
import path from 'path';
|
|
26
|
-
import { Worker, isMainThread } from 'worker_threads';
|
|
27
|
-
import { Transform } from 'stream';
|
|
28
|
-
import { performance } from 'perf_hooks';
|
|
26
|
+
import { Worker as _Worker, isMainThread as _isMainThread } from 'worker_threads';
|
|
27
|
+
import { Transform as _Transform } from 'stream';
|
|
28
|
+
import { performance as _performance } from 'perf_hooks';
|
|
29
29
|
import { createCustomFilters } from '../filters/index.js';
|
|
30
30
|
import { FrontmatterParser } from '../parser/frontmatter.js';
|
|
31
31
|
import { VariableExtractor } from '../parser/variables.js';
|
|
@@ -150,7 +150,13 @@ class TemplateContextPool {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
*
|
|
155
|
+
*/
|
|
153
156
|
export class TemplateEngine {
|
|
157
|
+
/**
|
|
158
|
+
*
|
|
159
|
+
*/
|
|
154
160
|
constructor(options = {}) {
|
|
155
161
|
this.templatesDir = options.templatesDir || './templates';
|
|
156
162
|
this.enableCache = options.enableCache !== false;
|
|
@@ -503,6 +509,9 @@ export class TemplateEngine {
|
|
|
503
509
|
* Wrapper that provides both basic and inheritance-enabled rendering
|
|
504
510
|
*/
|
|
505
511
|
export class EnhancedTemplateEngine extends TemplateEngine {
|
|
512
|
+
/**
|
|
513
|
+
*
|
|
514
|
+
*/
|
|
506
515
|
constructor(options = {}) {
|
|
507
516
|
super({
|
|
508
517
|
...options,
|