@unrdf/project-engine 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.
Files changed (39) hide show
  1. package/package.json +16 -15
  2. package/src/golden-structure.mjs +2 -2
  3. package/src/materialize-apply.mjs +2 -2
  4. package/README.md +0 -53
  5. package/src/api-contract-validator.mjs +0 -711
  6. package/src/auto-test-generator.mjs +0 -444
  7. package/src/autonomic-mapek.mjs +0 -511
  8. package/src/capabilities-manifest.mjs +0 -125
  9. package/src/code-complexity-js.mjs +0 -368
  10. package/src/dependency-graph.mjs +0 -276
  11. package/src/doc-drift-checker.mjs +0 -172
  12. package/src/doc-generator.mjs +0 -229
  13. package/src/domain-infer.mjs +0 -966
  14. package/src/drift-snapshot.mjs +0 -775
  15. package/src/file-roles.mjs +0 -94
  16. package/src/fs-scan.mjs +0 -305
  17. package/src/gap-finder.mjs +0 -376
  18. package/src/hotspot-analyzer.mjs +0 -412
  19. package/src/index.mjs +0 -151
  20. package/src/initialize.mjs +0 -957
  21. package/src/lens/project-structure.mjs +0 -74
  22. package/src/mapek-orchestration.mjs +0 -665
  23. package/src/materialize-plan.mjs +0 -422
  24. package/src/materialize.mjs +0 -137
  25. package/src/policy-derivation.mjs +0 -869
  26. package/src/project-config.mjs +0 -142
  27. package/src/project-diff.mjs +0 -28
  28. package/src/project-engine/build-utils.mjs +0 -237
  29. package/src/project-engine/code-analyzer.mjs +0 -248
  30. package/src/project-engine/doc-generator.mjs +0 -407
  31. package/src/project-engine/infrastructure.mjs +0 -213
  32. package/src/project-engine/metrics.mjs +0 -146
  33. package/src/project-model.mjs +0 -111
  34. package/src/project-report.mjs +0 -348
  35. package/src/refactoring-guide.mjs +0 -242
  36. package/src/stack-detect.mjs +0 -102
  37. package/src/stack-linter.mjs +0 -213
  38. package/src/template-infer.mjs +0 -674
  39. package/src/type-auditor.mjs +0 -609
@@ -1,957 +0,0 @@
1
- /**
2
- * @file Project initialization pipeline - orchestrates all 8 capabilities
3
- * @module project-engine/initialize
4
- */
5
-
6
- import { z } from 'zod';
7
- import { createHash } from 'crypto';
8
- import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
9
- import { createStore } from '@unrdf/oxigraph'; // TODO: Replace with Oxigraph Store
10
- import { scanFileSystemToStore } from './fs-scan.mjs';
11
- import { detectStackFromFs } from './stack-detect.mjs';
12
- import { buildProjectModelFromFs } from './project-model.mjs';
13
- import { classifyFiles } from './file-roles.mjs';
14
- import { analyzeJsComplexity } from './code-complexity-js.mjs';
15
-
16
- const { namedNode, literal } = DataFactory;
17
-
18
- /**
19
- * @typedef {Object} PhaseReceipt
20
- * @property {number} duration - Phase duration in ms
21
- * @property {boolean} success - Phase success status
22
- * @property {string} [error] - Error message if failed
23
- * @property {Object} [data] - Phase-specific data
24
- */
25
-
26
- /**
27
- * @typedef {Object} InitializationReceipt
28
- * @property {Object} phases - Receipt for each phase
29
- * @property {number} totalDuration - Total duration in ms
30
- * @property {boolean} success - Overall success
31
- * @property {Object} [metrics] - Code complexity metrics summary (from Phase 6.5)
32
- */
33
-
34
- /**
35
- * @typedef {Object} InitializationState
36
- * @property {Store} fsStore - Filesystem RDF store
37
- * @property {Store} projectStore - Project model store
38
- * @property {Store} domainStore - Domain inference store
39
- * @property {Store} [complexityStore] - Code complexity analysis store
40
- * @property {Object} templateGraph - Template inference graph
41
- * @property {Object} snapshot - Baseline snapshot
42
- */
43
-
44
- /**
45
- * @typedef {Object} InitializationResult
46
- * @property {boolean} success
47
- * @property {InitializationReceipt} receipt
48
- * @property {Object} report
49
- * @property {InitializationState} state
50
- */
51
-
52
- const InitializeOptionsSchema = z.object({
53
- ignorePatterns: z.array(z.string()).optional(),
54
- baseIri: z.string().default('http://example.org/unrdf/'),
55
- conventions: z
56
- .object({
57
- sourcePaths: z.array(z.string()).default(['src']),
58
- featurePaths: z.array(z.string()).default(['features', 'modules']),
59
- testPaths: z.array(z.string()).default(['__tests__', 'test', 'tests', 'spec']),
60
- })
61
- .optional(),
62
- skipPhases: z.array(z.string()).optional(),
63
- });
64
-
65
- /**
66
- * Create and execute the project initialization pipeline
67
- *
68
- * @param {string} projectRoot - Root directory of the project
69
- * @param {Object} [options] - Pipeline options
70
- * @param {string[]} [options.ignorePatterns] - Patterns to ignore during scan
71
- * @param {string} [options.baseIri] - Base IRI for RDF resources
72
- * @param {Object} [options.conventions] - Naming conventions
73
- * @param {string[]} [options.skipPhases] - Phases to skip
74
- * @returns {Promise<InitializationResult>}
75
- */
76
- export async function createProjectInitializationPipeline(projectRoot, options = {}) {
77
- const validated = InitializeOptionsSchema.parse(options);
78
- const startTime = Date.now();
79
-
80
- const phases = {};
81
- const state = {
82
- fsStore: null,
83
- projectStore: null,
84
- domainStore: null,
85
- templateGraph: null,
86
- snapshot: null,
87
- };
88
-
89
- const skipPhases = new Set(validated.skipPhases || []);
90
-
91
- // Phase 1: Scan FS
92
- if (!skipPhases.has('scan')) {
93
- phases.scan = await executeScanPhase(projectRoot, validated);
94
- if (!phases.scan.success) {
95
- return buildFailureResult(phases, startTime, 'scan', phases.scan.error);
96
- }
97
- state.fsStore = phases.scan.data.store;
98
- }
99
-
100
- // Phase 2: Detect stack
101
- if (!skipPhases.has('stackDetection') && state.fsStore) {
102
- phases.stackDetection = executeStackDetectionPhase(state.fsStore, validated);
103
- if (!phases.stackDetection.success) {
104
- return buildFailureResult(phases, startTime, 'stackDetection', phases.stackDetection.error);
105
- }
106
- }
107
-
108
- // Phase 3: Build project model
109
- if (!skipPhases.has('projectModel') && state.fsStore) {
110
- phases.projectModel = executeProjectModelPhase(state.fsStore, validated);
111
- if (!phases.projectModel.success) {
112
- return buildFailureResult(phases, startTime, 'projectModel', phases.projectModel.error);
113
- }
114
- state.projectStore = phases.projectModel.data.store;
115
- }
116
-
117
- // Phase 4: Classify file roles
118
- if (!skipPhases.has('fileRoles') && state.projectStore) {
119
- phases.fileRoles = executeFileRolesPhase(
120
- state.projectStore,
121
- phases.stackDetection?.data?.profile,
122
- validated
123
- );
124
- if (!phases.fileRoles.success) {
125
- return buildFailureResult(phases, startTime, 'fileRoles', phases.fileRoles.error);
126
- }
127
- }
128
-
129
- // Phase 5: Infer domain model
130
- if (!skipPhases.has('domainInference') && state.projectStore) {
131
- phases.domainInference = executeDomainInferencePhase(state.projectStore, validated);
132
- if (!phases.domainInference.success) {
133
- return buildFailureResult(phases, startTime, 'domainInference', phases.domainInference.error);
134
- }
135
- state.domainStore = phases.domainInference.data.store;
136
- }
137
-
138
- // Phase 6.5: Analyze code complexity (JavaScript/TypeScript)
139
- if (!skipPhases.has('codeComplexity')) {
140
- phases.codeComplexity = await executeCodeComplexityPhase(
141
- projectRoot,
142
- state.domainStore,
143
- validated
144
- );
145
- if (!phases.codeComplexity.success) {
146
- return buildFailureResult(phases, startTime, 'codeComplexity', phases.codeComplexity.error);
147
- }
148
- state.complexityStore = phases.codeComplexity.data.store;
149
- }
150
-
151
- // Phase 6: Infer templates
152
- if (!skipPhases.has('templateInference') && state.domainStore) {
153
- phases.templateInference = executeTemplateInferencePhase(state.domainStore, validated);
154
- if (!phases.templateInference.success) {
155
- return buildFailureResult(
156
- phases,
157
- startTime,
158
- 'templateInference',
159
- phases.templateInference.error
160
- );
161
- }
162
- state.templateGraph = phases.templateInference.data.templateGraph;
163
- }
164
-
165
- // Phase 7: Create baseline snapshot
166
- if (!skipPhases.has('snapshot')) {
167
- phases.snapshot = executeSnapshotPhase(state, validated);
168
- if (!phases.snapshot.success) {
169
- return buildFailureResult(phases, startTime, 'snapshot', phases.snapshot.error);
170
- }
171
- state.snapshot = phases.snapshot.data.snapshot;
172
- }
173
-
174
- // Phase 8: Derive and register hooks
175
- if (!skipPhases.has('hooks') && state.domainStore) {
176
- phases.hooks = executeHooksPhase(state, validated);
177
- if (!phases.hooks.success) {
178
- return buildFailureResult(phases, startTime, 'hooks', phases.hooks.error);
179
- }
180
- }
181
-
182
- // Phase 9: Generate report
183
- phases.report = generateReportPhase(state, phases, validated);
184
-
185
- const totalDuration = Date.now() - startTime;
186
-
187
- return {
188
- success: true,
189
- receipt: {
190
- phases,
191
- totalDuration,
192
- success: true,
193
- metrics: phases.codeComplexity?.data?.summary,
194
- },
195
- report: phases.report.data.report,
196
- state,
197
- };
198
- }
199
-
200
- /**
201
- * Execute filesystem scan phase
202
- *
203
- * @private
204
- * @param {string} projectRoot
205
- * @param {Object} options
206
- * @returns {Promise<PhaseReceipt>}
207
- */
208
- async function executeScanPhase(projectRoot, options) {
209
- const startTime = Date.now();
210
-
211
- try {
212
- const { store, summary } = await scanFileSystemToStore({
213
- root: projectRoot,
214
- ignorePatterns: options.ignorePatterns,
215
- baseIri: `${options.baseIri}fs#`,
216
- });
217
-
218
- return {
219
- duration: Date.now() - startTime,
220
- success: true,
221
- data: {
222
- store,
223
- files: summary.fileCount,
224
- folders: summary.folderCount,
225
- ignored: summary.ignoredCount,
226
- },
227
- };
228
- } catch (error) {
229
- return {
230
- duration: Date.now() - startTime,
231
- success: false,
232
- error: error.message,
233
- };
234
- }
235
- }
236
-
237
- /**
238
- * Execute stack detection phase
239
- *
240
- * @private
241
- * @param {Store} fsStore
242
- * @param {Object} options
243
- * @returns {PhaseReceipt}
244
- */
245
- function executeStackDetectionPhase(fsStore, options) {
246
- const startTime = Date.now();
247
-
248
- try {
249
- const profile = detectStackFromFs({
250
- fsStore,
251
- projectIri: `${options.baseIri}project#project`,
252
- });
253
-
254
- const frameworks = [];
255
- if (profile.uiFramework) frameworks.push(profile.uiFramework);
256
- if (profile.webFramework) frameworks.push(profile.webFramework);
257
- if (profile.apiFramework && profile.apiFramework !== profile.webFramework) {
258
- frameworks.push(profile.apiFramework);
259
- }
260
- if (profile.testFramework) frameworks.push(profile.testFramework);
261
-
262
- return {
263
- duration: Date.now() - startTime,
264
- success: true,
265
- data: {
266
- profile,
267
- frameworks,
268
- },
269
- };
270
- } catch (error) {
271
- return {
272
- duration: Date.now() - startTime,
273
- success: false,
274
- error: error.message,
275
- };
276
- }
277
- }
278
-
279
- /**
280
- * Execute project model building phase
281
- *
282
- * @private
283
- * @param {Store} fsStore
284
- * @param {Object} options
285
- * @returns {PhaseReceipt}
286
- */
287
- function executeProjectModelPhase(fsStore, options) {
288
- const startTime = Date.now();
289
-
290
- try {
291
- const store = buildProjectModelFromFs({
292
- fsStore,
293
- baseIri: `${options.baseIri}project#`,
294
- conventions: options.conventions,
295
- });
296
-
297
- // Count features
298
- const featureQuads = store.getQuads(
299
- null,
300
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
301
- namedNode('http://example.org/unrdf/project#Feature')
302
- );
303
-
304
- // Count files
305
- const fileQuads = store.getQuads(
306
- null,
307
- namedNode('http://example.org/unrdf/filesystem#relativePath'),
308
- null
309
- );
310
-
311
- return {
312
- duration: Date.now() - startTime,
313
- success: true,
314
- data: {
315
- store,
316
- features: featureQuads.length,
317
- files: fileQuads.length,
318
- },
319
- };
320
- } catch (error) {
321
- return {
322
- duration: Date.now() - startTime,
323
- success: false,
324
- error: error.message,
325
- };
326
- }
327
- }
328
-
329
- /**
330
- * Execute file roles classification phase
331
- *
332
- * @private
333
- * @param {Store} projectStore
334
- * @param {Object} stackProfile
335
- * @param {Object} options
336
- * @returns {PhaseReceipt}
337
- */
338
- function executeFileRolesPhase(projectStore, stackProfile, options) {
339
- const startTime = Date.now();
340
-
341
- try {
342
- const store = classifyFiles({
343
- fsStore: projectStore,
344
- stackInfo: stackProfile,
345
- baseIri: `${options.baseIri}project#`,
346
- });
347
-
348
- // Count classified files
349
- const classifiedQuads = store.getQuads(
350
- null,
351
- namedNode('http://example.org/unrdf/project#roleString'),
352
- null
353
- );
354
-
355
- // Count total files
356
- const totalQuads = store.getQuads(
357
- null,
358
- namedNode('http://example.org/unrdf/filesystem#relativePath'),
359
- null
360
- );
361
-
362
- return {
363
- duration: Date.now() - startTime,
364
- success: true,
365
- data: {
366
- classified: classifiedQuads.length,
367
- unclassified: totalQuads.length - classifiedQuads.length,
368
- },
369
- };
370
- } catch (error) {
371
- return {
372
- duration: Date.now() - startTime,
373
- success: false,
374
- error: error.message,
375
- };
376
- }
377
- }
378
-
379
- /**
380
- * Execute domain inference phase
381
- *
382
- * @private
383
- * @param {Store} projectStore
384
- * @param {Object} options
385
- * @returns {PhaseReceipt}
386
- */
387
- function executeDomainInferencePhase(projectStore, options) {
388
- const startTime = Date.now();
389
-
390
- try {
391
- // Create domain store from project store
392
- const domainStore = createStore();
393
- const baseIri = `${options.baseIri}domain#`;
394
-
395
- // Extract entities from feature names and file patterns
396
- const featureQuads = projectStore.getQuads(
397
- null,
398
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
399
- null
400
- );
401
-
402
- const entities = new Map();
403
-
404
- for (const quad of featureQuads) {
405
- const featureName = quad.object.value;
406
- const entityName = inferEntityFromFeatureName(featureName);
407
-
408
- if (entityName && !entities.has(entityName)) {
409
- entities.set(entityName, { fields: [], source: featureName });
410
-
411
- const entityIri = namedNode(`${baseIri}${encodeURIComponent(entityName)}`);
412
- domainStore.addQuad(
413
- entityIri,
414
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
415
- namedNode('http://example.org/unrdf/domain#Entity')
416
- );
417
- domainStore.addQuad(
418
- entityIri,
419
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
420
- literal(entityName)
421
- );
422
- }
423
- }
424
-
425
- // Infer common fields for entities
426
- let totalFields = 0;
427
- for (const [entityName, _entity] of entities) {
428
- const fields = inferEntityFields(entityName);
429
- totalFields += fields.length;
430
-
431
- const entityIri = namedNode(`${baseIri}${encodeURIComponent(entityName)}`);
432
- for (const field of fields) {
433
- const fieldIri = namedNode(
434
- `${baseIri}${encodeURIComponent(entityName)}/${encodeURIComponent(field.name)}`
435
- );
436
- domainStore.addQuad(
437
- entityIri,
438
- namedNode('http://example.org/unrdf/domain#hasField'),
439
- fieldIri
440
- );
441
- domainStore.addQuad(
442
- fieldIri,
443
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
444
- literal(field.name)
445
- );
446
- domainStore.addQuad(
447
- fieldIri,
448
- namedNode('http://example.org/unrdf/domain#fieldType'),
449
- literal(field.type)
450
- );
451
- }
452
- }
453
-
454
- return {
455
- duration: Date.now() - startTime,
456
- success: true,
457
- data: {
458
- store: domainStore,
459
- entities: entities.size,
460
- fields: totalFields,
461
- },
462
- };
463
- } catch (error) {
464
- return {
465
- duration: Date.now() - startTime,
466
- success: false,
467
- error: error.message,
468
- };
469
- }
470
- }
471
-
472
- /**
473
- * Execute template inference phase
474
- *
475
- * @private
476
- * @param {Store} domainStore
477
- * @param {Object} options
478
- * @returns {PhaseReceipt}
479
- */
480
- function executeTemplateInferencePhase(domainStore, _options) {
481
- const startTime = Date.now();
482
-
483
- try {
484
- const templateGraph = {
485
- templates: [],
486
- patterns: [],
487
- };
488
-
489
- // Infer templates from entities
490
- const entityQuads = domainStore.getQuads(
491
- null,
492
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
493
- namedNode('http://example.org/unrdf/domain#Entity')
494
- );
495
-
496
- for (const quad of entityQuads) {
497
- const _entityIri = quad.subject.value;
498
- const labelQuads = domainStore.getQuads(
499
- quad.subject,
500
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
501
- null
502
- );
503
- const entityName = labelQuads[0]?.object.value || 'Unknown';
504
-
505
- // Infer templates for each entity
506
- const templates = inferTemplatesForEntity(entityName);
507
- templateGraph.templates.push(...templates);
508
- }
509
-
510
- // Infer patterns from template collection
511
- const patterns = inferPatternsFromTemplates(templateGraph.templates);
512
- templateGraph.patterns = patterns;
513
-
514
- return {
515
- duration: Date.now() - startTime,
516
- success: true,
517
- data: {
518
- templateGraph,
519
- templates: templateGraph.templates.length,
520
- patterns: templateGraph.patterns,
521
- },
522
- };
523
- } catch (error) {
524
- return {
525
- duration: Date.now() - startTime,
526
- success: false,
527
- error: error.message,
528
- };
529
- }
530
- }
531
-
532
- /**
533
- * Execute snapshot phase
534
- *
535
- * @private
536
- * @param {InitializationState} state
537
- * @param {Object} options
538
- * @returns {PhaseReceipt}
539
- */
540
- function executeSnapshotPhase(state, _options) {
541
- const startTime = Date.now();
542
-
543
- try {
544
- const snapshot = {
545
- hash: createSnapshotHash(state),
546
- timestamp: new Date().toISOString(),
547
- stores: {
548
- fsStoreSize: state.fsStore?.size || 0,
549
- projectStoreSize: state.projectStore?.size || 0,
550
- domainStoreSize: state.domainStore?.size || 0,
551
- },
552
- templateCount: state.templateGraph?.templates?.length || 0,
553
- };
554
-
555
- return {
556
- duration: Date.now() - startTime,
557
- success: true,
558
- data: {
559
- snapshot,
560
- hash: snapshot.hash,
561
- timestamp: snapshot.timestamp,
562
- },
563
- };
564
- } catch (error) {
565
- return {
566
- duration: Date.now() - startTime,
567
- success: false,
568
- error: error.message,
569
- };
570
- }
571
- }
572
-
573
- /**
574
- * Execute code complexity analysis phase
575
- *
576
- * @private
577
- * @param {string} projectRoot
578
- * @param {Store} [domainStore]
579
- * @param {Object} options
580
- * @returns {Promise<PhaseReceipt>}
581
- */
582
- async function executeCodeComplexityPhase(projectRoot, domainStore, _options) {
583
- const startTime = Date.now();
584
-
585
- try {
586
- const { store, summary } = await analyzeJsComplexity({
587
- projectRoot,
588
- baseStore: domainStore ? createStore(domainStore) : undefined,
589
- mode: 'observe',
590
- });
591
-
592
- return {
593
- duration: Date.now() - startTime,
594
- success: true,
595
- data: {
596
- store,
597
- summary,
598
- filesAnalyzed: summary.filesAnalyzed,
599
- averageComplexity: summary.averageCyclomatic,
600
- topRisks: summary.topRisks?.length || 0,
601
- },
602
- };
603
- } catch (error) {
604
- return {
605
- duration: Date.now() - startTime,
606
- success: false,
607
- error: error.message,
608
- };
609
- }
610
- }
611
-
612
- /**
613
- * Execute hooks registration phase
614
- *
615
- * @private
616
- * @param {InitializationState} state
617
- * @param {Object} options
618
- * @returns {PhaseReceipt}
619
- */
620
- function executeHooksPhase(state, _options) {
621
- const startTime = Date.now();
622
-
623
- try {
624
- const hooks = [];
625
- const invariants = [];
626
-
627
- // Derive hooks from domain entities
628
- const entityQuads = state.domainStore.getQuads(
629
- null,
630
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
631
- namedNode('http://example.org/unrdf/domain#Entity')
632
- );
633
-
634
- for (const quad of entityQuads) {
635
- const labelQuads = state.domainStore.getQuads(
636
- quad.subject,
637
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
638
- null
639
- );
640
- const entityName = labelQuads[0]?.object.value || 'Unknown';
641
-
642
- // Register validation hooks
643
- hooks.push({
644
- name: `validate${entityName}`,
645
- type: 'validation',
646
- entity: entityName,
647
- trigger: 'pre-commit',
648
- });
649
-
650
- // Register sync hooks
651
- hooks.push({
652
- name: `sync${entityName}ToStore`,
653
- type: 'sync',
654
- entity: entityName,
655
- trigger: 'post-save',
656
- });
657
-
658
- // Register invariants
659
- invariants.push({
660
- name: `${entityName}RequiredFields`,
661
- entity: entityName,
662
- rule: 'all-required-fields-present',
663
- });
664
- }
665
-
666
- return {
667
- duration: Date.now() - startTime,
668
- success: true,
669
- data: {
670
- registered: hooks.length,
671
- invariants,
672
- hooks,
673
- },
674
- };
675
- } catch (error) {
676
- return {
677
- duration: Date.now() - startTime,
678
- success: false,
679
- error: error.message,
680
- };
681
- }
682
- }
683
-
684
- /**
685
- * Generate final report phase
686
- *
687
- * @private
688
- * @param {InitializationState} state
689
- * @param {Object} phases
690
- * @param {Object} options
691
- * @returns {PhaseReceipt}
692
- */
693
- function generateReportPhase(state, phases, _options) {
694
- const startTime = Date.now();
695
-
696
- const report = {
697
- summary: generateSummary(phases),
698
- features: extractFeaturesList(state.projectStore),
699
- stack: phases.stackDetection?.data?.profile || null,
700
- entities: extractEntitiesList(state.domainStore),
701
- templates: state.templateGraph?.templates || [],
702
- hooks: phases.hooks?.data?.hooks || [],
703
- };
704
-
705
- return {
706
- duration: Date.now() - startTime,
707
- success: true,
708
- data: {
709
- report,
710
- },
711
- };
712
- }
713
-
714
- /**
715
- * Build failure result
716
- *
717
- * @private
718
- */
719
- function buildFailureResult(phases, startTime, failedPhase, errorMessage) {
720
- return {
721
- success: false,
722
- receipt: {
723
- phases,
724
- totalDuration: Date.now() - startTime,
725
- success: false,
726
- failedPhase,
727
- error: errorMessage,
728
- },
729
- report: {
730
- summary: `Initialization failed at phase: ${failedPhase}`,
731
- error: errorMessage,
732
- },
733
- state: {
734
- fsStore: null,
735
- projectStore: null,
736
- domainStore: null,
737
- templateGraph: null,
738
- snapshot: null,
739
- },
740
- };
741
- }
742
-
743
- /**
744
- * Infer entity name from feature name
745
- *
746
- * @private
747
- */
748
- function inferEntityFromFeatureName(featureName) {
749
- // Skip common non-entity folders
750
- const nonEntities = ['utils', 'helpers', 'lib', 'shared', 'common', 'config', 'hooks', 'types'];
751
- if (nonEntities.includes(featureName.toLowerCase())) {
752
- return null;
753
- }
754
-
755
- // Singularize common patterns
756
- let entity = featureName;
757
- if (entity.endsWith('s') && !entity.endsWith('ss')) {
758
- entity = entity.slice(0, -1);
759
- }
760
-
761
- // PascalCase
762
- return entity.charAt(0).toUpperCase() + entity.slice(1);
763
- }
764
-
765
- /**
766
- * Infer common fields for an entity
767
- *
768
- * @private
769
- */
770
- function inferEntityFields(entityName) {
771
- // Common fields for all entities
772
- const commonFields = [
773
- { name: 'id', type: 'string' },
774
- { name: 'createdAt', type: 'datetime' },
775
- { name: 'updatedAt', type: 'datetime' },
776
- ];
777
-
778
- // Entity-specific fields
779
- const specificFields = {
780
- User: [
781
- { name: 'email', type: 'string' },
782
- { name: 'name', type: 'string' },
783
- { name: 'role', type: 'string' },
784
- ],
785
- Product: [
786
- { name: 'name', type: 'string' },
787
- { name: 'price', type: 'number' },
788
- { name: 'description', type: 'string' },
789
- ],
790
- Order: [
791
- { name: 'status', type: 'string' },
792
- { name: 'total', type: 'number' },
793
- { name: 'items', type: 'array' },
794
- ],
795
- Post: [
796
- { name: 'title', type: 'string' },
797
- { name: 'content', type: 'string' },
798
- { name: 'author', type: 'reference' },
799
- ],
800
- };
801
-
802
- return [...commonFields, ...(specificFields[entityName] || [])];
803
- }
804
-
805
- /**
806
- * Infer templates for an entity
807
- *
808
- * @private
809
- */
810
- function inferTemplatesForEntity(entityName) {
811
- return [
812
- { name: `${entityName}Component`, type: 'component', entity: entityName },
813
- { name: `${entityName}Form`, type: 'form', entity: entityName },
814
- { name: `${entityName}List`, type: 'list', entity: entityName },
815
- { name: `${entityName}Service`, type: 'service', entity: entityName },
816
- { name: `${entityName}Schema`, type: 'schema', entity: entityName },
817
- ];
818
- }
819
-
820
- /**
821
- * Infer patterns from templates
822
- *
823
- * @private
824
- */
825
- function inferPatternsFromTemplates(templates) {
826
- const patterns = [];
827
- const templateTypes = new Set(templates.map(t => t.type));
828
-
829
- if (templateTypes.has('component') && templateTypes.has('form')) {
830
- patterns.push('crud-ui');
831
- }
832
- if (templateTypes.has('service') && templateTypes.has('schema')) {
833
- patterns.push('api-first');
834
- }
835
- if (templateTypes.has('list')) {
836
- patterns.push('data-table');
837
- }
838
-
839
- return patterns;
840
- }
841
-
842
- /**
843
- * Create hash for snapshot
844
- *
845
- * @private
846
- */
847
- function createSnapshotHash(state) {
848
- const hash = createHash('sha256');
849
-
850
- if (state.fsStore) hash.update(String(state.fsStore.size));
851
- if (state.projectStore) hash.update(String(state.projectStore.size));
852
- if (state.domainStore) hash.update(String(state.domainStore.size));
853
- if (state.templateGraph) hash.update(String(state.templateGraph.templates?.length || 0));
854
-
855
- hash.update(new Date().toISOString());
856
-
857
- return hash.digest('hex').substring(0, 16);
858
- }
859
-
860
- /**
861
- * Generate summary from phases
862
- *
863
- * @private
864
- */
865
- function generateSummary(phases) {
866
- const parts = [];
867
-
868
- if (phases.scan?.success) {
869
- parts.push(`Scanned ${phases.scan.data.files} files in ${phases.scan.data.folders} folders`);
870
- }
871
- if (phases.stackDetection?.success) {
872
- const frameworks = phases.stackDetection.data.frameworks;
873
- if (frameworks.length > 0) {
874
- parts.push(`Detected stack: ${frameworks.join(', ')}`);
875
- }
876
- }
877
- if (phases.projectModel?.success) {
878
- parts.push(`Found ${phases.projectModel.data.features} features`);
879
- }
880
- if (phases.fileRoles?.success) {
881
- parts.push(`Classified ${phases.fileRoles.data.classified} files`);
882
- }
883
- if (phases.domainInference?.success) {
884
- parts.push(
885
- `Inferred ${phases.domainInference.data.entities} entities with ${phases.domainInference.data.fields} fields`
886
- );
887
- }
888
- if (phases.templateInference?.success) {
889
- parts.push(`Generated ${phases.templateInference.data.templates} templates`);
890
- }
891
- if (phases.hooks?.success) {
892
- parts.push(`Registered ${phases.hooks.data.registered} hooks`);
893
- }
894
-
895
- return parts.join('. ') + '.';
896
- }
897
-
898
- /**
899
- * Extract features list from project store
900
- *
901
- * @private
902
- */
903
- function extractFeaturesList(projectStore) {
904
- if (!projectStore) return [];
905
-
906
- const features = [];
907
- const labelQuads = projectStore.getQuads(
908
- null,
909
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
910
- null
911
- );
912
-
913
- for (const quad of labelQuads) {
914
- // Check if this is a feature
915
- const typeQuads = projectStore.getQuads(
916
- quad.subject,
917
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
918
- namedNode('http://example.org/unrdf/project#Feature')
919
- );
920
-
921
- if (typeQuads.length > 0) {
922
- features.push(quad.object.value);
923
- }
924
- }
925
-
926
- return features;
927
- }
928
-
929
- /**
930
- * Extract entities list from domain store
931
- *
932
- * @private
933
- */
934
- function extractEntitiesList(domainStore) {
935
- if (!domainStore) return [];
936
-
937
- const entities = [];
938
- const entityQuads = domainStore.getQuads(
939
- null,
940
- namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
941
- namedNode('http://example.org/unrdf/domain#Entity')
942
- );
943
-
944
- for (const quad of entityQuads) {
945
- const labelQuads = domainStore.getQuads(
946
- quad.subject,
947
- namedNode('http://www.w3.org/2000/01/rdf-schema#label'),
948
- null
949
- );
950
-
951
- if (labelQuads.length > 0) {
952
- entities.push(labelQuads[0].object.value);
953
- }
954
- }
955
-
956
- return entities;
957
- }