@unrdf/kgn 5.0.1

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 (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/package.json +90 -0
  4. package/src/MIGRATION_COMPLETE.md +186 -0
  5. package/src/PORT-MAP.md +302 -0
  6. package/src/base/filter-templates.js +479 -0
  7. package/src/base/index.js +92 -0
  8. package/src/base/injection-targets.js +583 -0
  9. package/src/base/macro-templates.js +298 -0
  10. package/src/base/macro-templates.js.bak +461 -0
  11. package/src/base/shacl-templates.js +617 -0
  12. package/src/base/template-base.js +388 -0
  13. package/src/core/attestor.js +381 -0
  14. package/src/core/filters.js +518 -0
  15. package/src/core/index.js +21 -0
  16. package/src/core/kgen-engine.js +372 -0
  17. package/src/core/parser.js +447 -0
  18. package/src/core/post-processor.js +313 -0
  19. package/src/core/renderer.js +469 -0
  20. package/src/doc-generator/cli.mjs +122 -0
  21. package/src/doc-generator/index.mjs +28 -0
  22. package/src/doc-generator/mdx-generator.mjs +71 -0
  23. package/src/doc-generator/nav-generator.mjs +136 -0
  24. package/src/doc-generator/parser.mjs +291 -0
  25. package/src/doc-generator/rdf-builder.mjs +306 -0
  26. package/src/doc-generator/scanner.mjs +189 -0
  27. package/src/engine/index.js +42 -0
  28. package/src/engine/pipeline.js +448 -0
  29. package/src/engine/renderer.js +604 -0
  30. package/src/engine/template-engine.js +566 -0
  31. package/src/filters/array.js +436 -0
  32. package/src/filters/data.js +479 -0
  33. package/src/filters/index.js +270 -0
  34. package/src/filters/rdf.js +264 -0
  35. package/src/filters/text.js +369 -0
  36. package/src/index.js +109 -0
  37. package/src/inheritance/index.js +40 -0
  38. package/src/injection/api.js +260 -0
  39. package/src/injection/atomic-writer.js +327 -0
  40. package/src/injection/constants.js +136 -0
  41. package/src/injection/idempotency-manager.js +295 -0
  42. package/src/injection/index.js +28 -0
  43. package/src/injection/injection-engine.js +378 -0
  44. package/src/injection/integration.js +339 -0
  45. package/src/injection/modes/index.js +341 -0
  46. package/src/injection/rollback-manager.js +373 -0
  47. package/src/injection/target-resolver.js +323 -0
  48. package/src/injection/tests/atomic-writer.test.js +382 -0
  49. package/src/injection/tests/injection-engine.test.js +611 -0
  50. package/src/injection/tests/integration.test.js +392 -0
  51. package/src/injection/tests/run-tests.js +283 -0
  52. package/src/injection/validation-engine.js +547 -0
  53. package/src/linter/determinism-linter.js +473 -0
  54. package/src/linter/determinism.js +410 -0
  55. package/src/linter/index.js +6 -0
  56. package/src/linter/test-doubles.js +475 -0
  57. package/src/parser/frontmatter.js +228 -0
  58. package/src/parser/variables.js +344 -0
  59. package/src/renderer/deterministic.js +245 -0
  60. package/src/renderer/index.js +6 -0
  61. package/src/templates/latex/academic-paper.njk +186 -0
  62. package/src/templates/latex/index.js +104 -0
  63. package/src/templates/nextjs/app-page.njk +66 -0
  64. package/src/templates/nextjs/index.js +80 -0
  65. package/src/templates/office/docx/document.njk +368 -0
  66. package/src/templates/office/index.js +79 -0
  67. package/src/templates/office/word-report.njk +129 -0
  68. package/src/utils/template-utils.js +426 -0
@@ -0,0 +1,479 @@
1
+ /**
2
+ * KGEN Filter Templates - Deterministic filter definitions
3
+ *
4
+ * Provides templates for creating custom filters that maintain deterministic behavior
5
+ * All filter templates are designed to be composable and reusable
6
+ */
7
+
8
+ import crypto from 'crypto';
9
+
10
+ export class KGenFilterTemplates {
11
+ constructor(options = {}) {
12
+ this.options = {
13
+ deterministicMode: options.deterministicMode !== false,
14
+ staticBuildTime: options.staticBuildTime || '2024-01-01T00:00:00.000Z',
15
+ namespace: options.namespace || 'kgen',
16
+ ...options
17
+ };
18
+
19
+ this.filterTemplates = new Map();
20
+ this.initializeFilterTemplates();
21
+ }
22
+
23
+ /**
24
+ * Initialize built-in filter templates
25
+ */
26
+ initializeFilterTemplates() {
27
+ // Basic filter template
28
+ this.registerFilterTemplate('basic_filter', {
29
+ name: '{{ filterName }}',
30
+ description: '{{ filterDescription | default("Custom filter") }}',
31
+ code: `(value, ...args) => {
32
+ // Input validation
33
+ if (value === null || value === undefined) {
34
+ return {{ defaultValue | default('value') }};
35
+ }
36
+
37
+ // Filter logic
38
+ {{ filterLogic | default('return value;') }}
39
+ }`,
40
+ tests: [
41
+ {
42
+ input: '{{ testInput | default("test") }}',
43
+ expected: '{{ testOutput | default("test") }}',
44
+ description: 'Basic test case'
45
+ }
46
+ ]
47
+ });
48
+
49
+ // Text processing filter template
50
+ this.registerFilterTemplate('text_filter', {
51
+ name: '{{ filterName }}',
52
+ description: 'Text processing filter: {{ filterDescription }}',
53
+ code: `(text, options = {}) => {
54
+ const str = String(text || '');
55
+
56
+ if (str === '') {
57
+ return {{ emptyValue | default('str') }};
58
+ }
59
+
60
+ // Text processing options
61
+ const {
62
+ {{ filterOptions | join(',\n ') | default('trim = true') }}
63
+ } = options;
64
+
65
+ let result = str;
66
+
67
+ {{ textProcessingSteps | default('// Processing steps here') }}
68
+
69
+ return result;
70
+ }`,
71
+ tests: [
72
+ {
73
+ input: '" Hello World "',
74
+ expected: '"Hello World"',
75
+ description: 'Text trimming'
76
+ }
77
+ ]
78
+ });
79
+
80
+ // Array processing filter template
81
+ this.registerFilterTemplate('array_filter', {
82
+ name: '{{ filterName }}',
83
+ description: 'Array processing filter: {{ filterDescription }}',
84
+ code: `(array, {{ filterParams | default('') }}) => {
85
+ if (!Array.isArray(array)) {
86
+ return {{ nonArrayDefault | default('[]') }};
87
+ }
88
+
89
+ if (array.length === 0) {
90
+ return {{ emptyArrayDefault | default('array') }};
91
+ }
92
+
93
+ // Array processing
94
+ const result = array{{ arrayMethod | default('.map(item => item)') }};
95
+
96
+ {{ additionalProcessing | default('// Additional processing') }}
97
+
98
+ return result;
99
+ }`,
100
+ tests: [
101
+ {
102
+ input: '[1, 2, 3, 4, 5]',
103
+ expected: '[1, 2, 3, 4, 5]',
104
+ description: 'Array processing test'
105
+ }
106
+ ]
107
+ });
108
+
109
+ // Object processing filter template
110
+ this.registerFilterTemplate('object_filter', {
111
+ name: '{{ filterName }}',
112
+ description: 'Object processing filter: {{ filterDescription }}',
113
+ code: `(obj, {{ filterParams | default('') }}) => {
114
+ if (typeof obj !== 'object' || obj === null) {
115
+ return {{ nonObjectDefault | default('{}') }};
116
+ }
117
+
118
+ const result = {{ objectDefault | default('{}') }};
119
+
120
+ {{ objectProcessing | default('// Object processing logic') }}
121
+
122
+ return result;
123
+ }`,
124
+ tests: [
125
+ {
126
+ input: '{ "name": "test" }',
127
+ expected: '{ "name": "test" }',
128
+ description: 'Object processing test'
129
+ }
130
+ ]
131
+ });
132
+
133
+ // Deterministic filter template
134
+ this.registerFilterTemplate('deterministic_filter', {
135
+ name: '{{ filterName }}',
136
+ description: 'Deterministic filter: {{ filterDescription }}',
137
+ code: `(value, options = {}) => {
138
+ const { deterministicMode = ${this.options.deterministicMode} } = options;
139
+
140
+ // Deterministic behavior check
141
+ if (deterministicMode) {
142
+ {{ deterministicLogic | default('// Deterministic implementation') }}
143
+ } else {
144
+ {{ nonDeterministicLogic | default('// Non-deterministic implementation') }}
145
+ }
146
+
147
+ return value;
148
+ }`,
149
+ tests: [
150
+ {
151
+ input: '"test"',
152
+ options: '{ deterministicMode: true }',
153
+ expected: '"test"',
154
+ description: 'Deterministic mode test'
155
+ }
156
+ ]
157
+ });
158
+
159
+ // Hash filter template
160
+ this.registerFilterTemplate('hash_filter', {
161
+ name: '{{ filterName }}',
162
+ description: 'Hash-based filter: {{ filterDescription }}',
163
+ code: `(content, algorithm = 'sha256', length = null) => {
164
+ const hash = crypto.createHash(algorithm)
165
+ .update(String(content || ''), 'utf8')
166
+ .digest('hex');
167
+
168
+ return length ? hash.substring(0, length) : hash;
169
+ }`,
170
+ tests: [
171
+ {
172
+ input: '"hello"',
173
+ expected: 'hash string',
174
+ description: 'Hash generation test'
175
+ }
176
+ ]
177
+ });
178
+
179
+ // Validation filter template
180
+ this.registerFilterTemplate('validation_filter', {
181
+ name: '{{ filterName }}',
182
+ description: 'Validation filter: {{ filterDescription }}',
183
+ code: `(value, rules = {}) => {
184
+ const errors = [];
185
+
186
+ {{ validationRules | default('// Validation rules') }}
187
+
188
+ if (errors.length > 0) {
189
+ {{ onValidationError | default('throw new Error(\'Validation failed: \' + errors.join(\', \'));') }}
190
+ }
191
+
192
+ return value;
193
+ }`,
194
+ tests: [
195
+ {
196
+ input: '"valid_value"',
197
+ expected: '"valid_value"',
198
+ description: 'Valid input test'
199
+ }
200
+ ]
201
+ });
202
+
203
+ // Format filter template
204
+ this.registerFilterTemplate('format_filter', {
205
+ name: '{{ filterName }}',
206
+ description: 'Format filter: {{ filterDescription }}',
207
+ code: `(value, format = '{{ defaultFormat | default("default") }}') => {
208
+ if (value === null || value === undefined) {
209
+ return '';
210
+ }
211
+
212
+ switch (format) {
213
+ {{ formatCases | default('case "default": return String(value);') }}
214
+ default:
215
+ return String(value);
216
+ }
217
+ }`,
218
+ tests: [
219
+ {
220
+ input: '"test"',
221
+ format: '"default"',
222
+ expected: '"test"',
223
+ description: 'Default format test'
224
+ }
225
+ ]
226
+ });
227
+
228
+ // Composition filter template
229
+ this.registerFilterTemplate('composition_filter', {
230
+ name: '{{ filterName }}',
231
+ description: 'Composition filter: {{ filterDescription }}',
232
+ code: `(value, filters = [], context = {}) => {
233
+ let result = value;
234
+
235
+ for (const filter of filters) {
236
+ if (typeof filter === 'function') {
237
+ result = filter(result, context);
238
+ } else if (typeof filter === 'string' && context.filters && context.filters[filter]) {
239
+ result = context.filters[filter](result);
240
+ }
241
+ }
242
+
243
+ return result;
244
+ }`,
245
+ tests: [
246
+ {
247
+ input: '"test"',
248
+ filters: '[]',
249
+ expected: '"test"',
250
+ description: 'Empty composition test'
251
+ }
252
+ ]
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Register a filter template
258
+ */
259
+ registerFilterTemplate(name, template) {
260
+ this.filterTemplates.set(name, {
261
+ ...template,
262
+ registered: this.options.staticBuildTime,
263
+ namespace: this.options.namespace
264
+ });
265
+ }
266
+
267
+ /**
268
+ * Generate filter code from template
269
+ */
270
+ generateFilter(templateName, context = {}) {
271
+ const template = this.filterTemplates.get(templateName);
272
+ if (!template) {
273
+ throw new Error(`Filter template '${templateName}' not found`);
274
+ }
275
+
276
+ // Simple template substitution
277
+ let code = template.code;
278
+
279
+ // Replace template variables
280
+ for (const [key, value] of Object.entries(context)) {
281
+ const regex = new RegExp(`{{\\s*${key}\\s*(?:\\|[^}]*)?\\s*}}`, 'g');
282
+
283
+ // Handle default values
284
+ const matches = code.match(regex);
285
+ if (matches) {
286
+ for (const match of matches) {
287
+ const defaultMatch = match.match(/\|\s*default\('([^']*)'\)/);
288
+ const replacement = value !== undefined ? value : (defaultMatch ? defaultMatch[1] : match);
289
+ code = code.replace(match, replacement);
290
+ }
291
+ } else {
292
+ // Simple replacement without defaults
293
+ const simpleRegex = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
294
+ code = code.replace(simpleRegex, String(value || ''));
295
+ }
296
+ }
297
+
298
+ return {
299
+ name: this.interpolate(template.name, context),
300
+ description: this.interpolate(template.description, context),
301
+ code,
302
+ tests: template.tests?.map(test => ({
303
+ ...test,
304
+ input: this.interpolate(test.input, context),
305
+ expected: this.interpolate(test.expected, context)
306
+ })) || []
307
+ };
308
+ }
309
+
310
+ /**
311
+ * Generate complete filter module
312
+ */
313
+ generateFilterModule(filters = [], moduleName = 'CustomFilters') {
314
+ const generatedFilters = filters.map(filter =>
315
+ this.generateFilter(filter.template, filter.context)
316
+ );
317
+
318
+ const code = [`/**`];
319
+ code.push(` * ${moduleName} - Generated KGEN Filters`);
320
+ code.push(` * `);
321
+ code.push(` * @generated ${this.options.staticBuildTime}`);
322
+ code.push(` * @namespace ${this.options.namespace}`);
323
+ code.push(` */`);
324
+ code.push('');
325
+ code.push('import crypto from \'crypto\';');
326
+ code.push('');
327
+ code.push(`export class ${moduleName} {`);
328
+ code.push(' constructor(options = {}) {');
329
+ code.push(' this.options = { ...options };');
330
+ code.push(' this.filters = new Map();');
331
+ code.push(' this.registerFilters();');
332
+ code.push(' }');
333
+ code.push('');
334
+ code.push(' registerFilters() {');
335
+
336
+ // Add each generated filter
337
+ for (const filter of generatedFilters) {
338
+ code.push(` // ${filter.description}`);
339
+ code.push(` this.filters.set('${filter.name}', ${filter.code});`);
340
+ code.push('');
341
+ }
342
+
343
+ code.push(' }');
344
+ code.push('');
345
+ code.push(' getFilter(name) {');
346
+ code.push(' return this.filters.get(name);');
347
+ code.push(' }');
348
+ code.push('');
349
+ code.push(' getAllFilters() {');
350
+ code.push(' return Object.fromEntries(this.filters);');
351
+ code.push(' }');
352
+ code.push('}');
353
+ code.push('');
354
+ code.push(`export default ${moduleName};`);
355
+
356
+ return {
357
+ code: code.join('\n'),
358
+ filters: generatedFilters,
359
+ metadata: {
360
+ moduleName,
361
+ filterCount: generatedFilters.length,
362
+ generated: this.options.staticBuildTime,
363
+ namespace: this.options.namespace
364
+ }
365
+ };
366
+ }
367
+
368
+ /**
369
+ * Simple template interpolation
370
+ */
371
+ interpolate(template, context) {
372
+ let result = template;
373
+
374
+ for (const [key, value] of Object.entries(context)) {
375
+ const regex = new RegExp(`{{\\s*${key}\\s*(?:\\|[^}]*)?\\s*}}`, 'g');
376
+
377
+ const matches = result.match(regex);
378
+ if (matches) {
379
+ for (const match of matches) {
380
+ const defaultMatch = match.match(/\|\s*default\('([^']*)'\)/);
381
+ const replacement = value !== undefined ? value : (defaultMatch ? defaultMatch[1] : match);
382
+ result = result.replace(match, replacement);
383
+ }
384
+ }
385
+ }
386
+
387
+ return result;
388
+ }
389
+
390
+ /**
391
+ * Get available filter template names
392
+ */
393
+ getTemplateNames() {
394
+ return Array.from(this.filterTemplates.keys()).sort();
395
+ }
396
+
397
+ /**
398
+ * Get filter template by name
399
+ */
400
+ getTemplate(name) {
401
+ return this.filterTemplates.get(name);
402
+ }
403
+
404
+ /**
405
+ * Generate filter documentation
406
+ */
407
+ generateDocs(templateNames = []) {
408
+ const templates = templateNames.length > 0
409
+ ? templateNames.map(name => ({ name, ...this.filterTemplates.get(name) })).filter(t => t.name)
410
+ : Array.from(this.filterTemplates.entries()).map(([name, template]) => ({ name, ...template }));
411
+
412
+ const docs = ['# KGEN Filter Templates'];
413
+ docs.push('');
414
+ docs.push(`Generated: ${this.options.staticBuildTime}`);
415
+ docs.push(`Templates: ${templates.length}`);
416
+ docs.push('');
417
+
418
+ for (const template of templates.sort((a, b) => a.name.localeCompare(b.name))) {
419
+ docs.push(`## ${template.name}`);
420
+ docs.push('');
421
+ docs.push(template.description);
422
+ docs.push('');
423
+
424
+ if (template.tests && template.tests.length > 0) {
425
+ docs.push('### Tests');
426
+ docs.push('');
427
+
428
+ for (const test of template.tests) {
429
+ docs.push(`- **${test.description}**`);
430
+ docs.push(` - Input: \`${test.input}\``);
431
+ docs.push(` - Expected: \`${test.expected}\``);
432
+ docs.push('');
433
+ }
434
+ }
435
+
436
+ docs.push('---');
437
+ docs.push('');
438
+ }
439
+
440
+ return docs.join('\n');
441
+ }
442
+
443
+ /**
444
+ * Export filter templates
445
+ */
446
+ exportTemplates(templateNames = []) {
447
+ const templatesToExport = templateNames.length > 0
448
+ ? templateNames.filter(name => this.filterTemplates.has(name))
449
+ : Array.from(this.filterTemplates.keys());
450
+
451
+ const exported = {
452
+ format: 'kgen-filter-templates',
453
+ version: '1.0.0',
454
+ generated: this.options.staticBuildTime,
455
+ namespace: this.options.namespace,
456
+ templates: {}
457
+ };
458
+
459
+ for (const name of templatesToExport) {
460
+ exported.templates[name] = this.filterTemplates.get(name);
461
+ }
462
+
463
+ return exported;
464
+ }
465
+
466
+ /**
467
+ * Get template statistics
468
+ */
469
+ getStats() {
470
+ return {
471
+ totalTemplates: this.filterTemplates.size,
472
+ namespace: this.options.namespace,
473
+ deterministicMode: this.options.deterministicMode,
474
+ templates: Array.from(this.filterTemplates.keys()).sort()
475
+ };
476
+ }
477
+ }
478
+
479
+ export default KGenFilterTemplates;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * KGEN Base Templates - Foundation template system
3
+ *
4
+ * Exports all base template classes and utilities for building
5
+ * deterministic, reusable template components
6
+ */
7
+
8
+ // Base template foundation
9
+ export { KGenTemplateBase } from './template-base.js';
10
+
11
+ // Macro system for reusable components
12
+ export { KGenMacroTemplates } from './macro-templates.js';
13
+
14
+ // Filter system for deterministic data processing
15
+ export { KGenFilterTemplates } from './filter-templates.js';
16
+
17
+ // SHACL validation templates for RDF knowledge graphs
18
+ export { KGenSHACLTemplates } from './shacl-templates.js';
19
+
20
+ // Injection targets for code modification
21
+ export { KGenInjectionTargets } from './injection-targets.js';
22
+
23
+ // Convenience factory function
24
+ export function createBaseTemplate(options = {}) {
25
+ return new KGenTemplateBase(options);
26
+ }
27
+
28
+ // Template system factory
29
+ export function createTemplateSystem(options = {}) {
30
+ const base = new KGenTemplateBase(options);
31
+ const macros = new KGenMacroTemplates(options);
32
+ const filters = new KGenFilterTemplates(options);
33
+ const shacl = new KGenSHACLTemplates(options);
34
+ const injection = new KGenInjectionTargets(options);
35
+
36
+ return {
37
+ base,
38
+ macros,
39
+ filters,
40
+ shacl,
41
+ injection,
42
+
43
+ // Convenience methods
44
+ generateTemplate(templateName, context = {}) {
45
+ return base.generateFromTemplate(templateName, context);
46
+ },
47
+
48
+ generateMacro(macroName, context = {}) {
49
+ const macro = macros.getMacro(macroName);
50
+ if (!macro) {
51
+ throw new Error(`Macro '${macroName}' not found`);
52
+ }
53
+ return base.engine.renderTemplate(macro.template, context);
54
+ },
55
+
56
+ generateFilter(filterName, context = {}) {
57
+ return filters.generateFilter(filterName, context);
58
+ },
59
+
60
+ generateSHACLShape(shapeName, context = {}) {
61
+ return shacl.generateShape(shapeName, context);
62
+ },
63
+
64
+ generateInjectionTarget(targetName, context = {}) {
65
+ return injection.generateTarget(targetName, context);
66
+ },
67
+
68
+ // System information
69
+ getStats() {
70
+ return {
71
+ base: base.getStats(),
72
+ macros: macros.getStats(),
73
+ filters: filters.getStats(),
74
+ shacl: shacl.getStats(),
75
+ injection: injection.getStats()
76
+ };
77
+ }
78
+ };
79
+ }
80
+
81
+ // Default export object
82
+ const BaseTemplates = {
83
+ get KGenTemplateBase() { return KGenTemplateBase; },
84
+ get KGenMacroTemplates() { return KGenMacroTemplates; },
85
+ get KGenFilterTemplates() { return KGenFilterTemplates; },
86
+ get KGenSHACLTemplates() { return KGenSHACLTemplates; },
87
+ get KGenInjectionTargets() { return KGenInjectionTargets; },
88
+ createBaseTemplate,
89
+ createTemplateSystem
90
+ };
91
+
92
+ export default BaseTemplates;