@archpilotlabs/archpilot 0.0.9 → 0.0.11
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/archpilot-cli.js +1227 -201
- package/package.json +1 -1
package/dist/archpilot-cli.js
CHANGED
|
@@ -213475,7 +213475,264 @@ async function listModuleDirectoryNames(workspaceRoot, modulesRootRelativePath =
|
|
|
213475
213475
|
const entries = await import_node_fs.promises.readdir(modulesRoot, { withFileTypes: true });
|
|
213476
213476
|
return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort((left, right) => left.localeCompare(right));
|
|
213477
213477
|
}
|
|
213478
|
+
var ignoredModuleDirectoryNames = /* @__PURE__ */ new Set([
|
|
213479
|
+
".git",
|
|
213480
|
+
".archpilot",
|
|
213481
|
+
".vscode",
|
|
213482
|
+
".vscode-test",
|
|
213483
|
+
"node_modules",
|
|
213484
|
+
"dist",
|
|
213485
|
+
"build",
|
|
213486
|
+
"out",
|
|
213487
|
+
"coverage",
|
|
213488
|
+
".next",
|
|
213489
|
+
"generated",
|
|
213490
|
+
"target",
|
|
213491
|
+
"vendor",
|
|
213492
|
+
".venv",
|
|
213493
|
+
"venv",
|
|
213494
|
+
"__pycache__"
|
|
213495
|
+
]);
|
|
213496
|
+
var noisyModuleDirectoryNames = /* @__PURE__ */ new Set([
|
|
213497
|
+
"components",
|
|
213498
|
+
"hooks",
|
|
213499
|
+
"utils",
|
|
213500
|
+
"util",
|
|
213501
|
+
"lib",
|
|
213502
|
+
"common",
|
|
213503
|
+
"shared",
|
|
213504
|
+
"shared-ui",
|
|
213505
|
+
"types",
|
|
213506
|
+
"constants",
|
|
213507
|
+
"config",
|
|
213508
|
+
"test",
|
|
213509
|
+
"tests",
|
|
213510
|
+
"__tests__",
|
|
213511
|
+
"fixtures",
|
|
213512
|
+
"mocks",
|
|
213513
|
+
"__mocks__",
|
|
213514
|
+
"generated",
|
|
213515
|
+
"dist",
|
|
213516
|
+
"build",
|
|
213517
|
+
"out",
|
|
213518
|
+
"node_modules"
|
|
213519
|
+
]);
|
|
213520
|
+
var sourceFileExtensions = /* @__PURE__ */ new Set([
|
|
213521
|
+
".ts",
|
|
213522
|
+
".tsx",
|
|
213523
|
+
".js",
|
|
213524
|
+
".jsx",
|
|
213525
|
+
".vue",
|
|
213526
|
+
".java",
|
|
213527
|
+
".py",
|
|
213528
|
+
".php",
|
|
213529
|
+
".go",
|
|
213530
|
+
".cs",
|
|
213531
|
+
".rb",
|
|
213532
|
+
".kt",
|
|
213533
|
+
".swift",
|
|
213534
|
+
".rs"
|
|
213535
|
+
]);
|
|
213536
|
+
var publicEntrypointNames = /* @__PURE__ */ new Set([
|
|
213537
|
+
"index.ts",
|
|
213538
|
+
"index.tsx",
|
|
213539
|
+
"index.js",
|
|
213540
|
+
"index.jsx",
|
|
213541
|
+
"index.vue",
|
|
213542
|
+
"__init__.py",
|
|
213543
|
+
"main.go",
|
|
213544
|
+
"mod.ts",
|
|
213545
|
+
"mod.js"
|
|
213546
|
+
]);
|
|
213547
|
+
function isIgnoredDirectoryName(directoryName) {
|
|
213548
|
+
return ignoredModuleDirectoryNames.has(directoryName.toLowerCase());
|
|
213549
|
+
}
|
|
213550
|
+
function isNoisyModuleName(moduleName) {
|
|
213551
|
+
return noisyModuleDirectoryNames.has(moduleName.toLowerCase());
|
|
213552
|
+
}
|
|
213553
|
+
function toPathSegments(relativePath) {
|
|
213554
|
+
return normalizePath(relativePath).split("/").filter((segment) => segment.length > 0);
|
|
213555
|
+
}
|
|
213556
|
+
function toModuleIdFromPath(relativePath, fallbackRoot) {
|
|
213557
|
+
const segments = toPathSegments(relativePath);
|
|
213558
|
+
const lowerSegments = segments.map((segment) => segment.toLowerCase());
|
|
213559
|
+
const sourceIndex = lowerSegments.lastIndexOf("src");
|
|
213560
|
+
if (sourceIndex >= 0 && sourceIndex + 2 < segments.length) {
|
|
213561
|
+
const parent = segments[sourceIndex - 1];
|
|
213562
|
+
const container = lowerSegments[sourceIndex + 1];
|
|
213563
|
+
if (["modules", "features"].includes(container)) {
|
|
213564
|
+
return [parent, segments[sourceIndex + 2]].filter(Boolean).join("/");
|
|
213565
|
+
}
|
|
213566
|
+
if (["domain", "domains", "application", "infrastructure"].includes(container)) {
|
|
213567
|
+
return [segments[sourceIndex + 1], segments[sourceIndex + 2]].join("/");
|
|
213568
|
+
}
|
|
213569
|
+
return [parent, segments[sourceIndex + 1]].filter(Boolean).join("/");
|
|
213570
|
+
}
|
|
213571
|
+
if (sourceIndex >= 0 && sourceIndex + 1 < segments.length) {
|
|
213572
|
+
const parent = segments[sourceIndex - 1];
|
|
213573
|
+
return [parent, segments[sourceIndex + 1]].filter(Boolean).join("/");
|
|
213574
|
+
}
|
|
213575
|
+
if (segments[0] === "src" && segments.length >= 3) {
|
|
213576
|
+
return `${segments[1]}/${segments[2]}`;
|
|
213577
|
+
}
|
|
213578
|
+
if (fallbackRoot) {
|
|
213579
|
+
const rootSegments = toPathSegments(fallbackRoot);
|
|
213580
|
+
const relativeSegments = segments.slice(rootSegments.length);
|
|
213581
|
+
if (relativeSegments.length > 0) {
|
|
213582
|
+
return relativeSegments.join("/");
|
|
213583
|
+
}
|
|
213584
|
+
}
|
|
213585
|
+
return segments.slice(-1)[0] ?? relativePath;
|
|
213586
|
+
}
|
|
213587
|
+
function isKnownNestedModuleRoot(relativePath) {
|
|
213588
|
+
const segments = toPathSegments(relativePath).map((segment) => segment.toLowerCase());
|
|
213589
|
+
if (segments.length < 2) {
|
|
213590
|
+
return false;
|
|
213591
|
+
}
|
|
213592
|
+
const lastParent = segments[segments.length - 2];
|
|
213593
|
+
if (["modules", "features", "domain", "domains", "application", "infrastructure"].includes(lastParent)) {
|
|
213594
|
+
return true;
|
|
213595
|
+
}
|
|
213596
|
+
if (segments.length >= 3 && segments[segments.length - 3] === "src") {
|
|
213597
|
+
return true;
|
|
213598
|
+
}
|
|
213599
|
+
return false;
|
|
213600
|
+
}
|
|
213601
|
+
async function inspectPotentialModuleRoot(absolutePath) {
|
|
213602
|
+
let sourceFileCount = 0;
|
|
213603
|
+
let hasPublicEntrypoint = false;
|
|
213604
|
+
const queue = [{ absolutePath, depth: 0 }];
|
|
213605
|
+
while (queue.length > 0) {
|
|
213606
|
+
const current = queue.shift();
|
|
213607
|
+
if (!current) {
|
|
213608
|
+
continue;
|
|
213609
|
+
}
|
|
213610
|
+
let entries;
|
|
213611
|
+
try {
|
|
213612
|
+
entries = await import_node_fs.promises.readdir(current.absolutePath, { withFileTypes: true });
|
|
213613
|
+
} catch {
|
|
213614
|
+
continue;
|
|
213615
|
+
}
|
|
213616
|
+
for (const entry of entries) {
|
|
213617
|
+
const entryPath = path.join(current.absolutePath, entry.name);
|
|
213618
|
+
if (entry.isDirectory()) {
|
|
213619
|
+
if (current.depth >= 2 || isIgnoredDirectoryName(entry.name)) {
|
|
213620
|
+
continue;
|
|
213621
|
+
}
|
|
213622
|
+
queue.push({ absolutePath: entryPath, depth: current.depth + 1 });
|
|
213623
|
+
continue;
|
|
213624
|
+
}
|
|
213625
|
+
if (!entry.isFile()) {
|
|
213626
|
+
continue;
|
|
213627
|
+
}
|
|
213628
|
+
if (sourceFileExtensions.has(path.extname(entry.name).toLowerCase())) {
|
|
213629
|
+
sourceFileCount += 1;
|
|
213630
|
+
}
|
|
213631
|
+
if (current.depth === 0 && publicEntrypointNames.has(entry.name.toLowerCase())) {
|
|
213632
|
+
hasPublicEntrypoint = true;
|
|
213633
|
+
}
|
|
213634
|
+
}
|
|
213635
|
+
}
|
|
213636
|
+
return { sourceFileCount, hasPublicEntrypoint };
|
|
213637
|
+
}
|
|
213638
|
+
async function addModuleIfStrongCandidate(workspaceRoot, discovered, sourcePath, moduleId, options) {
|
|
213639
|
+
const normalizedSourcePath = normalizePath(sourcePath);
|
|
213640
|
+
const name = normalizedSourcePath.split("/").pop() ?? moduleId;
|
|
213641
|
+
if (options?.allowNoisyNames !== true && isNoisyModuleName(name)) {
|
|
213642
|
+
return;
|
|
213643
|
+
}
|
|
213644
|
+
const absolutePath = path.join(workspaceRoot, ...normalizedSourcePath.split("/"));
|
|
213645
|
+
const inspected = await inspectPotentialModuleRoot(absolutePath);
|
|
213646
|
+
const hasStrongEvidence = inspected.sourceFileCount >= 2 || inspected.hasPublicEntrypoint || isKnownNestedModuleRoot(normalizedSourcePath);
|
|
213647
|
+
if (options?.requireStrongEvidence !== false && !hasStrongEvidence) {
|
|
213648
|
+
return;
|
|
213649
|
+
}
|
|
213650
|
+
const normalizedModuleId = normalizePath(moduleId || toModuleIdFromPath(normalizedSourcePath, options?.fallbackRoot));
|
|
213651
|
+
if (!normalizedModuleId || options?.allowNoisyNames !== true && isNoisyModuleName(normalizedModuleId.split("/").pop() ?? normalizedModuleId)) {
|
|
213652
|
+
return;
|
|
213653
|
+
}
|
|
213654
|
+
if (!discovered.has(normalizedModuleId)) {
|
|
213655
|
+
discovered.set(normalizedModuleId, {
|
|
213656
|
+
moduleId: normalizedModuleId,
|
|
213657
|
+
sourcePath: normalizedSourcePath
|
|
213658
|
+
});
|
|
213659
|
+
}
|
|
213660
|
+
}
|
|
213661
|
+
async function addChildrenFromRoot(workspaceRoot, discovered, rootRelativePath, options) {
|
|
213662
|
+
const normalizedRoot = normalizePath(rootRelativePath);
|
|
213663
|
+
const absoluteRoot = path.join(workspaceRoot, ...normalizedRoot.split("/"));
|
|
213664
|
+
if (!await pathExists(absoluteRoot)) {
|
|
213665
|
+
return;
|
|
213666
|
+
}
|
|
213667
|
+
const entries = (await import_node_fs.promises.readdir(absoluteRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && !isIgnoredDirectoryName(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
|
|
213668
|
+
for (const entry of entries) {
|
|
213669
|
+
const sourcePath = `${normalizedRoot}/${entry.name}`;
|
|
213670
|
+
const moduleId = options?.includeParentPrefix && options.parentId ? `${options.parentId}/${entry.name}` : toModuleIdFromPath(sourcePath, normalizedRoot);
|
|
213671
|
+
await addModuleIfStrongCandidate(workspaceRoot, discovered, sourcePath, moduleId, {
|
|
213672
|
+
fallbackRoot: normalizedRoot,
|
|
213673
|
+
...options?.requireStrongEvidence !== void 0 ? { requireStrongEvidence: options.requireStrongEvidence } : {},
|
|
213674
|
+
...options?.allowNoisyNames !== void 0 ? { allowNoisyNames: options.allowNoisyNames } : {}
|
|
213675
|
+
});
|
|
213676
|
+
}
|
|
213677
|
+
}
|
|
213678
|
+
async function addMonorepoContainerModules(workspaceRoot, discovered, container) {
|
|
213679
|
+
const absoluteContainer = path.join(workspaceRoot, container);
|
|
213680
|
+
if (!await pathExists(absoluteContainer)) {
|
|
213681
|
+
return;
|
|
213682
|
+
}
|
|
213683
|
+
const entries = (await import_node_fs.promises.readdir(absoluteContainer, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".") && !isIgnoredDirectoryName(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
|
|
213684
|
+
for (const entry of entries) {
|
|
213685
|
+
const packagePath = `${container}/${entry.name}`;
|
|
213686
|
+
await addModuleIfStrongCandidate(workspaceRoot, discovered, packagePath, entry.name, {
|
|
213687
|
+
requireStrongEvidence: false
|
|
213688
|
+
});
|
|
213689
|
+
for (const sourceRoot of [
|
|
213690
|
+
`${packagePath}/src`,
|
|
213691
|
+
`${packagePath}/src/modules`,
|
|
213692
|
+
`${packagePath}/src/features`,
|
|
213693
|
+
`${packagePath}/src/domain`,
|
|
213694
|
+
`${packagePath}/src/domains`,
|
|
213695
|
+
`${packagePath}/src/application`,
|
|
213696
|
+
`${packagePath}/src/infrastructure`
|
|
213697
|
+
]) {
|
|
213698
|
+
await addChildrenFromRoot(workspaceRoot, discovered, sourceRoot, {
|
|
213699
|
+
parentId: entry.name,
|
|
213700
|
+
includeParentPrefix: true
|
|
213701
|
+
});
|
|
213702
|
+
}
|
|
213703
|
+
}
|
|
213704
|
+
}
|
|
213705
|
+
async function discoverHierarchicalModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules") {
|
|
213706
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
213707
|
+
await addChildrenFromRoot(workspaceRoot, discovered, normalizePath(modulesRootRelativePath), {
|
|
213708
|
+
requireStrongEvidence: false,
|
|
213709
|
+
allowNoisyNames: normalizePath(modulesRootRelativePath) === "src"
|
|
213710
|
+
});
|
|
213711
|
+
for (const root of [
|
|
213712
|
+
"src/modules",
|
|
213713
|
+
"src/features",
|
|
213714
|
+
"src/domain",
|
|
213715
|
+
"src/domains",
|
|
213716
|
+
"src/application",
|
|
213717
|
+
"src/infrastructure"
|
|
213718
|
+
]) {
|
|
213719
|
+
await addChildrenFromRoot(workspaceRoot, discovered, root);
|
|
213720
|
+
}
|
|
213721
|
+
for (const container of ["packages", "apps", "services"]) {
|
|
213722
|
+
await addMonorepoContainerModules(workspaceRoot, discovered, container);
|
|
213723
|
+
}
|
|
213724
|
+
return [...discovered.values()].sort((left, right) => left.moduleId.localeCompare(right.moduleId));
|
|
213725
|
+
}
|
|
213478
213726
|
async function discoverModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules") {
|
|
213727
|
+
const hierarchicalModules = await discoverHierarchicalModuleRoots(workspaceRoot, modulesRootRelativePath);
|
|
213728
|
+
if (hierarchicalModules.length > 0) {
|
|
213729
|
+
return new Map(
|
|
213730
|
+
hierarchicalModules.map((entry) => [
|
|
213731
|
+
entry.moduleId,
|
|
213732
|
+
path.join(workspaceRoot, ...entry.sourcePath.split("/"))
|
|
213733
|
+
])
|
|
213734
|
+
);
|
|
213735
|
+
}
|
|
213479
213736
|
const moduleDirectories = await listModuleDirectoryNames(workspaceRoot, modulesRootRelativePath);
|
|
213480
213737
|
const modulesRoot = path.join(workspaceRoot, ...modulesRootRelativePath.split("/"));
|
|
213481
213738
|
return new Map(
|
|
@@ -214854,7 +215111,8 @@ function buildArchitectureContract(base, overrides) {
|
|
|
214854
215111
|
}
|
|
214855
215112
|
function buildDefaultModuleContractPath(moduleName, contract) {
|
|
214856
215113
|
const contractsRoot = resolveContractsRootFromContract(contract);
|
|
214857
|
-
|
|
215114
|
+
const safeModuleName = moduleName.replace(/\\/g, "/").split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
|
|
215115
|
+
return `${contractsRoot}/${safeModuleName}.contract.json`;
|
|
214858
215116
|
}
|
|
214859
215117
|
async function loadArchitectureContract(workspaceRoot) {
|
|
214860
215118
|
const configPath = path7.join(workspaceRoot, ".archpilot", "architecture.json");
|
|
@@ -214985,8 +215243,63 @@ var DependencyRulesConfigError = class extends Error {
|
|
|
214985
215243
|
function normalizePath2(filePath) {
|
|
214986
215244
|
return filePath.replace(/\\/g, "/");
|
|
214987
215245
|
}
|
|
214988
|
-
function
|
|
214989
|
-
return
|
|
215246
|
+
function toSafeContractModuleFileStem(moduleName) {
|
|
215247
|
+
return normalizePath2(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
|
|
215248
|
+
}
|
|
215249
|
+
function normalizeAbsolutePath(filePath) {
|
|
215250
|
+
return normalizePath2(path8.resolve(filePath)).toLowerCase();
|
|
215251
|
+
}
|
|
215252
|
+
function isPathInsideOrEqual(childPath, parentPath) {
|
|
215253
|
+
const child = normalizeAbsolutePath(childPath);
|
|
215254
|
+
const parent = normalizeAbsolutePath(parentPath);
|
|
215255
|
+
return child === parent || child.startsWith(`${parent}/`);
|
|
215256
|
+
}
|
|
215257
|
+
function isParentChildModuleRelationship(leftModule, rightModule) {
|
|
215258
|
+
if (leftModule === rightModule) {
|
|
215259
|
+
return false;
|
|
215260
|
+
}
|
|
215261
|
+
return leftModule.startsWith(`${rightModule}/`) || rightModule.startsWith(`${leftModule}/`);
|
|
215262
|
+
}
|
|
215263
|
+
function isPeerModuleImport(dependencyImport) {
|
|
215264
|
+
return !isParentChildModuleRelationship(
|
|
215265
|
+
dependencyImport.sourceModule,
|
|
215266
|
+
dependencyImport.targetModule
|
|
215267
|
+
);
|
|
215268
|
+
}
|
|
215269
|
+
function filterPeerModuleImports(imports) {
|
|
215270
|
+
return imports.filter(isPeerModuleImport);
|
|
215271
|
+
}
|
|
215272
|
+
function buildModuleHierarchyEdges(moduleIds) {
|
|
215273
|
+
const moduleIdSet = new Set(moduleIds);
|
|
215274
|
+
const edges = [];
|
|
215275
|
+
for (const moduleId of moduleIds) {
|
|
215276
|
+
const parentModule = moduleId.split("/").slice(0, -1).map((_, index, segments) => segments.slice(0, segments.length - index).join("/")).find((candidate) => moduleIdSet.has(candidate));
|
|
215277
|
+
if (!parentModule) {
|
|
215278
|
+
continue;
|
|
215279
|
+
}
|
|
215280
|
+
edges.push({ parentModule, childModule: moduleId });
|
|
215281
|
+
}
|
|
215282
|
+
return edges.sort((left, right) => {
|
|
215283
|
+
const parentCompare = left.parentModule.localeCompare(right.parentModule);
|
|
215284
|
+
if (parentCompare !== 0) {
|
|
215285
|
+
return parentCompare;
|
|
215286
|
+
}
|
|
215287
|
+
return left.childModule.localeCompare(right.childModule);
|
|
215288
|
+
});
|
|
215289
|
+
}
|
|
215290
|
+
function buildChildModulesByParent(hierarchyEdges) {
|
|
215291
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
215292
|
+
for (const edge of hierarchyEdges) {
|
|
215293
|
+
const children = byParent.get(edge.parentModule) ?? /* @__PURE__ */ new Set();
|
|
215294
|
+
children.add(edge.childModule);
|
|
215295
|
+
byParent.set(edge.parentModule, children);
|
|
215296
|
+
}
|
|
215297
|
+
return new Map(
|
|
215298
|
+
[...byParent.entries()].map(([parentModule, childModules]) => [
|
|
215299
|
+
parentModule,
|
|
215300
|
+
sortUnique2(childModules)
|
|
215301
|
+
])
|
|
215302
|
+
);
|
|
214990
215303
|
}
|
|
214991
215304
|
function getScriptKind(filePath) {
|
|
214992
215305
|
const extension = path8.extname(filePath).toLowerCase();
|
|
@@ -215020,6 +215333,14 @@ function usesPythonImportParser(adapter) {
|
|
|
215020
215333
|
function supportsDependencyImportParsing(adapter) {
|
|
215021
215334
|
return usesTypeScriptParser(adapter) || usesJavaImportParser(adapter) || usesPhpImportParser(adapter) || usesGoImportParser(adapter) || usesPythonImportParser(adapter);
|
|
215022
215335
|
}
|
|
215336
|
+
async function pathExists4(targetPath) {
|
|
215337
|
+
try {
|
|
215338
|
+
await import_node_fs8.promises.access(targetPath);
|
|
215339
|
+
return true;
|
|
215340
|
+
} catch {
|
|
215341
|
+
return false;
|
|
215342
|
+
}
|
|
215343
|
+
}
|
|
215023
215344
|
async function readTextFileIfExists2(filePath) {
|
|
215024
215345
|
try {
|
|
215025
215346
|
return await import_node_fs8.promises.readFile(filePath, { encoding: "utf8" });
|
|
@@ -215027,6 +215348,95 @@ async function readTextFileIfExists2(filePath) {
|
|
|
215027
215348
|
return void 0;
|
|
215028
215349
|
}
|
|
215029
215350
|
}
|
|
215351
|
+
async function readPackageName(packageJsonPath) {
|
|
215352
|
+
const contents = await readTextFileIfExists2(packageJsonPath);
|
|
215353
|
+
if (!contents) {
|
|
215354
|
+
return void 0;
|
|
215355
|
+
}
|
|
215356
|
+
try {
|
|
215357
|
+
const parsed = JSON.parse(contents);
|
|
215358
|
+
return typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : void 0;
|
|
215359
|
+
} catch {
|
|
215360
|
+
return void 0;
|
|
215361
|
+
}
|
|
215362
|
+
}
|
|
215363
|
+
async function buildWorkspacePackageAliasMap(workspaceRoot, moduleRoots) {
|
|
215364
|
+
const aliases = [];
|
|
215365
|
+
for (const [moduleId, moduleRoot] of [...moduleRoots.entries()].sort(
|
|
215366
|
+
([left], [right]) => left.localeCompare(right)
|
|
215367
|
+
)) {
|
|
215368
|
+
const packageName = await readPackageName(path8.join(moduleRoot, "package.json"));
|
|
215369
|
+
if (!packageName) {
|
|
215370
|
+
continue;
|
|
215371
|
+
}
|
|
215372
|
+
aliases.push({ packageName, moduleId, moduleRoot });
|
|
215373
|
+
}
|
|
215374
|
+
aliases.push(...await buildTsConfigPathAliasMap(workspaceRoot, moduleRoots));
|
|
215375
|
+
return aliases.sort((left, right) => {
|
|
215376
|
+
const lengthCompare = right.packageName.length - left.packageName.length;
|
|
215377
|
+
if (lengthCompare !== 0) {
|
|
215378
|
+
return lengthCompare;
|
|
215379
|
+
}
|
|
215380
|
+
return left.packageName.localeCompare(right.packageName);
|
|
215381
|
+
});
|
|
215382
|
+
}
|
|
215383
|
+
async function buildTsConfigPathAliasMap(workspaceRoot, moduleRoots) {
|
|
215384
|
+
const contents = await readTextFileIfExists2(path8.join(workspaceRoot, "tsconfig.json"));
|
|
215385
|
+
if (!contents) {
|
|
215386
|
+
return [];
|
|
215387
|
+
}
|
|
215388
|
+
let paths;
|
|
215389
|
+
try {
|
|
215390
|
+
const parsed = JSON.parse(contents);
|
|
215391
|
+
paths = parsed.compilerOptions?.paths;
|
|
215392
|
+
} catch {
|
|
215393
|
+
return [];
|
|
215394
|
+
}
|
|
215395
|
+
if (!paths) {
|
|
215396
|
+
return [];
|
|
215397
|
+
}
|
|
215398
|
+
const aliases = [];
|
|
215399
|
+
for (const [aliasPattern, targetPatterns] of Object.entries(paths).sort(
|
|
215400
|
+
([left], [right]) => left.localeCompare(right)
|
|
215401
|
+
)) {
|
|
215402
|
+
if (!Array.isArray(targetPatterns)) {
|
|
215403
|
+
continue;
|
|
215404
|
+
}
|
|
215405
|
+
const aliasPrefix = aliasPattern.replace(/\/\*$/u, "");
|
|
215406
|
+
if (aliasPrefix.length === 0) {
|
|
215407
|
+
continue;
|
|
215408
|
+
}
|
|
215409
|
+
for (const targetPattern of targetPatterns) {
|
|
215410
|
+
if (typeof targetPattern !== "string" || targetPattern.trim().length === 0) {
|
|
215411
|
+
continue;
|
|
215412
|
+
}
|
|
215413
|
+
const isWildcard = /\/\*$/u.test(aliasPattern) && /\/\*$/u.test(targetPattern);
|
|
215414
|
+
const normalizedTarget = normalizePath2(targetPattern).replace(/\/\*$/u, "");
|
|
215415
|
+
const absoluteTarget = path8.join(workspaceRoot, ...normalizedTarget.split("/"));
|
|
215416
|
+
const moduleEntry = [...moduleRoots.entries()].filter(([, moduleRoot2]) => isPathInsideOrEqual(absoluteTarget, moduleRoot2)).sort((left, right) => right[1].length - left[1].length || left[0].localeCompare(right[0]))[0];
|
|
215417
|
+
if (!moduleEntry) {
|
|
215418
|
+
continue;
|
|
215419
|
+
}
|
|
215420
|
+
const [moduleId, moduleRoot] = moduleEntry;
|
|
215421
|
+
if (isWildcard) {
|
|
215422
|
+
aliases.push({
|
|
215423
|
+
packageName: aliasPrefix,
|
|
215424
|
+
moduleId,
|
|
215425
|
+
moduleRoot,
|
|
215426
|
+
targetRoot: absoluteTarget
|
|
215427
|
+
});
|
|
215428
|
+
continue;
|
|
215429
|
+
}
|
|
215430
|
+
aliases.push({
|
|
215431
|
+
packageName: aliasPrefix,
|
|
215432
|
+
moduleId,
|
|
215433
|
+
moduleRoot,
|
|
215434
|
+
targetFile: absoluteTarget
|
|
215435
|
+
});
|
|
215436
|
+
}
|
|
215437
|
+
}
|
|
215438
|
+
return aliases;
|
|
215439
|
+
}
|
|
215030
215440
|
function validateDependencyModuleRules(moduleName, value) {
|
|
215031
215441
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
215032
215442
|
throw new DependencyRulesConfigError(
|
|
@@ -215086,8 +215496,44 @@ async function readDependencyRulesConfig(workspaceRoot) {
|
|
|
215086
215496
|
}, {});
|
|
215087
215497
|
return { modules };
|
|
215088
215498
|
}
|
|
215089
|
-
async function findModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules") {
|
|
215090
|
-
|
|
215499
|
+
async function findModuleRoots(workspaceRoot, modulesRootRelativePath = "src/modules", architectureContract) {
|
|
215500
|
+
const discoveredModuleRoots = await discoverModuleRoots(
|
|
215501
|
+
workspaceRoot,
|
|
215502
|
+
modulesRootRelativePath
|
|
215503
|
+
);
|
|
215504
|
+
const moduleRoots = /* @__PURE__ */ new Map();
|
|
215505
|
+
const registryEntries = architectureContract?.modules ? Object.entries(architectureContract.modules).sort(
|
|
215506
|
+
([left], [right]) => left.localeCompare(right)
|
|
215507
|
+
) : [];
|
|
215508
|
+
for (const [moduleName, moduleReference] of registryEntries) {
|
|
215509
|
+
const configuredPath = moduleReference.path;
|
|
215510
|
+
if (!configuredPath || typeof configuredPath !== "string") {
|
|
215511
|
+
continue;
|
|
215512
|
+
}
|
|
215513
|
+
const normalizedConfiguredPath = normalizePath2(configuredPath);
|
|
215514
|
+
if (/\.[a-z0-9]+$/iu.test(normalizedConfiguredPath)) {
|
|
215515
|
+
continue;
|
|
215516
|
+
}
|
|
215517
|
+
const absolutePath = path8.join(
|
|
215518
|
+
workspaceRoot,
|
|
215519
|
+
...normalizedConfiguredPath.split("/")
|
|
215520
|
+
);
|
|
215521
|
+
try {
|
|
215522
|
+
const stats = await import_node_fs8.promises.stat(absolutePath);
|
|
215523
|
+
if (stats.isDirectory()) {
|
|
215524
|
+
moduleRoots.set(moduleName, absolutePath);
|
|
215525
|
+
}
|
|
215526
|
+
} catch {
|
|
215527
|
+
}
|
|
215528
|
+
}
|
|
215529
|
+
for (const [moduleName, moduleRoot] of discoveredModuleRoots.entries()) {
|
|
215530
|
+
if (!moduleRoots.has(moduleName)) {
|
|
215531
|
+
moduleRoots.set(moduleName, moduleRoot);
|
|
215532
|
+
}
|
|
215533
|
+
}
|
|
215534
|
+
return new Map(
|
|
215535
|
+
[...moduleRoots.entries()].sort(([left], [right]) => left.localeCompare(right))
|
|
215536
|
+
);
|
|
215091
215537
|
}
|
|
215092
215538
|
async function buildExplicitStandaloneModulePathMap(workspaceRoot, architectureContract) {
|
|
215093
215539
|
const moduleRegistry = architectureContract?.modules && typeof architectureContract.modules === "object" && !Array.isArray(architectureContract.modules) ? architectureContract.modules : void 0;
|
|
@@ -215500,7 +215946,45 @@ async function resolveImportPath(basePath, adapter) {
|
|
|
215500
215946
|
}
|
|
215501
215947
|
return void 0;
|
|
215502
215948
|
}
|
|
215503
|
-
|
|
215949
|
+
function resolvePackageAliasRemainder(packageName, importSpecifier) {
|
|
215950
|
+
if (importSpecifier === packageName) {
|
|
215951
|
+
return "";
|
|
215952
|
+
}
|
|
215953
|
+
if (importSpecifier.startsWith(`${packageName}/`)) {
|
|
215954
|
+
return importSpecifier.slice(packageName.length + 1);
|
|
215955
|
+
}
|
|
215956
|
+
return void 0;
|
|
215957
|
+
}
|
|
215958
|
+
async function resolveWorkspacePackageImportPath(importSpecifier, workspacePackageAliases, adapter) {
|
|
215959
|
+
const packageAlias = workspacePackageAliases.map((alias2) => ({
|
|
215960
|
+
alias: alias2,
|
|
215961
|
+
remainder: resolvePackageAliasRemainder(alias2.packageName, importSpecifier)
|
|
215962
|
+
})).sort((left, right) => {
|
|
215963
|
+
const leftCanResolveRemainder = left.remainder !== void 0 && left.remainder.length > 0 && left.alias.targetRoot !== void 0;
|
|
215964
|
+
const rightCanResolveRemainder = right.remainder !== void 0 && right.remainder.length > 0 && right.alias.targetRoot !== void 0;
|
|
215965
|
+
if (leftCanResolveRemainder !== rightCanResolveRemainder) {
|
|
215966
|
+
return leftCanResolveRemainder ? -1 : 1;
|
|
215967
|
+
}
|
|
215968
|
+
return 0;
|
|
215969
|
+
}).find(
|
|
215970
|
+
(candidate) => candidate.remainder !== void 0
|
|
215971
|
+
);
|
|
215972
|
+
if (!packageAlias) {
|
|
215973
|
+
return void 0;
|
|
215974
|
+
}
|
|
215975
|
+
const { alias, remainder } = packageAlias;
|
|
215976
|
+
if (remainder.length === 0) {
|
|
215977
|
+
return resolveImportPath(alias.targetFile ?? alias.targetRoot ?? alias.moduleRoot, adapter);
|
|
215978
|
+
}
|
|
215979
|
+
if (alias.targetRoot) {
|
|
215980
|
+
return resolveImportPath(
|
|
215981
|
+
path8.join(alias.targetRoot, ...remainder.split("/").filter((segment) => segment.length > 0)),
|
|
215982
|
+
adapter
|
|
215983
|
+
);
|
|
215984
|
+
}
|
|
215985
|
+
return void 0;
|
|
215986
|
+
}
|
|
215987
|
+
async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, workspacePackageAliases, sourceFilePath, importSpecifier, adapter) {
|
|
215504
215988
|
let basePath;
|
|
215505
215989
|
const normalizedModulesRoot = normalizePath2(modulesRootRelativePath).replace(/^\/+/, "");
|
|
215506
215990
|
if (usesJavaImportParser(adapter) && !importSpecifier.startsWith(".")) {
|
|
@@ -215555,6 +216039,22 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
|
|
|
215555
216039
|
basePath = path8.join(workspaceRoot, importSpecifier.slice(1));
|
|
215556
216040
|
} else if (normalizedModulesRoot.startsWith("src/") && importSpecifier.startsWith(`${normalizedModulesRoot.slice("src/".length)}/`)) {
|
|
215557
216041
|
basePath = path8.join(workspaceRoot, "src", importSpecifier);
|
|
216042
|
+
} else {
|
|
216043
|
+
const workspacePackageImportPath = await resolveWorkspacePackageImportPath(
|
|
216044
|
+
importSpecifier,
|
|
216045
|
+
workspacePackageAliases,
|
|
216046
|
+
adapter
|
|
216047
|
+
);
|
|
216048
|
+
if (workspacePackageImportPath) {
|
|
216049
|
+
basePath = workspacePackageImportPath;
|
|
216050
|
+
} else {
|
|
216051
|
+
const moduleImportTarget = [...moduleRoots.entries()].filter(([moduleId]) => importSpecifier === moduleId || importSpecifier.startsWith(`${moduleId}/`)).sort((left, right) => right[0].length - left[0].length || left[0].localeCompare(right[0]))[0];
|
|
216052
|
+
if (moduleImportTarget) {
|
|
216053
|
+
const [moduleId, moduleRoot] = moduleImportTarget;
|
|
216054
|
+
const remainder = importSpecifier === moduleId ? "" : importSpecifier.slice(moduleId.length + 1);
|
|
216055
|
+
basePath = path8.join(moduleRoot, ...remainder.split("/").filter((segment) => segment.length > 0));
|
|
216056
|
+
}
|
|
216057
|
+
}
|
|
215558
216058
|
}
|
|
215559
216059
|
if (!basePath) {
|
|
215560
216060
|
return void 0;
|
|
@@ -215563,17 +216063,8 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
|
|
|
215563
216063
|
if (!resolvedPath) {
|
|
215564
216064
|
return void 0;
|
|
215565
216065
|
}
|
|
215566
|
-
const
|
|
215567
|
-
|
|
215568
|
-
if (relativeToModulesRoot === "" || relativeToModulesRoot.startsWith("../") || relativeToModulesRoot.startsWith("..\\")) {
|
|
215569
|
-
return void 0;
|
|
215570
|
-
}
|
|
215571
|
-
const segments = relativeToModulesRoot.split("/");
|
|
215572
|
-
if (segments.length === 0) {
|
|
215573
|
-
return void 0;
|
|
215574
|
-
}
|
|
215575
|
-
const targetModule = segments[0];
|
|
215576
|
-
if (!moduleRoots.has(targetModule)) {
|
|
216066
|
+
const targetModuleEntry = [...moduleRoots.entries()].filter(([, moduleRoot]) => isPathInsideOrEqual(resolvedPath, moduleRoot)).sort((left, right) => right[1].length - left[1].length || left[0].localeCompare(right[0]))[0];
|
|
216067
|
+
if (!targetModuleEntry) {
|
|
215577
216068
|
const standaloneTargetModule = explicitStandaloneModuleByPath.get(
|
|
215578
216069
|
normalizePath2(path8.relative(workspaceRoot, resolvedPath))
|
|
215579
216070
|
);
|
|
@@ -215586,11 +216077,18 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
|
|
|
215586
216077
|
isPublicImport: true
|
|
215587
216078
|
};
|
|
215588
216079
|
}
|
|
215589
|
-
const
|
|
216080
|
+
const [targetModule, targetModuleRoot] = targetModuleEntry;
|
|
216081
|
+
const targetSubPath = normalizePath2(path8.relative(targetModuleRoot, resolvedPath));
|
|
216082
|
+
if (targetSubPath === "" || targetSubPath.startsWith("../") || targetSubPath.startsWith("..\\")) {
|
|
216083
|
+
return void 0;
|
|
216084
|
+
}
|
|
215590
216085
|
const indexEntrypointCandidates = adapter.dependencyParsingFileExtensions.map(
|
|
215591
216086
|
(extension) => `index${extension}`
|
|
215592
216087
|
);
|
|
215593
|
-
const
|
|
216088
|
+
const nestedIndexEntrypointCandidates = adapter.dependencyParsingFileExtensions.flatMap(
|
|
216089
|
+
(extension) => [`src/index${extension}`, `public/index${extension}`]
|
|
216090
|
+
);
|
|
216091
|
+
const isPublicImport = indexEntrypointCandidates.includes(targetSubPath) || nestedIndexEntrypointCandidates.includes(targetSubPath) || adapter.publicEntrypointDirectoryNames.some(
|
|
215594
216092
|
(dirName) => targetSubPath.startsWith(`${dirName}/`)
|
|
215595
216093
|
);
|
|
215596
216094
|
return {
|
|
@@ -215599,7 +216097,7 @@ async function resolveCrossModuleImport(workspaceRoot, modulesRootRelativePath,
|
|
|
215599
216097
|
isPublicImport
|
|
215600
216098
|
};
|
|
215601
216099
|
}
|
|
215602
|
-
async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, adapter, options) {
|
|
216100
|
+
async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath, moduleRoots, explicitStandaloneModuleByPath, workspacePackageAliases, adapter, options) {
|
|
215603
216101
|
const imports = [];
|
|
215604
216102
|
const includeTestFiles = options?.includeTestFiles === true;
|
|
215605
216103
|
if (!supportsDependencyImportParsing(adapter)) {
|
|
@@ -215608,7 +216106,10 @@ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath,
|
|
|
215608
216106
|
for (const [moduleName, moduleRoot] of [...moduleRoots.entries()].sort(
|
|
215609
216107
|
([left], [right]) => left.localeCompare(right)
|
|
215610
216108
|
)) {
|
|
215611
|
-
const
|
|
216109
|
+
const childModuleRoots = [...moduleRoots.entries()].filter(([childModuleName, childModuleRoot]) => childModuleName !== moduleName && isPathInsideOrEqual(childModuleRoot, moduleRoot)).map(([, childModuleRoot]) => childModuleRoot);
|
|
216110
|
+
const sourceFiles = (await collectSourceFiles(moduleRoot, adapter)).filter(
|
|
216111
|
+
(sourceFile) => !childModuleRoots.some((childModuleRoot) => isPathInsideOrEqual(sourceFile, childModuleRoot))
|
|
216112
|
+
);
|
|
215612
216113
|
for (const sourceFilePath of sourceFiles) {
|
|
215613
216114
|
const sourceFileRelativePath = normalizePath2(
|
|
215614
216115
|
path8.relative(workspaceRoot, sourceFilePath)
|
|
@@ -215631,6 +216132,7 @@ async function collectCrossModuleImports(workspaceRoot, modulesRootRelativePath,
|
|
|
215631
216132
|
modulesRootRelativePath,
|
|
215632
216133
|
moduleRoots,
|
|
215633
216134
|
explicitStandaloneModuleByPath,
|
|
216135
|
+
workspacePackageAliases,
|
|
215634
216136
|
sourceFilePath,
|
|
215635
216137
|
importReference.specifier,
|
|
215636
216138
|
adapter
|
|
@@ -215776,7 +216278,7 @@ async function loadModuleArchitectureContract(workspaceRoot, architectureContrac
|
|
|
215776
216278
|
const registryEntry = architectureContract.modules[moduleName];
|
|
215777
216279
|
const contractPath = registryEntry?.contract ?? path8.posix.join(
|
|
215778
216280
|
resolveContractsRootFromContract(architectureContract),
|
|
215779
|
-
`${moduleName}.contract.json`
|
|
216281
|
+
`${toSafeContractModuleFileStem(moduleName)}.contract.json`
|
|
215780
216282
|
);
|
|
215781
216283
|
const fullContractPath = path8.join(workspaceRoot, ...contractPath.split("/"));
|
|
215782
216284
|
const content = await readTextFileIfExists2(fullContractPath);
|
|
@@ -215862,11 +216364,89 @@ function isImportWithinPublicEntrypoints(resolvedTargetRelativePath, publicEntry
|
|
|
215862
216364
|
}
|
|
215863
216365
|
}
|
|
215864
216366
|
}
|
|
215865
|
-
return false;
|
|
216367
|
+
return false;
|
|
216368
|
+
}
|
|
216369
|
+
async function filterExistingPublicEntrypoints(workspaceRoot, publicEntrypoints) {
|
|
216370
|
+
const existingEntrypoints = [];
|
|
216371
|
+
for (const publicEntrypoint of normalizePathList([...publicEntrypoints])) {
|
|
216372
|
+
const absolutePath = path8.join(workspaceRoot, ...publicEntrypoint.split("/"));
|
|
216373
|
+
if (await pathExists4(absolutePath)) {
|
|
216374
|
+
existingEntrypoints.push(publicEntrypoint);
|
|
216375
|
+
}
|
|
216376
|
+
}
|
|
216377
|
+
return existingEntrypoints;
|
|
216378
|
+
}
|
|
216379
|
+
async function inferExistingPublicEntrypointsFromModuleRoot(workspaceRoot, moduleRoot) {
|
|
216380
|
+
if (!moduleRoot) {
|
|
216381
|
+
return [];
|
|
216382
|
+
}
|
|
216383
|
+
const candidateSubpaths = [
|
|
216384
|
+
"index.ts",
|
|
216385
|
+
"index.tsx",
|
|
216386
|
+
"index.js",
|
|
216387
|
+
"index.jsx",
|
|
216388
|
+
"src/index.ts",
|
|
216389
|
+
"src/index.tsx",
|
|
216390
|
+
"src/index.js",
|
|
216391
|
+
"src/index.jsx",
|
|
216392
|
+
"public/index.ts",
|
|
216393
|
+
"public/index.tsx",
|
|
216394
|
+
"public/index.js",
|
|
216395
|
+
"public/index.jsx"
|
|
216396
|
+
];
|
|
216397
|
+
const existingEntrypoints = [];
|
|
216398
|
+
for (const candidateSubpath of candidateSubpaths) {
|
|
216399
|
+
const candidatePath = path8.join(moduleRoot, ...candidateSubpath.split("/"));
|
|
216400
|
+
if (await pathExists4(candidatePath)) {
|
|
216401
|
+
existingEntrypoints.push(
|
|
216402
|
+
normalizePath2(path8.relative(workspaceRoot, candidatePath))
|
|
216403
|
+
);
|
|
216404
|
+
}
|
|
216405
|
+
}
|
|
216406
|
+
return existingEntrypoints.sort((left, right) => left.localeCompare(right));
|
|
216407
|
+
}
|
|
216408
|
+
async function resolveModulePublicEntrypoints(workspaceRoot, architectureContract, moduleName, targetContract, moduleRoots) {
|
|
216409
|
+
const registryPublicEntrypoints = architectureContract.modules[moduleName]?.publicEntrypoints ?? [];
|
|
216410
|
+
const explicitPublicEntrypoints = sortUnique2([
|
|
216411
|
+
...registryPublicEntrypoints,
|
|
216412
|
+
...targetContract.publicEntrypoints
|
|
216413
|
+
]);
|
|
216414
|
+
const existingExplicitEntrypoints = await filterExistingPublicEntrypoints(
|
|
216415
|
+
workspaceRoot,
|
|
216416
|
+
explicitPublicEntrypoints
|
|
216417
|
+
);
|
|
216418
|
+
if (existingExplicitEntrypoints.length > 0) {
|
|
216419
|
+
return existingExplicitEntrypoints;
|
|
216420
|
+
}
|
|
216421
|
+
return inferExistingPublicEntrypointsFromModuleRoot(
|
|
216422
|
+
workspaceRoot,
|
|
216423
|
+
moduleRoots.get(moduleName)
|
|
216424
|
+
);
|
|
216425
|
+
}
|
|
216426
|
+
function labelPublicEntrypoint(publicEntrypoint) {
|
|
216427
|
+
const normalizedEntrypoint = normalizePath2(publicEntrypoint);
|
|
216428
|
+
const fileName = normalizedEntrypoint.split("/").at(-1) ?? "";
|
|
216429
|
+
return /^index\.[cm]?[jt]sx?$/iu.test(fileName) ? `${fileName} public entrypoint` : "public entrypoint";
|
|
215866
216430
|
}
|
|
215867
|
-
function
|
|
215868
|
-
|
|
215869
|
-
|
|
216431
|
+
function describePublicEntrypointTargets(publicEntrypoints) {
|
|
216432
|
+
if (publicEntrypoints.length <= 1) {
|
|
216433
|
+
return publicEntrypoints[0] ?? "unknown public entrypoint";
|
|
216434
|
+
}
|
|
216435
|
+
return publicEntrypoints.join(", ");
|
|
216436
|
+
}
|
|
216437
|
+
async function describeModulePublicImportGuidance(workspaceRoot, moduleName, moduleRoots) {
|
|
216438
|
+
const moduleRoot = moduleRoots.get(moduleName);
|
|
216439
|
+
const inferredEntrypoints = await inferExistingPublicEntrypointsFromModuleRoot(
|
|
216440
|
+
workspaceRoot,
|
|
216441
|
+
moduleRoot
|
|
216442
|
+
);
|
|
216443
|
+
if (inferredEntrypoints.length > 0) {
|
|
216444
|
+
return `Use the public entrypoint at ${describePublicEntrypointTargets(inferredEntrypoints)} instead.`;
|
|
216445
|
+
}
|
|
216446
|
+
if (moduleRoot) {
|
|
216447
|
+
return `Use an existing public entrypoint under ${normalizePath2(path8.relative(workspaceRoot, moduleRoot))} instead.`;
|
|
216448
|
+
}
|
|
216449
|
+
return "Use an existing target module public entrypoint instead.";
|
|
215870
216450
|
}
|
|
215871
216451
|
function buildActualImportedModuleSetBySource(imports, registeredModuleIds) {
|
|
215872
216452
|
const bySource = /* @__PURE__ */ new Map();
|
|
@@ -215918,11 +216498,19 @@ function buildInboundDependencyMap(bySource, moduleIds) {
|
|
|
215918
216498
|
async function buildDependencyGraphSummary(workspaceRoot, architectureContract, options) {
|
|
215919
216499
|
const modulesRoot = options?.modulesRootRelativePath ?? resolveModulesRootFromContract(architectureContract);
|
|
215920
216500
|
const adapter = resolvePrimaryAdapterFromContract(architectureContract);
|
|
215921
|
-
const moduleRoots = await findModuleRoots(
|
|
216501
|
+
const moduleRoots = await findModuleRoots(
|
|
216502
|
+
workspaceRoot,
|
|
216503
|
+
modulesRoot,
|
|
216504
|
+
architectureContract
|
|
216505
|
+
);
|
|
215922
216506
|
const explicitStandaloneModuleByPath = await buildExplicitStandaloneModulePathMap(
|
|
215923
216507
|
workspaceRoot,
|
|
215924
216508
|
architectureContract
|
|
215925
216509
|
);
|
|
216510
|
+
const workspacePackageAliases = await buildWorkspacePackageAliasMap(
|
|
216511
|
+
workspaceRoot,
|
|
216512
|
+
moduleRoots
|
|
216513
|
+
);
|
|
215926
216514
|
const moduleIds = sortUnique2([...moduleRoots.keys(), ...explicitStandaloneModuleByPath.values()]);
|
|
215927
216515
|
const registeredModuleIds = new Set(moduleIds);
|
|
215928
216516
|
const imports = await collectCrossModuleImports(
|
|
@@ -215930,9 +216518,11 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
|
|
|
215930
216518
|
modulesRoot,
|
|
215931
216519
|
moduleRoots,
|
|
215932
216520
|
explicitStandaloneModuleByPath,
|
|
216521
|
+
workspacePackageAliases,
|
|
215933
216522
|
adapter
|
|
215934
216523
|
);
|
|
215935
|
-
const
|
|
216524
|
+
const peerImports = filterPeerModuleImports(imports);
|
|
216525
|
+
const actualBySource = buildActualImportedModuleSetBySource(peerImports, registeredModuleIds);
|
|
215936
216526
|
const moduleContractCache = /* @__PURE__ */ new Map();
|
|
215937
216527
|
const declaredBySource = /* @__PURE__ */ new Map();
|
|
215938
216528
|
const hasContractByModule = /* @__PURE__ */ new Map();
|
|
@@ -215950,7 +216540,7 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
|
|
|
215950
216540
|
new Set(
|
|
215951
216541
|
sortUnique2(
|
|
215952
216542
|
sourceContract.contract.dependsOn.filter(
|
|
215953
|
-
(dependencyModule) => registeredModuleIds.has(dependencyModule)
|
|
216543
|
+
(dependencyModule) => registeredModuleIds.has(dependencyModule) && !isParentChildModuleRelationship(moduleId, dependencyModule)
|
|
215954
216544
|
)
|
|
215955
216545
|
)
|
|
215956
216546
|
)
|
|
@@ -215962,6 +216552,11 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
|
|
|
215962
216552
|
}
|
|
215963
216553
|
const inboundDeclared = buildInboundDependencyMap(declaredBySource, moduleIds);
|
|
215964
216554
|
const inboundActual = buildInboundDependencyMap(actualBySource, moduleIds);
|
|
216555
|
+
const hierarchyEdges = buildModuleHierarchyEdges(moduleIds);
|
|
216556
|
+
const childModulesByParent = buildChildModulesByParent(hierarchyEdges);
|
|
216557
|
+
const parentModuleByChild = new Map(
|
|
216558
|
+
hierarchyEdges.map((edge) => [edge.childModule, edge.parentModule])
|
|
216559
|
+
);
|
|
215965
216560
|
return {
|
|
215966
216561
|
modules: moduleIds.map((moduleId) => {
|
|
215967
216562
|
const declaredDependencies = sortUnique2(declaredBySource.get(moduleId) ?? []);
|
|
@@ -215975,6 +216570,8 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
|
|
|
215975
216570
|
return {
|
|
215976
216571
|
module: moduleId,
|
|
215977
216572
|
hasContract: hasContractByModule.get(moduleId) ?? false,
|
|
216573
|
+
...parentModuleByChild.has(moduleId) ? { parentModule: parentModuleByChild.get(moduleId) } : {},
|
|
216574
|
+
childModules: childModulesByParent.get(moduleId) ?? [],
|
|
215978
216575
|
declaredDependencies,
|
|
215979
216576
|
actualDependencies,
|
|
215980
216577
|
inboundDeclaredFrom: inboundDeclared.get(moduleId) ?? [],
|
|
@@ -215982,7 +216579,8 @@ async function buildDependencyGraphSummary(workspaceRoot, architectureContract,
|
|
|
215982
216579
|
unusedDeclaredDependencies,
|
|
215983
216580
|
undeclaredActualDependencies
|
|
215984
216581
|
};
|
|
215985
|
-
})
|
|
216582
|
+
}),
|
|
216583
|
+
hierarchyEdges
|
|
215986
216584
|
};
|
|
215987
216585
|
}
|
|
215988
216586
|
async function validateDependencyContractBoundaries(workspaceRoot, architectureContract, options) {
|
|
@@ -215991,24 +216589,34 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
215991
216589
|
}
|
|
215992
216590
|
const modulesRoot = options.modulesRootRelativePath ?? resolveModulesRootFromContract(architectureContract);
|
|
215993
216591
|
const adapter = resolvePrimaryAdapterFromContract(architectureContract);
|
|
215994
|
-
const moduleRoots = await findModuleRoots(
|
|
216592
|
+
const moduleRoots = await findModuleRoots(
|
|
216593
|
+
workspaceRoot,
|
|
216594
|
+
modulesRoot,
|
|
216595
|
+
architectureContract
|
|
216596
|
+
);
|
|
215995
216597
|
const explicitStandaloneModuleByPath = await buildExplicitStandaloneModulePathMap(
|
|
215996
216598
|
workspaceRoot,
|
|
215997
216599
|
architectureContract
|
|
215998
216600
|
);
|
|
216601
|
+
const workspacePackageAliases = await buildWorkspacePackageAliasMap(
|
|
216602
|
+
workspaceRoot,
|
|
216603
|
+
moduleRoots
|
|
216604
|
+
);
|
|
215999
216605
|
const imports = await collectCrossModuleImports(
|
|
216000
216606
|
workspaceRoot,
|
|
216001
216607
|
modulesRoot,
|
|
216002
216608
|
moduleRoots,
|
|
216003
216609
|
explicitStandaloneModuleByPath,
|
|
216610
|
+
workspacePackageAliases,
|
|
216004
216611
|
adapter
|
|
216005
216612
|
);
|
|
216613
|
+
const peerImports = filterPeerModuleImports(imports);
|
|
216006
216614
|
const findings = [];
|
|
216007
216615
|
const moduleContractCache = /* @__PURE__ */ new Map();
|
|
216008
216616
|
if (options.checkDeclaredDependencies) {
|
|
216009
216617
|
const failures = [];
|
|
216010
216618
|
const skippedFindings = /* @__PURE__ */ new Map();
|
|
216011
|
-
for (const dependencyImport of
|
|
216619
|
+
for (const dependencyImport of peerImports) {
|
|
216012
216620
|
const sourceContract = await loadModuleArchitectureContract(
|
|
216013
216621
|
workspaceRoot,
|
|
216014
216622
|
architectureContract,
|
|
@@ -216050,6 +216658,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216050
216658
|
),
|
|
216051
216659
|
filePath: dependencyImport.sourceFileRelativePath,
|
|
216052
216660
|
line: dependencyImport.line,
|
|
216661
|
+
importSpecifier: dependencyImport.importSpecifier,
|
|
216053
216662
|
findingType: "module-dependency",
|
|
216054
216663
|
module: dependencyImport.sourceModule,
|
|
216055
216664
|
target: dependencyImport.targetModule
|
|
@@ -216072,6 +216681,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216072
216681
|
),
|
|
216073
216682
|
filePath: dependencyImport.sourceFileRelativePath,
|
|
216074
216683
|
line: dependencyImport.line,
|
|
216684
|
+
importSpecifier: dependencyImport.importSpecifier,
|
|
216075
216685
|
findingType: "module-dependency",
|
|
216076
216686
|
module: dependencyImport.sourceModule,
|
|
216077
216687
|
target: dependencyImport.targetModule
|
|
@@ -216080,7 +216690,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216080
216690
|
}
|
|
216081
216691
|
if (failures.length > 0) {
|
|
216082
216692
|
findings.push(...failures);
|
|
216083
|
-
} else if (
|
|
216693
|
+
} else if (peerImports.length === 0) {
|
|
216084
216694
|
findings.push({
|
|
216085
216695
|
result: makeValidationResult(
|
|
216086
216696
|
"AP-DEP-004",
|
|
@@ -216105,7 +216715,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216105
216715
|
if (options.checkPublicSurfaceImports) {
|
|
216106
216716
|
const failures = [];
|
|
216107
216717
|
const skippedFindings = /* @__PURE__ */ new Map();
|
|
216108
|
-
for (const dependencyImport of
|
|
216718
|
+
for (const dependencyImport of peerImports) {
|
|
216109
216719
|
const sourceContract = await loadModuleArchitectureContract(
|
|
216110
216720
|
workspaceRoot,
|
|
216111
216721
|
architectureContract,
|
|
@@ -216165,6 +216775,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216165
216775
|
),
|
|
216166
216776
|
filePath: dependencyImport.sourceFileRelativePath,
|
|
216167
216777
|
line: dependencyImport.line,
|
|
216778
|
+
importSpecifier: dependencyImport.importSpecifier,
|
|
216168
216779
|
findingType: "module-dependency",
|
|
216169
216780
|
module: dependencyImport.sourceModule,
|
|
216170
216781
|
target: dependencyImport.targetModule
|
|
@@ -216172,41 +216783,31 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216172
216783
|
}
|
|
216173
216784
|
continue;
|
|
216174
216785
|
}
|
|
216175
|
-
|
|
216176
|
-
|
|
216786
|
+
const publicEntrypoints = await resolveModulePublicEntrypoints(
|
|
216787
|
+
workspaceRoot,
|
|
216788
|
+
architectureContract,
|
|
216177
216789
|
dependencyImport.targetModule,
|
|
216178
|
-
|
|
216179
|
-
|
|
216180
|
-
|
|
216181
|
-
|
|
216182
|
-
|
|
216183
|
-
|
|
216184
|
-
|
|
216185
|
-
`Module '${dependencyImport.sourceModule}' must import module '${dependencyImport.targetModule}' via its index.ts public entrypoint: ${buildModuleIndexEntrypointPath(modulesRoot, dependencyImport.targetModule, adapter)}.`,
|
|
216186
|
-
{
|
|
216187
|
-
findingType: "module-dependency",
|
|
216188
|
-
module: dependencyImport.sourceModule,
|
|
216189
|
-
target: dependencyImport.targetModule
|
|
216190
|
-
}
|
|
216191
|
-
),
|
|
216192
|
-
filePath: dependencyImport.sourceFileRelativePath,
|
|
216193
|
-
line: dependencyImport.line,
|
|
216194
|
-
findingType: "module-dependency",
|
|
216195
|
-
module: dependencyImport.sourceModule,
|
|
216196
|
-
target: dependencyImport.targetModule
|
|
216197
|
-
});
|
|
216790
|
+
targetContract.contract,
|
|
216791
|
+
moduleRoots
|
|
216792
|
+
);
|
|
216793
|
+
if (publicEntrypoints.length === 0) {
|
|
216794
|
+
continue;
|
|
216795
|
+
}
|
|
216796
|
+
if (options.suppressPublicSurfaceFailuresForNonPublicImports === true && !dependencyImport.isPublicImport) {
|
|
216198
216797
|
continue;
|
|
216199
216798
|
}
|
|
216200
|
-
if (
|
|
216799
|
+
if (!isImportWithinPublicEntrypoints(
|
|
216201
216800
|
dependencyImport.resolvedTargetRelativePath,
|
|
216202
|
-
|
|
216801
|
+
publicEntrypoints
|
|
216203
216802
|
)) {
|
|
216803
|
+
const publicEntrypointLabel = labelPublicEntrypoint(publicEntrypoints[0] ?? "");
|
|
216804
|
+
const expectedEntrypoint = describePublicEntrypointTargets(publicEntrypoints);
|
|
216204
216805
|
failures.push({
|
|
216205
216806
|
result: makeValidationResult(
|
|
216206
216807
|
"AP-DEP-005",
|
|
216207
216808
|
"error",
|
|
216208
216809
|
false,
|
|
216209
|
-
`Module '${dependencyImport.sourceModule}'
|
|
216810
|
+
`Module '${dependencyImport.sourceModule}' must import module '${dependencyImport.targetModule}' via its ${publicEntrypointLabel}: ${expectedEntrypoint}.`,
|
|
216210
216811
|
{
|
|
216211
216812
|
findingType: "module-dependency",
|
|
216212
216813
|
module: dependencyImport.sourceModule,
|
|
@@ -216215,6 +216816,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216215
216816
|
),
|
|
216216
216817
|
filePath: dependencyImport.sourceFileRelativePath,
|
|
216217
216818
|
line: dependencyImport.line,
|
|
216819
|
+
importSpecifier: dependencyImport.importSpecifier,
|
|
216218
216820
|
findingType: "module-dependency",
|
|
216219
216821
|
module: dependencyImport.sourceModule,
|
|
216220
216822
|
target: dependencyImport.targetModule
|
|
@@ -216223,7 +216825,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216223
216825
|
}
|
|
216224
216826
|
if (failures.length > 0) {
|
|
216225
216827
|
findings.push(...failures);
|
|
216226
|
-
} else if (
|
|
216828
|
+
} else if (peerImports.length === 0) {
|
|
216227
216829
|
findings.push({
|
|
216228
216830
|
result: makeValidationResult(
|
|
216229
216831
|
"AP-DEP-005",
|
|
@@ -216252,7 +216854,7 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216252
216854
|
...explicitStandaloneModuleByPath.values()
|
|
216253
216855
|
]);
|
|
216254
216856
|
const importedBySource = buildActualImportedModuleSetBySource(
|
|
216255
|
-
|
|
216857
|
+
peerImports,
|
|
216256
216858
|
registeredModuleIds
|
|
216257
216859
|
);
|
|
216258
216860
|
for (const moduleName of [...registeredModuleIds].sort(
|
|
@@ -216267,7 +216869,9 @@ async function validateDependencyContractBoundaries(workspaceRoot, architectureC
|
|
|
216267
216869
|
if (sourceContract.status !== "ok" || !sourceContract.contract) {
|
|
216268
216870
|
continue;
|
|
216269
216871
|
}
|
|
216270
|
-
const declaredDependencies = [...sourceContract.contract.dependsOn].filter(
|
|
216872
|
+
const declaredDependencies = [...sourceContract.contract.dependsOn].filter(
|
|
216873
|
+
(dependencyModule) => registeredModuleIds.has(dependencyModule) && !isParentChildModuleRelationship(moduleName, dependencyModule)
|
|
216874
|
+
).sort((left, right) => left.localeCompare(right));
|
|
216271
216875
|
if (declaredDependencies.length === 0) {
|
|
216272
216876
|
continue;
|
|
216273
216877
|
}
|
|
@@ -216317,18 +216921,28 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216317
216921
|
const parsedArchitectureContract = await loadArchitectureContract(workspaceRoot);
|
|
216318
216922
|
const adapter = resolvePrimaryAdapterFromContract(parsedArchitectureContract);
|
|
216319
216923
|
const modulesRootRelativePath = options.modulesRootRelativePath ?? resolveModulesRootFromContract(parsedArchitectureContract);
|
|
216320
|
-
const moduleRoots = await findModuleRoots(
|
|
216924
|
+
const moduleRoots = await findModuleRoots(
|
|
216925
|
+
workspaceRoot,
|
|
216926
|
+
modulesRootRelativePath,
|
|
216927
|
+
parsedArchitectureContract
|
|
216928
|
+
);
|
|
216321
216929
|
const explicitStandaloneModuleByPath = await buildExplicitStandaloneModulePathMap(
|
|
216322
216930
|
workspaceRoot,
|
|
216323
216931
|
parsedArchitectureContract
|
|
216324
216932
|
);
|
|
216933
|
+
const workspacePackageAliases = await buildWorkspacePackageAliasMap(
|
|
216934
|
+
workspaceRoot,
|
|
216935
|
+
moduleRoots
|
|
216936
|
+
);
|
|
216325
216937
|
const imports = await collectCrossModuleImports(
|
|
216326
216938
|
workspaceRoot,
|
|
216327
216939
|
modulesRootRelativePath,
|
|
216328
216940
|
moduleRoots,
|
|
216329
216941
|
explicitStandaloneModuleByPath,
|
|
216942
|
+
workspacePackageAliases,
|
|
216330
216943
|
adapter
|
|
216331
216944
|
);
|
|
216945
|
+
const peerImports = filterPeerModuleImports(imports);
|
|
216332
216946
|
const findings = [];
|
|
216333
216947
|
let dependencyRules;
|
|
216334
216948
|
let dependencyRulesSkipReason;
|
|
@@ -216349,7 +216963,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216349
216963
|
}
|
|
216350
216964
|
}
|
|
216351
216965
|
if (options.checkCircularDependencies) {
|
|
216352
|
-
const cycles = detectCircularDependencies([...moduleRoots.keys()],
|
|
216966
|
+
const cycles = detectCircularDependencies([...moduleRoots.keys()], peerImports);
|
|
216353
216967
|
if (cycles.length === 0) {
|
|
216354
216968
|
findings.push({
|
|
216355
216969
|
result: makeValidationResult(
|
|
@@ -216381,7 +216995,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216381
216995
|
})
|
|
216382
216996
|
);
|
|
216383
216997
|
} else {
|
|
216384
|
-
const violations =
|
|
216998
|
+
const violations = peerImports.filter((dependencyImport) => {
|
|
216385
216999
|
const moduleRules = dependencyRules.modules[dependencyImport.sourceModule];
|
|
216386
217000
|
if (!moduleRules) {
|
|
216387
217001
|
return false;
|
|
@@ -216416,6 +217030,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216416
217030
|
),
|
|
216417
217031
|
filePath: violation.sourceFileRelativePath,
|
|
216418
217032
|
line: violation.line,
|
|
217033
|
+
importSpecifier: violation.importSpecifier,
|
|
216419
217034
|
findingType: "module-dependency",
|
|
216420
217035
|
module: violation.sourceModule,
|
|
216421
217036
|
target: violation.targetModule
|
|
@@ -216433,7 +217048,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216433
217048
|
})
|
|
216434
217049
|
);
|
|
216435
217050
|
} else {
|
|
216436
|
-
const violations =
|
|
217051
|
+
const violations = peerImports.filter((dependencyImport) => {
|
|
216437
217052
|
const moduleRules = dependencyRules.modules[dependencyImport.sourceModule];
|
|
216438
217053
|
return moduleRules?.publicEntrypointsOnly === true && !dependencyImport.isPublicImport;
|
|
216439
217054
|
});
|
|
@@ -216448,12 +217063,17 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216448
217063
|
});
|
|
216449
217064
|
} else {
|
|
216450
217065
|
for (const violation of violations) {
|
|
217066
|
+
const publicImportGuidance = await describeModulePublicImportGuidance(
|
|
217067
|
+
workspaceRoot,
|
|
217068
|
+
violation.targetModule,
|
|
217069
|
+
moduleRoots
|
|
217070
|
+
);
|
|
216451
217071
|
findings.push({
|
|
216452
217072
|
result: makeValidationResult(
|
|
216453
217073
|
"AP-DEP-003",
|
|
216454
217074
|
"error",
|
|
216455
217075
|
false,
|
|
216456
|
-
`${violation.sourceFileRelativePath}:${violation.line} imports non-public path "${violation.importSpecifier}" from module "${violation.targetModule}".
|
|
217076
|
+
`${violation.sourceFileRelativePath}:${violation.line} imports non-public path "${violation.importSpecifier}" from module "${violation.targetModule}". ${publicImportGuidance}`,
|
|
216457
217077
|
{
|
|
216458
217078
|
findingType: "module-dependency",
|
|
216459
217079
|
module: violation.sourceModule,
|
|
@@ -216462,6 +217082,7 @@ async function validateDependencyBoundaries(workspaceRoot, options) {
|
|
|
216462
217082
|
),
|
|
216463
217083
|
filePath: violation.sourceFileRelativePath,
|
|
216464
217084
|
line: violation.line,
|
|
217085
|
+
importSpecifier: violation.importSpecifier,
|
|
216465
217086
|
findingType: "module-dependency",
|
|
216466
217087
|
module: violation.sourceModule,
|
|
216467
217088
|
target: violation.targetModule
|
|
@@ -216476,11 +217097,19 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
|
|
|
216476
217097
|
const parsedArchitectureContract = await loadArchitectureContract(workspaceRoot);
|
|
216477
217098
|
const adapter = resolvePrimaryAdapterFromContract(parsedArchitectureContract);
|
|
216478
217099
|
const modulesRootRelativePath = options?.modulesRootRelativePath ?? resolveModulesRootFromContract(parsedArchitectureContract);
|
|
216479
|
-
const moduleRoots = await findModuleRoots(
|
|
217100
|
+
const moduleRoots = await findModuleRoots(
|
|
217101
|
+
workspaceRoot,
|
|
217102
|
+
modulesRootRelativePath,
|
|
217103
|
+
parsedArchitectureContract
|
|
217104
|
+
);
|
|
216480
217105
|
const explicitStandaloneModuleByPath = await buildExplicitStandaloneModulePathMap(
|
|
216481
217106
|
workspaceRoot,
|
|
216482
217107
|
parsedArchitectureContract
|
|
216483
217108
|
);
|
|
217109
|
+
const workspacePackageAliases = await buildWorkspacePackageAliasMap(
|
|
217110
|
+
workspaceRoot,
|
|
217111
|
+
moduleRoots
|
|
217112
|
+
);
|
|
216484
217113
|
const discoveredModules = sortUnique2([
|
|
216485
217114
|
...moduleRoots.keys(),
|
|
216486
217115
|
...explicitStandaloneModuleByPath.values()
|
|
@@ -216493,9 +217122,10 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
|
|
|
216493
217122
|
modulesRootRelativePath,
|
|
216494
217123
|
moduleRoots,
|
|
216495
217124
|
explicitStandaloneModuleByPath,
|
|
217125
|
+
workspacePackageAliases,
|
|
216496
217126
|
adapter
|
|
216497
217127
|
);
|
|
216498
|
-
const imports = allImports.filter(
|
|
217128
|
+
const imports = filterPeerModuleImports(allImports).filter(
|
|
216499
217129
|
(dependencyImport) => moduleSet.has(dependencyImport.sourceModule) && moduleSet.has(dependencyImport.targetModule)
|
|
216500
217130
|
).sort((left, right) => {
|
|
216501
217131
|
const sourceCompare = left.sourceModule.localeCompare(right.sourceModule);
|
|
@@ -216548,6 +217178,7 @@ async function buildModuleDependencyGraphSnapshot(workspaceRoot, options) {
|
|
|
216548
217178
|
return {
|
|
216549
217179
|
modules,
|
|
216550
217180
|
edges,
|
|
217181
|
+
hierarchyEdges: buildModuleHierarchyEdges(modules),
|
|
216551
217182
|
cycles,
|
|
216552
217183
|
imports
|
|
216553
217184
|
};
|
|
@@ -216572,7 +217203,7 @@ function normalizeStringArray(value) {
|
|
|
216572
217203
|
}
|
|
216573
217204
|
return normalizedValues;
|
|
216574
217205
|
}
|
|
216575
|
-
async function
|
|
217206
|
+
async function pathExists5(targetPath) {
|
|
216576
217207
|
try {
|
|
216577
217208
|
await import_node_fs9.promises.access(targetPath);
|
|
216578
217209
|
return true;
|
|
@@ -216708,7 +217339,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
|
|
|
216708
217339
|
if (!moduleReference.contract) {
|
|
216709
217340
|
continue;
|
|
216710
217341
|
}
|
|
216711
|
-
const exists = await
|
|
217342
|
+
const exists = await pathExists5(
|
|
216712
217343
|
toWorkspaceAbsolutePath(workspaceRoot, moduleReference.contract)
|
|
216713
217344
|
);
|
|
216714
217345
|
if (!exists) {
|
|
@@ -216744,7 +217375,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
|
|
|
216744
217375
|
}
|
|
216745
217376
|
const contractPath = moduleReference.contract;
|
|
216746
217377
|
const fullContractPath = toWorkspaceAbsolutePath(workspaceRoot, contractPath);
|
|
216747
|
-
if (!await
|
|
217378
|
+
if (!await pathExists5(fullContractPath)) {
|
|
216748
217379
|
continue;
|
|
216749
217380
|
}
|
|
216750
217381
|
const parsedContract = await readModuleContract(workspaceRoot, contractPath);
|
|
@@ -216803,7 +217434,7 @@ async function validateModuleContractIntegrity(workspaceRoot, contract, options)
|
|
|
216803
217434
|
}
|
|
216804
217435
|
const contractPath = moduleReference.contract;
|
|
216805
217436
|
const fullContractPath = toWorkspaceAbsolutePath(workspaceRoot, contractPath);
|
|
216806
|
-
if (!await
|
|
217437
|
+
if (!await pathExists5(fullContractPath)) {
|
|
216807
217438
|
continue;
|
|
216808
217439
|
}
|
|
216809
217440
|
const parsedContract = await readModuleContract(workspaceRoot, contractPath);
|
|
@@ -217161,7 +217792,7 @@ function hasKeywordMatch(record, keywords) {
|
|
|
217161
217792
|
const haystack = `${record.fileName} ${record.title}`.toLowerCase();
|
|
217162
217793
|
return keywords.some((keyword) => haystack.includes(keyword));
|
|
217163
217794
|
}
|
|
217164
|
-
function
|
|
217795
|
+
function pathExists6(targetPath) {
|
|
217165
217796
|
return (0, import_promises.access)(targetPath).then(() => true).catch(() => false);
|
|
217166
217797
|
}
|
|
217167
217798
|
function buildSummary(records) {
|
|
@@ -217186,7 +217817,7 @@ function createAdrValidationResult(input2) {
|
|
|
217186
217817
|
async function validateAdrEnforcement(workspaceRoot, config) {
|
|
217187
217818
|
const adrDirectoryRelativePath = await resolveAdrDirectoryRelativePath(workspaceRoot);
|
|
217188
217819
|
const adrDirectory = getAdrDirectoryPath(workspaceRoot, adrDirectoryRelativePath);
|
|
217189
|
-
const adrDirectoryExists = await
|
|
217820
|
+
const adrDirectoryExists = await pathExists6(adrDirectory);
|
|
217190
217821
|
if (!adrDirectoryExists) {
|
|
217191
217822
|
return {
|
|
217192
217823
|
results: [
|
|
@@ -217239,7 +217870,7 @@ async function validateAdrEnforcement(workspaceRoot, config) {
|
|
|
217239
217870
|
}
|
|
217240
217871
|
]
|
|
217241
217872
|
];
|
|
217242
|
-
const dependencyContextExists = await
|
|
217873
|
+
const dependencyContextExists = await pathExists6(path11.join(workspaceRoot, ".archpilot", "dependency-rules.json")) || await pathExists6(path11.join(workspaceRoot, ".archpilot", "contracts"));
|
|
217243
217874
|
const checksToRun = [
|
|
217244
217875
|
requiredCoverageChecks[0],
|
|
217245
217876
|
...dependencyContextExists ? [requiredCoverageChecks[1]] : [],
|
|
@@ -217750,13 +218381,6 @@ var overallSetupGapWarningPenalty = 1;
|
|
|
217750
218381
|
var overallSetupGapInfoPenalty = 1;
|
|
217751
218382
|
var minScore = 0;
|
|
217752
218383
|
var maxScore = 100;
|
|
217753
|
-
var crossModuleDependencyRuleIds = /* @__PURE__ */ new Set([
|
|
217754
|
-
"AP-DEP-002",
|
|
217755
|
-
"AP-DEP-003",
|
|
217756
|
-
"AP-DEP-004",
|
|
217757
|
-
"AP-DEP-005",
|
|
217758
|
-
"AP-DEP-010"
|
|
217759
|
-
]);
|
|
217760
218384
|
var crossModuleContractRuleIds = /* @__PURE__ */ new Set(["AP-DEP-004", "AP-DEP-005"]);
|
|
217761
218385
|
var cycleRuleIds = /* @__PURE__ */ new Set(["AP-DEP-001", "AP-DEP-008"]);
|
|
217762
218386
|
function clampScore(value) {
|
|
@@ -217810,6 +218434,22 @@ function getQualityPenaltyForResult(result) {
|
|
|
217810
218434
|
}
|
|
217811
218435
|
return base + getAdditionalQualityPenalty(result);
|
|
217812
218436
|
}
|
|
218437
|
+
function dedupeResultsByDeductionKey(results) {
|
|
218438
|
+
const seen = /* @__PURE__ */ new Set();
|
|
218439
|
+
const deduped = [];
|
|
218440
|
+
for (const result of results) {
|
|
218441
|
+
if (!result.deductionKey) {
|
|
218442
|
+
deduped.push(result);
|
|
218443
|
+
continue;
|
|
218444
|
+
}
|
|
218445
|
+
if (seen.has(result.deductionKey)) {
|
|
218446
|
+
continue;
|
|
218447
|
+
}
|
|
218448
|
+
seen.add(result.deductionKey);
|
|
218449
|
+
deduped.push(result);
|
|
218450
|
+
}
|
|
218451
|
+
return deduped;
|
|
218452
|
+
}
|
|
217813
218453
|
function getReadinessPenaltyForSetupGapSeverity(severity) {
|
|
217814
218454
|
if (severity === "error") {
|
|
217815
218455
|
return readinessSetupGapErrorPenalty;
|
|
@@ -217820,7 +218460,7 @@ function getReadinessPenaltyForSetupGapSeverity(severity) {
|
|
|
217820
218460
|
return readinessSetupGapInfoPenalty;
|
|
217821
218461
|
}
|
|
217822
218462
|
function deriveGovernanceRiskLevelFromResults(results) {
|
|
217823
|
-
const qualityFailures = results.filter(
|
|
218463
|
+
const qualityFailures = dedupeResultsByDeductionKey(results).filter(
|
|
217824
218464
|
(result) => !result.passed && (result.impact ?? "quality") === "quality"
|
|
217825
218465
|
);
|
|
217826
218466
|
const hasCriticalRule = qualityFailures.some(
|
|
@@ -217839,21 +218479,14 @@ function deriveGovernanceRiskLevelFromResults(results) {
|
|
|
217839
218479
|
}
|
|
217840
218480
|
function applyFinalScoreAdjustments(input2) {
|
|
217841
218481
|
let adjusted = input2.baseScore;
|
|
217842
|
-
const
|
|
217843
|
-
|
|
217844
|
-
).length;
|
|
217845
|
-
const crossModuleContractViolations = input2.results.filter(
|
|
218482
|
+
const uniqueResults = dedupeResultsByDeductionKey(input2.results);
|
|
218483
|
+
const crossModuleContractViolations = uniqueResults.filter(
|
|
217846
218484
|
(result) => !result.passed && (result.impact ?? "quality") === "quality" && typeof result.ruleId === "string" && crossModuleContractRuleIds.has(result.ruleId)
|
|
217847
218485
|
).length;
|
|
217848
|
-
const cycleViolations =
|
|
218486
|
+
const cycleViolations = uniqueResults.filter(
|
|
217849
218487
|
(result) => !result.passed && (result.impact ?? "quality") === "quality" && typeof result.ruleId === "string" && cycleRuleIds.has(result.ruleId)
|
|
217850
218488
|
).length;
|
|
217851
|
-
const blockingViolations = input2.results.filter(
|
|
217852
|
-
(result) => !result.passed && result.severity === "error" && (result.impact ?? "quality") === "quality"
|
|
217853
|
-
).length;
|
|
217854
|
-
adjusted -= Math.min(8, blockingViolations * 2);
|
|
217855
218489
|
adjusted -= Math.min(6, crossModuleContractViolations * 2);
|
|
217856
|
-
adjusted -= Math.min(4, crossModuleDependencyViolations);
|
|
217857
218490
|
adjusted -= Math.min(4, cycleViolations * 2);
|
|
217858
218491
|
const governanceRiskLevel = input2.context?.governanceRiskLevel ?? deriveGovernanceRiskLevelFromResults(input2.results);
|
|
217859
218492
|
if (governanceRiskLevel === "critical") {
|
|
@@ -219337,7 +219970,7 @@ function normalizeSqlTableName(raw) {
|
|
|
219337
219970
|
}
|
|
219338
219971
|
return trimmed;
|
|
219339
219972
|
}
|
|
219340
|
-
async function
|
|
219973
|
+
async function pathExists7(targetPath) {
|
|
219341
219974
|
try {
|
|
219342
219975
|
await import_node_fs19.promises.access(targetPath);
|
|
219343
219976
|
return true;
|
|
@@ -219358,7 +219991,7 @@ async function readTextFileIfReasonable(filePath) {
|
|
|
219358
219991
|
}
|
|
219359
219992
|
async function collectFilesRecursive(rootPath, includeFile, ignoredDirectoryNames8) {
|
|
219360
219993
|
const collected = [];
|
|
219361
|
-
if (!await
|
|
219994
|
+
if (!await pathExists7(rootPath)) {
|
|
219362
219995
|
return collected;
|
|
219363
219996
|
}
|
|
219364
219997
|
const stack = [rootPath];
|
|
@@ -219949,11 +220582,11 @@ src/
|
|
|
219949
220582
|
},
|
|
219950
220583
|
DEP_ISOLATED_MODULE_DETECTED: {
|
|
219951
220584
|
id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
|
|
219952
|
-
title: "
|
|
220585
|
+
title: "Potential orphan module detected",
|
|
219953
220586
|
category: "dependency",
|
|
219954
220587
|
defaultSeverity: "warning",
|
|
219955
|
-
description: "Checks whether a registered module has no
|
|
219956
|
-
recommendedFix: "
|
|
220588
|
+
description: "Checks whether a registered module has no peer-module dependencies and little evidence of intentional architectural use.",
|
|
220589
|
+
recommendedFix: "Add intentional-use evidence such as a contract, README, public entrypoint, package entrypoint, or remove the module if it is stale."
|
|
219957
220590
|
},
|
|
219958
220591
|
DEP_TRANSITIVE_CIRCULAR_MODULE_DEPENDENCY: {
|
|
219959
220592
|
id: ValidationRuleIds.DEP_TRANSITIVE_CIRCULAR_MODULE_DEPENDENCY,
|
|
@@ -220242,6 +220875,23 @@ function buildSetupGapDeductionKeyFromMessage(message) {
|
|
|
220242
220875
|
}
|
|
220243
220876
|
return void 0;
|
|
220244
220877
|
}
|
|
220878
|
+
function buildDependencyDeductionKey(result) {
|
|
220879
|
+
if (result.findingType !== "module-dependency") {
|
|
220880
|
+
return void 0;
|
|
220881
|
+
}
|
|
220882
|
+
if (typeof result.sourceFile !== "string" || typeof result.sourceLine !== "number" || typeof result.module !== "string" || typeof result.target !== "string") {
|
|
220883
|
+
return void 0;
|
|
220884
|
+
}
|
|
220885
|
+
return [
|
|
220886
|
+
"quality",
|
|
220887
|
+
result.id,
|
|
220888
|
+
result.module,
|
|
220889
|
+
result.target,
|
|
220890
|
+
result.sourceFile.replace(/\\/g, "/"),
|
|
220891
|
+
String(result.sourceLine),
|
|
220892
|
+
result.importSpecifier ?? ""
|
|
220893
|
+
].join("|");
|
|
220894
|
+
}
|
|
220245
220895
|
function classifyValidationResult(result) {
|
|
220246
220896
|
if (result.passed) {
|
|
220247
220897
|
return {
|
|
@@ -220269,7 +220919,7 @@ function classifyValidationResult(result) {
|
|
|
220269
220919
|
return {
|
|
220270
220920
|
kind: "violation",
|
|
220271
220921
|
scoreImpact: "quality",
|
|
220272
|
-
deductionKey: `quality:${result.id}:${normalizedMessage}`
|
|
220922
|
+
deductionKey: buildDependencyDeductionKey(result) ?? `quality:${result.id}:${normalizedMessage}`
|
|
220273
220923
|
};
|
|
220274
220924
|
}
|
|
220275
220925
|
function getRuleIdSet() {
|
|
@@ -220859,7 +221509,7 @@ function applyValidationExceptions(results, exceptions) {
|
|
|
220859
221509
|
approvedExceptions: dedupedApprovedExceptions
|
|
220860
221510
|
};
|
|
220861
221511
|
}
|
|
220862
|
-
async function
|
|
221512
|
+
async function pathExists8(targetPath) {
|
|
220863
221513
|
try {
|
|
220864
221514
|
await import_node_fs20.promises.access(targetPath);
|
|
220865
221515
|
return true;
|
|
@@ -220898,11 +221548,11 @@ async function readDependencyRulesRawConfig(workspaceRoot) {
|
|
|
220898
221548
|
async function resolveValidationConfigPath(workspaceRoot) {
|
|
220899
221549
|
const configDir = path21.join(workspaceRoot, ".archpilot");
|
|
220900
221550
|
const jsoncPath = path21.join(configDir, "validation-config.jsonc");
|
|
220901
|
-
if (await
|
|
221551
|
+
if (await pathExists8(jsoncPath)) {
|
|
220902
221552
|
return jsoncPath;
|
|
220903
221553
|
}
|
|
220904
221554
|
const jsonPath = path21.join(configDir, "validation-config.json");
|
|
220905
|
-
if (await
|
|
221555
|
+
if (await pathExists8(jsonPath)) {
|
|
220906
221556
|
return jsonPath;
|
|
220907
221557
|
}
|
|
220908
221558
|
return void 0;
|
|
@@ -221028,7 +221678,7 @@ async function validateApiStyle(workspaceRoot, contract, config, validationConfi
|
|
|
221028
221678
|
}
|
|
221029
221679
|
const openApiRelativePath = resolveOpenApiRelativePath(contract);
|
|
221030
221680
|
const openApiPath = path21.join(workspaceRoot, ...openApiRelativePath.split("/"));
|
|
221031
|
-
const exists = await
|
|
221681
|
+
const exists = await pathExists8(openApiPath);
|
|
221032
221682
|
if (openApiRequired) {
|
|
221033
221683
|
results.push({
|
|
221034
221684
|
id: ValidationRuleIds.API_OPENAPI_EXISTS,
|
|
@@ -221081,7 +221731,7 @@ async function validateTenantModel(workspaceRoot, contract, config, validationCo
|
|
|
221081
221731
|
if (config.tenantModel === "same_db_different_schema" && !isRuleDisabled(ValidationRuleIds.DOC_TENANT_DIFFERENT_SCHEMA_ADR, validationConfig)) {
|
|
221082
221732
|
const tenantModelAdrRelativePath = resolveTenantModelAdrRelativePath(contract);
|
|
221083
221733
|
const adrPath = path21.join(workspaceRoot, ...tenantModelAdrRelativePath.split("/"));
|
|
221084
|
-
const exists = await
|
|
221734
|
+
const exists = await pathExists8(adrPath);
|
|
221085
221735
|
results.push({
|
|
221086
221736
|
id: ValidationRuleIds.DOC_TENANT_DIFFERENT_SCHEMA_ADR,
|
|
221087
221737
|
severity: "warning",
|
|
@@ -221134,7 +221784,7 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
|
|
|
221134
221784
|
if (implementationProfile === "typescript-backend" && !isRuleDisabled(ValidationRuleIds.ARCH_OVERVIEW_ARTIFACT_EXISTS, validationConfig)) {
|
|
221135
221785
|
const overviewRelativePath = resolveOverviewRelativePath(contract);
|
|
221136
221786
|
const overviewPath = path21.join(workspaceRoot, ...overviewRelativePath.split("/"));
|
|
221137
|
-
const overviewExists = await
|
|
221787
|
+
const overviewExists = await pathExists8(overviewPath);
|
|
221138
221788
|
results.push({
|
|
221139
221789
|
id: ValidationRuleIds.ARCH_OVERVIEW_ARTIFACT_EXISTS,
|
|
221140
221790
|
severity: "error",
|
|
@@ -221146,7 +221796,7 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
|
|
|
221146
221796
|
const normalizeEntrypoint = (entry) => normalizeRelativePath2(entry.trim());
|
|
221147
221797
|
const hasDeclaredPublicEntrypoint = async (moduleName, entry) => {
|
|
221148
221798
|
const entryPath = path21.join(workspaceRoot, ...normalizeEntrypoint(entry).split("/"));
|
|
221149
|
-
return
|
|
221799
|
+
return pathExists8(entryPath);
|
|
221150
221800
|
};
|
|
221151
221801
|
const readModuleContractPublicEntrypoints = async (moduleName) => {
|
|
221152
221802
|
const registryEntry = contract.modules[moduleName];
|
|
@@ -221171,9 +221821,18 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
|
|
|
221171
221821
|
};
|
|
221172
221822
|
const modulesRootRelativePath2 = await getConfiguredModulesRoot(workspaceRoot, contract);
|
|
221173
221823
|
const modulesRoot = path21.join(workspaceRoot, ...modulesRootRelativePath2.split("/"));
|
|
221174
|
-
if (await
|
|
221175
|
-
const
|
|
221176
|
-
|
|
221824
|
+
if (await pathExists8(modulesRoot)) {
|
|
221825
|
+
const hierarchicalModules = await discoverHierarchicalModuleRoots(
|
|
221826
|
+
workspaceRoot,
|
|
221827
|
+
modulesRootRelativePath2
|
|
221828
|
+
);
|
|
221829
|
+
const moduleDirectories2 = hierarchicalModules.length > 0 ? hierarchicalModules.map((entry) => ({
|
|
221830
|
+
moduleName: entry.moduleId,
|
|
221831
|
+
sourcePath: entry.sourcePath
|
|
221832
|
+
})) : (await import_node_fs20.promises.readdir(modulesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
221833
|
+
moduleName: entry.name,
|
|
221834
|
+
sourcePath: `${modulesRootRelativePath2}/${entry.name}`
|
|
221835
|
+
})).sort((left, right) => left.moduleName.localeCompare(right.moduleName));
|
|
221177
221836
|
const dependencySummary = await buildDependencyGraphSummary(workspaceRoot, contract, {
|
|
221178
221837
|
modulesRootRelativePath: modulesRootRelativePath2
|
|
221179
221838
|
});
|
|
@@ -221181,10 +221840,11 @@ async function validateArchitectureStyle(workspaceRoot, contract, validationConf
|
|
|
221181
221840
|
dependencySummary.modules.filter((moduleSummary) => moduleSummary.inboundDeclaredFrom.length > 0).map((moduleSummary) => moduleSummary.module)
|
|
221182
221841
|
);
|
|
221183
221842
|
const incompleteModules = [];
|
|
221184
|
-
for (const
|
|
221185
|
-
const
|
|
221186
|
-
const
|
|
221187
|
-
const
|
|
221843
|
+
for (const moduleDirectory of moduleDirectories2) {
|
|
221844
|
+
const moduleName = moduleDirectory.moduleName;
|
|
221845
|
+
const moduleDir = path21.join(workspaceRoot, ...moduleDirectory.sourcePath.split("/"));
|
|
221846
|
+
const readmeExists = await pathExists8(path21.join(moduleDir, "README.md"));
|
|
221847
|
+
const indexExists = await pathExists8(path21.join(moduleDir, "index.ts"));
|
|
221188
221848
|
const registryPublicEntrypoints = (contract.modules[moduleName]?.publicEntrypoints ?? []).filter((entry) => typeof entry === "string").map((entry) => normalizeEntrypoint(entry));
|
|
221189
221849
|
const contractPublicEntrypoints = await readModuleContractPublicEntrypoints(moduleName);
|
|
221190
221850
|
const declaredPublicEntrypoints = [
|
|
@@ -221231,7 +221891,7 @@ async function validateDatabaseArtifacts(workspaceRoot, contract, config, valida
|
|
|
221231
221891
|
}
|
|
221232
221892
|
const sqlBaselineRelativePath = resolveSqlBaselineRelativePath(contract);
|
|
221233
221893
|
const sqlBaselinePath = path21.join(workspaceRoot, ...sqlBaselineRelativePath.split("/"));
|
|
221234
|
-
const exists = await
|
|
221894
|
+
const exists = await pathExists8(sqlBaselinePath);
|
|
221235
221895
|
results.push({
|
|
221236
221896
|
id: ValidationRuleIds.DB_SQL_BASELINE_EXISTS,
|
|
221237
221897
|
severity: "error",
|
|
@@ -221240,6 +221900,34 @@ async function validateDatabaseArtifacts(workspaceRoot, contract, config, valida
|
|
|
221240
221900
|
});
|
|
221241
221901
|
return results;
|
|
221242
221902
|
}
|
|
221903
|
+
function buildDependencyFindingStableKey(finding) {
|
|
221904
|
+
if (!finding.result.id || !finding.module || !finding.target || !finding.filePath || finding.line === void 0 || !finding.importSpecifier) {
|
|
221905
|
+
return void 0;
|
|
221906
|
+
}
|
|
221907
|
+
return [
|
|
221908
|
+
finding.result.id,
|
|
221909
|
+
finding.module,
|
|
221910
|
+
finding.target,
|
|
221911
|
+
finding.filePath.replace(/\\/g, "/"),
|
|
221912
|
+
String(finding.line),
|
|
221913
|
+
finding.importSpecifier
|
|
221914
|
+
].join("|");
|
|
221915
|
+
}
|
|
221916
|
+
function dedupeDependencyFindings(findings) {
|
|
221917
|
+
const seen = /* @__PURE__ */ new Set();
|
|
221918
|
+
const deduped = [];
|
|
221919
|
+
for (const finding of findings) {
|
|
221920
|
+
const stableKey = buildDependencyFindingStableKey(finding);
|
|
221921
|
+
if (stableKey && seen.has(stableKey)) {
|
|
221922
|
+
continue;
|
|
221923
|
+
}
|
|
221924
|
+
if (stableKey) {
|
|
221925
|
+
seen.add(stableKey);
|
|
221926
|
+
}
|
|
221927
|
+
deduped.push(finding);
|
|
221928
|
+
}
|
|
221929
|
+
return deduped;
|
|
221930
|
+
}
|
|
221243
221931
|
async function validateModuleDependencies(workspaceRoot, contract, validationConfig, onDependencyConfigError, dependencyRulesConfigOverride) {
|
|
221244
221932
|
const modulesRootRelativePath = await getConfiguredModulesRoot(workspaceRoot, contract);
|
|
221245
221933
|
const dependencyRuleChecks = {
|
|
@@ -221279,10 +221967,11 @@ async function validateModuleDependencies(workspaceRoot, contract, validationCon
|
|
|
221279
221967
|
}),
|
|
221280
221968
|
validateDependencyContractBoundaries(workspaceRoot, contract, {
|
|
221281
221969
|
...contractDependencyRuleChecks,
|
|
221282
|
-
modulesRootRelativePath
|
|
221970
|
+
modulesRootRelativePath,
|
|
221971
|
+
suppressPublicSurfaceFailuresForNonPublicImports: dependencyRuleChecks.checkNonPublicImports
|
|
221283
221972
|
})
|
|
221284
221973
|
]);
|
|
221285
|
-
const findings = [...legacyFindings, ...contractFindings];
|
|
221974
|
+
const findings = dedupeDependencyFindings([...legacyFindings, ...contractFindings]);
|
|
221286
221975
|
const results = [];
|
|
221287
221976
|
for (const finding of findings) {
|
|
221288
221977
|
const resultWithSource = {
|
|
@@ -221293,7 +221982,8 @@ async function validateModuleDependencies(workspaceRoot, contract, validationCon
|
|
|
221293
221982
|
...finding.api ? { api: finding.api } : {},
|
|
221294
221983
|
...finding.findingType ? { findingType: finding.findingType } : {},
|
|
221295
221984
|
...finding.filePath ? { sourceFile: finding.filePath, filePath: finding.filePath } : {},
|
|
221296
|
-
...finding.line !== void 0 ? { sourceLine: finding.line } : {}
|
|
221985
|
+
...finding.line !== void 0 ? { sourceLine: finding.line } : {},
|
|
221986
|
+
...finding.importSpecifier ? { importSpecifier: finding.importSpecifier } : {}
|
|
221297
221987
|
};
|
|
221298
221988
|
results.push(resultWithSource);
|
|
221299
221989
|
}
|
|
@@ -221311,24 +222001,117 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
|
|
|
221311
222001
|
return [];
|
|
221312
222002
|
}
|
|
221313
222003
|
const isolatedResults = [];
|
|
221314
|
-
const
|
|
222004
|
+
const sourceFileExtensions4 = /* @__PURE__ */ new Set([
|
|
222005
|
+
".ts",
|
|
222006
|
+
".tsx",
|
|
222007
|
+
".js",
|
|
222008
|
+
".jsx",
|
|
222009
|
+
".mjs",
|
|
222010
|
+
".cjs",
|
|
222011
|
+
".mts",
|
|
222012
|
+
".cts",
|
|
222013
|
+
".py",
|
|
222014
|
+
".go",
|
|
222015
|
+
".java",
|
|
222016
|
+
".kt",
|
|
222017
|
+
".kts",
|
|
222018
|
+
".cs",
|
|
222019
|
+
".php",
|
|
222020
|
+
".rb",
|
|
222021
|
+
".vue",
|
|
222022
|
+
".svelte"
|
|
222023
|
+
]);
|
|
221315
222024
|
const isTestLikeModule = (moduleName) => {
|
|
221316
222025
|
const normalized = moduleName.toLowerCase();
|
|
221317
222026
|
return normalized === "test" || normalized === "tests" || normalized.endsWith("-test") || normalized.endsWith("-tests");
|
|
221318
222027
|
};
|
|
222028
|
+
const collectModuleSourceEvidence2 = async (directoryPath) => {
|
|
222029
|
+
let entries;
|
|
222030
|
+
try {
|
|
222031
|
+
entries = await import_node_fs20.promises.readdir(directoryPath, { withFileTypes: true });
|
|
222032
|
+
} catch {
|
|
222033
|
+
return { sourceFileCount: 0, hasReadme: false, hasEntrypointFile: false };
|
|
222034
|
+
}
|
|
222035
|
+
let sourceFileCount = 0;
|
|
222036
|
+
let hasReadme = false;
|
|
222037
|
+
let hasEntrypointFile = false;
|
|
222038
|
+
for (const entry of entries) {
|
|
222039
|
+
const fullPath = path21.join(directoryPath, entry.name);
|
|
222040
|
+
if (entry.isDirectory()) {
|
|
222041
|
+
if (["node_modules", "dist", "out", "build", "coverage", ".git"].includes(entry.name)) {
|
|
222042
|
+
continue;
|
|
222043
|
+
}
|
|
222044
|
+
const nested = await collectModuleSourceEvidence2(fullPath);
|
|
222045
|
+
sourceFileCount += nested.sourceFileCount;
|
|
222046
|
+
hasReadme ||= nested.hasReadme;
|
|
222047
|
+
hasEntrypointFile ||= nested.hasEntrypointFile;
|
|
222048
|
+
continue;
|
|
222049
|
+
}
|
|
222050
|
+
if (!entry.isFile()) {
|
|
222051
|
+
continue;
|
|
222052
|
+
}
|
|
222053
|
+
const lowerName = entry.name.toLowerCase();
|
|
222054
|
+
if (lowerName === "readme.md" || lowerName === "readme.mdx") {
|
|
222055
|
+
hasReadme = true;
|
|
222056
|
+
}
|
|
222057
|
+
if (/^(index|main|app|extension|cli)\.[cm]?[jt]sx?$/iu.test(entry.name)) {
|
|
222058
|
+
hasEntrypointFile = true;
|
|
222059
|
+
}
|
|
222060
|
+
if (sourceFileExtensions4.has(path21.extname(entry.name).toLowerCase())) {
|
|
222061
|
+
sourceFileCount += 1;
|
|
222062
|
+
}
|
|
222063
|
+
}
|
|
222064
|
+
return { sourceFileCount, hasReadme, hasEntrypointFile };
|
|
222065
|
+
};
|
|
222066
|
+
const readPackageJsonIfExists2 = async (moduleDirectoryPath) => {
|
|
222067
|
+
const content = await readTextFileIfExists3(path21.join(moduleDirectoryPath, "package.json"));
|
|
222068
|
+
if (!content) {
|
|
222069
|
+
return void 0;
|
|
222070
|
+
}
|
|
222071
|
+
try {
|
|
222072
|
+
const parsed = JSON.parse(content);
|
|
222073
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
222074
|
+
} catch {
|
|
222075
|
+
return void 0;
|
|
222076
|
+
}
|
|
222077
|
+
};
|
|
222078
|
+
const hasPackageEntrypoint2 = async (moduleDirectoryPath) => {
|
|
222079
|
+
const packageJson = await readPackageJsonIfExists2(moduleDirectoryPath);
|
|
222080
|
+
if (!packageJson) {
|
|
222081
|
+
return false;
|
|
222082
|
+
}
|
|
222083
|
+
return ["main", "module", "browser", "types", "bin", "exports"].some(
|
|
222084
|
+
(field) => packageJson[field] !== void 0
|
|
222085
|
+
);
|
|
222086
|
+
};
|
|
222087
|
+
const hasKnownBoundaryRole2 = (moduleName) => {
|
|
222088
|
+
const normalized = moduleName.toLowerCase();
|
|
222089
|
+
const compact = normalized.replace(/[-_/]/gu, "");
|
|
222090
|
+
const segments = normalized.split(/[/-]/u);
|
|
222091
|
+
return ["adr", "ci", "compliance", "config", "governance", "policy", "validation", "smartinit"].some(
|
|
222092
|
+
(role) => compact.includes(role) || segments.includes(role)
|
|
222093
|
+
);
|
|
222094
|
+
};
|
|
222095
|
+
const hasConfiguredPublicEntrypoint2 = (moduleName) => {
|
|
222096
|
+
const publicEntrypoints = contract.modules[moduleName]?.publicEntrypoints;
|
|
222097
|
+
return Array.isArray(publicEntrypoints) && publicEntrypoints.some(
|
|
222098
|
+
(entry) => typeof entry === "string" && entry.trim().length > 0
|
|
222099
|
+
);
|
|
222100
|
+
};
|
|
222101
|
+
const hasIntentionalIndependentEvidence2 = async (moduleSummary, moduleDirectoryPath) => {
|
|
222102
|
+
const sourceEvidence = await collectModuleSourceEvidence2(moduleDirectoryPath);
|
|
222103
|
+
return moduleSummary.hasContract || hasConfiguredPublicEntrypoint2(moduleSummary.module) || sourceEvidence.hasReadme || sourceEvidence.hasEntrypointFile || await hasPackageEntrypoint2(moduleDirectoryPath) || moduleSummary.childModules.length > 0 || moduleSummary.parentModule !== void 0 && moduleSummary.childModules.length === 0 && sourceEvidence.sourceFileCount > 0 || hasKnownBoundaryRole2(moduleSummary.module) || sourceEvidence.sourceFileCount >= 2;
|
|
222104
|
+
};
|
|
221319
222105
|
for (const moduleSummary of dependencyGraphSummary.modules) {
|
|
221320
222106
|
if (isTestLikeModule(moduleSummary.module)) {
|
|
221321
222107
|
continue;
|
|
221322
222108
|
}
|
|
221323
|
-
if (isolationExemptInfrastructureModules.has(moduleSummary.module.toLowerCase())) {
|
|
221324
|
-
continue;
|
|
221325
|
-
}
|
|
221326
222109
|
const registryEntry = contract.modules[moduleSummary.module];
|
|
221327
222110
|
if (!registryEntry?.path) {
|
|
221328
222111
|
continue;
|
|
221329
222112
|
}
|
|
221330
222113
|
const moduleDirectoryPath = path21.join(workspaceRoot, ...registryEntry.path.split("/"));
|
|
221331
|
-
const moduleDirectoryExists = await
|
|
222114
|
+
const moduleDirectoryExists = await pathExists8(moduleDirectoryPath);
|
|
221332
222115
|
if (!moduleDirectoryExists) {
|
|
221333
222116
|
continue;
|
|
221334
222117
|
}
|
|
@@ -221336,11 +222119,14 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
|
|
|
221336
222119
|
if (!isIsolated) {
|
|
221337
222120
|
continue;
|
|
221338
222121
|
}
|
|
222122
|
+
if (await hasIntentionalIndependentEvidence2(moduleSummary, moduleDirectoryPath)) {
|
|
222123
|
+
continue;
|
|
222124
|
+
}
|
|
221339
222125
|
isolatedResults.push({
|
|
221340
222126
|
id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
|
|
221341
222127
|
severity: "warning",
|
|
221342
222128
|
passed: false,
|
|
221343
|
-
message: `Module '${moduleSummary.module}' is
|
|
222129
|
+
message: `Module '${moduleSummary.module}' is a potential orphan: it has no declared or actual inbound/outbound module dependencies and little evidence of intentional architectural use.`,
|
|
221344
222130
|
findingType: "module-dependency",
|
|
221345
222131
|
module: moduleSummary.module
|
|
221346
222132
|
});
|
|
@@ -221353,7 +222139,7 @@ async function validateDependencyGraphIsolation(workspaceRoot, contract, depende
|
|
|
221353
222139
|
id: ValidationRuleIds.DEP_ISOLATED_MODULE_DETECTED,
|
|
221354
222140
|
severity: "warning",
|
|
221355
222141
|
passed: true,
|
|
221356
|
-
message: "No
|
|
222142
|
+
message: "No potential orphan modules detected among registered modules with existing registry paths."
|
|
221357
222143
|
}
|
|
221358
222144
|
];
|
|
221359
222145
|
}
|
|
@@ -222135,7 +222921,10 @@ function filterDependencyGraphSummaryByModuleScope(dependencyGraphSummary, modul
|
|
|
222135
222921
|
)
|
|
222136
222922
|
}));
|
|
222137
222923
|
return {
|
|
222138
|
-
modules: scopedModules
|
|
222924
|
+
modules: scopedModules,
|
|
222925
|
+
hierarchyEdges: dependencyGraphSummary.hierarchyEdges.filter(
|
|
222926
|
+
(edge) => scopeSet.has(edge.parentModule) && scopeSet.has(edge.childModule)
|
|
222927
|
+
)
|
|
222139
222928
|
};
|
|
222140
222929
|
}
|
|
222141
222930
|
async function runArchitectureValidationForWorkspace(workspaceRoot, options) {
|
|
@@ -223892,7 +224681,7 @@ var import_node_fs22 = require("node:fs");
|
|
|
223892
224681
|
async function ensureDirectory(directoryPath) {
|
|
223893
224682
|
await import_node_fs22.promises.mkdir(directoryPath, { recursive: true });
|
|
223894
224683
|
}
|
|
223895
|
-
async function
|
|
224684
|
+
async function pathExists9(targetPath) {
|
|
223896
224685
|
try {
|
|
223897
224686
|
await import_node_fs22.promises.access(targetPath);
|
|
223898
224687
|
return true;
|
|
@@ -223901,7 +224690,7 @@ async function pathExists8(targetPath) {
|
|
|
223901
224690
|
}
|
|
223902
224691
|
}
|
|
223903
224692
|
async function createFileIfMissing(filePath, content) {
|
|
223904
|
-
if (await
|
|
224693
|
+
if (await pathExists9(filePath)) {
|
|
223905
224694
|
return false;
|
|
223906
224695
|
}
|
|
223907
224696
|
await ensureDirectory(path23.dirname(filePath));
|
|
@@ -224009,7 +224798,7 @@ async function previewArch001(context) {
|
|
|
224009
224798
|
];
|
|
224010
224799
|
const filesCreated = [];
|
|
224011
224800
|
for (const targetPath of targetPaths) {
|
|
224012
|
-
if (!await
|
|
224801
|
+
if (!await pathExists9(targetPath)) {
|
|
224013
224802
|
filesCreated.push(relative5(targetPath, context.workspaceRoot));
|
|
224014
224803
|
}
|
|
224015
224804
|
}
|
|
@@ -224030,7 +224819,7 @@ async function applyArch001(context) {
|
|
|
224030
224819
|
];
|
|
224031
224820
|
const filesCreated = [];
|
|
224032
224821
|
for (const targetPath of targetPaths) {
|
|
224033
|
-
const existed = await
|
|
224822
|
+
const existed = await pathExists9(targetPath);
|
|
224034
224823
|
await ensureDirectory(targetPath);
|
|
224035
224824
|
if (!existed) {
|
|
224036
224825
|
filesCreated.push(relative5(targetPath, context.workspaceRoot));
|
|
@@ -224046,8 +224835,8 @@ async function applyArch001(context) {
|
|
|
224046
224835
|
async function previewArch003(context) {
|
|
224047
224836
|
const directoryPath = path24.join(context.workspaceRoot, "docs", "architecture");
|
|
224048
224837
|
const filePath = path24.join(directoryPath, "overview.md");
|
|
224049
|
-
const directoryExists2 = await
|
|
224050
|
-
const fileExists4 = await
|
|
224838
|
+
const directoryExists2 = await pathExists9(directoryPath);
|
|
224839
|
+
const fileExists4 = await pathExists9(filePath);
|
|
224051
224840
|
const filesCreated = [];
|
|
224052
224841
|
if (!directoryExists2) {
|
|
224053
224842
|
filesCreated.push(relative5(directoryPath, context.workspaceRoot));
|
|
@@ -224066,7 +224855,7 @@ async function previewArch003(context) {
|
|
|
224066
224855
|
async function applyArch003(context) {
|
|
224067
224856
|
const directoryPath = path24.join(context.workspaceRoot, "docs", "architecture");
|
|
224068
224857
|
const filePath = path24.join(directoryPath, "overview.md");
|
|
224069
|
-
const directoryExisted = await
|
|
224858
|
+
const directoryExisted = await pathExists9(directoryPath);
|
|
224070
224859
|
const fileCreated = await createFileIfMissing(filePath, architectureOverviewStarterTemplate);
|
|
224071
224860
|
const filesCreated = [];
|
|
224072
224861
|
if (!directoryExisted) {
|
|
@@ -224084,7 +224873,7 @@ async function applyArch003(context) {
|
|
|
224084
224873
|
}
|
|
224085
224874
|
async function previewApi001(context) {
|
|
224086
224875
|
const filePath = path24.join(context.workspaceRoot, "contracts", "openapi.yaml");
|
|
224087
|
-
const exists = await
|
|
224876
|
+
const exists = await pathExists9(filePath);
|
|
224088
224877
|
return {
|
|
224089
224878
|
filesCreated: exists ? [] : [relative5(filePath, context.workspaceRoot)],
|
|
224090
224879
|
filesModified: [],
|
|
@@ -224125,7 +224914,7 @@ async function previewArch005(context) {
|
|
|
224125
224914
|
};
|
|
224126
224915
|
}
|
|
224127
224916
|
const absolutePath = path24.join(context.workspaceRoot, ...modulePath.split("/"));
|
|
224128
|
-
const exists = await
|
|
224917
|
+
const exists = await pathExists9(absolutePath);
|
|
224129
224918
|
return {
|
|
224130
224919
|
filesCreated: exists ? [] : [modulePath],
|
|
224131
224920
|
filesModified: [],
|
|
@@ -224144,7 +224933,7 @@ async function applyArch005(context) {
|
|
|
224144
224933
|
};
|
|
224145
224934
|
}
|
|
224146
224935
|
const absolutePath = path24.join(context.workspaceRoot, ...modulePath.split("/"));
|
|
224147
|
-
const existed = await
|
|
224936
|
+
const existed = await pathExists9(absolutePath);
|
|
224148
224937
|
await ensureDirectory(absolutePath);
|
|
224149
224938
|
return {
|
|
224150
224939
|
applied: !existed,
|
|
@@ -224165,7 +224954,7 @@ async function previewArch006(context) {
|
|
|
224165
224954
|
};
|
|
224166
224955
|
}
|
|
224167
224956
|
const absolutePath = path24.join(context.workspaceRoot, ...contractPath.split("/"));
|
|
224168
|
-
const exists = await
|
|
224957
|
+
const exists = await pathExists9(absolutePath);
|
|
224169
224958
|
return {
|
|
224170
224959
|
filesCreated: exists ? [] : [contractPath],
|
|
224171
224960
|
filesModified: [],
|
|
@@ -224207,7 +224996,7 @@ async function applyArch006(context) {
|
|
|
224207
224996
|
}
|
|
224208
224997
|
async function previewDoc001(context) {
|
|
224209
224998
|
const filePath = path24.join(context.workspaceRoot, "docs", "adrs", "adr-001-tenant-model.md");
|
|
224210
|
-
const exists = await
|
|
224999
|
+
const exists = await pathExists9(filePath);
|
|
224211
225000
|
return {
|
|
224212
225001
|
filesCreated: exists ? [] : [relative5(filePath, context.workspaceRoot)],
|
|
224213
225002
|
filesModified: [],
|
|
@@ -224240,7 +225029,7 @@ async function applyDoc001(context) {
|
|
|
224240
225029
|
}
|
|
224241
225030
|
async function previewDoc002(context) {
|
|
224242
225031
|
const filePath = path24.join(context.workspaceRoot, "docs", "adrs", "adr-rbac-model.md");
|
|
224243
|
-
const exists = await
|
|
225032
|
+
const exists = await pathExists9(filePath);
|
|
224244
225033
|
return {
|
|
224245
225034
|
filesCreated: exists ? [] : [relative5(filePath, context.workspaceRoot)],
|
|
224246
225035
|
filesModified: [],
|
|
@@ -224375,7 +225164,7 @@ async function applyDep006(context) {
|
|
|
224375
225164
|
"contracts",
|
|
224376
225165
|
`${parsed.sourceModule}.contract.json`
|
|
224377
225166
|
);
|
|
224378
|
-
if (!await
|
|
225167
|
+
if (!await pathExists9(contractPath)) {
|
|
224379
225168
|
return {
|
|
224380
225169
|
applied: false,
|
|
224381
225170
|
filesCreated: [],
|
|
@@ -224788,7 +225577,7 @@ var jsxExtensions = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
|
|
|
224788
225577
|
function normalizePath4(value) {
|
|
224789
225578
|
return value.replace(/\\/g, "/").replace(/^\.\/+/u, "").replace(/\/+$/u, "").toLowerCase();
|
|
224790
225579
|
}
|
|
224791
|
-
function
|
|
225580
|
+
function pathExists10(targetPath) {
|
|
224792
225581
|
try {
|
|
224793
225582
|
fs24.accessSync(targetPath);
|
|
224794
225583
|
return true;
|
|
@@ -224875,7 +225664,7 @@ function hasDependencyPrefix(dependencies, prefixes) {
|
|
|
224875
225664
|
return false;
|
|
224876
225665
|
}
|
|
224877
225666
|
function hasAnyFile(candidateRoot, filePaths) {
|
|
224878
|
-
return filePaths.some((filePath) =>
|
|
225667
|
+
return filePaths.some((filePath) => pathExists10(path25.join(candidateRoot, ...filePath.split("/"))));
|
|
224879
225668
|
}
|
|
224880
225669
|
function scanForJsxFiles(candidateRoot) {
|
|
224881
225670
|
const queue = [{ absolutePath: candidateRoot, depth: 0 }];
|
|
@@ -224911,25 +225700,25 @@ function collectCandidateSignals(candidateRoot) {
|
|
|
224911
225700
|
const dependencies = collectDependencyNames(packageJsonPath);
|
|
224912
225701
|
return {
|
|
224913
225702
|
dependencies,
|
|
224914
|
-
hasNextConfig:
|
|
224915
|
-
hasViteConfig:
|
|
224916
|
-
hasIndexHtml:
|
|
224917
|
-
hasPublicDir:
|
|
224918
|
-
hasSrcComponents:
|
|
224919
|
-
hasSrcPages:
|
|
224920
|
-
hasSrcApp:
|
|
225703
|
+
hasNextConfig: pathExists10(path25.join(candidateRoot, "next.config.js")) || pathExists10(path25.join(candidateRoot, "next.config.mjs")) || pathExists10(path25.join(candidateRoot, "next.config.ts")),
|
|
225704
|
+
hasViteConfig: pathExists10(path25.join(candidateRoot, "vite.config.js")) || pathExists10(path25.join(candidateRoot, "vite.config.ts")) || pathExists10(path25.join(candidateRoot, "vite.config.mjs")),
|
|
225705
|
+
hasIndexHtml: pathExists10(path25.join(candidateRoot, "index.html")),
|
|
225706
|
+
hasPublicDir: pathExists10(path25.join(candidateRoot, "public")),
|
|
225707
|
+
hasSrcComponents: pathExists10(path25.join(candidateRoot, "src", "components")),
|
|
225708
|
+
hasSrcPages: pathExists10(path25.join(candidateRoot, "src", "pages")),
|
|
225709
|
+
hasSrcApp: pathExists10(path25.join(candidateRoot, "src", "app")),
|
|
224921
225710
|
hasJsxTsconfig: hasJsxEnabled(path25.join(candidateRoot, "tsconfig.json")) || hasJsxEnabled(path25.join(candidateRoot, "jsconfig.json")),
|
|
224922
225711
|
hasJsxFiles: scanForJsxFiles(candidateRoot),
|
|
224923
|
-
hasRoutesDir:
|
|
224924
|
-
hasControllersDir:
|
|
224925
|
-
hasPrismaDir:
|
|
224926
|
-
hasDbDir:
|
|
224927
|
-
hasMigrationsDir:
|
|
224928
|
-
hasApiDir:
|
|
225712
|
+
hasRoutesDir: pathExists10(path25.join(candidateRoot, "routes")),
|
|
225713
|
+
hasControllersDir: pathExists10(path25.join(candidateRoot, "controllers")),
|
|
225714
|
+
hasPrismaDir: pathExists10(path25.join(candidateRoot, "prisma")),
|
|
225715
|
+
hasDbDir: pathExists10(path25.join(candidateRoot, "db")),
|
|
225716
|
+
hasMigrationsDir: pathExists10(path25.join(candidateRoot, "migrations")),
|
|
225717
|
+
hasApiDir: pathExists10(path25.join(candidateRoot, "api")),
|
|
224929
225718
|
hasServerEntrypoint: hasAnyFile(candidateRoot, backendEntrypoints),
|
|
224930
225719
|
hasOpenApiArtifacts: hasAnyFile(candidateRoot, openApiArtifacts),
|
|
224931
225720
|
hasWorkerEntrypoint: hasAnyFile(candidateRoot, workerEntrypoints),
|
|
224932
|
-
hasPackageJson:
|
|
225721
|
+
hasPackageJson: pathExists10(packageJsonPath),
|
|
224933
225722
|
hasExportsField: hasExportsField(packageJsonPath),
|
|
224934
225723
|
hasIndexEntrypoint: hasAnyFile(candidateRoot, indexEntrypoints)
|
|
224935
225724
|
};
|
|
@@ -225098,7 +225887,7 @@ function classifyModuleScope(input2) {
|
|
|
225098
225887
|
return "backend";
|
|
225099
225888
|
}
|
|
225100
225889
|
const candidateRoots = getCandidateRoots(input2.workspaceRoot, input2.modulePath).filter(
|
|
225101
|
-
(candidate) =>
|
|
225890
|
+
(candidate) => pathExists10(candidate)
|
|
225102
225891
|
);
|
|
225103
225892
|
const scores = sumScores(
|
|
225104
225893
|
candidateRoots.map(
|
|
@@ -225121,7 +225910,7 @@ function classifyModuleScope(input2) {
|
|
|
225121
225910
|
function normalizePath5(value) {
|
|
225122
225911
|
return value.replace(/\\/g, "/");
|
|
225123
225912
|
}
|
|
225124
|
-
async function
|
|
225913
|
+
async function pathExists11(targetPath) {
|
|
225125
225914
|
try {
|
|
225126
225915
|
await import_node_fs24.promises.access(targetPath);
|
|
225127
225916
|
return true;
|
|
@@ -225136,9 +225925,32 @@ async function readTextFileIfExists4(filePath) {
|
|
|
225136
225925
|
return void 0;
|
|
225137
225926
|
}
|
|
225138
225927
|
}
|
|
225928
|
+
var sourceFileExtensions2 = /* @__PURE__ */ new Set([
|
|
225929
|
+
".ts",
|
|
225930
|
+
".tsx",
|
|
225931
|
+
".js",
|
|
225932
|
+
".jsx",
|
|
225933
|
+
".mjs",
|
|
225934
|
+
".cjs",
|
|
225935
|
+
".mts",
|
|
225936
|
+
".cts",
|
|
225937
|
+
".py",
|
|
225938
|
+
".go",
|
|
225939
|
+
".java",
|
|
225940
|
+
".kt",
|
|
225941
|
+
".kts",
|
|
225942
|
+
".cs",
|
|
225943
|
+
".php",
|
|
225944
|
+
".rb",
|
|
225945
|
+
".vue",
|
|
225946
|
+
".svelte"
|
|
225947
|
+
]);
|
|
225139
225948
|
function sortUnique3(values) {
|
|
225140
225949
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
225141
225950
|
}
|
|
225951
|
+
function toSafeContractModuleFileStem2(moduleName) {
|
|
225952
|
+
return normalizePath5(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
|
|
225953
|
+
}
|
|
225142
225954
|
function getModuleRegistry(contract) {
|
|
225143
225955
|
const modules = contract?.modules;
|
|
225144
225956
|
if (!modules || typeof modules !== "object" || Array.isArray(modules)) {
|
|
@@ -225149,6 +225961,83 @@ function getModuleRegistry(contract) {
|
|
|
225149
225961
|
function normalizePublicEntrypointList(entries) {
|
|
225150
225962
|
return sortUnique3(entries.map((entry) => normalizePath5(entry.trim())).filter((entry) => entry.length > 0));
|
|
225151
225963
|
}
|
|
225964
|
+
function hasConfiguredPublicEntrypoint(registryEntry) {
|
|
225965
|
+
return Array.isArray(registryEntry?.publicEntrypoints) && registryEntry.publicEntrypoints.some(
|
|
225966
|
+
(entry) => typeof entry === "string" && entry.trim().length > 0
|
|
225967
|
+
);
|
|
225968
|
+
}
|
|
225969
|
+
async function readPackageJsonIfExists(moduleDirectoryPath) {
|
|
225970
|
+
const content = await readTextFileIfExists4(path26.join(moduleDirectoryPath, "package.json"));
|
|
225971
|
+
if (!content) {
|
|
225972
|
+
return void 0;
|
|
225973
|
+
}
|
|
225974
|
+
try {
|
|
225975
|
+
const parsed = JSON.parse(content);
|
|
225976
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
225977
|
+
} catch {
|
|
225978
|
+
return void 0;
|
|
225979
|
+
}
|
|
225980
|
+
}
|
|
225981
|
+
async function collectModuleSourceEvidence(directoryPath) {
|
|
225982
|
+
let entries;
|
|
225983
|
+
try {
|
|
225984
|
+
entries = await import_node_fs24.promises.readdir(directoryPath, { withFileTypes: true });
|
|
225985
|
+
} catch {
|
|
225986
|
+
return { sourceFileCount: 0, hasReadme: false, hasEntrypointFile: false };
|
|
225987
|
+
}
|
|
225988
|
+
let sourceFileCount = 0;
|
|
225989
|
+
let hasReadme = false;
|
|
225990
|
+
let hasEntrypointFile = false;
|
|
225991
|
+
for (const entry of entries) {
|
|
225992
|
+
const fullPath = path26.join(directoryPath, entry.name);
|
|
225993
|
+
if (entry.isDirectory()) {
|
|
225994
|
+
if (["node_modules", "dist", "out", "build", "coverage", ".git"].includes(entry.name)) {
|
|
225995
|
+
continue;
|
|
225996
|
+
}
|
|
225997
|
+
const nested = await collectModuleSourceEvidence(fullPath);
|
|
225998
|
+
sourceFileCount += nested.sourceFileCount;
|
|
225999
|
+
hasReadme ||= nested.hasReadme;
|
|
226000
|
+
hasEntrypointFile ||= nested.hasEntrypointFile;
|
|
226001
|
+
continue;
|
|
226002
|
+
}
|
|
226003
|
+
if (!entry.isFile()) {
|
|
226004
|
+
continue;
|
|
226005
|
+
}
|
|
226006
|
+
const lowerName = entry.name.toLowerCase();
|
|
226007
|
+
if (lowerName === "readme.md" || lowerName === "readme.mdx") {
|
|
226008
|
+
hasReadme = true;
|
|
226009
|
+
}
|
|
226010
|
+
if (/^(index|main|app|extension|cli)\.[cm]?[jt]sx?$/iu.test(entry.name)) {
|
|
226011
|
+
hasEntrypointFile = true;
|
|
226012
|
+
}
|
|
226013
|
+
if (sourceFileExtensions2.has(path26.extname(entry.name).toLowerCase())) {
|
|
226014
|
+
sourceFileCount += 1;
|
|
226015
|
+
}
|
|
226016
|
+
}
|
|
226017
|
+
return { sourceFileCount, hasReadme, hasEntrypointFile };
|
|
226018
|
+
}
|
|
226019
|
+
function hasKnownBoundaryRole(moduleName) {
|
|
226020
|
+
const normalized = moduleName.toLowerCase();
|
|
226021
|
+
const compact = normalized.replace(/[-_/]/gu, "");
|
|
226022
|
+
const segments = normalized.split(/[/-]/u);
|
|
226023
|
+
return ["adr", "ci", "compliance", "config", "governance", "policy", "validation", "smartinit"].some(
|
|
226024
|
+
(role) => compact.includes(role) || segments.includes(role)
|
|
226025
|
+
);
|
|
226026
|
+
}
|
|
226027
|
+
async function hasPackageEntrypoint(moduleDirectoryPath) {
|
|
226028
|
+
const packageJson = await readPackageJsonIfExists(moduleDirectoryPath);
|
|
226029
|
+
if (!packageJson) {
|
|
226030
|
+
return false;
|
|
226031
|
+
}
|
|
226032
|
+
return ["main", "module", "browser", "types", "bin", "exports"].some(
|
|
226033
|
+
(field) => packageJson[field] !== void 0
|
|
226034
|
+
);
|
|
226035
|
+
}
|
|
226036
|
+
async function hasIntentionalIndependentEvidence(args) {
|
|
226037
|
+
const moduleDirectoryPath = path26.join(args.workspaceRoot, ...args.moduleEntry.sourcePath.split("/"));
|
|
226038
|
+
const evidence = await collectModuleSourceEvidence(moduleDirectoryPath);
|
|
226039
|
+
return args.moduleEntry.contractExists || args.moduleEntry.hasPublicEntrypoint === true || evidence.hasReadme || evidence.hasEntrypointFile || await hasPackageEntrypoint(moduleDirectoryPath) || args.hasChildren || args.isLeafChild && evidence.sourceFileCount > 0 || hasKnownBoundaryRole(args.moduleEntry.moduleName) || evidence.sourceFileCount >= 2;
|
|
226040
|
+
}
|
|
225152
226041
|
async function loadModuleContractPublicEntrypoints(workspaceRoot, contractPath) {
|
|
225153
226042
|
const fullContractPath = path26.join(workspaceRoot, ...contractPath.split("/"));
|
|
225154
226043
|
const content = await readTextFileIfExists4(fullContractPath);
|
|
@@ -225189,7 +226078,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
|
|
|
225189
226078
|
const discovered = [];
|
|
225190
226079
|
const discoveredNames = /* @__PURE__ */ new Set();
|
|
225191
226080
|
const toContractPath = (moduleName, registryEntry) => normalizePath5(
|
|
225192
|
-
typeof registryEntry?.contract === "string" ? registryEntry.contract : `${contractsRoot}/${moduleName}.contract.json`
|
|
226081
|
+
typeof registryEntry?.contract === "string" ? registryEntry.contract : `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`
|
|
225193
226082
|
);
|
|
225194
226083
|
const resolveMissingPublicEntrypointAlignment = async (registryEntry, contractPath) => {
|
|
225195
226084
|
if (!Array.isArray(registryEntry?.publicEntrypoints)) {
|
|
@@ -225233,9 +226122,9 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
|
|
|
225233
226122
|
continue;
|
|
225234
226123
|
}
|
|
225235
226124
|
const contractPath = normalizePath5(
|
|
225236
|
-
typeof registryEntry.contract === "string" ? registryEntry.contract : `${contractsRoot}/${moduleName}.contract.json`
|
|
226125
|
+
typeof registryEntry.contract === "string" ? registryEntry.contract : `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`
|
|
225237
226126
|
);
|
|
225238
|
-
const contractExists = await
|
|
226127
|
+
const contractExists = await pathExists11(path26.join(workspaceRoot, ...contractPath.split("/")));
|
|
225239
226128
|
const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(
|
|
225240
226129
|
registryEntry,
|
|
225241
226130
|
contractPath
|
|
@@ -225248,6 +226137,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
|
|
|
225248
226137
|
...resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, normalizedSourcePath, contract) } : {},
|
|
225249
226138
|
contractPath,
|
|
225250
226139
|
contractExists,
|
|
226140
|
+
hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
|
|
225251
226141
|
...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
|
|
225252
226142
|
});
|
|
225253
226143
|
discoveredNames.add(moduleName);
|
|
@@ -225259,7 +226149,7 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
|
|
|
225259
226149
|
const registryEntry = moduleRegistry[moduleName];
|
|
225260
226150
|
const sourcePath = normalizePath5(registryEntry?.path ?? `${normalizedModulesRoot}/${moduleName}`);
|
|
225261
226151
|
const contractPath = toContractPath(moduleName, registryEntry);
|
|
225262
|
-
const contractExists = await
|
|
226152
|
+
const contractExists = await pathExists11(path26.join(workspaceRoot, ...contractPath.split("/")));
|
|
225263
226153
|
const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(
|
|
225264
226154
|
registryEntry,
|
|
225265
226155
|
contractPath
|
|
@@ -225272,18 +226162,56 @@ async function discoverModulesFromArchitectureContract(workspaceRoot, contract,
|
|
|
225272
226162
|
...resolveModuleScopeForPath(workspaceRoot, sourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, sourcePath, contract) } : {},
|
|
225273
226163
|
contractPath,
|
|
225274
226164
|
contractExists,
|
|
226165
|
+
hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
|
|
225275
226166
|
...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
|
|
225276
226167
|
});
|
|
225277
226168
|
discoveredNames.add(moduleName);
|
|
225278
226169
|
}
|
|
226170
|
+
for (const moduleRoot of await discoverHierarchicalModuleRoots(workspaceRoot, normalizedModulesRoot)) {
|
|
226171
|
+
if (discoveredNames.has(moduleRoot.moduleId)) {
|
|
226172
|
+
continue;
|
|
226173
|
+
}
|
|
226174
|
+
const registryEntry = moduleRegistry[moduleRoot.moduleId];
|
|
226175
|
+
const contractPath = toContractPath(moduleRoot.moduleId, registryEntry);
|
|
226176
|
+
const contractExists = await pathExists11(path26.join(workspaceRoot, ...contractPath.split("/")));
|
|
226177
|
+
const missingPublicEntrypointAlignment = await resolveMissingPublicEntrypointAlignment(
|
|
226178
|
+
registryEntry,
|
|
226179
|
+
contractPath
|
|
226180
|
+
);
|
|
226181
|
+
discovered.push({
|
|
226182
|
+
moduleName: moduleRoot.moduleId,
|
|
226183
|
+
sourcePath: moduleRoot.sourcePath,
|
|
226184
|
+
discoverySource: "architecture.json",
|
|
226185
|
+
sourcePathExists: true,
|
|
226186
|
+
...resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath, contract) ? { scope: resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath, contract) } : {},
|
|
226187
|
+
contractPath,
|
|
226188
|
+
contractExists,
|
|
226189
|
+
hasPublicEntrypoint: hasConfiguredPublicEntrypoint(registryEntry),
|
|
226190
|
+
...missingPublicEntrypointAlignment !== void 0 ? { missingPublicEntrypointAlignment } : {}
|
|
226191
|
+
});
|
|
226192
|
+
discoveredNames.add(moduleRoot.moduleId);
|
|
226193
|
+
}
|
|
225279
226194
|
return discovered.sort((left, right) => left.moduleName.localeCompare(right.moduleName));
|
|
225280
226195
|
}
|
|
225281
226196
|
async function discoverModulesFromFallbackScan(workspaceRoot, modulesRoot = "src/modules", contractsRoot = ".archpilot/contracts") {
|
|
225282
|
-
const
|
|
226197
|
+
const hierarchicalModules = await discoverHierarchicalModuleRoots(workspaceRoot, modulesRoot);
|
|
226198
|
+
const moduleNames = hierarchicalModules.length > 0 ? [] : await listModuleDirectoryNames(workspaceRoot, modulesRoot);
|
|
225283
226199
|
const discovered = [];
|
|
226200
|
+
for (const moduleRoot of hierarchicalModules) {
|
|
226201
|
+
const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem2(moduleRoot.moduleId)}.contract.json`;
|
|
226202
|
+
discovered.push({
|
|
226203
|
+
moduleName: moduleRoot.moduleId,
|
|
226204
|
+
sourcePath: moduleRoot.sourcePath,
|
|
226205
|
+
discoverySource: "inferred-scan",
|
|
226206
|
+
sourcePathExists: true,
|
|
226207
|
+
...resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath) ? { scope: resolveModuleScopeForPath(workspaceRoot, moduleRoot.sourcePath) } : {},
|
|
226208
|
+
contractPath,
|
|
226209
|
+
contractExists: await pathExists11(path26.join(workspaceRoot, ...contractPath.split("/")))
|
|
226210
|
+
});
|
|
226211
|
+
}
|
|
225284
226212
|
for (const moduleName of moduleNames) {
|
|
225285
226213
|
const sourcePath = `${modulesRoot}/${moduleName}`;
|
|
225286
|
-
const contractPath = `${contractsRoot}/${moduleName}.contract.json`;
|
|
226214
|
+
const contractPath = `${contractsRoot}/${toSafeContractModuleFileStem2(moduleName)}.contract.json`;
|
|
225287
226215
|
discovered.push({
|
|
225288
226216
|
moduleName,
|
|
225289
226217
|
sourcePath,
|
|
@@ -225291,7 +226219,7 @@ async function discoverModulesFromFallbackScan(workspaceRoot, modulesRoot = "src
|
|
|
225291
226219
|
sourcePathExists: true,
|
|
225292
226220
|
...resolveModuleScopeForPath(workspaceRoot, sourcePath) ? { scope: resolveModuleScopeForPath(workspaceRoot, sourcePath) } : {},
|
|
225293
226221
|
contractPath,
|
|
225294
|
-
contractExists: await
|
|
226222
|
+
contractExists: await pathExists11(path26.join(workspaceRoot, ...contractPath.split("/")))
|
|
225295
226223
|
});
|
|
225296
226224
|
}
|
|
225297
226225
|
return discovered;
|
|
@@ -225381,14 +226309,39 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225381
226309
|
moduleFilter: moduleIds
|
|
225382
226310
|
});
|
|
225383
226311
|
const edges = dependencySnapshot.edges.map((edge) => toArchitectureMapEdge(edge));
|
|
226312
|
+
const hierarchyEdges = dependencySnapshot.hierarchyEdges;
|
|
225384
226313
|
const parsedCycles = dependencySnapshot.cycles.map((cycle) => parseCycleString(cycle)).filter((cycle) => cycle.length > 1).sort((left, right) => left.join("->").localeCompare(right.join("->")));
|
|
225385
226314
|
const incomingMap = buildIncomingMap(modules, edges);
|
|
225386
226315
|
const outgoingMap = buildOutgoingMap(modules, edges);
|
|
225387
226316
|
const cycleMembership = new Set(parsedCycles.flatMap((cycle) => cycle));
|
|
225388
|
-
const
|
|
226317
|
+
const hierarchyParentByChild = new Map(
|
|
226318
|
+
hierarchyEdges.map((edge) => [edge.childModule, edge.parentModule])
|
|
226319
|
+
);
|
|
226320
|
+
const childModulesByParent = /* @__PURE__ */ new Map();
|
|
226321
|
+
for (const edge of hierarchyEdges) {
|
|
226322
|
+
const children = childModulesByParent.get(edge.parentModule) ?? [];
|
|
226323
|
+
children.push(edge.childModule);
|
|
226324
|
+
childModulesByParent.set(edge.parentModule, children);
|
|
226325
|
+
}
|
|
226326
|
+
const independentModuleNames = [];
|
|
226327
|
+
const potentialOrphanModuleNames = [];
|
|
226328
|
+
const hotspotSummary = await Promise.all(modules.map(async (moduleEntry) => {
|
|
225389
226329
|
const incomingDependencyCount = incomingMap.get(moduleEntry.moduleName)?.length ?? 0;
|
|
225390
226330
|
const outgoingDependencyCount = outgoingMap.get(moduleEntry.moduleName)?.length ?? 0;
|
|
225391
|
-
const
|
|
226331
|
+
const hasNoPeerUsage = incomingDependencyCount === 0 && outgoingDependencyCount === 0;
|
|
226332
|
+
const hasIntentionalEvidence = hasNoPeerUsage ? await hasIntentionalIndependentEvidence({
|
|
226333
|
+
workspaceRoot,
|
|
226334
|
+
moduleEntry,
|
|
226335
|
+
hasChildren: (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) > 0,
|
|
226336
|
+
isLeafChild: hierarchyParentByChild.has(moduleEntry.moduleName) && (childModulesByParent.get(moduleEntry.moduleName)?.length ?? 0) === 0
|
|
226337
|
+
}) : false;
|
|
226338
|
+
const orphan = hasNoPeerUsage && !hasIntentionalEvidence;
|
|
226339
|
+
if (hasNoPeerUsage && hasIntentionalEvidence) {
|
|
226340
|
+
independentModuleNames.push(moduleEntry.moduleName);
|
|
226341
|
+
}
|
|
226342
|
+
if (orphan) {
|
|
226343
|
+
potentialOrphanModuleNames.push(moduleEntry.moduleName);
|
|
226344
|
+
}
|
|
225392
226345
|
return {
|
|
225393
226346
|
moduleName: moduleEntry.moduleName,
|
|
225394
226347
|
incomingDependencyCount,
|
|
@@ -225400,7 +226353,7 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225400
226353
|
missingPublicEntrypointAlignment: moduleEntry.missingPublicEntrypointAlignment
|
|
225401
226354
|
} : {}
|
|
225402
226355
|
};
|
|
225403
|
-
});
|
|
226356
|
+
}));
|
|
225404
226357
|
const mostDependedOnModules = sortRankedCounts(
|
|
225405
226358
|
hotspotSummary.filter((entry) => entry.incomingDependencyCount > 0).map((entry) => ({
|
|
225406
226359
|
moduleName: entry.moduleName,
|
|
@@ -225416,9 +226369,9 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225416
226369
|
const modulesInCircularDependencies = sortUnique3(
|
|
225417
226370
|
hotspotSummary.filter((entry) => entry.participatesInCycle).map((entry) => entry.moduleName)
|
|
225418
226371
|
);
|
|
225419
|
-
const
|
|
225420
|
-
|
|
225421
|
-
|
|
226372
|
+
const independentModules = sortUnique3(independentModuleNames);
|
|
226373
|
+
const potentialOrphanModules = sortUnique3(potentialOrphanModuleNames);
|
|
226374
|
+
const orphanModules = potentialOrphanModules;
|
|
225422
226375
|
const missingContracts = sortUnique3(
|
|
225423
226376
|
hotspotSummary.filter((entry) => entry.missingContract).map((entry) => entry.moduleName)
|
|
225424
226377
|
);
|
|
@@ -225441,11 +226394,14 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225441
226394
|
modules,
|
|
225442
226395
|
moduleHotspotSummary: hotspotSummary,
|
|
225443
226396
|
edges,
|
|
226397
|
+
hierarchyEdges,
|
|
225444
226398
|
cycles: parsedCycles,
|
|
225445
226399
|
hotspots: {
|
|
225446
226400
|
mostDependedOnModules,
|
|
225447
226401
|
highestOutgoingFanOutModules,
|
|
225448
226402
|
modulesInCircularDependencies,
|
|
226403
|
+
independentModules,
|
|
226404
|
+
potentialOrphanModules,
|
|
225449
226405
|
orphanModules,
|
|
225450
226406
|
missingContracts,
|
|
225451
226407
|
highlyConnectedModules,
|
|
@@ -225455,6 +226411,8 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225455
226411
|
moduleCount: modules.length,
|
|
225456
226412
|
edgeCount: edges.length,
|
|
225457
226413
|
cycleCount: parsedCycles.length,
|
|
226414
|
+
independentCount: independentModules.length,
|
|
226415
|
+
potentialOrphanCount: potentialOrphanModules.length,
|
|
225458
226416
|
orphanCount: orphanModules.length,
|
|
225459
226417
|
highlyConnectedCount: highlyConnectedModules.length,
|
|
225460
226418
|
missingContractCount: missingContracts.length
|
|
@@ -225470,6 +226428,11 @@ async function generateArchitectureMap(workspaceRoot, options) {
|
|
|
225470
226428
|
importCount: edge.importCount,
|
|
225471
226429
|
publicImportCount: edge.publicImportCount,
|
|
225472
226430
|
nonPublicImportCount: edge.nonPublicImportCount
|
|
226431
|
+
})),
|
|
226432
|
+
hierarchyEdges: hierarchyEdges.map((edge) => ({
|
|
226433
|
+
source: edge.parentModule,
|
|
226434
|
+
target: edge.childModule,
|
|
226435
|
+
relationship: "contains"
|
|
225473
226436
|
}))
|
|
225474
226437
|
},
|
|
225475
226438
|
notes: {
|
|
@@ -227018,7 +227981,7 @@ async function runGithubPrCommentAdapter(workspaceRoot) {
|
|
|
227018
227981
|
// ../core/src/generateOnboardingDocs.ts
|
|
227019
227982
|
var path31 = __toESM(require("node:path"));
|
|
227020
227983
|
var import_node_fs29 = require("node:fs");
|
|
227021
|
-
async function
|
|
227984
|
+
async function pathExists12(filePath) {
|
|
227022
227985
|
try {
|
|
227023
227986
|
await import_node_fs29.promises.access(filePath);
|
|
227024
227987
|
return true;
|
|
@@ -227072,10 +228035,10 @@ async function generateOnboardingDocs(workspaceRoot) {
|
|
|
227072
228035
|
[...map.modules].sort((left, right) => left.moduleName.localeCompare(right.moduleName)).map(async (moduleEntry) => {
|
|
227073
228036
|
const readmePath = `${moduleEntry.sourcePath}/README.md`;
|
|
227074
228037
|
const indexPath = `${moduleEntry.sourcePath}/index.ts`;
|
|
227075
|
-
const readmeExists = await
|
|
228038
|
+
const readmeExists = await pathExists12(
|
|
227076
228039
|
path31.join(workspaceRoot, ...readmePath.split("/"))
|
|
227077
228040
|
);
|
|
227078
|
-
const indexExists = await
|
|
228041
|
+
const indexExists = await pathExists12(
|
|
227079
228042
|
path31.join(workspaceRoot, ...indexPath.split("/"))
|
|
227080
228043
|
);
|
|
227081
228044
|
const hotspot = hotspotByModule.get(moduleEntry.moduleName);
|
|
@@ -227857,7 +228820,7 @@ function normalizePath9(value) {
|
|
|
227857
228820
|
function sortUnique10(values) {
|
|
227858
228821
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
227859
228822
|
}
|
|
227860
|
-
async function
|
|
228823
|
+
async function pathExists13(targetPath) {
|
|
227861
228824
|
try {
|
|
227862
228825
|
await import_node_fs30.promises.access(targetPath);
|
|
227863
228826
|
return true;
|
|
@@ -228102,18 +229065,18 @@ async function generateImpactAnalysis(workspaceRoot, target, options) {
|
|
|
228102
229065
|
const contractPath = moduleEntry.contractPath;
|
|
228103
229066
|
suggestedFilesToInspect.push({
|
|
228104
229067
|
path: readmePath,
|
|
228105
|
-
exists: await
|
|
229068
|
+
exists: await pathExists13(path32.join(workspaceRoot, ...readmePath.split("/"))),
|
|
228106
229069
|
kind: "readme"
|
|
228107
229070
|
});
|
|
228108
229071
|
suggestedFilesToInspect.push({
|
|
228109
229072
|
path: indexPath,
|
|
228110
|
-
exists: await
|
|
229073
|
+
exists: await pathExists13(path32.join(workspaceRoot, ...indexPath.split("/"))),
|
|
228111
229074
|
kind: "entrypoint"
|
|
228112
229075
|
});
|
|
228113
229076
|
if (contractPath) {
|
|
228114
229077
|
suggestedFilesToInspect.push({
|
|
228115
229078
|
path: contractPath,
|
|
228116
|
-
exists: await
|
|
229079
|
+
exists: await pathExists13(path32.join(workspaceRoot, ...contractPath.split("/"))),
|
|
228117
229080
|
kind: "contract"
|
|
228118
229081
|
});
|
|
228119
229082
|
}
|
|
@@ -230436,7 +231399,7 @@ async function applyQuickFixPlan(workspaceRoot, plan) {
|
|
|
230436
231399
|
continue;
|
|
230437
231400
|
}
|
|
230438
231401
|
const absoluteTargetPath = path43.resolve(workspaceRoot, action.targetPath);
|
|
230439
|
-
if (await
|
|
231402
|
+
if (await pathExists9(absoluteTargetPath)) {
|
|
230440
231403
|
skippedExists.push(action.targetPath);
|
|
230441
231404
|
continue;
|
|
230442
231405
|
}
|
|
@@ -230489,7 +231452,7 @@ function normalizePath11(value) {
|
|
|
230489
231452
|
function toAbsolutePath(workspaceRoot, relativePath) {
|
|
230490
231453
|
return path44.join(workspaceRoot, ...relativePath.split("/"));
|
|
230491
231454
|
}
|
|
230492
|
-
async function
|
|
231455
|
+
async function pathExists14(targetPath) {
|
|
230493
231456
|
try {
|
|
230494
231457
|
await import_node_fs39.promises.access(targetPath);
|
|
230495
231458
|
return true;
|
|
@@ -230500,6 +231463,9 @@ async function pathExists13(targetPath) {
|
|
|
230500
231463
|
function sortUnique12(values) {
|
|
230501
231464
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
230502
231465
|
}
|
|
231466
|
+
function toSafeContractModuleFileStem3(moduleName) {
|
|
231467
|
+
return normalizePath11(moduleName).split("/").map((segment) => segment.trim()).filter((segment) => segment.length > 0).join(".");
|
|
231468
|
+
}
|
|
230503
231469
|
function wildcardToRegex(pattern) {
|
|
230504
231470
|
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
230505
231471
|
return new RegExp(`^${escaped.replace(/\*/g, ".*")}$`, "u");
|
|
@@ -230515,7 +231481,7 @@ async function inferModulePublicEntrypoints(workspaceRoot, moduleSourcePath, ada
|
|
|
230515
231481
|
const normalizedSourcePath = normalizePath11(moduleSourcePath);
|
|
230516
231482
|
if (/\.[a-z0-9]+$/iu.test(normalizedSourcePath)) {
|
|
230517
231483
|
const absoluteSourcePath = toAbsolutePath(workspaceRoot, normalizedSourcePath);
|
|
230518
|
-
if (await
|
|
231484
|
+
if (await pathExists14(absoluteSourcePath)) {
|
|
230519
231485
|
return [normalizedSourcePath];
|
|
230520
231486
|
}
|
|
230521
231487
|
}
|
|
@@ -230542,14 +231508,14 @@ async function inferModulePublicEntrypoints(workspaceRoot, moduleSourcePath, ada
|
|
|
230542
231508
|
const inferred = [];
|
|
230543
231509
|
for (const fileName of orderedCandidates) {
|
|
230544
231510
|
const candidateRelative = `${normalizedSourcePath}/${fileName}`;
|
|
230545
|
-
if (await
|
|
231511
|
+
if (await pathExists14(toAbsolutePath(workspaceRoot, candidateRelative))) {
|
|
230546
231512
|
inferred.push(candidateRelative);
|
|
230547
231513
|
break;
|
|
230548
231514
|
}
|
|
230549
231515
|
}
|
|
230550
231516
|
for (const publicDirName of adapter.publicEntrypointDirectoryNames) {
|
|
230551
231517
|
const publicDirectoryRelative = `${normalizedSourcePath}/${publicDirName}`;
|
|
230552
|
-
if (await
|
|
231518
|
+
if (await pathExists14(toAbsolutePath(workspaceRoot, publicDirectoryRelative))) {
|
|
230553
231519
|
inferred.push(publicDirectoryRelative);
|
|
230554
231520
|
break;
|
|
230555
231521
|
}
|
|
@@ -230581,7 +231547,10 @@ function resolveContractPath(contract, moduleName) {
|
|
|
230581
231547
|
return normalizePath11(configured);
|
|
230582
231548
|
}
|
|
230583
231549
|
return normalizePath11(
|
|
230584
|
-
path44.posix.join(
|
|
231550
|
+
path44.posix.join(
|
|
231551
|
+
resolveContractsRootFromContract(contract),
|
|
231552
|
+
`${toSafeContractModuleFileStem3(moduleName)}.contract.json`
|
|
231553
|
+
)
|
|
230585
231554
|
);
|
|
230586
231555
|
}
|
|
230587
231556
|
function createModuleContract(input2) {
|
|
@@ -230593,6 +231562,23 @@ function createModuleContract(input2) {
|
|
|
230593
231562
|
exposedApis: []
|
|
230594
231563
|
};
|
|
230595
231564
|
}
|
|
231565
|
+
async function readExistingModuleContractPublicEntrypoints(workspaceRoot, contractPath) {
|
|
231566
|
+
try {
|
|
231567
|
+
const raw = await import_node_fs39.promises.readFile(toAbsolutePath(workspaceRoot, contractPath), {
|
|
231568
|
+
encoding: "utf8"
|
|
231569
|
+
});
|
|
231570
|
+
const parsed = JSON.parse(raw);
|
|
231571
|
+
if (!Array.isArray(parsed.publicEntrypoints)) {
|
|
231572
|
+
return void 0;
|
|
231573
|
+
}
|
|
231574
|
+
if (parsed.publicEntrypoints.some((entry) => typeof entry !== "string")) {
|
|
231575
|
+
return void 0;
|
|
231576
|
+
}
|
|
231577
|
+
return sortUnique12(parsed.publicEntrypoints.map((entry) => normalizePath11(entry)));
|
|
231578
|
+
} catch {
|
|
231579
|
+
return void 0;
|
|
231580
|
+
}
|
|
231581
|
+
}
|
|
230596
231582
|
function isRegistryEntryDifferent(input2) {
|
|
230597
231583
|
const moduleRegistry = getModuleRegistry2(input2.contract);
|
|
230598
231584
|
const existing = moduleRegistry[input2.moduleName] ?? {};
|
|
@@ -230619,7 +231605,15 @@ async function generateMissingModuleContracts(workspaceRoot) {
|
|
|
230619
231605
|
)) {
|
|
230620
231606
|
const contractPath = resolveContractPath(contract, moduleEntry.moduleName);
|
|
230621
231607
|
const sourcePath = normalizePath11(moduleEntry.sourcePath);
|
|
230622
|
-
const
|
|
231608
|
+
const absoluteContractPath = toAbsolutePath(workspaceRoot, contractPath);
|
|
231609
|
+
const contractExists = await pathExists14(absoluteContractPath);
|
|
231610
|
+
const existingContractPublicEntrypoints = contractExists ? await readExistingModuleContractPublicEntrypoints(workspaceRoot, contractPath) : void 0;
|
|
231611
|
+
const configuredPublicEntrypoints = !contractExists && Array.isArray(getModuleRegistry2(contract)[moduleEntry.moduleName]?.publicEntrypoints) ? sortUnique12(
|
|
231612
|
+
getModuleRegistry2(contract)[moduleEntry.moduleName]?.publicEntrypoints?.map(
|
|
231613
|
+
(entry) => normalizePath11(entry)
|
|
231614
|
+
) ?? []
|
|
231615
|
+
) : void 0;
|
|
231616
|
+
const publicEntrypoints = existingContractPublicEntrypoints ?? configuredPublicEntrypoints ?? await inferModulePublicEntrypoints(
|
|
230623
231617
|
workspaceRoot,
|
|
230624
231618
|
sourcePath,
|
|
230625
231619
|
adapter
|
|
@@ -230629,8 +231623,7 @@ async function generateMissingModuleContracts(workspaceRoot) {
|
|
|
230629
231623
|
dependsOn: dependsOnBySource.get(moduleEntry.moduleName) ?? [],
|
|
230630
231624
|
publicEntrypoints
|
|
230631
231625
|
});
|
|
230632
|
-
|
|
230633
|
-
if (await pathExists13(absoluteContractPath)) {
|
|
231626
|
+
if (contractExists) {
|
|
230634
231627
|
skippedExistingContracts.push(contractPath);
|
|
230635
231628
|
} else {
|
|
230636
231629
|
await import_node_fs39.promises.mkdir(path44.dirname(absoluteContractPath), { recursive: true });
|
|
@@ -230676,7 +231669,7 @@ function normalizePath12(value) {
|
|
|
230676
231669
|
function toAbsolutePath2(workspaceRoot, relativePath) {
|
|
230677
231670
|
return path45.join(workspaceRoot, ...relativePath.split("/"));
|
|
230678
231671
|
}
|
|
230679
|
-
async function
|
|
231672
|
+
async function pathExists15(targetPath) {
|
|
230680
231673
|
try {
|
|
230681
231674
|
await import_node_fs40.promises.access(targetPath);
|
|
230682
231675
|
return true;
|
|
@@ -230739,7 +231732,7 @@ async function bootstrapArchitectureConfig(workspaceRoot, options) {
|
|
|
230739
231732
|
ensuredDirectories.push(".archpilot", ".archpilot/contracts");
|
|
230740
231733
|
const dependencyRulesPath = ".archpilot/dependency-rules.json";
|
|
230741
231734
|
const dependencyRulesAbsolutePath = toAbsolutePath2(workspaceRoot, dependencyRulesPath);
|
|
230742
|
-
if (await
|
|
231735
|
+
if (await pathExists15(dependencyRulesAbsolutePath)) {
|
|
230743
231736
|
skippedExistingFiles.push(dependencyRulesPath);
|
|
230744
231737
|
} else {
|
|
230745
231738
|
await import_node_fs40.promises.writeFile(
|
|
@@ -230751,7 +231744,7 @@ async function bootstrapArchitectureConfig(workspaceRoot, options) {
|
|
|
230751
231744
|
}
|
|
230752
231745
|
const layerRulesPath = ".archpilot/layer-rules.json";
|
|
230753
231746
|
const layerRulesAbsolutePath = toAbsolutePath2(workspaceRoot, layerRulesPath);
|
|
230754
|
-
if (await
|
|
231747
|
+
if (await pathExists15(layerRulesAbsolutePath)) {
|
|
230755
231748
|
skippedExistingFiles.push(layerRulesPath);
|
|
230756
231749
|
} else {
|
|
230757
231750
|
await import_node_fs40.promises.writeFile(layerRulesAbsolutePath, renderLayerRulesConfig(modules), {
|
|
@@ -232776,7 +233769,7 @@ var appRouteReservedDirectoryNames = /* @__PURE__ */ new Set([
|
|
|
232776
233769
|
"common",
|
|
232777
233770
|
"shared-ui"
|
|
232778
233771
|
]);
|
|
232779
|
-
var
|
|
233772
|
+
var sourceFileExtensions3 = /* @__PURE__ */ new Set([
|
|
232780
233773
|
".ts",
|
|
232781
233774
|
".tsx",
|
|
232782
233775
|
".js",
|
|
@@ -232830,7 +233823,7 @@ function safeReadDirEntries(directoryPath) {
|
|
|
232830
233823
|
return [];
|
|
232831
233824
|
}
|
|
232832
233825
|
}
|
|
232833
|
-
function
|
|
233826
|
+
function pathExists16(pathValue) {
|
|
232834
233827
|
try {
|
|
232835
233828
|
fs48.accessSync(pathValue);
|
|
232836
233829
|
return true;
|
|
@@ -232894,7 +233887,7 @@ function inspectModuleFolder(absolutePath) {
|
|
|
232894
233887
|
continue;
|
|
232895
233888
|
}
|
|
232896
233889
|
const extension = path53.extname(entry.name).toLowerCase();
|
|
232897
|
-
if (
|
|
233890
|
+
if (sourceFileExtensions3.has(extension)) {
|
|
232898
233891
|
hasSourceFiles = true;
|
|
232899
233892
|
sourceFileCount += 1;
|
|
232900
233893
|
}
|
|
@@ -232974,14 +233967,17 @@ function collectModuleCandidatesFromRoot(workspaceRoot, modulesRootRelative, def
|
|
|
232974
233967
|
if (skipFrontendUtilities && frontendUtilityDirectoryNames.has(entry.name.toLowerCase())) {
|
|
232975
233968
|
continue;
|
|
232976
233969
|
}
|
|
232977
|
-
const
|
|
232978
|
-
const
|
|
233970
|
+
const rootSegments = modulesRootRelative.split("/").filter((segment) => segment.length > 0);
|
|
233971
|
+
const sourceIndex = rootSegments.lastIndexOf("src");
|
|
233972
|
+
const rootLeaf = rootSegments[rootSegments.length - 1]?.toLowerCase();
|
|
233973
|
+
const parentName = sourceIndex > 0 && (rootLeaf === "src" || ["modules", "features"].includes(rootLeaf ?? "")) ? rootSegments[sourceIndex - 1] : void 0;
|
|
233974
|
+
const moduleName = parentName && parentName !== "src" ? `${parentName}/${entry.name}` : ["domain", "domains", "application", "infrastructure"].includes(rootLeaf ?? "") ? `${rootSegments[rootSegments.length - 1]}/${entry.name}` : entry.name;
|
|
232979
233975
|
const moduleAbsolutePath = path53.join(absoluteRoot, entry.name);
|
|
232980
233976
|
const inspected = inspectModuleFolder(moduleAbsolutePath);
|
|
232981
233977
|
const detected = makeDetectedModule(
|
|
232982
233978
|
workspaceRoot,
|
|
232983
233979
|
moduleName,
|
|
232984
|
-
|
|
233980
|
+
normalizePath13(`${modulesRootRelative}/${entry.name}`),
|
|
232985
233981
|
modulesRootRelative,
|
|
232986
233982
|
inspected.hasSourceFiles,
|
|
232987
233983
|
inspected.hasRoleFiles,
|
|
@@ -233042,6 +234038,10 @@ function collectExplicitRoots(workspaceRoot) {
|
|
|
233042
234038
|
for (const root of [
|
|
233043
234039
|
"src/modules",
|
|
233044
234040
|
"src/features",
|
|
234041
|
+
"src/domain",
|
|
234042
|
+
"src/domains",
|
|
234043
|
+
"src/application",
|
|
234044
|
+
"src/infrastructure",
|
|
233045
234045
|
"src/app",
|
|
233046
234046
|
"app",
|
|
233047
234047
|
"backend/src/modules",
|
|
@@ -233058,7 +234058,7 @@ function collectExplicitRoots(workspaceRoot) {
|
|
|
233058
234058
|
"packages",
|
|
233059
234059
|
"libs"
|
|
233060
234060
|
]) {
|
|
233061
|
-
if (
|
|
234061
|
+
if (pathExists16(path53.join(workspaceRoot, ...root.split("/")))) {
|
|
233062
234062
|
roots.push(root);
|
|
233063
234063
|
}
|
|
233064
234064
|
}
|
|
@@ -233068,23 +234068,49 @@ function collectExplicitRoots(workspaceRoot) {
|
|
|
233068
234068
|
continue;
|
|
233069
234069
|
}
|
|
233070
234070
|
for (const candidate of [
|
|
234071
|
+
`apps/${appEntry.name}/src`,
|
|
233071
234072
|
`apps/${appEntry.name}/src/modules`,
|
|
233072
234073
|
`apps/${appEntry.name}/src/features`,
|
|
234074
|
+
`apps/${appEntry.name}/src/domain`,
|
|
234075
|
+
`apps/${appEntry.name}/src/domains`,
|
|
234076
|
+
`apps/${appEntry.name}/src/application`,
|
|
234077
|
+
`apps/${appEntry.name}/src/infrastructure`,
|
|
233073
234078
|
`apps/${appEntry.name}/app`,
|
|
233074
234079
|
`apps/${appEntry.name}/src/app`
|
|
233075
234080
|
]) {
|
|
233076
|
-
if (
|
|
234081
|
+
if (pathExists16(path53.join(workspaceRoot, ...candidate.split("/")))) {
|
|
233077
234082
|
roots.push(candidate);
|
|
233078
234083
|
}
|
|
233079
234084
|
}
|
|
233080
234085
|
}
|
|
234086
|
+
for (const container of ["packages", "services"]) {
|
|
234087
|
+
const containerRoot = path53.join(workspaceRoot, container);
|
|
234088
|
+
for (const containerEntry of safeReadDirEntries(containerRoot)) {
|
|
234089
|
+
if (!containerEntry.isDirectory() || ignoredDirectoryNames4.has(containerEntry.name)) {
|
|
234090
|
+
continue;
|
|
234091
|
+
}
|
|
234092
|
+
for (const candidate of [
|
|
234093
|
+
`${container}/${containerEntry.name}/src`,
|
|
234094
|
+
`${container}/${containerEntry.name}/src/modules`,
|
|
234095
|
+
`${container}/${containerEntry.name}/src/features`,
|
|
234096
|
+
`${container}/${containerEntry.name}/src/domain`,
|
|
234097
|
+
`${container}/${containerEntry.name}/src/domains`,
|
|
234098
|
+
`${container}/${containerEntry.name}/src/application`,
|
|
234099
|
+
`${container}/${containerEntry.name}/src/infrastructure`
|
|
234100
|
+
]) {
|
|
234101
|
+
if (pathExists16(path53.join(workspaceRoot, ...candidate.split("/")))) {
|
|
234102
|
+
roots.push(candidate);
|
|
234103
|
+
}
|
|
234104
|
+
}
|
|
234105
|
+
}
|
|
234106
|
+
}
|
|
233081
234107
|
return uniqueSorted(roots);
|
|
233082
234108
|
}
|
|
233083
234109
|
function collectJavaPackageRoots(workspaceRoot) {
|
|
233084
234110
|
const roots = [];
|
|
233085
234111
|
for (const sourceRoot of ["src/main/java", "src/main/kotlin", "src"]) {
|
|
233086
234112
|
const absoluteSourceRoot = path53.join(workspaceRoot, ...sourceRoot.split("/"));
|
|
233087
|
-
if (!
|
|
234113
|
+
if (!pathExists16(absoluteSourceRoot)) {
|
|
233088
234114
|
continue;
|
|
233089
234115
|
}
|
|
233090
234116
|
const queue = [
|
|
@@ -233891,7 +234917,7 @@ function safeReadText3(filePath, maxChars = 3e4) {
|
|
|
233891
234917
|
return void 0;
|
|
233892
234918
|
}
|
|
233893
234919
|
}
|
|
233894
|
-
function
|
|
234920
|
+
function pathExists17(pathValue) {
|
|
233895
234921
|
try {
|
|
233896
234922
|
fs51.accessSync(pathValue);
|
|
233897
234923
|
return true;
|
|
@@ -233997,7 +235023,7 @@ function collectCandidateRoots(workspaceRoot, topology) {
|
|
|
233997
235023
|
}
|
|
233998
235024
|
}
|
|
233999
235025
|
for (const root of ["backend", "frontend"]) {
|
|
234000
|
-
if (
|
|
235026
|
+
if (pathExists17(path56.join(workspaceRoot, root))) {
|
|
234001
235027
|
roots.add(root);
|
|
234002
235028
|
}
|
|
234003
235029
|
}
|