@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 Data Filters - P0 Essential Data Processing
3
+ *
4
+ * The 20% of data filters that provide 80% of value
5
+ * Deterministic implementations with comprehensive error handling
6
+ */
7
+
8
+ /**
9
+ * Convert value to JSON string
10
+ * @param {any} obj - Input value
11
+ * @param {number} indent - Indentation spaces (default: 2)
12
+ * @returns {string} JSON string
13
+ */
14
+ export const json = (obj, indent = 2) => {
15
+ try {
16
+ return JSON.stringify(obj, null, indent);
17
+ } catch (error) {
18
+ // Handle circular references and non-serializable values
19
+ try {
20
+ return JSON.stringify(obj, (key, value) => {
21
+ if (typeof value === 'function') return '[Function]';
22
+ if (typeof value === 'symbol') return '[Symbol]';
23
+ if (typeof value === 'undefined') return '[Undefined]';
24
+ if (typeof value === 'bigint') return `[BigInt: ${value.toString()}]`;
25
+ return value;
26
+ }, indent);
27
+ } catch (e) {
28
+ return '{}';
29
+ }
30
+ }
31
+ };
32
+
33
+ /**
34
+ * Parse JSON string to object
35
+ * @param {any} str - JSON string
36
+ * @returns {any} Parsed object or null on error
37
+ */
38
+ export const parseJson = (str) => {
39
+ try {
40
+ return JSON.parse(String(str));
41
+ } catch (error) {
42
+ return null;
43
+ }
44
+ };
45
+
46
+ /**
47
+ * Provide default value if input is null/undefined/empty
48
+ * @param {any} value - Input value
49
+ * @param {any} defaultValue - Default value to use
50
+ * @returns {any} Value or default
51
+ */
52
+ export const defaultValue = (value, defaultValue = '') => {
53
+ if (value === null || value === undefined) return defaultValue;
54
+ if (typeof value === 'string' && value === '') return defaultValue;
55
+ if (Array.isArray(value) && value.length === 0) return defaultValue;
56
+ if (typeof value === 'object' && Object.keys(value).length === 0) return defaultValue;
57
+ return value;
58
+ };
59
+
60
+ /**
61
+ * Get type of value
62
+ * @param {any} value - Input value
63
+ * @returns {string} Type name
64
+ */
65
+ export const typeOf = (value) => {
66
+ if (value === null) return 'null';
67
+ if (Array.isArray(value)) return 'array';
68
+ if (value instanceof Date) return 'date';
69
+ if (value instanceof RegExp) return 'regexp';
70
+ return typeof value;
71
+ };
72
+
73
+ /**
74
+ * Check if value is empty
75
+ * @param {any} value - Input value
76
+ * @returns {boolean} True if empty
77
+ */
78
+ export const isEmpty = (value) => {
79
+ if (value === null || value === undefined) return true;
80
+ if (typeof value === 'string') return value === '';
81
+ if (Array.isArray(value)) return value.length === 0;
82
+ if (typeof value === 'object') return Object.keys(value).length === 0;
83
+ if (typeof value === 'number') return isNaN(value);
84
+ return false;
85
+ };
86
+
87
+ /**
88
+ * Check if value is defined (not null or undefined)
89
+ * @param {any} value - Input value
90
+ * @returns {boolean} True if defined
91
+ */
92
+ export const isDefined = (value) => {
93
+ return value !== null && value !== undefined;
94
+ };
95
+
96
+ /**
97
+ * Check if value is null
98
+ * @param {any} value - Input value
99
+ * @returns {boolean} True if null
100
+ */
101
+ export const isNull = (value) => {
102
+ return value === null;
103
+ };
104
+
105
+ /**
106
+ * Check if value is a number
107
+ * @param {any} value - Input value
108
+ * @returns {boolean} True if number
109
+ */
110
+ export const isNumber = (value) => {
111
+ return typeof value === 'number' && !isNaN(value);
112
+ };
113
+
114
+ /**
115
+ * Check if value is a string
116
+ * @param {any} value - Input value
117
+ * @returns {boolean} True if string
118
+ */
119
+ export const isString = (value) => {
120
+ return typeof value === 'string';
121
+ };
122
+
123
+ /**
124
+ * Check if value is an array
125
+ * @param {any} value - Input value
126
+ * @returns {boolean} True if array
127
+ */
128
+ export const isArray = (value) => {
129
+ return Array.isArray(value);
130
+ };
131
+
132
+ /**
133
+ * Check if value is an object (excluding arrays and null)
134
+ * @param {any} value - Input value
135
+ * @returns {boolean} True if object
136
+ */
137
+ export const isObject = (value) => {
138
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
139
+ };
140
+
141
+ /**
142
+ * Check if value is boolean
143
+ * @param {any} value - Input value
144
+ * @returns {boolean} True if boolean
145
+ */
146
+ export const isBoolean = (value) => {
147
+ return typeof value === 'boolean';
148
+ };
149
+
150
+ /**
151
+ * Convert value to string
152
+ * @param {any} value - Input value
153
+ * @returns {string} String representation
154
+ */
155
+ export const toString = (value) => {
156
+ if (value === null || value === undefined) return '';
157
+ return String(value);
158
+ };
159
+
160
+ /**
161
+ * Convert value to number
162
+ * @param {any} value - Input value
163
+ * @param {number} defaultValue - Default if conversion fails
164
+ * @returns {number} Number value
165
+ */
166
+ export const toNumber = (value, defaultValue = 0) => {
167
+ if (value === null || value === undefined) return defaultValue;
168
+ const num = Number(value);
169
+ return isNaN(num) ? defaultValue : num;
170
+ };
171
+
172
+ /**
173
+ * Convert value to integer
174
+ * @param {any} value - Input value
175
+ * @param {number} defaultValue - Default if conversion fails
176
+ * @returns {number} Integer value
177
+ */
178
+ export const toInt = (value, defaultValue = 0) => {
179
+ if (value === null || value === undefined) return defaultValue;
180
+ const num = parseInt(value, 10);
181
+ return isNaN(num) ? defaultValue : num;
182
+ };
183
+
184
+ /**
185
+ * Convert value to float
186
+ * @param {any} value - Input value
187
+ * @param {number} defaultValue - Default if conversion fails
188
+ * @returns {number} Float value
189
+ */
190
+ export const toFloat = (value, defaultValue = 0.0) => {
191
+ if (value === null || value === undefined) return defaultValue;
192
+ const num = parseFloat(value);
193
+ return isNaN(num) ? defaultValue : num;
194
+ };
195
+
196
+ /**
197
+ * Convert value to boolean
198
+ * @param {any} value - Input value
199
+ * @returns {boolean} Boolean value
200
+ */
201
+ export const toBoolean = (value) => {
202
+ if (value === null || value === undefined) return false;
203
+ if (typeof value === 'boolean') return value;
204
+ if (typeof value === 'string') {
205
+ const lower = value.toLowerCase().trim();
206
+ return lower === 'true' || lower === 'yes' || lower === '1';
207
+ }
208
+ if (typeof value === 'number') return value !== 0;
209
+ if (Array.isArray(value)) return value.length > 0;
210
+ if (typeof value === 'object') return Object.keys(value).length > 0;
211
+ return Boolean(value);
212
+ };
213
+
214
+ /**
215
+ * Deep clone an object (deterministic)
216
+ * @param {any} obj - Object to clone
217
+ * @returns {any} Cloned object
218
+ */
219
+ export const clone = (obj) => {
220
+ try {
221
+ return JSON.parse(JSON.stringify(obj));
222
+ } catch (error) {
223
+ // Fallback for objects with circular references or non-serializable values
224
+ if (obj === null || typeof obj !== 'object') return obj;
225
+ if (Array.isArray(obj)) return [...obj];
226
+ return { ...obj };
227
+ }
228
+ };
229
+
230
+ /**
231
+ * Get object keys
232
+ * @param {any} obj - Input object
233
+ * @returns {Array} Array of keys
234
+ */
235
+ export const keys = (obj) => {
236
+ if (obj === null || obj === undefined) return [];
237
+ if (typeof obj !== 'object') return [];
238
+ return Object.keys(obj);
239
+ };
240
+
241
+ /**
242
+ * Get object values
243
+ * @param {any} obj - Input object
244
+ * @returns {Array} Array of values
245
+ */
246
+ export const values = (obj) => {
247
+ if (obj === null || obj === undefined) return [];
248
+ if (typeof obj !== 'object') return [];
249
+ return Object.values(obj);
250
+ };
251
+
252
+ /**
253
+ * Get object entries as [key, value] pairs
254
+ * @param {any} obj - Input object
255
+ * @returns {Array} Array of [key, value] pairs
256
+ */
257
+ export const entries = (obj) => {
258
+ if (obj === null || obj === undefined) return [];
259
+ if (typeof obj !== 'object') return [];
260
+ return Object.entries(obj);
261
+ };
262
+
263
+ /**
264
+ * Get value at object path
265
+ * @param {any} obj - Input object
266
+ * @param {string} path - Dot-separated path (e.g., 'user.profile.name')
267
+ * @param {any} defaultValue - Default value if path doesn't exist
268
+ * @returns {any} Value at path or default
269
+ */
270
+ export const get = (obj, path, defaultValue = null) => {
271
+ if (obj === null || obj === undefined) return defaultValue;
272
+ if (!path) return obj;
273
+
274
+ const keys = String(path).split('.');
275
+ let current = obj;
276
+
277
+ for (const key of keys) {
278
+ if (current === null || current === undefined || !(key in current)) {
279
+ return defaultValue;
280
+ }
281
+ current = current[key];
282
+ }
283
+
284
+ return current;
285
+ };
286
+
287
+ /**
288
+ * Check if object has property at path
289
+ * @param {any} obj - Input object
290
+ * @param {string} path - Dot-separated path
291
+ * @returns {boolean} True if path exists
292
+ */
293
+ export const has = (obj, path) => {
294
+ if (obj === null || obj === undefined) return false;
295
+ if (!path) return false;
296
+
297
+ const keys = String(path).split('.');
298
+ let current = obj;
299
+
300
+ for (const key of keys) {
301
+ if (current === null || current === undefined || !(key in current)) {
302
+ return false;
303
+ }
304
+ current = current[key];
305
+ }
306
+
307
+ return true;
308
+ };
309
+
310
+ /**
311
+ * Merge objects (shallow merge)
312
+ * @param {any} target - Target object
313
+ * @param {any} source - Source object
314
+ * @returns {Object} Merged object
315
+ */
316
+ export const merge = (target, source) => {
317
+ if (!isObject(target)) target = {};
318
+ if (!isObject(source)) source = {};
319
+ return { ...target, ...source };
320
+ };
321
+
322
+ /**
323
+ * Round number to specified precision
324
+ * @param {any} num - Number to round
325
+ * @param {number} precision - Decimal places
326
+ * @returns {number} Rounded number
327
+ */
328
+ export const round = (num, precision = 0) => {
329
+ if (typeof num !== 'number' || isNaN(num)) return 0;
330
+ const factor = Math.pow(10, Math.max(0, Math.floor(precision)));
331
+ return Math.round(num * factor) / factor;
332
+ };
333
+
334
+ /**
335
+ * Ceiling of number
336
+ * @param {any} num - Number
337
+ * @returns {number} Ceiling value
338
+ */
339
+ export const ceil = (num) => {
340
+ if (typeof num !== 'number' || isNaN(num)) return 0;
341
+ return Math.ceil(num);
342
+ };
343
+
344
+ /**
345
+ * Floor of number
346
+ * @param {any} num - Number
347
+ * @returns {number} Floor value
348
+ */
349
+ export const floor = (num) => {
350
+ if (typeof num !== 'number' || isNaN(num)) return 0;
351
+ return Math.floor(num);
352
+ };
353
+
354
+ /**
355
+ * Absolute value of number
356
+ * @param {any} num - Number
357
+ * @returns {number} Absolute value
358
+ */
359
+ export const abs = (num) => {
360
+ if (typeof num !== 'number' || isNaN(num)) return 0;
361
+ return Math.abs(num);
362
+ };
363
+
364
+ /**
365
+ * Set value at object path (immutable)
366
+ * @param {any} obj - Input object
367
+ * @param {string} path - Dot-separated path
368
+ * @param {any} value - Value to set
369
+ * @returns {Object} New object with value set
370
+ */
371
+ export const set = (obj, path, value) => {
372
+ if (obj === null || obj === undefined) obj = {};
373
+ if (!path) return obj;
374
+
375
+ const keys = String(path).split('.');
376
+ const result = clone(obj);
377
+ let current = result;
378
+
379
+ for (let i = 0; i < keys.length - 1; i++) {
380
+ const key = keys[i];
381
+ if (!(key in current) || typeof current[key] !== 'object') {
382
+ current[key] = {};
383
+ }
384
+ current = current[key];
385
+ }
386
+
387
+ current[keys[keys.length - 1]] = value;
388
+ return result;
389
+ };
390
+
391
+ /**
392
+ * Omit properties from object
393
+ * @param {any} obj - Input object
394
+ * @param {...string} keys - Keys to omit
395
+ * @returns {Object} Object without specified keys
396
+ */
397
+ export const omit = (obj, ...keys) => {
398
+ if (!isObject(obj)) return {};
399
+ const result = { ...obj };
400
+ for (const key of keys) {
401
+ delete result[key];
402
+ }
403
+ return result;
404
+ };
405
+
406
+ /**
407
+ * Pick properties from object
408
+ * @param {any} obj - Input object
409
+ * @param {...string} keys - Keys to pick
410
+ * @returns {Object} Object with only specified keys
411
+ */
412
+ export const pick = (obj, ...keys) => {
413
+ if (!isObject(obj)) return {};
414
+ const result = {};
415
+ for (const key of keys) {
416
+ if (key in obj) {
417
+ result[key] = obj[key];
418
+ }
419
+ }
420
+ return result;
421
+ };
422
+
423
+ /**
424
+ * Convert object to array of [key, value] pairs for iteration
425
+ * Enables Nunjucks iteration: {% for key, value in obj | items %}
426
+ * @param {any} obj - Input object
427
+ * @returns {Array} Array of [key, value] pairs
428
+ */
429
+ export const items = (obj) => {
430
+ if (!isObject(obj)) return [];
431
+ return Object.entries(obj);
432
+ };
433
+
434
+ /**
435
+ * Convert object to key-value pairs (alias for items)
436
+ * @param {any} obj - Input object
437
+ * @returns {Array} Array of [key, value] pairs
438
+ */
439
+ export const dictItems = items;
440
+
441
+ // Collection of all data filters for easy import
442
+ export const dataFilters = {
443
+ json,
444
+ parseJson,
445
+ defaultValue,
446
+ default: defaultValue,
447
+ typeOf,
448
+ isEmpty,
449
+ isDefined,
450
+ isNull,
451
+ isNumber,
452
+ isString,
453
+ isArray,
454
+ isObject,
455
+ isBoolean,
456
+ toString,
457
+ toNumber,
458
+ toInt,
459
+ toFloat,
460
+ toBoolean,
461
+ clone,
462
+ keys,
463
+ values,
464
+ entries,
465
+ get,
466
+ has,
467
+ merge,
468
+ round,
469
+ ceil,
470
+ floor,
471
+ abs,
472
+ set,
473
+ omit,
474
+ pick,
475
+ items,
476
+ dictItems
477
+ };
478
+
479
+ export default dataFilters;