@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
|
@@ -12,17 +12,23 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { createHash } from 'crypto';
|
|
15
|
-
import { EventEmitter } from 'events';
|
|
15
|
+
import { EventEmitter as _EventEmitter } from 'events';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* TEMPORAL TEST DOUBLES
|
|
19
19
|
* Replace all time-based nondeterministic functions
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
22
25
|
export class DeterministicDate extends Date {
|
|
23
26
|
static FIXED_TIMESTAMP = '2025-01-01T00:00:00.000Z';
|
|
24
27
|
static FIXED_TIME_MS = new Date(DeterministicDate.FIXED_TIMESTAMP).getTime();
|
|
25
28
|
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
26
32
|
constructor(...args) {
|
|
27
33
|
if (args.length === 0) {
|
|
28
34
|
// No arguments = current time -> use fixed time
|
|
@@ -36,28 +42,46 @@ export class DeterministicDate extends Date {
|
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
39
48
|
static now() {
|
|
40
49
|
return DeterministicDate.FIXED_TIME_MS;
|
|
41
50
|
}
|
|
42
51
|
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
43
55
|
static deterministic() {
|
|
44
56
|
return DeterministicDate.FIXED_TIME_MS;
|
|
45
57
|
}
|
|
46
58
|
}
|
|
47
59
|
|
|
60
|
+
/**
|
|
61
|
+
*
|
|
62
|
+
*/
|
|
48
63
|
export class MockMath {
|
|
49
64
|
static seed = 0.12345; // Fixed seed for deterministic "random"
|
|
50
65
|
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
51
69
|
static random() {
|
|
52
70
|
// Linear congruential generator - deterministic pseudorandom
|
|
53
71
|
MockMath.seed = (MockMath.seed * 9301 + 49297) % 233280;
|
|
54
72
|
return MockMath.seed / 233280;
|
|
55
73
|
}
|
|
56
74
|
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
*/
|
|
57
78
|
static resetSeed() {
|
|
58
79
|
MockMath.seed = 0.12345;
|
|
59
80
|
}
|
|
60
81
|
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
*/
|
|
61
85
|
static setSeed(newSeed) {
|
|
62
86
|
MockMath.seed = newSeed;
|
|
63
87
|
}
|
|
@@ -76,7 +100,13 @@ export class MockMath {
|
|
|
76
100
|
* Replace UUID and random ID generation with content-based deterministic IDs
|
|
77
101
|
*/
|
|
78
102
|
|
|
103
|
+
/**
|
|
104
|
+
*
|
|
105
|
+
*/
|
|
79
106
|
export class DeterministicIdGenerator {
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
*/
|
|
80
110
|
constructor(config = {}) {
|
|
81
111
|
this.config = {
|
|
82
112
|
defaultSalt: 'kgen-deterministic',
|
|
@@ -87,6 +117,9 @@ export class DeterministicIdGenerator {
|
|
|
87
117
|
this.counter = 0;
|
|
88
118
|
}
|
|
89
119
|
|
|
120
|
+
/**
|
|
121
|
+
*
|
|
122
|
+
*/
|
|
90
123
|
generateId(content, salt = null) {
|
|
91
124
|
const actualSalt = salt || this.config.defaultSalt;
|
|
92
125
|
const hash = createHash(this.config.hashAlgorithm);
|
|
@@ -103,12 +136,18 @@ export class DeterministicIdGenerator {
|
|
|
103
136
|
return hash.digest('hex').substring(0, this.config.idLength);
|
|
104
137
|
}
|
|
105
138
|
|
|
139
|
+
/**
|
|
140
|
+
*
|
|
141
|
+
*/
|
|
106
142
|
generateUUID(content, salt = null) {
|
|
107
143
|
const hash = this.generateId(content, salt);
|
|
108
144
|
// Format as UUID v4 structure (but deterministic)
|
|
109
145
|
return `${hash.substring(0, 8)}-${hash.substring(8, 12)}-4${hash.substring(12, 15)}-8${hash.substring(15, 18)}-${hash.substring(18, 30)}000000`.substring(0, 36);
|
|
110
146
|
}
|
|
111
147
|
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
*/
|
|
112
151
|
reset() {
|
|
113
152
|
this.counter = 0;
|
|
114
153
|
}
|
|
@@ -119,6 +158,9 @@ export class DeterministicIdGenerator {
|
|
|
119
158
|
* Replace process.env and system information with deterministic alternatives
|
|
120
159
|
*/
|
|
121
160
|
|
|
161
|
+
/**
|
|
162
|
+
*
|
|
163
|
+
*/
|
|
122
164
|
export class MockProcessEnv {
|
|
123
165
|
static FIXED_ENV = {
|
|
124
166
|
NODE_ENV: 'test',
|
|
@@ -130,23 +172,38 @@ export class MockProcessEnv {
|
|
|
130
172
|
HOST: '0.0.0.0'
|
|
131
173
|
};
|
|
132
174
|
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
*/
|
|
133
178
|
static get(key) {
|
|
134
179
|
return MockProcessEnv.FIXED_ENV[key];
|
|
135
180
|
}
|
|
136
181
|
|
|
182
|
+
/**
|
|
183
|
+
*
|
|
184
|
+
*/
|
|
137
185
|
static set(key, value) {
|
|
138
186
|
MockProcessEnv.FIXED_ENV[key] = value;
|
|
139
187
|
}
|
|
140
188
|
|
|
189
|
+
/**
|
|
190
|
+
*
|
|
191
|
+
*/
|
|
141
192
|
static reset() {
|
|
142
193
|
MockProcessEnv.FIXED_ENV = { ...MockProcessEnv.FIXED_ENV };
|
|
143
194
|
}
|
|
144
195
|
|
|
196
|
+
/**
|
|
197
|
+
*
|
|
198
|
+
*/
|
|
145
199
|
static toObject() {
|
|
146
200
|
return { ...MockProcessEnv.FIXED_ENV };
|
|
147
201
|
}
|
|
148
202
|
}
|
|
149
203
|
|
|
204
|
+
/**
|
|
205
|
+
*
|
|
206
|
+
*/
|
|
150
207
|
export class MockOS {
|
|
151
208
|
static FIXED_INFO = {
|
|
152
209
|
hostname: 'test-hostname',
|
|
@@ -163,26 +220,44 @@ export class MockOS {
|
|
|
163
220
|
}
|
|
164
221
|
};
|
|
165
222
|
|
|
223
|
+
/**
|
|
224
|
+
*
|
|
225
|
+
*/
|
|
166
226
|
static hostname() {
|
|
167
227
|
return MockOS.FIXED_INFO.hostname;
|
|
168
228
|
}
|
|
169
229
|
|
|
230
|
+
/**
|
|
231
|
+
*
|
|
232
|
+
*/
|
|
170
233
|
static platform() {
|
|
171
234
|
return MockOS.FIXED_INFO.platform;
|
|
172
235
|
}
|
|
173
236
|
|
|
237
|
+
/**
|
|
238
|
+
*
|
|
239
|
+
*/
|
|
174
240
|
static arch() {
|
|
175
241
|
return MockOS.FIXED_INFO.arch;
|
|
176
242
|
}
|
|
177
243
|
|
|
244
|
+
/**
|
|
245
|
+
*
|
|
246
|
+
*/
|
|
178
247
|
static version() {
|
|
179
248
|
return MockOS.FIXED_INFO.version;
|
|
180
249
|
}
|
|
181
250
|
|
|
251
|
+
/**
|
|
252
|
+
*
|
|
253
|
+
*/
|
|
182
254
|
static tmpdir() {
|
|
183
255
|
return MockOS.FIXED_INFO.tmpdir;
|
|
184
256
|
}
|
|
185
257
|
|
|
258
|
+
/**
|
|
259
|
+
*
|
|
260
|
+
*/
|
|
186
261
|
static userInfo() {
|
|
187
262
|
return { ...MockOS.FIXED_INFO.userInfo };
|
|
188
263
|
}
|
|
@@ -193,11 +268,17 @@ export class MockOS {
|
|
|
193
268
|
* Replace filesystem operations with deterministic alternatives
|
|
194
269
|
*/
|
|
195
270
|
|
|
271
|
+
/**
|
|
272
|
+
*
|
|
273
|
+
*/
|
|
196
274
|
export class MockFS {
|
|
197
275
|
static sortFiles = true;
|
|
198
276
|
static fixedFiles = new Map();
|
|
199
277
|
|
|
200
|
-
|
|
278
|
+
/**
|
|
279
|
+
*
|
|
280
|
+
*/
|
|
281
|
+
static async readdir(path, _options = {}) {
|
|
201
282
|
// Simulate async operation
|
|
202
283
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
203
284
|
|
|
@@ -210,7 +291,10 @@ export class MockFS {
|
|
|
210
291
|
return MockFS.sortFiles ? files.sort() : files;
|
|
211
292
|
}
|
|
212
293
|
|
|
213
|
-
|
|
294
|
+
/**
|
|
295
|
+
*
|
|
296
|
+
*/
|
|
297
|
+
static async readFile(path, _encoding = 'utf8') {
|
|
214
298
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
215
299
|
|
|
216
300
|
const content = MockFS.fixedFiles.get(`content:${path}`) ||
|
|
@@ -219,24 +303,39 @@ export class MockFS {
|
|
|
219
303
|
return content;
|
|
220
304
|
}
|
|
221
305
|
|
|
306
|
+
/**
|
|
307
|
+
*
|
|
308
|
+
*/
|
|
222
309
|
static setFixedFiles(path, files) {
|
|
223
310
|
MockFS.fixedFiles.set(path, files);
|
|
224
311
|
}
|
|
225
312
|
|
|
313
|
+
/**
|
|
314
|
+
*
|
|
315
|
+
*/
|
|
226
316
|
static setFixedContent(path, content) {
|
|
227
317
|
MockFS.fixedFiles.set(`content:${path}`, content);
|
|
228
318
|
}
|
|
229
319
|
|
|
320
|
+
/**
|
|
321
|
+
*
|
|
322
|
+
*/
|
|
230
323
|
static reset() {
|
|
231
324
|
MockFS.fixedFiles.clear();
|
|
232
325
|
MockFS.sortFiles = true;
|
|
233
326
|
}
|
|
234
327
|
}
|
|
235
328
|
|
|
329
|
+
/**
|
|
330
|
+
*
|
|
331
|
+
*/
|
|
236
332
|
export class MockGlob {
|
|
237
333
|
static patterns = new Map();
|
|
238
334
|
|
|
239
|
-
|
|
335
|
+
/**
|
|
336
|
+
*
|
|
337
|
+
*/
|
|
338
|
+
static async glob(pattern, _options = {}) {
|
|
240
339
|
await new Promise(resolve => setTimeout(resolve, 0));
|
|
241
340
|
|
|
242
341
|
const matches = MockGlob.patterns.get(pattern) || [
|
|
@@ -248,10 +347,16 @@ export class MockGlob {
|
|
|
248
347
|
return matches.sort(); // Always sorted for determinism
|
|
249
348
|
}
|
|
250
349
|
|
|
350
|
+
/**
|
|
351
|
+
*
|
|
352
|
+
*/
|
|
251
353
|
static setFixedMatches(pattern, matches) {
|
|
252
354
|
MockGlob.patterns.set(pattern, matches);
|
|
253
355
|
}
|
|
254
356
|
|
|
357
|
+
/**
|
|
358
|
+
*
|
|
359
|
+
*/
|
|
255
360
|
static reset() {
|
|
256
361
|
MockGlob.patterns.clear();
|
|
257
362
|
}
|
|
@@ -262,6 +367,9 @@ export class MockGlob {
|
|
|
262
367
|
* Replace network operations with deterministic responses
|
|
263
368
|
*/
|
|
264
369
|
|
|
370
|
+
/**
|
|
371
|
+
*
|
|
372
|
+
*/
|
|
265
373
|
export class MockFetch {
|
|
266
374
|
static responses = new Map();
|
|
267
375
|
static defaultResponse = {
|
|
@@ -272,6 +380,9 @@ export class MockFetch {
|
|
|
272
380
|
text: async () => 'deterministic text response'
|
|
273
381
|
};
|
|
274
382
|
|
|
383
|
+
/**
|
|
384
|
+
*
|
|
385
|
+
*/
|
|
275
386
|
static async fetch(url, options = {}) {
|
|
276
387
|
await new Promise(resolve => setTimeout(resolve, 10)); // Simulate network delay
|
|
277
388
|
|
|
@@ -285,11 +396,17 @@ export class MockFetch {
|
|
|
285
396
|
};
|
|
286
397
|
}
|
|
287
398
|
|
|
399
|
+
/**
|
|
400
|
+
*
|
|
401
|
+
*/
|
|
288
402
|
static setResponse(method, url, response) {
|
|
289
403
|
const key = `${method} ${url}`;
|
|
290
404
|
MockFetch.responses.set(key, response);
|
|
291
405
|
}
|
|
292
406
|
|
|
407
|
+
/**
|
|
408
|
+
*
|
|
409
|
+
*/
|
|
293
410
|
static reset() {
|
|
294
411
|
MockFetch.responses.clear();
|
|
295
412
|
}
|
|
@@ -300,13 +417,22 @@ export class MockFetch {
|
|
|
300
417
|
* Replace all nondeterministic globals with deterministic alternatives
|
|
301
418
|
*/
|
|
302
419
|
|
|
420
|
+
/**
|
|
421
|
+
*
|
|
422
|
+
*/
|
|
303
423
|
export class DeterministicTestEnvironment {
|
|
424
|
+
/**
|
|
425
|
+
*
|
|
426
|
+
*/
|
|
304
427
|
constructor() {
|
|
305
428
|
this.originalGlobals = {};
|
|
306
429
|
this.idGenerator = new DeterministicIdGenerator();
|
|
307
430
|
this.isActive = false;
|
|
308
431
|
}
|
|
309
432
|
|
|
433
|
+
/**
|
|
434
|
+
*
|
|
435
|
+
*/
|
|
310
436
|
activate() {
|
|
311
437
|
if (this.isActive) return;
|
|
312
438
|
|
|
@@ -340,6 +466,9 @@ export class DeterministicTestEnvironment {
|
|
|
340
466
|
this.isActive = true;
|
|
341
467
|
}
|
|
342
468
|
|
|
469
|
+
/**
|
|
470
|
+
*
|
|
471
|
+
*/
|
|
343
472
|
deactivate() {
|
|
344
473
|
if (!this.isActive) return;
|
|
345
474
|
|
|
@@ -348,6 +477,9 @@ export class DeterministicTestEnvironment {
|
|
|
348
477
|
this.isActive = false;
|
|
349
478
|
}
|
|
350
479
|
|
|
480
|
+
/**
|
|
481
|
+
*
|
|
482
|
+
*/
|
|
351
483
|
reset() {
|
|
352
484
|
MockMath.resetSeed();
|
|
353
485
|
MockProcessEnv.reset();
|
|
@@ -357,6 +489,9 @@ export class DeterministicTestEnvironment {
|
|
|
357
489
|
this.idGenerator.reset();
|
|
358
490
|
}
|
|
359
491
|
|
|
492
|
+
/**
|
|
493
|
+
*
|
|
494
|
+
*/
|
|
360
495
|
generateDeterministicData(schema) {
|
|
361
496
|
const data = {};
|
|
362
497
|
|
|
@@ -391,7 +526,13 @@ export class DeterministicTestEnvironment {
|
|
|
391
526
|
* Behavior-driven development helpers for deterministic testing
|
|
392
527
|
*/
|
|
393
528
|
|
|
529
|
+
/**
|
|
530
|
+
*
|
|
531
|
+
*/
|
|
394
532
|
export class BDDTestHelpers {
|
|
533
|
+
/**
|
|
534
|
+
*
|
|
535
|
+
*/
|
|
395
536
|
static createDeterministicFixture(name, schema) {
|
|
396
537
|
const env = new DeterministicTestEnvironment();
|
|
397
538
|
env.activate();
|
|
@@ -403,6 +544,9 @@ export class BDDTestHelpers {
|
|
|
403
544
|
return fixture;
|
|
404
545
|
}
|
|
405
546
|
|
|
547
|
+
/**
|
|
548
|
+
*
|
|
549
|
+
*/
|
|
406
550
|
static async verifyDeterministicBehavior(testFunction, iterations = 3) {
|
|
407
551
|
const results = [];
|
|
408
552
|
const env = new DeterministicTestEnvironment();
|
|
@@ -428,6 +572,9 @@ export class BDDTestHelpers {
|
|
|
428
572
|
return JSON.parse(firstResult);
|
|
429
573
|
}
|
|
430
574
|
|
|
575
|
+
/**
|
|
576
|
+
*
|
|
577
|
+
*/
|
|
431
578
|
static createMockContext(overrides = {}) {
|
|
432
579
|
return {
|
|
433
580
|
metadata: {
|
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
import matter from 'gray-matter';
|
|
7
7
|
import { parse as parseYAML, stringify as stringifyYAML } from 'yaml';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
9
12
|
export class FrontmatterParser {
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
10
16
|
constructor(options = {}) {
|
|
11
17
|
this.strict = options.strict !== false;
|
|
12
18
|
this.allowEmpty = options.allowEmpty !== false;
|
package/src/parser/variables.js
CHANGED
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* Migrated from ~/unjucks with enhanced pattern matching
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
6
9
|
export class VariableExtractor {
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
7
13
|
constructor(options = {}) {
|
|
8
14
|
this.includeFilters = options.includeFilters !== false;
|
|
9
15
|
this.includeFunctions = options.includeFunctions !== false;
|
|
@@ -67,7 +73,7 @@ export class VariableExtractor {
|
|
|
67
73
|
let match;
|
|
68
74
|
|
|
69
75
|
while ((match = forPattern.exec(content)) !== null) {
|
|
70
|
-
const [,
|
|
76
|
+
const [, _itemVar, _indexVar, collection] = match;
|
|
71
77
|
|
|
72
78
|
// Collection is a variable we need
|
|
73
79
|
const collectionVar = collection.trim().split('.')[0].split('|')[0].trim();
|