@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,583 @@
1
+ /**
2
+ * KGEN Injection Target Templates - Code injection patterns
3
+ *
4
+ * Provides templates for creating injection targets in existing codebases
5
+ * Supports marker-based, semantic-based, and position-based injection strategies
6
+ */
7
+
8
+ export class KGenInjectionTargets {
9
+ constructor(options = {}) {
10
+ this.options = {
11
+ deterministicMode: options.deterministicMode !== false,
12
+ staticBuildTime: options.staticBuildTime || '2024-01-01T00:00:00.000Z',
13
+ namespace: options.namespace || 'kgen',
14
+ ...options
15
+ };
16
+
17
+ this.targetTemplates = new Map();
18
+ this.initializeTargetTemplates();
19
+ }
20
+
21
+ /**
22
+ * Initialize built-in injection target templates
23
+ */
24
+ initializeTargetTemplates() {
25
+ // Marker-based injection target
26
+ this.registerTargetTemplate('marker_target', {
27
+ name: 'MarkerBasedTarget',
28
+ description: 'Injection target using comment markers',
29
+ pattern: {
30
+ startMarker: '{{ startComment | default("// KGEN:START") }} {{ markerName }}',
31
+ endMarker: '{{ endComment | default("// KGEN:END") }} {{ markerName }}',
32
+ content: '{{ injectionContent }}'
33
+ },
34
+ template: `{{ startComment | default("// KGEN:START") }} {{ markerName }}
35
+ {{ injectionContent | indent(indentLevel | default(0)) }}
36
+ {{ endComment | default("// KGEN:END") }} {{ markerName }}`,
37
+ detection: {
38
+ regex: '{{ startComment | escape_regex }} {{ markerName | escape_regex }}[\\s\\S]*?{{ endComment | escape_regex }} {{ markerName | escape_regex }}',
39
+ flags: 'g'
40
+ }
41
+ });
42
+
43
+ // Function injection target
44
+ this.registerTargetTemplate('function_target', {
45
+ name: 'FunctionInjectionTarget',
46
+ description: 'Inject code at specific points in functions',
47
+ pattern: {
48
+ functionStart: 'function {{ functionName }}({{ parameters | default("") }}) {',
49
+ functionEnd: '}',
50
+ injectionPoint: '{{ injectionPoint | default("start") }}' // start, end, before-return
51
+ },
52
+ template: `{% if injectionPoint == "start" -%}
53
+ function {{ functionName }}({{ parameters | default("") }}) {
54
+ {{ injectionContent | indent(2) }}
55
+ {% elif injectionPoint == "end" -%}
56
+ {{ injectionContent | indent(2) }}
57
+ }
58
+ {% elif injectionPoint == "before-return" -%}
59
+ {{ injectionContent | indent(2) }}
60
+ return
61
+ {% endif -%}`,
62
+ detection: {
63
+ regex: 'function\\s+{{ functionName | escape_regex }}\\s*\\([^)]*\\)\\s*{',
64
+ flags: 'g'
65
+ }
66
+ });
67
+
68
+ // Class injection target
69
+ this.registerTargetTemplate('class_target', {
70
+ name: 'ClassInjectionTarget',
71
+ description: 'Inject code into class definitions',
72
+ pattern: {
73
+ className: '{{ className }}',
74
+ injectionType: '{{ injectionType | default("method") }}', // method, property, constructor
75
+ visibility: '{{ visibility | default("public") }}'
76
+ },
77
+ template: `{% if injectionType == "method" -%}
78
+ {{ visibility }} {{ methodName }}({{ parameters | default("") }}) {
79
+ {{ methodBody | indent(4) }}
80
+ }
81
+ {% elif injectionType == "property" -%}
82
+ {{ visibility }} {{ propertyName }}{{ propertyValue ? " = " + propertyValue : "" }};
83
+ {% elif injectionType == "constructor" -%}
84
+ constructor({{ parameters | default("") }}) {
85
+ {{ constructorBody | indent(4) }}
86
+ }
87
+ {% endif -%}`,
88
+ detection: {
89
+ regex: 'class\\s+{{ className | escape_regex }}\\s*(?:extends\\s+\\w+)?\\s*{',
90
+ flags: 'g'
91
+ }
92
+ });
93
+
94
+ // Import injection target
95
+ this.registerTargetTemplate('import_target', {
96
+ name: 'ImportInjectionTarget',
97
+ description: 'Inject import statements',
98
+ pattern: {
99
+ importType: '{{ importType | default("named") }}', // named, default, namespace
100
+ modulePath: '{{ modulePath }}'
101
+ },
102
+ template: `{% if importType == "named" -%}
103
+ import { {{ importNames | join(", ") }} } from '{{ modulePath }}';
104
+ {% elif importType == "default" -%}
105
+ import {{ defaultImport }} from '{{ modulePath }}';
106
+ {% elif importType == "namespace" -%}
107
+ import * as {{ namespaceImport }} from '{{ modulePath }}';
108
+ {% elif importType == "side-effect" -%}
109
+ import '{{ modulePath }}';
110
+ {% endif -%}`,
111
+ detection: {
112
+ regex: '^\\s*import\\s+.*from\\s+["\']{{ modulePath | escape_regex }}["\'];?\\s*$',
113
+ flags: 'gm'
114
+ }
115
+ });
116
+
117
+ // Configuration injection target
118
+ this.registerTargetTemplate('config_target', {
119
+ name: 'ConfigurationTarget',
120
+ description: 'Inject configuration values',
121
+ pattern: {
122
+ configFormat: '{{ configFormat | default("json") }}', // json, yaml, js, env
123
+ configKey: '{{ configKey }}'
124
+ },
125
+ template: `{% if configFormat == "json" -%}
126
+ "{{ configKey }}": {{ configValue | json }}
127
+ {% elif configFormat == "yaml" -%}
128
+ {{ configKey }}: {{ configValue | yaml }}
129
+ {% elif configFormat == "js" -%}
130
+ {{ configKey }}: {{ configValue | js_value }},
131
+ {% elif configFormat == "env" -%}
132
+ {{ configKey }}={{ configValue }}
133
+ {% endif -%}`,
134
+ detection: {
135
+ regex: '"{{ configKey | escape_regex }}"\\s*:',
136
+ flags: 'g'
137
+ }
138
+ });
139
+
140
+ // HTML injection target
141
+ this.registerTargetTemplate('html_target', {
142
+ name: 'HTMLInjectionTarget',
143
+ description: 'Inject HTML content at specific points',
144
+ pattern: {
145
+ targetElement: '{{ targetElement | default("body") }}',
146
+ position: '{{ position | default("append") }}' // append, prepend, before, after
147
+ },
148
+ template: `{% if position == "append" -%}
149
+ <{{ targetElement }}{{ attributes ? " " + attributes : "" }}>
150
+ {{ existingContent }}
151
+ {{ injectionContent | indent(2) }}
152
+ </{{ targetElement }}>
153
+ {% elif position == "prepend" -%}
154
+ <{{ targetElement }}{{ attributes ? " " + attributes : "" }}>
155
+ {{ injectionContent | indent(2) }}
156
+ {{ existingContent }}
157
+ </{{ targetElement }}>
158
+ {% elif position == "before" -%}
159
+ {{ injectionContent }}
160
+ <{{ targetElement }}{{ attributes ? " " + attributes : "" }}>{{ existingContent }}</{{ targetElement }}>
161
+ {% elif position == "after" -%}
162
+ <{{ targetElement }}{{ attributes ? " " + attributes : "" }}>{{ existingContent }}</{{ targetElement }}>
163
+ {{ injectionContent }}
164
+ {% endif -%}`,
165
+ detection: {
166
+ regex: '<{{ targetElement | escape_regex }}(?:\\s[^>]*)?>',
167
+ flags: 'gi'
168
+ }
169
+ });
170
+
171
+ // CSS injection target
172
+ this.registerTargetTemplate('css_target', {
173
+ name: 'CSSInjectionTarget',
174
+ description: 'Inject CSS rules and selectors',
175
+ pattern: {
176
+ selector: '{{ cssSelector }}',
177
+ injectionType: '{{ injectionType | default("rule") }}' // rule, property, media
178
+ },
179
+ template: `{% if injectionType == "rule" -%}
180
+ {{ cssSelector }} {
181
+ {{ cssProperties | indent(2) }}
182
+ }
183
+ {% elif injectionType == "property" -%}
184
+ {{ propertyName }}: {{ propertyValue }};
185
+ {% elif injectionType == "media" -%}
186
+ @media {{ mediaQuery }} {
187
+ {{ mediaRules | indent(2) }}
188
+ }
189
+ {% endif -%}`,
190
+ detection: {
191
+ regex: '{{ cssSelector | escape_regex }}\\s*{',
192
+ flags: 'g'
193
+ }
194
+ });
195
+
196
+ // JSON injection target
197
+ this.registerTargetTemplate('json_target', {
198
+ name: 'JSONInjectionTarget',
199
+ description: 'Inject properties into JSON objects',
200
+ pattern: {
201
+ targetPath: '{{ jsonPath }}',
202
+ operation: '{{ operation | default("merge") }}' // merge, replace, append
203
+ },
204
+ template: `{% if operation == "merge" -%}
205
+ {{ jsonKey }}: {{ jsonValue | json }}
206
+ {% elif operation == "replace" -%}
207
+ {{ jsonValue | json }}
208
+ {% elif operation == "append" and jsonValue is iterable -%}
209
+ {{ existingValue | concat(jsonValue) | json }}
210
+ {% endif -%}`,
211
+ detection: {
212
+ regex: '"{{ jsonKey | escape_regex }}"\\s*:\\s*',
213
+ flags: 'g'
214
+ }
215
+ });
216
+
217
+ // Package.json target
218
+ this.registerTargetTemplate('package_json_target', {
219
+ name: 'PackageJSONTarget',
220
+ description: 'Inject dependencies and scripts into package.json',
221
+ pattern: {
222
+ section: '{{ section | default("dependencies") }}', // dependencies, devDependencies, scripts, etc.
223
+ operation: '{{ operation | default("add") }}' // add, update, remove
224
+ },
225
+ template: `{% if section == "dependencies" or section == "devDependencies" -%}
226
+ "{{ packageName }}": "{{ packageVersion }}"
227
+ {% elif section == "scripts" -%}
228
+ "{{ scriptName }}": "{{ scriptCommand }}"
229
+ {% elif section == "keywords" -%}
230
+ "{{ keyword }}"
231
+ {% elif section == "exports" -%}
232
+ "{{ exportPath }}": "{{ exportTarget }}"
233
+ {% endif -%}`,
234
+ detection: {
235
+ regex: '"{{ section | escape_regex }}"\\s*:\\s*{',
236
+ flags: 'g'
237
+ }
238
+ });
239
+
240
+ // Docker injection target
241
+ this.registerTargetTemplate('dockerfile_target', {
242
+ name: 'DockerfileTarget',
243
+ description: 'Inject instructions into Dockerfile',
244
+ pattern: {
245
+ instruction: '{{ instruction | upper }}',
246
+ position: '{{ position | default("append") }}' // append, prepend, after-instruction
247
+ },
248
+ template: `{{ instruction | upper }} {{ instructionArgs }}`,
249
+ detection: {
250
+ regex: '^{{ instruction | upper | escape_regex }}\\s+',
251
+ flags: 'gm'
252
+ }
253
+ });
254
+
255
+ // YAML injection target
256
+ this.registerTargetTemplate('yaml_target', {
257
+ name: 'YAMLInjectionTarget',
258
+ description: 'Inject properties into YAML files',
259
+ pattern: {
260
+ yamlPath: '{{ yamlPath }}',
261
+ indentLevel: '{{ indentLevel | default(0) }}'
262
+ },
263
+ template: `{{ ' '.repeat(indentLevel * 2) }}{{ yamlKey }}: {{ yamlValue | yaml_value }}`,
264
+ detection: {
265
+ regex: '^\\s*{{ yamlKey | escape_regex }}\\s*:',
266
+ flags: 'gm'
267
+ }
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Register an injection target template
273
+ */
274
+ registerTargetTemplate(name, template) {
275
+ this.targetTemplates.set(name, {
276
+ ...template,
277
+ registered: this.options.staticBuildTime,
278
+ namespace: this.options.namespace
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Generate injection target from template
284
+ */
285
+ generateTarget(templateName, context = {}) {
286
+ const template = this.targetTemplates.get(templateName);
287
+ if (!template) {
288
+ throw new Error(`Injection target template '${templateName}' not found`);
289
+ }
290
+
291
+ // Process template with context
292
+ let targetContent = template.template;
293
+
294
+ // Replace template variables
295
+ for (const [key, value] of Object.entries(context)) {
296
+ const regex = new RegExp(`{{\\s*${key}\\s*(?:\\|[^}]*)?\\s*}}`, 'g');
297
+
298
+ const matches = targetContent.match(regex);
299
+ if (matches) {
300
+ for (const match of matches) {
301
+ const defaultMatch = match.match(/\|\s*default\('([^']*)'\)/);
302
+ const replacement = value !== undefined ? value : (defaultMatch ? defaultMatch[1] : match);
303
+ targetContent = targetContent.replace(match, String(replacement));
304
+ }
305
+ }
306
+ }
307
+
308
+ // Process template logic
309
+ targetContent = this.processTemplateLogic(targetContent, context);
310
+
311
+ // Generate detection pattern
312
+ const detectionPattern = this.generateDetectionPattern(template.detection, context);
313
+
314
+ return {
315
+ name: this.interpolate(template.name, context),
316
+ description: this.interpolate(template.description, context),
317
+ content: targetContent,
318
+ pattern: template.pattern ? this.processPattern(template.pattern, context) : null,
319
+ detection: detectionPattern,
320
+ metadata: {
321
+ template: templateName,
322
+ generated: this.options.staticBuildTime,
323
+ namespace: this.options.namespace,
324
+ context: Object.keys(context)
325
+ }
326
+ };
327
+ }
328
+
329
+ /**
330
+ * Generate detection pattern for finding injection points
331
+ */
332
+ generateDetectionPattern(detection, context) {
333
+ if (!detection) return null;
334
+
335
+ let regex = detection.regex;
336
+
337
+ // Replace template variables in regex
338
+ for (const [key, value] of Object.entries(context)) {
339
+ const regexVar = new RegExp(`{{\\s*${key}\\s*\\|\\s*escape_regex\\s*}}`, 'g');
340
+ regex = regex.replace(regexVar, this.escapeRegex(String(value || '')));
341
+
342
+ const simpleVar = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
343
+ regex = regex.replace(simpleVar, String(value || ''));
344
+ }
345
+
346
+ return {
347
+ regex: new RegExp(regex, detection.flags || 'g'),
348
+ source: regex,
349
+ flags: detection.flags || 'g'
350
+ };
351
+ }
352
+
353
+ /**
354
+ * Process pattern object with context
355
+ */
356
+ processPattern(pattern, context) {
357
+ const processed = {};
358
+
359
+ for (const [key, value] of Object.entries(pattern)) {
360
+ if (typeof value === 'string') {
361
+ processed[key] = this.interpolate(value, context);
362
+ } else {
363
+ processed[key] = value;
364
+ }
365
+ }
366
+
367
+ return processed;
368
+ }
369
+
370
+ /**
371
+ * Process template logic (loops and conditions)
372
+ */
373
+ processTemplateLogic(content, context) {
374
+ let result = content;
375
+
376
+ // Process {% if %} conditions
377
+ const ifRegex = /{%\s*if\s+([\w.\[\]|()\s!="']+)\s*%}([\s\S]*?)(?:{%\s*elif\s+([\w.\[\]|()\s!="']+)\s*%}([\s\S]*?))*(?:{%\s*else\s*%}([\s\S]*?))?{%\s*endif\s*%}/g;
378
+
379
+ result = result.replace(ifRegex, (match, condition, ifContent, elifCondition, elifContent, elseContent) => {
380
+ const conditionValue = this.evaluateCondition(condition, context);
381
+ if (conditionValue) {
382
+ return ifContent;
383
+ } else if (elifCondition && this.evaluateCondition(elifCondition, context)) {
384
+ return elifContent;
385
+ } else {
386
+ return elseContent || '';
387
+ }
388
+ });
389
+
390
+ // Process {% for %} loops
391
+ const forLoopRegex = /{%\s*for\s+(\w+)\s+in\s+([\w.\[\]|()]+)\s*%}([\s\S]*?){%\s*endfor\s*%}/g;
392
+
393
+ result = result.replace(forLoopRegex, (match, itemVar, listExpr, loopContent) => {
394
+ const listValue = this.evaluateExpression(listExpr, context);
395
+ if (!Array.isArray(listValue)) {
396
+ return '';
397
+ }
398
+
399
+ return listValue.map((item, index) => {
400
+ const loopContext = {
401
+ ...context,
402
+ [itemVar]: item,
403
+ loop: {
404
+ index: index,
405
+ first: index === 0,
406
+ last: index === listValue.length - 1
407
+ }
408
+ };
409
+
410
+ return this.interpolateWithContext(loopContent, loopContext);
411
+ }).join('');
412
+ });
413
+
414
+ return result;
415
+ }
416
+
417
+ /**
418
+ * Evaluate conditional expressions
419
+ */
420
+ evaluateCondition(condition, context) {
421
+ // Handle simple conditions
422
+ const trimmed = condition.trim();
423
+
424
+ // Handle == comparisons
425
+ const eqMatch = trimmed.match(/(\w+)\s*==\s*"([^"]*)"/);
426
+ if (eqMatch) {
427
+ const value = this.getNestedValue(context, eqMatch[1]);
428
+ return value === eqMatch[2];
429
+ }
430
+
431
+ // Handle simple property access
432
+ const value = this.evaluateExpression(trimmed, context);
433
+ return Boolean(value);
434
+ }
435
+
436
+ /**
437
+ * Evaluate simple expressions
438
+ */
439
+ evaluateExpression(expr, context) {
440
+ // Handle default expressions
441
+ const defaultMatch = expr.match(/(\w+)\s*\|\s*default\('([^']*)'\)/);
442
+ if (defaultMatch) {
443
+ const value = this.getNestedValue(context, defaultMatch[1]);
444
+ return value !== undefined ? value : defaultMatch[2];
445
+ }
446
+
447
+ // Handle simple property access
448
+ return this.getNestedValue(context, expr.trim());
449
+ }
450
+
451
+ /**
452
+ * Get nested value from object
453
+ */
454
+ getNestedValue(obj, path) {
455
+ return path.split('.').reduce((current, key) => {
456
+ return current && current[key] !== undefined ? current[key] : undefined;
457
+ }, obj);
458
+ }
459
+
460
+ /**
461
+ * Interpolate template with context
462
+ */
463
+ interpolateWithContext(template, context) {
464
+ let result = template;
465
+
466
+ for (const [key, value] of Object.entries(context)) {
467
+ if (typeof value === 'object' && value !== null) {
468
+ // Handle nested objects
469
+ for (const [nestedKey, nestedValue] of Object.entries(value)) {
470
+ const regex = new RegExp(`{{\\s*${key}\\.${nestedKey}\\s*}}`, 'g');
471
+ result = result.replace(regex, String(nestedValue));
472
+ }
473
+ } else {
474
+ const regex = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
475
+ result = result.replace(regex, String(value || ''));
476
+ }
477
+ }
478
+
479
+ return result;
480
+ }
481
+
482
+ /**
483
+ * Simple template interpolation
484
+ */
485
+ interpolate(template, context) {
486
+ let result = template;
487
+
488
+ for (const [key, value] of Object.entries(context)) {
489
+ const regex = new RegExp(`{{\\s*${key}\\s*(?:\\|[^}]*)?\\s*}}`, 'g');
490
+
491
+ const matches = result.match(regex);
492
+ if (matches) {
493
+ for (const match of matches) {
494
+ const defaultMatch = match.match(/\|\s*default\('([^']*)'\)/);
495
+ const replacement = value !== undefined ? value : (defaultMatch ? defaultMatch[1] : match);
496
+ result = result.replace(match, replacement);
497
+ }
498
+ }
499
+ }
500
+
501
+ return result;
502
+ }
503
+
504
+ /**
505
+ * Escape string for regex
506
+ */
507
+ escapeRegex(string) {
508
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
509
+ }
510
+
511
+ /**
512
+ * Generate injection operation specification
513
+ */
514
+ generateInjectionSpec(targetName, context = {}, options = {}) {
515
+ const target = this.generateTarget(targetName, context);
516
+
517
+ return {
518
+ target: target.name,
519
+ operation: options.operation || 'inject',
520
+ content: target.content,
521
+ detection: target.detection,
522
+ position: options.position || 'replace',
523
+ backup: options.backup !== false,
524
+ validate: options.validate !== false,
525
+ metadata: {
526
+ ...target.metadata,
527
+ operation: options.operation || 'inject',
528
+ position: options.position || 'replace'
529
+ }
530
+ };
531
+ }
532
+
533
+ /**
534
+ * Get available target template names
535
+ */
536
+ getTemplateNames() {
537
+ return Array.from(this.targetTemplates.keys()).sort();
538
+ }
539
+
540
+ /**
541
+ * Get target template by name
542
+ */
543
+ getTemplate(name) {
544
+ return this.targetTemplates.get(name);
545
+ }
546
+
547
+ /**
548
+ * Export injection target templates
549
+ */
550
+ exportTemplates(templateNames = []) {
551
+ const templatesToExport = templateNames.length > 0
552
+ ? templateNames.filter(name => this.targetTemplates.has(name))
553
+ : Array.from(this.targetTemplates.keys());
554
+
555
+ const exported = {
556
+ format: 'kgen-injection-targets',
557
+ version: '1.0.0',
558
+ generated: this.options.staticBuildTime,
559
+ namespace: this.options.namespace,
560
+ templates: {}
561
+ };
562
+
563
+ for (const name of templatesToExport) {
564
+ exported.templates[name] = this.targetTemplates.get(name);
565
+ }
566
+
567
+ return exported;
568
+ }
569
+
570
+ /**
571
+ * Get template statistics
572
+ */
573
+ getStats() {
574
+ return {
575
+ totalTemplates: this.targetTemplates.size,
576
+ namespace: this.options.namespace,
577
+ deterministicMode: this.options.deterministicMode,
578
+ templates: Array.from(this.targetTemplates.keys()).sort()
579
+ };
580
+ }
581
+ }
582
+
583
+ export default KGenInjectionTargets;