@unrdf/project-engine 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.
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/package.json +58 -0
- package/src/api-contract-validator.mjs +711 -0
- package/src/auto-test-generator.mjs +444 -0
- package/src/autonomic-mapek.mjs +511 -0
- package/src/capabilities-manifest.mjs +125 -0
- package/src/code-complexity-js.mjs +368 -0
- package/src/dependency-graph.mjs +276 -0
- package/src/doc-drift-checker.mjs +172 -0
- package/src/doc-generator.mjs +229 -0
- package/src/domain-infer.mjs +966 -0
- package/src/drift-snapshot.mjs +775 -0
- package/src/file-roles.mjs +94 -0
- package/src/fs-scan.mjs +305 -0
- package/src/gap-finder.mjs +376 -0
- package/src/golden-structure.mjs +149 -0
- package/src/hotspot-analyzer.mjs +412 -0
- package/src/index.mjs +151 -0
- package/src/initialize.mjs +957 -0
- package/src/lens/project-structure.mjs +74 -0
- package/src/mapek-orchestration.mjs +665 -0
- package/src/materialize-apply.mjs +505 -0
- package/src/materialize-plan.mjs +422 -0
- package/src/materialize.mjs +137 -0
- package/src/policy-derivation.mjs +869 -0
- package/src/project-config.mjs +142 -0
- package/src/project-diff.mjs +28 -0
- package/src/project-engine/build-utils.mjs +237 -0
- package/src/project-engine/code-analyzer.mjs +248 -0
- package/src/project-engine/doc-generator.mjs +407 -0
- package/src/project-engine/infrastructure.mjs +213 -0
- package/src/project-engine/metrics.mjs +146 -0
- package/src/project-model.mjs +111 -0
- package/src/project-report.mjs +348 -0
- package/src/refactoring-guide.mjs +242 -0
- package/src/stack-detect.mjs +102 -0
- package/src/stack-linter.mjs +213 -0
- package/src/template-infer.mjs +674 -0
- package/src/type-auditor.mjs +609 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Hotspot analyzer - identify high-risk features by complexity metrics
|
|
3
|
+
* @module project-engine/hotspot-analyzer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { UnrdfDataFactory as DataFactory } from '@unrdf/core/rdf/n3-justified-only';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
const { namedNode, _literal } = DataFactory;
|
|
10
|
+
|
|
11
|
+
const NS = {
|
|
12
|
+
rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
|
13
|
+
rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
|
|
14
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#',
|
|
15
|
+
fs: 'http://example.org/unrdf/filesystem#',
|
|
16
|
+
proj: 'http://example.org/unrdf/project#',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Scoring weights for hotspot calculation
|
|
21
|
+
* @type {{fileCount: number, testCoverage: number, dependencies: number, complexity: number}}
|
|
22
|
+
*/
|
|
23
|
+
const SCORING_WEIGHTS = {
|
|
24
|
+
fileCount: 0.3,
|
|
25
|
+
testCoverage: 0.4,
|
|
26
|
+
dependencies: 0.2,
|
|
27
|
+
complexity: 0.1,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Risk thresholds
|
|
32
|
+
*/
|
|
33
|
+
const RISK_THRESHOLDS = {
|
|
34
|
+
HIGH: 70,
|
|
35
|
+
MEDIUM: 40,
|
|
36
|
+
LOW: 0,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const HotspotOptionsSchema = z.object({
|
|
40
|
+
projectStore: z.custom(val => val && typeof val.getQuads === 'function', {
|
|
41
|
+
message: 'projectStore must be an RDF store with getQuads method',
|
|
42
|
+
}),
|
|
43
|
+
domainStore: z
|
|
44
|
+
.custom(val => val && typeof val.getQuads === 'function', {
|
|
45
|
+
message: 'domainStore must be an RDF store with getQuads method',
|
|
46
|
+
})
|
|
47
|
+
.optional(),
|
|
48
|
+
stackProfile: z
|
|
49
|
+
.object({
|
|
50
|
+
testFramework: z.string().nullable().optional(),
|
|
51
|
+
sourceRoot: z.string().optional(),
|
|
52
|
+
})
|
|
53
|
+
.optional(),
|
|
54
|
+
baseIri: z.string().default('http://example.org/unrdf/hotspot#'),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const FeatureMetricsSchema = z.object({
|
|
58
|
+
fileCount: z.number().min(0),
|
|
59
|
+
lineCount: z.number().min(0),
|
|
60
|
+
testCount: z.number().min(0),
|
|
61
|
+
testCoverage: z.number().min(0).max(100),
|
|
62
|
+
dependencies: z.number().min(0),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {Object} FeatureMetrics
|
|
67
|
+
* @property {number} fileCount - Total files in the feature
|
|
68
|
+
* @property {number} lineCount - Approximate line count (from byte size)
|
|
69
|
+
* @property {number} testCount - Number of test files
|
|
70
|
+
* @property {number} testCoverage - Test coverage percentage (testCount / fileCount * 100)
|
|
71
|
+
* @property {number} dependencies - Number of dependencies/relationships
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @typedef {Object} HotspotEntry
|
|
76
|
+
* @property {string} feature - Feature name
|
|
77
|
+
* @property {number} score - Hotspot score (0-100)
|
|
78
|
+
* @property {'HIGH'|'MEDIUM'|'LOW'} risk - Risk level
|
|
79
|
+
* @property {FeatureMetrics} metrics - Detailed metrics
|
|
80
|
+
* @property {string} recommendation - Actionable recommendation
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @typedef {Object} HotspotResult
|
|
85
|
+
* @property {HotspotEntry[]} hotspots - All features with scores
|
|
86
|
+
* @property {{feature: string, score: number, reason: string}[]} topRisks - Top risk features
|
|
87
|
+
* @property {string} summary - Human-readable summary
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Analyze project for hotspots - high-risk or high-complexity features
|
|
92
|
+
*
|
|
93
|
+
* @param {Object} options
|
|
94
|
+
* @param {Store} options.projectStore - Project model store (with features, file roles)
|
|
95
|
+
* @param {Store} [options.domainStore] - Domain model store (optional, for relationships)
|
|
96
|
+
* @param {Object} [options.stackProfile] - Stack information
|
|
97
|
+
* @param {string} [options.baseIri] - Base IRI for hotspot resources
|
|
98
|
+
* @returns {HotspotResult} Hotspot analysis results
|
|
99
|
+
*/
|
|
100
|
+
export function analyzeHotspots(options) {
|
|
101
|
+
const validated = HotspotOptionsSchema.parse(options);
|
|
102
|
+
const { projectStore, domainStore, _baseIri } = validated;
|
|
103
|
+
|
|
104
|
+
// Extract all features from the project store
|
|
105
|
+
const features = extractFeatures(projectStore);
|
|
106
|
+
|
|
107
|
+
// Calculate metrics for each feature
|
|
108
|
+
const hotspots = [];
|
|
109
|
+
for (const [featureName, featureData] of Object.entries(features)) {
|
|
110
|
+
const metrics = calculateFeatureMetrics(featureName, featureData, projectStore, domainStore);
|
|
111
|
+
const score = scoreFeature(featureName, metrics);
|
|
112
|
+
const risk = getRiskLevel(score);
|
|
113
|
+
const recommendation = generateRecommendation(featureName, metrics, risk);
|
|
114
|
+
|
|
115
|
+
hotspots.push({
|
|
116
|
+
feature: featureName,
|
|
117
|
+
score,
|
|
118
|
+
risk,
|
|
119
|
+
metrics,
|
|
120
|
+
recommendation,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Sort by score descending (highest risk first)
|
|
125
|
+
hotspots.sort((a, b) => b.score - a.score);
|
|
126
|
+
|
|
127
|
+
// Extract top risks (score > 40 or top 5)
|
|
128
|
+
const topRisks = hotspots
|
|
129
|
+
.filter(h => h.score > RISK_THRESHOLDS.MEDIUM)
|
|
130
|
+
.slice(0, 5)
|
|
131
|
+
.map(h => ({
|
|
132
|
+
feature: h.feature,
|
|
133
|
+
score: h.score,
|
|
134
|
+
reason: `${h.metrics.fileCount} files, ${h.metrics.testCoverage}% coverage`,
|
|
135
|
+
}));
|
|
136
|
+
|
|
137
|
+
// Generate summary
|
|
138
|
+
const highRiskCount = hotspots.filter(h => h.risk === 'HIGH').length;
|
|
139
|
+
const summary =
|
|
140
|
+
highRiskCount > 0
|
|
141
|
+
? `${highRiskCount} high-risk feature${highRiskCount > 1 ? 's' : ''} identified`
|
|
142
|
+
: 'No high-risk features identified';
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
hotspots,
|
|
146
|
+
topRisks,
|
|
147
|
+
summary,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Score a feature based on its metrics
|
|
153
|
+
*
|
|
154
|
+
* Formula:
|
|
155
|
+
* - File count: 30% weight - more files = higher score
|
|
156
|
+
* - Test coverage: 40% weight - LESS coverage = higher score
|
|
157
|
+
* - Dependencies: 20% weight - more deps = higher score
|
|
158
|
+
* - Complexity: 10% weight - larger files = higher score
|
|
159
|
+
*
|
|
160
|
+
* @param {string} feature - Feature name
|
|
161
|
+
* @param {FeatureMetrics} metrics - Feature metrics
|
|
162
|
+
* @returns {number} Score 0-100 (higher = more risk)
|
|
163
|
+
*/
|
|
164
|
+
export function scoreFeature(feature, metrics) {
|
|
165
|
+
const validatedMetrics = FeatureMetricsSchema.parse(metrics);
|
|
166
|
+
|
|
167
|
+
// File count score: normalized to 0-100 (40 files = 100)
|
|
168
|
+
const fileCountScore = Math.min(100, (validatedMetrics.fileCount / 40) * 100);
|
|
169
|
+
|
|
170
|
+
// Test coverage score: inverted (less coverage = higher score)
|
|
171
|
+
const testCoverageScore = 100 - validatedMetrics.testCoverage;
|
|
172
|
+
|
|
173
|
+
// Dependencies score: normalized to 0-100 (15 deps = 100)
|
|
174
|
+
const dependencyScore = Math.min(100, (validatedMetrics.dependencies / 15) * 100);
|
|
175
|
+
|
|
176
|
+
// Complexity score: based on average lines per file (200 lines/file = 100)
|
|
177
|
+
const avgLinesPerFile =
|
|
178
|
+
validatedMetrics.fileCount > 0 ? validatedMetrics.lineCount / validatedMetrics.fileCount : 0;
|
|
179
|
+
const complexityScore = Math.min(100, (avgLinesPerFile / 200) * 100);
|
|
180
|
+
|
|
181
|
+
// Weighted average
|
|
182
|
+
const score =
|
|
183
|
+
fileCountScore * SCORING_WEIGHTS.fileCount +
|
|
184
|
+
testCoverageScore * SCORING_WEIGHTS.testCoverage +
|
|
185
|
+
dependencyScore * SCORING_WEIGHTS.dependencies +
|
|
186
|
+
complexityScore * SCORING_WEIGHTS.complexity;
|
|
187
|
+
|
|
188
|
+
return Math.round(score);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extract features from project store
|
|
193
|
+
*
|
|
194
|
+
* @private
|
|
195
|
+
* @param {Store} projectStore
|
|
196
|
+
* @returns {Object<string, {iri: string, files: string[]}>}
|
|
197
|
+
*/
|
|
198
|
+
function extractFeatures(projectStore) {
|
|
199
|
+
const features = {};
|
|
200
|
+
|
|
201
|
+
// Get all feature IRIs
|
|
202
|
+
const featureQuads = projectStore.getQuads(
|
|
203
|
+
null,
|
|
204
|
+
namedNode(`${NS.rdf}type`),
|
|
205
|
+
namedNode(`${NS.proj}Feature`)
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
for (const quad of featureQuads) {
|
|
209
|
+
const featureIri = quad.subject.value;
|
|
210
|
+
|
|
211
|
+
// Get feature label
|
|
212
|
+
const labelQuads = projectStore.getQuads(quad.subject, namedNode(`${NS.rdfs}label`), null);
|
|
213
|
+
const featureName =
|
|
214
|
+
labelQuads.length > 0 ? labelQuads[0].object.value : extractNameFromIri(featureIri);
|
|
215
|
+
|
|
216
|
+
// Get files belonging to this feature
|
|
217
|
+
const fileQuads = projectStore.getQuads(
|
|
218
|
+
null,
|
|
219
|
+
namedNode(`${NS.proj}belongsToFeature`),
|
|
220
|
+
quad.subject
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const files = fileQuads.map(fq => {
|
|
224
|
+
const pathQuads = projectStore.getQuads(fq.subject, namedNode(`${NS.fs}relativePath`), null);
|
|
225
|
+
return pathQuads.length > 0 ? pathQuads[0].object.value : fq.subject.value;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
features[featureName] = {
|
|
229
|
+
iri: featureIri,
|
|
230
|
+
files,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return features;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Calculate metrics for a feature
|
|
239
|
+
*
|
|
240
|
+
* @private
|
|
241
|
+
* @param {string} featureName
|
|
242
|
+
* @param {{iri: string, files: string[]}} featureData
|
|
243
|
+
* @param {Store} projectStore
|
|
244
|
+
* @param {Store} [domainStore]
|
|
245
|
+
* @returns {FeatureMetrics}
|
|
246
|
+
*/
|
|
247
|
+
function calculateFeatureMetrics(featureName, featureData, projectStore, domainStore) {
|
|
248
|
+
const files = featureData.files;
|
|
249
|
+
const fileCount = files.length;
|
|
250
|
+
|
|
251
|
+
// Count test files (files with Test role or .test./.spec. in name)
|
|
252
|
+
let testCount = 0;
|
|
253
|
+
let totalByteSize = 0;
|
|
254
|
+
|
|
255
|
+
for (const filePath of files) {
|
|
256
|
+
// Check if test file
|
|
257
|
+
if (isTestFile(filePath, projectStore)) {
|
|
258
|
+
testCount++;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Get byte size for line count approximation
|
|
262
|
+
const fileIri = namedNode(`http://example.org/unrdf/fs#${encodeURIComponent(filePath)}`);
|
|
263
|
+
const sizeQuads = projectStore.getQuads(fileIri, namedNode(`${NS.fs}byteSize`), null);
|
|
264
|
+
if (sizeQuads.length > 0) {
|
|
265
|
+
totalByteSize += parseInt(sizeQuads[0].object.value, 10) || 0;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Approximate line count (assume ~40 bytes per line average)
|
|
270
|
+
const lineCount = Math.round(totalByteSize / 40);
|
|
271
|
+
|
|
272
|
+
// Test coverage: percentage of test files
|
|
273
|
+
const testCoverage = fileCount > 0 ? Math.round((testCount / fileCount) * 100) : 100; // No files = 100% coverage (nothing to test)
|
|
274
|
+
|
|
275
|
+
// Count dependencies from domain store or project relationships
|
|
276
|
+
const dependencies = countDependencies(featureData, projectStore, domainStore);
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
fileCount,
|
|
280
|
+
lineCount,
|
|
281
|
+
testCount,
|
|
282
|
+
testCoverage,
|
|
283
|
+
dependencies,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Check if a file is a test file
|
|
289
|
+
*
|
|
290
|
+
* @private
|
|
291
|
+
* @param {string} filePath
|
|
292
|
+
* @param {Store} projectStore
|
|
293
|
+
* @returns {boolean}
|
|
294
|
+
*/
|
|
295
|
+
function isTestFile(filePath, projectStore) {
|
|
296
|
+
// Check by file path pattern
|
|
297
|
+
if (/\.(test|spec)\.(tsx?|jsx?|mjs)$/.test(filePath)) {
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
if (/^(test|tests|__tests__|spec)\//.test(filePath)) {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Check by role in store
|
|
305
|
+
const fileIri = namedNode(`http://example.org/unrdf/fs#${encodeURIComponent(filePath)}`);
|
|
306
|
+
const roleQuads = projectStore.getQuads(fileIri, namedNode(`${NS.proj}roleString`), null);
|
|
307
|
+
|
|
308
|
+
return roleQuads.some(q => q.object.value === 'Test');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Count dependencies for a feature
|
|
313
|
+
*
|
|
314
|
+
* @private
|
|
315
|
+
* @param {{iri: string, files: string[]}} featureData
|
|
316
|
+
* @param {Store} projectStore
|
|
317
|
+
* @param {Store} [domainStore]
|
|
318
|
+
* @returns {number}
|
|
319
|
+
*/
|
|
320
|
+
function countDependencies(featureData, projectStore, domainStore) {
|
|
321
|
+
let deps = 0;
|
|
322
|
+
|
|
323
|
+
// Count relationships from project store
|
|
324
|
+
const featureIri = namedNode(featureData.iri);
|
|
325
|
+
const relQuads = projectStore.getQuads(featureIri, null, null);
|
|
326
|
+
|
|
327
|
+
// Count outgoing relationships (excluding type and label)
|
|
328
|
+
for (const quad of relQuads) {
|
|
329
|
+
if (quad.predicate.value !== `${NS.rdf}type` && quad.predicate.value !== `${NS.rdfs}label`) {
|
|
330
|
+
deps++;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// If domain store provided, count entity relationships
|
|
335
|
+
if (domainStore) {
|
|
336
|
+
const domainRels = domainStore.getQuads(
|
|
337
|
+
null,
|
|
338
|
+
namedNode('http://example.org/unrdf/domain#relatesTo'),
|
|
339
|
+
null
|
|
340
|
+
);
|
|
341
|
+
// Count unique relationships (simplified - just total)
|
|
342
|
+
deps += Math.min(domainRels.length, 20);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return deps;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Get risk level from score
|
|
350
|
+
*
|
|
351
|
+
* @private
|
|
352
|
+
* @param {number} score
|
|
353
|
+
* @returns {'HIGH'|'MEDIUM'|'LOW'}
|
|
354
|
+
*/
|
|
355
|
+
function getRiskLevel(score) {
|
|
356
|
+
if (score >= RISK_THRESHOLDS.HIGH) return 'HIGH';
|
|
357
|
+
if (score >= RISK_THRESHOLDS.MEDIUM) return 'MEDIUM';
|
|
358
|
+
return 'LOW';
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Generate recommendation based on metrics and risk
|
|
363
|
+
*
|
|
364
|
+
* @private
|
|
365
|
+
* @param {string} featureName
|
|
366
|
+
* @param {FeatureMetrics} metrics
|
|
367
|
+
* @param {'HIGH'|'MEDIUM'|'LOW'} risk
|
|
368
|
+
* @returns {string}
|
|
369
|
+
*/
|
|
370
|
+
function generateRecommendation(featureName, metrics, risk) {
|
|
371
|
+
const issues = [];
|
|
372
|
+
|
|
373
|
+
if (metrics.fileCount > 30) {
|
|
374
|
+
issues.push('high file count');
|
|
375
|
+
}
|
|
376
|
+
if (metrics.testCoverage < 50) {
|
|
377
|
+
issues.push('low test coverage');
|
|
378
|
+
}
|
|
379
|
+
if (metrics.dependencies > 10) {
|
|
380
|
+
issues.push('many dependencies');
|
|
381
|
+
}
|
|
382
|
+
if (metrics.lineCount > 5000) {
|
|
383
|
+
issues.push('large codebase');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (issues.length === 0) {
|
|
387
|
+
return 'Feature is within acceptable complexity thresholds.';
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const issueStr = issues.join(' + ');
|
|
391
|
+
const action =
|
|
392
|
+
risk === 'HIGH'
|
|
393
|
+
? 'Add tests or refactor.'
|
|
394
|
+
: risk === 'MEDIUM'
|
|
395
|
+
? 'Consider adding tests.'
|
|
396
|
+
: 'Monitor for growth.';
|
|
397
|
+
|
|
398
|
+
return `${issueStr.charAt(0).toUpperCase() + issueStr.slice(1)}. ${action}`;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Extract name from IRI
|
|
403
|
+
*
|
|
404
|
+
* @private
|
|
405
|
+
* @param {string} iri
|
|
406
|
+
* @returns {string}
|
|
407
|
+
*/
|
|
408
|
+
function extractNameFromIri(iri) {
|
|
409
|
+
const parts = iri.split(/[#/]/);
|
|
410
|
+
const last = parts[parts.length - 1];
|
|
411
|
+
return decodeURIComponent(last);
|
|
412
|
+
}
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Project engine exports
|
|
3
|
+
* @module project-engine
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { scanFileSystemToStore } from './fs-scan.mjs';
|
|
7
|
+
export { buildProjectModelFromFs } from './project-model.mjs';
|
|
8
|
+
export { detectStackFromFs } from './stack-detect.mjs';
|
|
9
|
+
export { classifyFiles } from './file-roles.mjs';
|
|
10
|
+
// Removed unused export: generateGoldenStructure (never imported/used)
|
|
11
|
+
export { diffProjectStructure } from './project-diff.mjs';
|
|
12
|
+
export { materializeArtifacts } from './materialize.mjs';
|
|
13
|
+
export { ProjectStructureLens } from './lens/project-structure.mjs';
|
|
14
|
+
export { getProjectEngineConfig, ProjectEngineConfigSchema } from './project-config.mjs';
|
|
15
|
+
export { buildProjectReport } from './project-report.mjs';
|
|
16
|
+
export { createProjectInitializationPipeline } from './initialize.mjs';
|
|
17
|
+
export {
|
|
18
|
+
deriveHooksFromStructure,
|
|
19
|
+
analyzePatternViolations,
|
|
20
|
+
createCustomPatternHook,
|
|
21
|
+
} from './policy-derivation.mjs';
|
|
22
|
+
export { inferDomainModel, inferDomainModelFromPath, DomainModelLens } from './domain-infer.mjs';
|
|
23
|
+
export {
|
|
24
|
+
inferTemplatesFromProject,
|
|
25
|
+
inferTemplatesWithDomainBinding,
|
|
26
|
+
getTemplatesByKind,
|
|
27
|
+
serializeTemplates,
|
|
28
|
+
} from './template-infer.mjs';
|
|
29
|
+
|
|
30
|
+
// Materialization planning and execution
|
|
31
|
+
export {
|
|
32
|
+
planMaterialization,
|
|
33
|
+
validatePlan,
|
|
34
|
+
createEmptyPlan,
|
|
35
|
+
mergePlans,
|
|
36
|
+
} from './materialize-plan.mjs';
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
applyMaterializationPlan,
|
|
40
|
+
rollbackMaterialization,
|
|
41
|
+
previewPlan,
|
|
42
|
+
checkPlanApplicability,
|
|
43
|
+
} from './materialize-apply.mjs';
|
|
44
|
+
|
|
45
|
+
// Drift detection
|
|
46
|
+
export {
|
|
47
|
+
createStructureSnapshot,
|
|
48
|
+
computeDrift,
|
|
49
|
+
createEmptyBaseline,
|
|
50
|
+
serializeSnapshot,
|
|
51
|
+
deserializeSnapshot,
|
|
52
|
+
} from './drift-snapshot.mjs';
|
|
53
|
+
|
|
54
|
+
// Hotspot analysis
|
|
55
|
+
export { analyzeHotspots, scoreFeature } from './hotspot-analyzer.mjs';
|
|
56
|
+
|
|
57
|
+
// Gap detection
|
|
58
|
+
export { findMissingRoles, scoreMissingRole } from './gap-finder.mjs';
|
|
59
|
+
|
|
60
|
+
// Type-safety auditing
|
|
61
|
+
export {
|
|
62
|
+
auditTypeConsistency,
|
|
63
|
+
auditEntityTypes,
|
|
64
|
+
compareTypes,
|
|
65
|
+
FieldInfoSchema,
|
|
66
|
+
MismatchSchema,
|
|
67
|
+
AuditResultSchema,
|
|
68
|
+
CompareTypesResultSchema,
|
|
69
|
+
} from './type-auditor.mjs';
|
|
70
|
+
|
|
71
|
+
// Autonomic MAPEK Loop - Full autonomics with Knowledge Hooks
|
|
72
|
+
export {
|
|
73
|
+
runMapekIteration,
|
|
74
|
+
createAutonomicHooks,
|
|
75
|
+
runContinuousMapekLoop,
|
|
76
|
+
reportMapekStatus,
|
|
77
|
+
} from './autonomic-mapek.mjs';
|
|
78
|
+
|
|
79
|
+
// API Contract Validation
|
|
80
|
+
export {
|
|
81
|
+
generateAPISchema,
|
|
82
|
+
generateAllAPISchemas,
|
|
83
|
+
validateAPIFiles,
|
|
84
|
+
detectContractBreaks,
|
|
85
|
+
detectAllContractBreaks,
|
|
86
|
+
FieldSchemaSchema,
|
|
87
|
+
EntitySchemaSchema,
|
|
88
|
+
ViolationSchema,
|
|
89
|
+
ValidationResultSchema,
|
|
90
|
+
BreakingChangeSchema,
|
|
91
|
+
ContractBreaksSchema,
|
|
92
|
+
} from './api-contract-validator.mjs';
|
|
93
|
+
|
|
94
|
+
// Stack-Aware Linter Rules
|
|
95
|
+
export { deriveLinterRules, analyzeCodePatterns, generateESLintConfig } from './stack-linter.mjs';
|
|
96
|
+
|
|
97
|
+
// Removed unused exports: planEntityRename, planEntityMerge, planServiceExtraction, validateRefactoringPlan (never imported/used)
|
|
98
|
+
|
|
99
|
+
// JavaScript Code Complexity Analysis
|
|
100
|
+
export { analyzeJsComplexity } from './code-complexity-js.mjs';
|
|
101
|
+
|
|
102
|
+
// Capabilities Manifest - Feature flags and metadata
|
|
103
|
+
export {
|
|
104
|
+
CODE_COMPLEXITY_JS,
|
|
105
|
+
CAPABILITIES,
|
|
106
|
+
FEATURE_FLAGS,
|
|
107
|
+
isCapabilityEnabled,
|
|
108
|
+
getCapabilityMetadata,
|
|
109
|
+
getEnabledCapabilities,
|
|
110
|
+
setCapabilityEnabled,
|
|
111
|
+
} from './capabilities-manifest.mjs';
|
|
112
|
+
|
|
113
|
+
// Feature Dependency Graph
|
|
114
|
+
export {
|
|
115
|
+
buildDependencyGraph,
|
|
116
|
+
detectCircularDependencies,
|
|
117
|
+
topologicalSort,
|
|
118
|
+
analyzeDependencyPath,
|
|
119
|
+
getTransitiveDependencies,
|
|
120
|
+
// Removed unused export: getTransitiveDependents (never imported/used, getTransitiveDependencies is used)
|
|
121
|
+
calculateImpactScore,
|
|
122
|
+
} from './dependency-graph.mjs';
|
|
123
|
+
|
|
124
|
+
// Auto-Test Generator
|
|
125
|
+
export {
|
|
126
|
+
inferTestPatterns,
|
|
127
|
+
generateTestSkeleton,
|
|
128
|
+
scoreTestCoverage,
|
|
129
|
+
generateTestFactory,
|
|
130
|
+
} from './auto-test-generator.mjs';
|
|
131
|
+
|
|
132
|
+
// Removed unused exports: generateEntityReference, generateAPIReference, generateArchitectureDiagram, generateCompleteDocumentation (never imported/used)
|
|
133
|
+
// Kept DocGenerationResultSchema as it may be used by checkDocConsistency
|
|
134
|
+
export { DocGenerationResultSchema } from './doc-generator.mjs';
|
|
135
|
+
|
|
136
|
+
// Documentation Drift Checker - validate documentation consistency against domain model
|
|
137
|
+
export {
|
|
138
|
+
checkDocConsistency,
|
|
139
|
+
extractDocReferences,
|
|
140
|
+
scoreDocDrift,
|
|
141
|
+
checkDocDrift,
|
|
142
|
+
DriftEntrySchema,
|
|
143
|
+
} from './doc-drift-checker.mjs';
|
|
144
|
+
|
|
145
|
+
// MAPEK Orchestration - Unified execution with all innovations
|
|
146
|
+
export {
|
|
147
|
+
runFullMapekWithAllInnovations,
|
|
148
|
+
runInnovationsParallel,
|
|
149
|
+
aggregateInnovationFindings,
|
|
150
|
+
ALL_INNOVATIONS,
|
|
151
|
+
} from './mapek-orchestration.mjs';
|