@vibgrate/cli 2026.814.2 → 2026.817.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +61 -0
- package/README.md +1 -0
- package/dist/agent-UQC7QN77.js +27 -0
- package/dist/{agent-5ANHRYEI.js.map → agent-UQC7QN77.js.map} +1 -1
- package/dist/{approvals-T2KXPJLV.js → approvals-ASPJQUZK.js} +6 -5
- package/dist/{approvals-T2KXPJLV.js.map → approvals-ASPJQUZK.js.map} +1 -1
- package/dist/baseline-FIV6PR2M.js +9 -0
- package/dist/{baseline-WVD6P5IO.js.map → baseline-FIV6PR2M.js.map} +1 -1
- package/dist/{chunk-FOW5IF73.js → chunk-2FEB5KJS.js} +11 -34
- package/dist/chunk-2FEB5KJS.js.map +1 -0
- package/dist/{chunk-WQLZSVNF.js → chunk-3FMRFECC.js} +7 -6
- package/dist/chunk-3FMRFECC.js.map +1 -0
- package/dist/{chunk-7QDHQLUS.js → chunk-3H3SVJUY.js} +13 -11
- package/dist/chunk-3H3SVJUY.js.map +1 -0
- package/dist/{chunk-REIGWTTH.js → chunk-3HNPVXUK.js} +3 -3
- package/dist/{chunk-REIGWTTH.js.map → chunk-3HNPVXUK.js.map} +1 -1
- package/dist/{chunk-YQNTIBKS.js → chunk-3NJUOIZQ.js} +6 -6
- package/dist/{chunk-YQNTIBKS.js.map → chunk-3NJUOIZQ.js.map} +1 -1
- package/dist/{chunk-BH54SLGZ.js → chunk-5OL2TSHK.js} +4 -4
- package/dist/{chunk-BH54SLGZ.js.map → chunk-5OL2TSHK.js.map} +1 -1
- package/dist/{chunk-TFAXW7VM.js → chunk-6K3XK7C5.js} +69 -976
- package/dist/chunk-6K3XK7C5.js.map +1 -0
- package/dist/{chunk-N3XFY3PX.js → chunk-74UBGF4P.js} +3 -3
- package/dist/{chunk-N3XFY3PX.js.map → chunk-74UBGF4P.js.map} +1 -1
- package/dist/{chunk-X76VPOYH.js → chunk-AXZZ5CCG.js} +4 -4
- package/dist/{chunk-X76VPOYH.js.map → chunk-AXZZ5CCG.js.map} +1 -1
- package/dist/{chunk-5GLQNMTI.js → chunk-C3LMWZKF.js} +6 -6
- package/dist/{chunk-5GLQNMTI.js.map → chunk-C3LMWZKF.js.map} +1 -1
- package/dist/{chunk-WWGLVF7D.js → chunk-DVW3SVCW.js} +9 -8
- package/dist/chunk-DVW3SVCW.js.map +1 -0
- package/dist/{chunk-TNROG5CO.js → chunk-E2FAQREZ.js} +1739 -116
- package/dist/chunk-E2FAQREZ.js.map +1 -0
- package/dist/{chunk-7NMXE6KG.js → chunk-EXV4QSAD.js} +4 -4
- package/dist/{chunk-7NMXE6KG.js.map → chunk-EXV4QSAD.js.map} +1 -1
- package/dist/{chunk-3LSG7Z4I.js → chunk-EZ7UC5Y5.js} +25 -4
- package/dist/chunk-EZ7UC5Y5.js.map +1 -0
- package/dist/{chunk-OWSFZQOP.js → chunk-FJG5AXKZ.js} +3 -3
- package/dist/{chunk-OWSFZQOP.js.map → chunk-FJG5AXKZ.js.map} +1 -1
- package/dist/{chunk-NKFXXP6W.js → chunk-GOGMS3ST.js} +8 -6
- package/dist/chunk-GOGMS3ST.js.map +1 -0
- package/dist/{chunk-WHJMS7XC.js → chunk-I5LP55B6.js} +3 -3
- package/dist/{chunk-WHJMS7XC.js.map → chunk-I5LP55B6.js.map} +1 -1
- package/dist/{chunk-IHXNOY3R.js → chunk-K6DXETMC.js} +12 -12
- package/dist/{chunk-IHXNOY3R.js.map → chunk-K6DXETMC.js.map} +1 -1
- package/dist/{chunk-DSUGC7F5.js → chunk-KJT2R6WW.js} +4 -4
- package/dist/{chunk-DSUGC7F5.js.map → chunk-KJT2R6WW.js.map} +1 -1
- package/dist/chunk-KNGAZDGF.js +467 -0
- package/dist/chunk-KNGAZDGF.js.map +1 -0
- package/dist/{chunk-JCN6MSXQ.js → chunk-LHKQGVRF.js} +17 -29
- package/dist/chunk-LHKQGVRF.js.map +1 -0
- package/dist/{chunk-YNV5M3JW.js → chunk-M7IO3DXH.js} +9 -8
- package/dist/chunk-M7IO3DXH.js.map +1 -0
- package/dist/chunk-MS6V5XKB.js +33 -0
- package/dist/chunk-MS6V5XKB.js.map +1 -0
- package/dist/{chunk-2U37PFB2.js → chunk-MVPRPSXU.js} +7 -4
- package/dist/chunk-MVPRPSXU.js.map +1 -0
- package/dist/{chunk-DT4KIVRI.js → chunk-NG4KIJW6.js} +34 -2
- package/dist/chunk-NG4KIJW6.js.map +1 -0
- package/dist/{chunk-IHLLWBZU.js → chunk-O2DL2Q55.js} +6 -6
- package/dist/{chunk-IHLLWBZU.js.map → chunk-O2DL2Q55.js.map} +1 -1
- package/dist/chunk-O3LABX6I.js +43 -0
- package/dist/chunk-O3LABX6I.js.map +1 -0
- package/dist/chunk-OZ3IFXRD.js +22 -0
- package/dist/chunk-OZ3IFXRD.js.map +1 -0
- package/dist/chunk-PRG2ULPK.js +6 -0
- package/dist/{chunk-2H2U3DC7.js.map → chunk-PRG2ULPK.js.map} +1 -1
- package/dist/{chunk-TVDYEHIM.js → chunk-Q3M6K3HY.js} +3 -3
- package/dist/{chunk-TVDYEHIM.js.map → chunk-Q3M6K3HY.js.map} +1 -1
- package/dist/{chunk-KGPX4EUN.js → chunk-Q4G2BWE3.js} +4 -4
- package/dist/{chunk-KGPX4EUN.js.map → chunk-Q4G2BWE3.js.map} +1 -1
- package/dist/chunk-T7RSQ5WD.js +227 -0
- package/dist/chunk-T7RSQ5WD.js.map +1 -0
- package/dist/{chunk-54RGT2T5.js → chunk-TVDMNIUT.js} +3 -3
- package/dist/{chunk-54RGT2T5.js.map → chunk-TVDMNIUT.js.map} +1 -1
- package/dist/{chunk-N6ZMZ5AI.js → chunk-WAKP7SK7.js} +4922 -1011
- package/dist/chunk-WAKP7SK7.js.map +1 -0
- package/dist/{chunk-75LJM5XD.js → chunk-WVMOGIPC.js} +9 -43
- package/dist/chunk-WVMOGIPC.js.map +1 -0
- package/dist/{chunk-UTNNGKKX.js → chunk-XLXJC7H3.js} +142 -14
- package/dist/chunk-XLXJC7H3.js.map +1 -0
- package/dist/cli.js +1727 -1127
- package/dist/cli.js.map +1 -1
- package/dist/daemon-FPTRHO5N.js +26 -0
- package/dist/daemon-FPTRHO5N.js.map +1 -0
- package/dist/embed-worker-main.js +5 -4
- package/dist/embed-worker-main.js.map +1 -1
- package/dist/ensure-map-342G2IV3.js +33 -0
- package/dist/{ensure-map-HQ7A5NDL.js.map → ensure-map-342G2IV3.js.map} +1 -1
- package/dist/{fs-NTQUFCXV.js → fs-TLPOWC2D.js} +3 -3
- package/dist/fs-TLPOWC2D.js.map +1 -0
- package/dist/graph-backend-RNWQBT3P.js +15 -0
- package/dist/{graph-backend-W2TNTMY7.js.map → graph-backend-RNWQBT3P.js.map} +1 -1
- package/dist/index.d.ts +28 -6
- package/dist/index.js +21 -18
- package/dist/index.js.map +1 -1
- package/dist/{interactive-EW2VJ3BZ.js → interactive-SR7TMF6M.js} +36 -33
- package/dist/interactive-SR7TMF6M.js.map +1 -0
- package/dist/load-AYFECIQB.js +11 -0
- package/dist/{load-64RK5O6C.js.map → load-AYFECIQB.js.map} +1 -1
- package/dist/local-runtime-6SNWKSA7.js +6 -0
- package/dist/{local-runtime-2ED33KK6.js.map → local-runtime-6SNWKSA7.js.map} +1 -1
- package/dist/model-manager-SXHZ5VD4.js +10 -0
- package/dist/{model-manager-GJ2YSTSK.js.map → model-manager-SXHZ5VD4.js.map} +1 -1
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +5 -2
- package/dist/parse-worker.js.map +1 -1
- package/dist/{run-outcome-6QNQIHPV.js → run-outcome-YQQJG3LW.js} +7 -6
- package/dist/run-outcome-YQQJG3LW.js.map +1 -0
- package/dist/runtime-session-CNJ4DAV5.js +22 -0
- package/dist/{runtime-session-RJHH3KMF.js.map → runtime-session-CNJ4DAV5.js.map} +1 -1
- package/dist/session-H34HUV2Y.js +17 -0
- package/dist/{session-4BGYASOH.js.map → session-H34HUV2Y.js.map} +1 -1
- package/dist/{stream-json-GY5N7WZT.js → stream-json-55YDNAFX.js} +18 -17
- package/dist/stream-json-55YDNAFX.js.map +1 -0
- package/dist/{types-DLH-Ritr.d.ts → types-DHqH0XIE.d.ts} +68 -6
- package/dist/version-WSE3QOPK.js +4 -0
- package/dist/{version-DPAMQW6M.js.map → version-WSE3QOPK.js.map} +1 -1
- package/dist/{vg-mcp-bridge-IGHJKKSL.js → vg-mcp-bridge-2CNLHNEL.js} +13 -12
- package/dist/vg-mcp-bridge-2CNLHNEL.js.map +1 -0
- package/dist/{vgd-ORPA5C2K.js → vgd-URUZQORN.js} +10 -9
- package/dist/vgd-URUZQORN.js.map +1 -0
- package/grammars/tree-sitter-hcl.wasm +0 -0
- package/package.json +9 -8
- package/dist/agent-5ANHRYEI.js +0 -26
- package/dist/baseline-WVD6P5IO.js +0 -9
- package/dist/chunk-2H2U3DC7.js +0 -6
- package/dist/chunk-2U37PFB2.js.map +0 -1
- package/dist/chunk-3LSG7Z4I.js.map +0 -1
- package/dist/chunk-75LJM5XD.js.map +0 -1
- package/dist/chunk-7QDHQLUS.js.map +0 -1
- package/dist/chunk-DT4KIVRI.js.map +0 -1
- package/dist/chunk-FOW5IF73.js.map +0 -1
- package/dist/chunk-JCN6MSXQ.js.map +0 -1
- package/dist/chunk-N6ZMZ5AI.js.map +0 -1
- package/dist/chunk-NKFXXP6W.js.map +0 -1
- package/dist/chunk-RXP66R2E.js +0 -39
- package/dist/chunk-RXP66R2E.js.map +0 -1
- package/dist/chunk-TFAXW7VM.js.map +0 -1
- package/dist/chunk-TNROG5CO.js.map +0 -1
- package/dist/chunk-UTNNGKKX.js.map +0 -1
- package/dist/chunk-WQLZSVNF.js.map +0 -1
- package/dist/chunk-WWGLVF7D.js.map +0 -1
- package/dist/chunk-YNV5M3JW.js.map +0 -1
- package/dist/ensure-map-HQ7A5NDL.js +0 -30
- package/dist/fs-NTQUFCXV.js.map +0 -1
- package/dist/graph-backend-W2TNTMY7.js +0 -14
- package/dist/interactive-EW2VJ3BZ.js.map +0 -1
- package/dist/load-64RK5O6C.js +0 -10
- package/dist/local-runtime-2ED33KK6.js +0 -6
- package/dist/model-manager-GJ2YSTSK.js +0 -10
- package/dist/run-outcome-6QNQIHPV.js.map +0 -1
- package/dist/runtime-session-RJHH3KMF.js +0 -21
- package/dist/session-4BGYASOH.js +0 -16
- package/dist/stream-json-GY5N7WZT.js.map +0 -1
- package/dist/version-DPAMQW6M.js +0 -4
- package/dist/vg-mcp-bridge-IGHJKKSL.js.map +0 -1
- package/dist/vgd-ORPA5C2K.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { runCoreScan, compactUiPurpose } from './chunk-
|
|
2
|
-
import { findPackageJsonFiles, readJsonFile, findFiles, readTextFile, pathExists
|
|
1
|
+
import { runCoreScan, compactUiPurpose, scanArchitectureBundle, mermaidFromArchitecture, aggregateSolutionArchitecture } from './chunk-WAKP7SK7.js';
|
|
2
|
+
import { findPackageJsonFiles, readJsonFile, findFiles, readTextFile, pathExists } from './chunk-NG4KIJW6.js';
|
|
3
3
|
import { writeJsonFile } from './chunk-CRAMOEBE.js';
|
|
4
4
|
import * as path3 from 'path';
|
|
5
5
|
import { Command } from 'commander';
|
|
@@ -1963,961 +1963,6 @@ function scanServiceDependencies(projects) {
|
|
|
1963
1963
|
}
|
|
1964
1964
|
return result;
|
|
1965
1965
|
}
|
|
1966
|
-
var ARCHETYPE_SIGNALS = [
|
|
1967
|
-
// Meta-frameworks (highest priority — they imply routing patterns)
|
|
1968
|
-
{ packages: ["next", "@next/core"], archetype: "nextjs", weight: 10 },
|
|
1969
|
-
{ packages: ["@remix-run/react", "@remix-run/node", "@remix-run/dev"], archetype: "remix", weight: 10 },
|
|
1970
|
-
{ packages: ["@sveltejs/kit"], archetype: "sveltekit", weight: 10 },
|
|
1971
|
-
{ packages: ["nuxt"], archetype: "nuxt", weight: 10 },
|
|
1972
|
-
// Backend frameworks
|
|
1973
|
-
{ packages: ["@nestjs/core", "@nestjs/common"], archetype: "nestjs", weight: 9 },
|
|
1974
|
-
{ packages: ["fastify"], archetype: "fastify", weight: 8 },
|
|
1975
|
-
{ packages: ["hono"], archetype: "hono", weight: 8 },
|
|
1976
|
-
{ packages: ["koa"], archetype: "koa", weight: 8 },
|
|
1977
|
-
{ packages: ["express"], archetype: "express", weight: 7 },
|
|
1978
|
-
// Serverless
|
|
1979
|
-
{ packages: ["serverless", "aws-lambda", "@aws-sdk/client-lambda", "middy", "@cloudflare/workers-types"], archetype: "serverless", weight: 6 },
|
|
1980
|
-
// CLI
|
|
1981
|
-
{ packages: ["commander", "yargs", "meow", "cac", "clipanion", "oclif"], archetype: "cli", weight: 5 }
|
|
1982
|
-
];
|
|
1983
|
-
function detectArchetype(projects) {
|
|
1984
|
-
const allPackages = /* @__PURE__ */ new Set();
|
|
1985
|
-
for (const p of projects) {
|
|
1986
|
-
for (const d of p.dependencies) {
|
|
1987
|
-
allPackages.add(d.package);
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
if (projects.length > 2) {
|
|
1991
|
-
return { archetype: "monorepo", confidence: 0.8 };
|
|
1992
|
-
}
|
|
1993
|
-
let bestArchetype = "unknown";
|
|
1994
|
-
let bestScore = 0;
|
|
1995
|
-
for (const signal of ARCHETYPE_SIGNALS) {
|
|
1996
|
-
const matched = signal.packages.filter((p) => allPackages.has(p)).length;
|
|
1997
|
-
if (matched > 0) {
|
|
1998
|
-
const score = matched * signal.weight;
|
|
1999
|
-
if (score > bestScore) {
|
|
2000
|
-
bestScore = score;
|
|
2001
|
-
bestArchetype = signal.archetype;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
}
|
|
2005
|
-
if (bestArchetype === "unknown") {
|
|
2006
|
-
bestArchetype = "library";
|
|
2007
|
-
bestScore = 3;
|
|
2008
|
-
}
|
|
2009
|
-
const confidence = Math.min(bestScore / 15, 1);
|
|
2010
|
-
return { archetype: bestArchetype, confidence: Math.round(confidence * 100) / 100 };
|
|
2011
|
-
}
|
|
2012
|
-
var PATH_RULES = [
|
|
2013
|
-
// ── Testing (high precision) ──
|
|
2014
|
-
{ pattern: /\/__tests__\//, layer: "testing", confidence: 0.95, signal: "__tests__ directory" },
|
|
2015
|
-
{ pattern: /\.test\.[jt]sx?$/, layer: "testing", confidence: 0.95, signal: ".test.* file" },
|
|
2016
|
-
{ pattern: /\.spec\.[jt]sx?$/, layer: "testing", confidence: 0.95, signal: ".spec.* file" },
|
|
2017
|
-
{ pattern: /\/test\//, layer: "testing", confidence: 0.85, signal: "test/ directory" },
|
|
2018
|
-
{ pattern: /\/tests\//, layer: "testing", confidence: 0.85, signal: "tests/ directory" },
|
|
2019
|
-
{ pattern: /\/__mocks__\//, layer: "testing", confidence: 0.9, signal: "__mocks__ directory" },
|
|
2020
|
-
{ pattern: /\/fixtures\//, layer: "testing", confidence: 0.8, signal: "fixtures/ directory" },
|
|
2021
|
-
// ── Config/Infrastructure (high precision) ──
|
|
2022
|
-
{ pattern: /\/config\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "config.* file" },
|
|
2023
|
-
{ pattern: /\/config\//, layer: "config", confidence: 0.8, signal: "config/ directory" },
|
|
2024
|
-
{ pattern: /\.config\.[jt]sx?$/, layer: "config", confidence: 0.9, signal: ".config.* file" },
|
|
2025
|
-
{ pattern: /\/env\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "env.* file" },
|
|
2026
|
-
{ pattern: /\/bootstrap\.[jt]sx?$/, layer: "config", confidence: 0.85, signal: "bootstrap file" },
|
|
2027
|
-
{ pattern: /\/setup\.[jt]sx?$/, layer: "config", confidence: 0.8, signal: "setup file" },
|
|
2028
|
-
// ── Next.js (archetype-specific) ──
|
|
2029
|
-
{ pattern: /(^|\/)app\/.*\/route\.[jt]sx?$/, layer: "routing", confidence: 0.95, signal: "Next.js App Router route", archetypes: ["nextjs"] },
|
|
2030
|
-
{ pattern: /(^|\/)pages\/api\//, layer: "routing", confidence: 0.95, signal: "Next.js Pages API route", archetypes: ["nextjs"] },
|
|
2031
|
-
{ pattern: /(^|\/)app\/.*page\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Next.js page component", archetypes: ["nextjs"] },
|
|
2032
|
-
{ pattern: /(^|\/)app\/.*layout\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Next.js layout component", archetypes: ["nextjs"] },
|
|
2033
|
-
{ pattern: /(^|\/)app\/.*loading\.[jt]sx?$/, layer: "presentation", confidence: 0.85, signal: "Next.js loading component", archetypes: ["nextjs"] },
|
|
2034
|
-
{ pattern: /(^|\/)app\/.*error\.[jt]sx?$/, layer: "presentation", confidence: 0.85, signal: "Next.js error component", archetypes: ["nextjs"] },
|
|
2035
|
-
{ pattern: /(^|\/)middleware\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "Next.js middleware", archetypes: ["nextjs"] },
|
|
2036
|
-
// ── Remix (archetype-specific) ──
|
|
2037
|
-
{ pattern: /\/app\/routes\//, layer: "routing", confidence: 0.95, signal: "Remix route file", archetypes: ["remix"] },
|
|
2038
|
-
{ pattern: /\/app\/root\.[jt]sx?$/, layer: "presentation", confidence: 0.9, signal: "Remix root", archetypes: ["remix"] },
|
|
2039
|
-
// ── SvelteKit (archetype-specific) ──
|
|
2040
|
-
{ pattern: /\/src\/routes\/.*\+server\.[jt]s$/, layer: "routing", confidence: 0.95, signal: "SvelteKit API route", archetypes: ["sveltekit"] },
|
|
2041
|
-
{ pattern: /\/src\/routes\/.*\+page\.svelte$/, layer: "presentation", confidence: 0.9, signal: "SvelteKit page", archetypes: ["sveltekit"] },
|
|
2042
|
-
{ pattern: /\/src\/routes\/.*\+layout\.svelte$/, layer: "presentation", confidence: 0.9, signal: "SvelteKit layout", archetypes: ["sveltekit"] },
|
|
2043
|
-
{ pattern: /\/src\/hooks\.server\.[jt]s$/, layer: "middleware", confidence: 0.9, signal: "SvelteKit server hooks", archetypes: ["sveltekit"] },
|
|
2044
|
-
// ── Nuxt (archetype-specific) ──
|
|
2045
|
-
{ pattern: /\/server\/api\//, layer: "routing", confidence: 0.95, signal: "Nuxt server API", archetypes: ["nuxt"] },
|
|
2046
|
-
{ pattern: /\/server\/routes\//, layer: "routing", confidence: 0.95, signal: "Nuxt server route", archetypes: ["nuxt"] },
|
|
2047
|
-
{ pattern: /\/server\/middleware\//, layer: "middleware", confidence: 0.95, signal: "Nuxt server middleware", archetypes: ["nuxt"] },
|
|
2048
|
-
{ pattern: /\/pages\//, layer: "presentation", confidence: 0.85, signal: "Nuxt pages directory", archetypes: ["nuxt"] },
|
|
2049
|
-
// ── NestJS (archetype-specific) ──
|
|
2050
|
-
{ pattern: /\.controller\.[jt]sx?$/, layer: "routing", confidence: 0.95, signal: "NestJS controller", archetypes: ["nestjs"] },
|
|
2051
|
-
{ pattern: /\.service\.[jt]sx?$/, layer: "services", confidence: 0.95, signal: "NestJS service", archetypes: ["nestjs"] },
|
|
2052
|
-
{ pattern: /\.module\.[jt]sx?$/, layer: "config", confidence: 0.9, signal: "NestJS module", archetypes: ["nestjs"] },
|
|
2053
|
-
{ pattern: /\.guard\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS guard", archetypes: ["nestjs"] },
|
|
2054
|
-
{ pattern: /\.interceptor\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS interceptor", archetypes: ["nestjs"] },
|
|
2055
|
-
{ pattern: /\.pipe\.[jt]sx?$/, layer: "middleware", confidence: 0.85, signal: "NestJS pipe", archetypes: ["nestjs"] },
|
|
2056
|
-
{ pattern: /\.middleware\.[jt]sx?$/, layer: "middleware", confidence: 0.9, signal: "NestJS middleware", archetypes: ["nestjs"] },
|
|
2057
|
-
{ pattern: /\.entity\.[jt]sx?$/, layer: "domain", confidence: 0.9, signal: "NestJS entity", archetypes: ["nestjs"] },
|
|
2058
|
-
{ pattern: /\.dto\.[jt]sx?$/, layer: "domain", confidence: 0.85, signal: "NestJS DTO", archetypes: ["nestjs"] },
|
|
2059
|
-
{ pattern: /\.repository\.[jt]sx?$/, layer: "data-access", confidence: 0.9, signal: "NestJS repository", archetypes: ["nestjs"] },
|
|
2060
|
-
// ── Generic routing patterns ──
|
|
2061
|
-
{ pattern: /\/routes\//, layer: "routing", confidence: 0.8, signal: "routes/ directory" },
|
|
2062
|
-
{ pattern: /\/router\//, layer: "routing", confidence: 0.8, signal: "router/ directory" },
|
|
2063
|
-
{ pattern: /\/controllers\//, layer: "routing", confidence: 0.8, signal: "controllers/ directory" },
|
|
2064
|
-
{ pattern: /\/handlers\//, layer: "routing", confidence: 0.75, signal: "handlers/ directory" },
|
|
2065
|
-
{ pattern: /\/api\//, layer: "routing", confidence: 0.7, signal: "api/ directory" },
|
|
2066
|
-
{ pattern: /\/endpoints\//, layer: "routing", confidence: 0.8, signal: "endpoints/ directory" },
|
|
2067
|
-
// ── Middleware ──
|
|
2068
|
-
{ pattern: /\/middleware\//, layer: "middleware", confidence: 0.85, signal: "middleware/ directory" },
|
|
2069
|
-
{ pattern: /\/middlewares\//, layer: "middleware", confidence: 0.85, signal: "middlewares/ directory" },
|
|
2070
|
-
{ pattern: /\/hooks\//, layer: "middleware", confidence: 0.6, signal: "hooks/ directory" },
|
|
2071
|
-
{ pattern: /\/plugins\//, layer: "middleware", confidence: 0.6, signal: "plugins/ directory" },
|
|
2072
|
-
{ pattern: /\/guards\//, layer: "middleware", confidence: 0.85, signal: "guards/ directory" },
|
|
2073
|
-
{ pattern: /\/interceptors\//, layer: "middleware", confidence: 0.85, signal: "interceptors/ directory" },
|
|
2074
|
-
// ── Services / application layer ──
|
|
2075
|
-
{ pattern: /\/services\//, layer: "services", confidence: 0.85, signal: "services/ directory" },
|
|
2076
|
-
{ pattern: /\/service\//, layer: "services", confidence: 0.8, signal: "service/ directory" },
|
|
2077
|
-
{ pattern: /\/usecases\//, layer: "services", confidence: 0.85, signal: "usecases/ directory" },
|
|
2078
|
-
{ pattern: /\/use-cases\//, layer: "services", confidence: 0.85, signal: "use-cases/ directory" },
|
|
2079
|
-
{ pattern: /\/application\//, layer: "services", confidence: 0.7, signal: "application/ directory" },
|
|
2080
|
-
{ pattern: /\/actions\//, layer: "services", confidence: 0.65, signal: "actions/ directory" },
|
|
2081
|
-
// ── Domain / models ──
|
|
2082
|
-
{ pattern: /\/domain\//, layer: "domain", confidence: 0.85, signal: "domain/ directory" },
|
|
2083
|
-
{ pattern: /\/models\//, layer: "domain", confidence: 0.8, signal: "models/ directory" },
|
|
2084
|
-
{ pattern: /\/entities\//, layer: "domain", confidence: 0.85, signal: "entities/ directory" },
|
|
2085
|
-
{ pattern: /\/types\//, layer: "domain", confidence: 0.7, signal: "types/ directory" },
|
|
2086
|
-
{ pattern: /\/schemas\//, layer: "domain", confidence: 0.7, signal: "schemas/ directory" },
|
|
2087
|
-
{ pattern: /\/validators\//, layer: "domain", confidence: 0.7, signal: "validators/ directory" },
|
|
2088
|
-
// ── Data access ──
|
|
2089
|
-
{ pattern: /\/repositories\//, layer: "data-access", confidence: 0.9, signal: "repositories/ directory" },
|
|
2090
|
-
{ pattern: /\/repository\//, layer: "data-access", confidence: 0.85, signal: "repository/ directory" },
|
|
2091
|
-
{ pattern: /\/dao\//, layer: "data-access", confidence: 0.9, signal: "dao/ directory" },
|
|
2092
|
-
{ pattern: /\/db\//, layer: "data-access", confidence: 0.8, signal: "db/ directory" },
|
|
2093
|
-
{ pattern: /\/database\//, layer: "data-access", confidence: 0.8, signal: "database/ directory" },
|
|
2094
|
-
{ pattern: /\/persistence\//, layer: "data-access", confidence: 0.85, signal: "persistence/ directory" },
|
|
2095
|
-
{ pattern: /\/migrations\//, layer: "data-access", confidence: 0.9, signal: "migrations/ directory" },
|
|
2096
|
-
{ pattern: /\/seeds\//, layer: "data-access", confidence: 0.85, signal: "seeds/ directory" },
|
|
2097
|
-
{ pattern: /\/prisma\//, layer: "data-access", confidence: 0.85, signal: "prisma/ directory" },
|
|
2098
|
-
{ pattern: /\/drizzle\//, layer: "data-access", confidence: 0.85, signal: "drizzle/ directory" },
|
|
2099
|
-
// ── Infrastructure ──
|
|
2100
|
-
{ pattern: /\/infra\//, layer: "infrastructure", confidence: 0.85, signal: "infra/ directory" },
|
|
2101
|
-
{ pattern: /\/infrastructure\//, layer: "infrastructure", confidence: 0.85, signal: "infrastructure/ directory" },
|
|
2102
|
-
{ pattern: /\/adapters\//, layer: "infrastructure", confidence: 0.8, signal: "adapters/ directory" },
|
|
2103
|
-
{ pattern: /\/clients\//, layer: "infrastructure", confidence: 0.75, signal: "clients/ directory" },
|
|
2104
|
-
{ pattern: /\/integrations\//, layer: "infrastructure", confidence: 0.8, signal: "integrations/ directory" },
|
|
2105
|
-
{ pattern: /\/external\//, layer: "infrastructure", confidence: 0.75, signal: "external/ directory" },
|
|
2106
|
-
{ pattern: /\/queue\//, layer: "infrastructure", confidence: 0.8, signal: "queue/ directory" },
|
|
2107
|
-
{ pattern: /\/jobs\//, layer: "infrastructure", confidence: 0.75, signal: "jobs/ directory" },
|
|
2108
|
-
{ pattern: /\/workers\//, layer: "infrastructure", confidence: 0.75, signal: "workers/ directory" },
|
|
2109
|
-
{ pattern: /\/cron\//, layer: "infrastructure", confidence: 0.8, signal: "cron/ directory" },
|
|
2110
|
-
// ── Presentation (UI layer) ──
|
|
2111
|
-
{ pattern: /\/components\//, layer: "presentation", confidence: 0.85, signal: "components/ directory" },
|
|
2112
|
-
{ pattern: /\/views\//, layer: "presentation", confidence: 0.85, signal: "views/ directory" },
|
|
2113
|
-
{ pattern: /\/pages\//, layer: "presentation", confidence: 0.8, signal: "pages/ directory" },
|
|
2114
|
-
{ pattern: /\/layouts\//, layer: "presentation", confidence: 0.85, signal: "layouts/ directory" },
|
|
2115
|
-
{ pattern: /\/templates\//, layer: "presentation", confidence: 0.8, signal: "templates/ directory" },
|
|
2116
|
-
{ pattern: /\/widgets\//, layer: "presentation", confidence: 0.8, signal: "widgets/ directory" },
|
|
2117
|
-
{ pattern: /\/ui\//, layer: "presentation", confidence: 0.75, signal: "ui/ directory" },
|
|
2118
|
-
// ── Shared / utils ──
|
|
2119
|
-
{ pattern: /\/utils\//, layer: "shared", confidence: 0.7, signal: "utils/ directory" },
|
|
2120
|
-
{ pattern: /\/helpers\//, layer: "shared", confidence: 0.7, signal: "helpers/ directory" },
|
|
2121
|
-
{ pattern: /\/lib\//, layer: "shared", confidence: 0.6, signal: "lib/ directory" },
|
|
2122
|
-
{ pattern: /\/common\//, layer: "shared", confidence: 0.65, signal: "common/ directory" },
|
|
2123
|
-
{ pattern: /\/shared\//, layer: "shared", confidence: 0.75, signal: "shared/ directory" },
|
|
2124
|
-
{ pattern: /\/constants\//, layer: "shared", confidence: 0.7, signal: "constants/ directory" },
|
|
2125
|
-
// ── CLI-specific (command layer → routing) ──
|
|
2126
|
-
{ pattern: /\/commands\//, layer: "routing", confidence: 0.8, signal: "commands/ directory", archetypes: ["cli"] },
|
|
2127
|
-
{ pattern: /\/formatters\//, layer: "presentation", confidence: 0.8, signal: "formatters/ directory", archetypes: ["cli"] },
|
|
2128
|
-
{ pattern: /\/scanners\//, layer: "services", confidence: 0.8, signal: "scanners/ directory", archetypes: ["cli"] },
|
|
2129
|
-
{ pattern: /\/scoring\//, layer: "domain", confidence: 0.8, signal: "scoring/ directory", archetypes: ["cli"] },
|
|
2130
|
-
// ── Serverless-specific ──
|
|
2131
|
-
{ pattern: /\/functions\//, layer: "routing", confidence: 0.8, signal: "functions/ directory", archetypes: ["serverless"] },
|
|
2132
|
-
{ pattern: /\/lambdas\//, layer: "routing", confidence: 0.85, signal: "lambdas/ directory", archetypes: ["serverless"] },
|
|
2133
|
-
{ pattern: /\/layers\//, layer: "shared", confidence: 0.7, signal: "Lambda layers/ directory", archetypes: ["serverless"] },
|
|
2134
|
-
// ── .NET conventions ──
|
|
2135
|
-
// Directory rules above already cover Controllers/, Services/, Models/,
|
|
2136
|
-
// Views/, Migrations/, Middleware/ … because matching is case-insensitive.
|
|
2137
|
-
{ pattern: /\.tests?\//, layer: "testing", confidence: 0.9, signal: "*.Tests project directory" },
|
|
2138
|
-
// Layer-named project directories (`Company.Product.Domain/`,
|
|
2139
|
-
// `Company.Product.Database/`) — the dotted segment carries the layer.
|
|
2140
|
-
{ pattern: /\.domain\//, layer: "domain", confidence: 0.85, signal: "*.Domain project" },
|
|
2141
|
-
{ pattern: /\.(database|data|persistence)\//, layer: "data-access", confidence: 0.85, signal: "*.Database project" },
|
|
2142
|
-
{ pattern: /\.(infrastructure|infra)\//, layer: "infrastructure", confidence: 0.85, signal: "*.Infrastructure project" },
|
|
2143
|
-
{ pattern: /\.worker\//, layer: "infrastructure", confidence: 0.8, signal: "*.Worker project" },
|
|
2144
|
-
{ pattern: /\.(webapi|api)\//, layer: "routing", confidence: 0.8, signal: "*.WebApi project" },
|
|
2145
|
-
{ pattern: /\.(webapp|web|ui)\//, layer: "presentation", confidence: 0.75, signal: "*.WebApp project" },
|
|
2146
|
-
{ pattern: /\.(services?|application)\//, layer: "services", confidence: 0.8, signal: "*.Services project" },
|
|
2147
|
-
{ pattern: /\/wwwroot\//, layer: "presentation", confidence: 0.85, signal: "wwwroot/ static assets" },
|
|
2148
|
-
{ pattern: /\/properties\//, layer: "config", confidence: 0.85, signal: "Properties/ directory" },
|
|
2149
|
-
{ pattern: /\/program\.cs$/, layer: "config", confidence: 0.9, signal: "Program.cs entry point" },
|
|
2150
|
-
{ pattern: /\/startup\.cs$/, layer: "config", confidence: 0.9, signal: "Startup.cs" },
|
|
2151
|
-
{ pattern: /\.(cshtml|razor)$/, layer: "presentation", confidence: 0.9, signal: "Razor view" },
|
|
2152
|
-
// ── JVM (Maven/Gradle standard layout + Spring package conventions) ──
|
|
2153
|
-
{ pattern: /\/src\/(test|androidtest|integrationtest)\//, layer: "testing", confidence: 0.95, signal: "src/test source set" },
|
|
2154
|
-
{ pattern: /\/controller\//, layer: "routing", confidence: 0.8, signal: "controller/ package" },
|
|
2155
|
-
{ pattern: /\/resource\//, layer: "routing", confidence: 0.7, signal: "resource/ package (JAX-RS)" },
|
|
2156
|
-
{ pattern: /\/model\//, layer: "domain", confidence: 0.75, signal: "model/ package" },
|
|
2157
|
-
{ pattern: /\/entity\//, layer: "domain", confidence: 0.85, signal: "entity/ package" },
|
|
2158
|
-
{ pattern: /\/dto\//, layer: "domain", confidence: 0.85, signal: "dto/ package" },
|
|
2159
|
-
{ pattern: /\/mappers?\//, layer: "data-access", confidence: 0.75, signal: "mapper/ package" },
|
|
2160
|
-
// ── Python (Django/Flask/FastAPI module conventions) ──
|
|
2161
|
-
{ pattern: /\/(test_[^/]*|conftest)\.py$/, layer: "testing", confidence: 0.95, signal: "pytest test module" },
|
|
2162
|
-
{ pattern: /\/urls\.py$/, layer: "routing", confidence: 0.95, signal: "Django urls.py" },
|
|
2163
|
-
{ pattern: /\/views\.py$/, layer: "routing", confidence: 0.9, signal: "Django views.py (request handlers)" },
|
|
2164
|
-
{ pattern: /\/models\.py$/, layer: "domain", confidence: 0.9, signal: "Django models.py" },
|
|
2165
|
-
{ pattern: /\/serializers\.py$/, layer: "domain", confidence: 0.85, signal: "DRF serializers.py" },
|
|
2166
|
-
{ pattern: /\/forms\.py$/, layer: "presentation", confidence: 0.8, signal: "Django forms.py" },
|
|
2167
|
-
{ pattern: /\/(settings|admin)\.py$/, layer: "config", confidence: 0.85, signal: "Django settings/admin module" },
|
|
2168
|
-
{ pattern: /\/middleware\.py$/, layer: "middleware", confidence: 0.9, signal: "middleware.py" },
|
|
2169
|
-
{ pattern: /\/(tasks|celery)\.py$/, layer: "services", confidence: 0.8, signal: "task queue module" },
|
|
2170
|
-
// ── Go / Rust / Dart / Ruby / Elixir test conventions ──
|
|
2171
|
-
{ pattern: /_(test|spec)\.[a-z]+$/, layer: "testing", confidence: 0.95, signal: "_test/_spec file" },
|
|
2172
|
-
{ pattern: /\/spec\//, layer: "testing", confidence: 0.85, signal: "spec/ directory (RSpec)" },
|
|
2173
|
-
{ pattern: /\/cmd\//, layer: "routing", confidence: 0.7, signal: "cmd/ entry points (Go)" },
|
|
2174
|
-
// ── Ruby on Rails ──
|
|
2175
|
-
{ pattern: /\/migrate\//, layer: "data-access", confidence: 0.9, signal: "db/migrate/ directory" },
|
|
2176
|
-
{ pattern: /\/mailers\//, layer: "infrastructure", confidence: 0.8, signal: "mailers/ directory" },
|
|
2177
|
-
{ pattern: /\.erb$/, layer: "presentation", confidence: 0.85, signal: "ERB view template" },
|
|
2178
|
-
// ── PHP (Laravel/Symfony) ──
|
|
2179
|
-
{ pattern: /\.blade\.php$/, layer: "presentation", confidence: 0.9, signal: "Blade view template" },
|
|
2180
|
-
// ── Elixir (Phoenix) ──
|
|
2181
|
-
{ pattern: /\/channels\//, layer: "routing", confidence: 0.7, signal: "channels/ directory" },
|
|
2182
|
-
{ pattern: /_controller\.exs?$/, layer: "routing", confidence: 0.9, signal: "Phoenix controller" },
|
|
2183
|
-
{ pattern: /_(view|live|html|component)\.exs?$/, layer: "presentation", confidence: 0.85, signal: "Phoenix view module" },
|
|
2184
|
-
{ pattern: /\/repo\.exs?$/, layer: "data-access", confidence: 0.9, signal: "Ecto repo" },
|
|
2185
|
-
{ pattern: /\.(eex|heex)$/, layer: "presentation", confidence: 0.85, signal: "EEx/HEEx template" },
|
|
2186
|
-
// ── Flutter / mobile ──
|
|
2187
|
-
{ pattern: /\/screens\//, layer: "presentation", confidence: 0.85, signal: "screens/ directory" }
|
|
2188
|
-
];
|
|
2189
|
-
var SUFFIX_RULES = [
|
|
2190
|
-
{ suffix: ".controller", layer: "routing", confidence: 0.85, signal: "controller suffix" },
|
|
2191
|
-
{ suffix: ".route", layer: "routing", confidence: 0.85, signal: "route suffix" },
|
|
2192
|
-
{ suffix: ".router", layer: "routing", confidence: 0.85, signal: "router suffix" },
|
|
2193
|
-
{ suffix: ".handler", layer: "routing", confidence: 0.8, signal: "handler suffix" },
|
|
2194
|
-
{ suffix: ".middleware", layer: "middleware", confidence: 0.85, signal: "middleware suffix" },
|
|
2195
|
-
{ suffix: ".guard", layer: "middleware", confidence: 0.85, signal: "guard suffix" },
|
|
2196
|
-
{ suffix: ".interceptor", layer: "middleware", confidence: 0.85, signal: "interceptor suffix" },
|
|
2197
|
-
{ suffix: ".service", layer: "services", confidence: 0.85, signal: "service suffix" },
|
|
2198
|
-
{ suffix: ".usecase", layer: "services", confidence: 0.85, signal: "usecase suffix" },
|
|
2199
|
-
{ suffix: ".model", layer: "domain", confidence: 0.8, signal: "model suffix" },
|
|
2200
|
-
{ suffix: ".entity", layer: "domain", confidence: 0.85, signal: "entity suffix" },
|
|
2201
|
-
{ suffix: ".dto", layer: "domain", confidence: 0.8, signal: "DTO suffix" },
|
|
2202
|
-
{ suffix: ".schema", layer: "domain", confidence: 0.75, signal: "schema suffix" },
|
|
2203
|
-
{ suffix: ".validator", layer: "domain", confidence: 0.75, signal: "validator suffix" },
|
|
2204
|
-
{ suffix: ".repository", layer: "data-access", confidence: 0.9, signal: "repository suffix" },
|
|
2205
|
-
{ suffix: ".repo", layer: "data-access", confidence: 0.85, signal: "repo suffix" },
|
|
2206
|
-
{ suffix: ".dao", layer: "data-access", confidence: 0.9, signal: "dao suffix" },
|
|
2207
|
-
{ suffix: ".migration", layer: "data-access", confidence: 0.85, signal: "migration suffix" },
|
|
2208
|
-
{ suffix: ".adapter", layer: "infrastructure", confidence: 0.8, signal: "adapter suffix" },
|
|
2209
|
-
{ suffix: ".client", layer: "infrastructure", confidence: 0.75, signal: "client suffix" },
|
|
2210
|
-
{ suffix: ".provider", layer: "infrastructure", confidence: 0.7, signal: "provider suffix" },
|
|
2211
|
-
{ suffix: ".config", layer: "config", confidence: 0.8, signal: "config suffix" },
|
|
2212
|
-
{ suffix: ".component", layer: "presentation", confidence: 0.8, signal: "component suffix" },
|
|
2213
|
-
{ suffix: ".page", layer: "presentation", confidence: 0.85, signal: "page suffix" },
|
|
2214
|
-
{ suffix: ".view", layer: "presentation", confidence: 0.8, signal: "view suffix" },
|
|
2215
|
-
{ suffix: ".layout", layer: "presentation", confidence: 0.85, signal: "layout suffix" },
|
|
2216
|
-
{ suffix: ".util", layer: "shared", confidence: 0.7, signal: "util suffix" },
|
|
2217
|
-
{ suffix: ".helper", layer: "shared", confidence: 0.7, signal: "helper suffix" },
|
|
2218
|
-
{ suffix: ".constant", layer: "shared", confidence: 0.7, signal: "constant suffix" }
|
|
2219
|
-
];
|
|
2220
|
-
var PASCAL_SUFFIX_RULES = [
|
|
2221
|
-
{ suffix: "Controller", layer: "routing", confidence: 0.9, signal: "Controller class" },
|
|
2222
|
-
{ suffix: "Endpoint", layer: "routing", confidence: 0.85, signal: "Endpoint class" },
|
|
2223
|
-
{ suffix: "Middleware", layer: "middleware", confidence: 0.9, signal: "Middleware class" },
|
|
2224
|
-
{ suffix: "Filter", layer: "middleware", confidence: 0.75, signal: "Filter class" },
|
|
2225
|
-
{ suffix: "Service", layer: "services", confidence: 0.85, signal: "Service class" },
|
|
2226
|
-
{ suffix: "Handler", layer: "services", confidence: 0.75, signal: "Handler class" },
|
|
2227
|
-
{ suffix: "UseCase", layer: "services", confidence: 0.85, signal: "UseCase class" },
|
|
2228
|
-
{ suffix: "Entity", layer: "domain", confidence: 0.85, signal: "Entity class" },
|
|
2229
|
-
{ suffix: "Dto", layer: "domain", confidence: 0.8, signal: "DTO class" },
|
|
2230
|
-
{ suffix: "Validator", layer: "domain", confidence: 0.75, signal: "Validator class" },
|
|
2231
|
-
{ suffix: "ViewModel", layer: "presentation", confidence: 0.85, signal: "ViewModel class" },
|
|
2232
|
-
{ suffix: "Repository", layer: "data-access", confidence: 0.9, signal: "Repository class" },
|
|
2233
|
-
{ suffix: "DbContext", layer: "data-access", confidence: 0.95, signal: "EF Core DbContext" },
|
|
2234
|
-
{ suffix: "Migration", layer: "data-access", confidence: 0.85, signal: "Migration class" },
|
|
2235
|
-
{ suffix: "Client", layer: "infrastructure", confidence: 0.7, signal: "Client class" },
|
|
2236
|
-
{ suffix: "Tests", layer: "testing", confidence: 0.95, signal: "Tests class" },
|
|
2237
|
-
{ suffix: "Test", layer: "testing", confidence: 0.9, signal: "Test class" },
|
|
2238
|
-
// JVM (Spring/JEE/Android)
|
|
2239
|
-
{ suffix: "ServiceImpl", layer: "services", confidence: 0.9, signal: "ServiceImpl class" },
|
|
2240
|
-
{ suffix: "Dao", layer: "data-access", confidence: 0.9, signal: "DAO class" },
|
|
2241
|
-
{ suffix: "Mapper", layer: "data-access", confidence: 0.75, signal: "Mapper class" },
|
|
2242
|
-
{ suffix: "Resource", layer: "routing", confidence: 0.75, signal: "JAX-RS resource class" },
|
|
2243
|
-
{ suffix: "Configuration", layer: "config", confidence: 0.85, signal: "Configuration class" },
|
|
2244
|
-
{ suffix: "Config", layer: "config", confidence: 0.8, signal: "Config class" },
|
|
2245
|
-
{ suffix: "Interceptor", layer: "middleware", confidence: 0.85, signal: "Interceptor class" },
|
|
2246
|
-
{ suffix: "Activity", layer: "presentation", confidence: 0.85, signal: "Android Activity" },
|
|
2247
|
-
{ suffix: "Fragment", layer: "presentation", confidence: 0.85, signal: "Android Fragment" },
|
|
2248
|
-
// Swift / iOS — higher confidence than the generic Controller→routing rule
|
|
2249
|
-
// so FooViewController lands in presentation, not routing.
|
|
2250
|
-
{ suffix: "ViewController", layer: "presentation", confidence: 0.95, signal: "UIKit ViewController" },
|
|
2251
|
-
// Flutter
|
|
2252
|
-
{ suffix: "Screen", layer: "presentation", confidence: 0.85, signal: "Screen widget" },
|
|
2253
|
-
{ suffix: "Widget", layer: "presentation", confidence: 0.75, signal: "Widget class" }
|
|
2254
|
-
];
|
|
2255
|
-
var PACKAGE_LAYER_MAP = {
|
|
2256
|
-
// Routing/controllers
|
|
2257
|
-
"express": "routing",
|
|
2258
|
-
"fastify": "routing",
|
|
2259
|
-
"@nestjs/core": "routing",
|
|
2260
|
-
"hono": "routing",
|
|
2261
|
-
"koa": "routing",
|
|
2262
|
-
"koa-router": "routing",
|
|
2263
|
-
"@hapi/hapi": "routing",
|
|
2264
|
-
"h3": "routing",
|
|
2265
|
-
// Middleware
|
|
2266
|
-
"cors": "middleware",
|
|
2267
|
-
"helmet": "middleware",
|
|
2268
|
-
"passport": "middleware",
|
|
2269
|
-
"express-rate-limit": "middleware",
|
|
2270
|
-
"cookie-parser": "middleware",
|
|
2271
|
-
"body-parser": "middleware",
|
|
2272
|
-
"multer": "middleware",
|
|
2273
|
-
"morgan": "middleware",
|
|
2274
|
-
"compression": "middleware",
|
|
2275
|
-
"express-session": "middleware",
|
|
2276
|
-
// Services / application
|
|
2277
|
-
"bullmq": "services",
|
|
2278
|
-
"bull": "services",
|
|
2279
|
-
"agenda": "services",
|
|
2280
|
-
"pg-boss": "services",
|
|
2281
|
-
"inngest": "services",
|
|
2282
|
-
// Domain / validation
|
|
2283
|
-
"zod": "domain",
|
|
2284
|
-
"joi": "domain",
|
|
2285
|
-
"yup": "domain",
|
|
2286
|
-
"class-validator": "domain",
|
|
2287
|
-
"class-transformer": "domain",
|
|
2288
|
-
"superstruct": "domain",
|
|
2289
|
-
"valibot": "domain",
|
|
2290
|
-
// Data access / ORM
|
|
2291
|
-
"prisma": "data-access",
|
|
2292
|
-
"@prisma/client": "data-access",
|
|
2293
|
-
"drizzle-orm": "data-access",
|
|
2294
|
-
"typeorm": "data-access",
|
|
2295
|
-
"sequelize": "data-access",
|
|
2296
|
-
"knex": "data-access",
|
|
2297
|
-
"pg": "data-access",
|
|
2298
|
-
"mysql2": "data-access",
|
|
2299
|
-
"mongodb": "data-access",
|
|
2300
|
-
"mongoose": "data-access",
|
|
2301
|
-
"ioredis": "data-access",
|
|
2302
|
-
"redis": "data-access",
|
|
2303
|
-
"better-sqlite3": "data-access",
|
|
2304
|
-
"kysely": "data-access",
|
|
2305
|
-
"@mikro-orm/core": "data-access",
|
|
2306
|
-
// Infrastructure
|
|
2307
|
-
"@aws-sdk/client-s3": "infrastructure",
|
|
2308
|
-
"@aws-sdk/client-sqs": "infrastructure",
|
|
2309
|
-
"@aws-sdk/client-sns": "infrastructure",
|
|
2310
|
-
"@aws-sdk/client-ses": "infrastructure",
|
|
2311
|
-
"@aws-sdk/client-lambda": "infrastructure",
|
|
2312
|
-
"@google-cloud/storage": "infrastructure",
|
|
2313
|
-
"@azure/storage-blob": "infrastructure",
|
|
2314
|
-
"nodemailer": "infrastructure",
|
|
2315
|
-
"@sendgrid/mail": "infrastructure",
|
|
2316
|
-
"stripe": "infrastructure",
|
|
2317
|
-
"kafkajs": "infrastructure",
|
|
2318
|
-
"amqplib": "infrastructure",
|
|
2319
|
-
// Presentation
|
|
2320
|
-
"react": "presentation",
|
|
2321
|
-
"react-dom": "presentation",
|
|
2322
|
-
"vue": "presentation",
|
|
2323
|
-
"@angular/core": "presentation",
|
|
2324
|
-
"svelte": "presentation",
|
|
2325
|
-
// Shared
|
|
2326
|
-
"lodash": "shared",
|
|
2327
|
-
"dayjs": "shared",
|
|
2328
|
-
"date-fns": "shared",
|
|
2329
|
-
"uuid": "shared",
|
|
2330
|
-
"nanoid": "shared",
|
|
2331
|
-
// Testing
|
|
2332
|
-
"vitest": "testing",
|
|
2333
|
-
"jest": "testing",
|
|
2334
|
-
"mocha": "testing",
|
|
2335
|
-
"@playwright/test": "testing",
|
|
2336
|
-
"cypress": "testing",
|
|
2337
|
-
"supertest": "testing",
|
|
2338
|
-
// Observability → infrastructure
|
|
2339
|
-
"@sentry/node": "infrastructure",
|
|
2340
|
-
"@opentelemetry/api": "infrastructure",
|
|
2341
|
-
"pino": "infrastructure",
|
|
2342
|
-
"winston": "infrastructure",
|
|
2343
|
-
"dd-trace": "infrastructure",
|
|
2344
|
-
// ── .NET (NuGet package ids) ──
|
|
2345
|
-
"Microsoft.EntityFrameworkCore": "data-access",
|
|
2346
|
-
"Dapper": "data-access",
|
|
2347
|
-
"Npgsql": "data-access",
|
|
2348
|
-
"Microsoft.Data.SqlClient": "data-access",
|
|
2349
|
-
"System.Data.SqlClient": "data-access",
|
|
2350
|
-
"MongoDB.Driver": "data-access",
|
|
2351
|
-
"StackExchange.Redis": "data-access",
|
|
2352
|
-
"MediatR": "services",
|
|
2353
|
-
"Hangfire": "services",
|
|
2354
|
-
"Quartz": "services",
|
|
2355
|
-
"FluentValidation": "domain",
|
|
2356
|
-
"AutoMapper": "domain",
|
|
2357
|
-
"Microsoft.AspNetCore.Authentication.JwtBearer": "middleware",
|
|
2358
|
-
"Swashbuckle.AspNetCore": "routing",
|
|
2359
|
-
"Serilog": "infrastructure",
|
|
2360
|
-
"NLog": "infrastructure",
|
|
2361
|
-
"Polly": "infrastructure",
|
|
2362
|
-
"RabbitMQ.Client": "infrastructure",
|
|
2363
|
-
"MassTransit": "infrastructure",
|
|
2364
|
-
"Confluent.Kafka": "infrastructure",
|
|
2365
|
-
"Azure.Storage.Blobs": "infrastructure",
|
|
2366
|
-
"AWSSDK.S3": "infrastructure",
|
|
2367
|
-
"Newtonsoft.Json": "shared",
|
|
2368
|
-
"xunit": "testing",
|
|
2369
|
-
"NUnit": "testing",
|
|
2370
|
-
"MSTest.TestFramework": "testing",
|
|
2371
|
-
"Moq": "testing",
|
|
2372
|
-
"NSubstitute": "testing",
|
|
2373
|
-
"FluentAssertions": "testing",
|
|
2374
|
-
// ── Python (PyPI) ──
|
|
2375
|
-
"django": "routing",
|
|
2376
|
-
"flask": "routing",
|
|
2377
|
-
"fastapi": "routing",
|
|
2378
|
-
"starlette": "routing",
|
|
2379
|
-
"sqlalchemy": "data-access",
|
|
2380
|
-
"alembic": "data-access",
|
|
2381
|
-
"psycopg2": "data-access",
|
|
2382
|
-
"psycopg2-binary": "data-access",
|
|
2383
|
-
"pymongo": "data-access",
|
|
2384
|
-
"pydantic": "domain",
|
|
2385
|
-
"marshmallow": "domain",
|
|
2386
|
-
"celery": "services",
|
|
2387
|
-
"pytest": "testing",
|
|
2388
|
-
"boto3": "infrastructure",
|
|
2389
|
-
"httpx": "infrastructure",
|
|
2390
|
-
"requests": "infrastructure",
|
|
2391
|
-
"gunicorn": "infrastructure",
|
|
2392
|
-
"uvicorn": "infrastructure",
|
|
2393
|
-
"structlog": "infrastructure",
|
|
2394
|
-
// ── JVM (Maven groupId:artifactId, as the Java scanner keys them) ──
|
|
2395
|
-
"org.springframework.boot:spring-boot-starter-web": "routing",
|
|
2396
|
-
"org.springframework:spring-webmvc": "routing",
|
|
2397
|
-
"io.ktor:ktor-server-core": "routing",
|
|
2398
|
-
"io.quarkus:quarkus-resteasy": "routing",
|
|
2399
|
-
"org.springframework.boot:spring-boot-starter-data-jpa": "data-access",
|
|
2400
|
-
"org.hibernate:hibernate-core": "data-access",
|
|
2401
|
-
"org.hibernate.orm:hibernate-core": "data-access",
|
|
2402
|
-
"org.mybatis:mybatis": "data-access",
|
|
2403
|
-
"com.zaxxer:HikariCP": "data-access",
|
|
2404
|
-
"org.jetbrains.exposed:exposed-core": "data-access",
|
|
2405
|
-
"org.springframework.boot:spring-boot-starter-security": "middleware",
|
|
2406
|
-
"jakarta.validation:jakarta.validation-api": "domain",
|
|
2407
|
-
"com.fasterxml.jackson.core:jackson-databind": "shared",
|
|
2408
|
-
"org.projectlombok:lombok": "shared",
|
|
2409
|
-
"junit:junit": "testing",
|
|
2410
|
-
"org.junit.jupiter:junit-jupiter": "testing",
|
|
2411
|
-
"org.mockito:mockito-core": "testing",
|
|
2412
|
-
"org.testng:testng": "testing",
|
|
2413
|
-
"ch.qos.logback:logback-classic": "infrastructure",
|
|
2414
|
-
"org.slf4j:slf4j-api": "infrastructure",
|
|
2415
|
-
"org.apache.kafka:kafka-clients": "infrastructure",
|
|
2416
|
-
"com.squareup.okhttp3:okhttp": "infrastructure",
|
|
2417
|
-
// ── Go (module paths) ──
|
|
2418
|
-
"github.com/gin-gonic/gin": "routing",
|
|
2419
|
-
"github.com/labstack/echo/v4": "routing",
|
|
2420
|
-
"github.com/gorilla/mux": "routing",
|
|
2421
|
-
"github.com/go-chi/chi/v5": "routing",
|
|
2422
|
-
"github.com/gofiber/fiber/v2": "routing",
|
|
2423
|
-
"github.com/spf13/cobra": "routing",
|
|
2424
|
-
"gorm.io/gorm": "data-access",
|
|
2425
|
-
"github.com/jmoiron/sqlx": "data-access",
|
|
2426
|
-
"github.com/jackc/pgx/v5": "data-access",
|
|
2427
|
-
"go.mongodb.org/mongo-driver": "data-access",
|
|
2428
|
-
"github.com/redis/go-redis/v9": "data-access",
|
|
2429
|
-
"github.com/spf13/viper": "config",
|
|
2430
|
-
"github.com/stretchr/testify": "testing",
|
|
2431
|
-
"go.uber.org/zap": "infrastructure",
|
|
2432
|
-
"github.com/sirupsen/logrus": "infrastructure",
|
|
2433
|
-
"google.golang.org/grpc": "infrastructure",
|
|
2434
|
-
// ── Rust (crates) ──
|
|
2435
|
-
"actix-web": "routing",
|
|
2436
|
-
"axum": "routing",
|
|
2437
|
-
"rocket": "routing",
|
|
2438
|
-
"warp": "routing",
|
|
2439
|
-
"clap": "routing",
|
|
2440
|
-
"diesel": "data-access",
|
|
2441
|
-
"sqlx": "data-access",
|
|
2442
|
-
"sea-orm": "data-access",
|
|
2443
|
-
"serde": "domain",
|
|
2444
|
-
"tokio": "infrastructure",
|
|
2445
|
-
"reqwest": "infrastructure",
|
|
2446
|
-
"tracing": "infrastructure",
|
|
2447
|
-
// ── Ruby (gems) ──
|
|
2448
|
-
"rails": "routing",
|
|
2449
|
-
"sinatra": "routing",
|
|
2450
|
-
"activerecord": "data-access",
|
|
2451
|
-
"sequel": "data-access",
|
|
2452
|
-
"devise": "middleware",
|
|
2453
|
-
"pundit": "middleware",
|
|
2454
|
-
"sidekiq": "services",
|
|
2455
|
-
"rspec": "testing",
|
|
2456
|
-
"rspec-rails": "testing",
|
|
2457
|
-
"minitest": "testing",
|
|
2458
|
-
"puma": "infrastructure",
|
|
2459
|
-
"faraday": "infrastructure",
|
|
2460
|
-
// ── PHP (Composer vendor/package) ──
|
|
2461
|
-
"laravel/framework": "routing",
|
|
2462
|
-
"symfony/http-kernel": "routing",
|
|
2463
|
-
"slim/slim": "routing",
|
|
2464
|
-
"doctrine/orm": "data-access",
|
|
2465
|
-
"illuminate/database": "data-access",
|
|
2466
|
-
"phpunit/phpunit": "testing",
|
|
2467
|
-
"pestphp/pest": "testing",
|
|
2468
|
-
"guzzlehttp/guzzle": "infrastructure",
|
|
2469
|
-
"monolog/monolog": "infrastructure",
|
|
2470
|
-
// ── Swift (SPM) ──
|
|
2471
|
-
"Alamofire": "infrastructure",
|
|
2472
|
-
"vapor": "routing",
|
|
2473
|
-
"Vapor": "routing",
|
|
2474
|
-
// ── Dart (pub) ──
|
|
2475
|
-
"dio": "infrastructure",
|
|
2476
|
-
"sqflite": "data-access",
|
|
2477
|
-
"flutter_bloc": "services",
|
|
2478
|
-
"riverpod": "services",
|
|
2479
|
-
"flutter_riverpod": "services",
|
|
2480
|
-
"go_router": "routing",
|
|
2481
|
-
"auto_route": "routing",
|
|
2482
|
-
"flutter_test": "testing",
|
|
2483
|
-
"mockito": "testing",
|
|
2484
|
-
// ── Elixir (Hex) ──
|
|
2485
|
-
"phoenix": "routing",
|
|
2486
|
-
"phoenix_live_view": "presentation",
|
|
2487
|
-
"ecto": "data-access",
|
|
2488
|
-
"ecto_sql": "data-access",
|
|
2489
|
-
"postgrex": "data-access",
|
|
2490
|
-
"oban": "services",
|
|
2491
|
-
"ex_machina": "testing",
|
|
2492
|
-
"tesla": "infrastructure",
|
|
2493
|
-
"httpoison": "infrastructure",
|
|
2494
|
-
"finch": "infrastructure",
|
|
2495
|
-
"jason": "shared"
|
|
2496
|
-
};
|
|
2497
|
-
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2498
|
-
".ts",
|
|
2499
|
-
".tsx",
|
|
2500
|
-
".js",
|
|
2501
|
-
".jsx",
|
|
2502
|
-
".mts",
|
|
2503
|
-
".mjs",
|
|
2504
|
-
".cts",
|
|
2505
|
-
".cjs",
|
|
2506
|
-
".svelte",
|
|
2507
|
-
".vue",
|
|
2508
|
-
// .NET — layer detection works off the same directory/suffix conventions
|
|
2509
|
-
".cs",
|
|
2510
|
-
".vb",
|
|
2511
|
-
".fs",
|
|
2512
|
-
".cshtml",
|
|
2513
|
-
".razor",
|
|
2514
|
-
// JVM
|
|
2515
|
-
".java",
|
|
2516
|
-
".kt",
|
|
2517
|
-
".kts",
|
|
2518
|
-
".scala",
|
|
2519
|
-
".groovy",
|
|
2520
|
-
// Python
|
|
2521
|
-
".py",
|
|
2522
|
-
".pyi",
|
|
2523
|
-
// Go / Rust
|
|
2524
|
-
".go",
|
|
2525
|
-
".rs",
|
|
2526
|
-
// Ruby (incl. ERB view templates)
|
|
2527
|
-
".rb",
|
|
2528
|
-
".rake",
|
|
2529
|
-
".erb",
|
|
2530
|
-
// PHP (incl. Blade — extname is still .php)
|
|
2531
|
-
".php",
|
|
2532
|
-
// Swift / Dart
|
|
2533
|
-
".swift",
|
|
2534
|
-
".dart",
|
|
2535
|
-
// Elixir (incl. EEx/HEEx view templates)
|
|
2536
|
-
".ex",
|
|
2537
|
-
".exs",
|
|
2538
|
-
".eex",
|
|
2539
|
-
".heex"
|
|
2540
|
-
]);
|
|
2541
|
-
async function walkSourceFiles(rootDir, cache) {
|
|
2542
|
-
if (cache) {
|
|
2543
|
-
const entries = await cache.walkDir(rootDir);
|
|
2544
|
-
return entries.filter((e) => {
|
|
2545
|
-
if (!e.isFile) return false;
|
|
2546
|
-
const name = path3.basename(e.absPath);
|
|
2547
|
-
if (name.startsWith(".") && name !== ".") return false;
|
|
2548
|
-
const ext = path3.extname(name);
|
|
2549
|
-
return SOURCE_EXTENSIONS.has(ext);
|
|
2550
|
-
}).map((e) => e.relPath);
|
|
2551
|
-
}
|
|
2552
|
-
const files = [];
|
|
2553
|
-
async function walk(dir) {
|
|
2554
|
-
let entries;
|
|
2555
|
-
try {
|
|
2556
|
-
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2557
|
-
} catch {
|
|
2558
|
-
return;
|
|
2559
|
-
}
|
|
2560
|
-
for (const entry of entries) {
|
|
2561
|
-
if (entry.name.startsWith(".") && entry.name !== ".") continue;
|
|
2562
|
-
const fullPath = path3.join(dir, entry.name);
|
|
2563
|
-
if (entry.isDirectory()) {
|
|
2564
|
-
if (!isSkippedDirName(entry.name)) {
|
|
2565
|
-
await walk(fullPath);
|
|
2566
|
-
}
|
|
2567
|
-
} else if (entry.isFile()) {
|
|
2568
|
-
const ext = path3.extname(entry.name);
|
|
2569
|
-
if (SOURCE_EXTENSIONS.has(ext)) {
|
|
2570
|
-
files.push(path3.relative(rootDir, fullPath));
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
await walk(rootDir);
|
|
2576
|
-
return files;
|
|
2577
|
-
}
|
|
2578
|
-
function classifyFile(filePath, archetype) {
|
|
2579
|
-
const normalised = "/" + filePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2580
|
-
const lowered = normalised.toLowerCase();
|
|
2581
|
-
let bestMatch = null;
|
|
2582
|
-
for (const rule of PATH_RULES) {
|
|
2583
|
-
if (rule.archetypes && rule.archetypes.length > 0 && !rule.archetypes.includes(archetype)) {
|
|
2584
|
-
continue;
|
|
2585
|
-
}
|
|
2586
|
-
if (rule.pattern.test(lowered)) {
|
|
2587
|
-
const boost = rule.archetypes ? 0.05 : 0;
|
|
2588
|
-
const adjustedConfidence = Math.min(rule.confidence + boost, 1);
|
|
2589
|
-
if (!bestMatch || adjustedConfidence > bestMatch.confidence) {
|
|
2590
|
-
bestMatch = { layer: rule.layer, confidence: adjustedConfidence, signal: rule.signal };
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
if (!bestMatch || bestMatch.confidence < 0.7) {
|
|
2595
|
-
const baseName = path3.basename(filePath, path3.extname(filePath));
|
|
2596
|
-
const cleanBase = baseName.replace(/\.(test|spec)$/, "");
|
|
2597
|
-
for (const rule of SUFFIX_RULES) {
|
|
2598
|
-
if (cleanBase.endsWith(rule.suffix)) {
|
|
2599
|
-
if (!bestMatch || rule.confidence > bestMatch.confidence) {
|
|
2600
|
-
bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
for (const rule of PASCAL_SUFFIX_RULES) {
|
|
2605
|
-
if (cleanBase.endsWith(rule.suffix)) {
|
|
2606
|
-
if (!bestMatch || rule.confidence > bestMatch.confidence) {
|
|
2607
|
-
bestMatch = { layer: rule.layer, confidence: rule.confidence, signal: rule.signal };
|
|
2608
|
-
}
|
|
2609
|
-
}
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
if (bestMatch) {
|
|
2613
|
-
return {
|
|
2614
|
-
filePath,
|
|
2615
|
-
layer: bestMatch.layer,
|
|
2616
|
-
confidence: bestMatch.confidence,
|
|
2617
|
-
signals: [bestMatch.signal]
|
|
2618
|
-
};
|
|
2619
|
-
}
|
|
2620
|
-
return null;
|
|
2621
|
-
}
|
|
2622
|
-
function computeLayerDrift(packages) {
|
|
2623
|
-
if (packages.length === 0) {
|
|
2624
|
-
return { score: 0, riskLevel: "none" };
|
|
2625
|
-
}
|
|
2626
|
-
let current = 0;
|
|
2627
|
-
let oneBehind = 0;
|
|
2628
|
-
let twoPlusBehind = 0;
|
|
2629
|
-
for (const pkg of packages) {
|
|
2630
|
-
if (pkg.majorsBehind === null) ; else if (pkg.majorsBehind === 0) {
|
|
2631
|
-
current++;
|
|
2632
|
-
} else if (pkg.majorsBehind === 1) {
|
|
2633
|
-
oneBehind++;
|
|
2634
|
-
} else {
|
|
2635
|
-
twoPlusBehind++;
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
const known = current + oneBehind + twoPlusBehind;
|
|
2639
|
-
if (known === 0) return { score: 0, riskLevel: "none" };
|
|
2640
|
-
const currentPct = current / known;
|
|
2641
|
-
const onePct = oneBehind / known;
|
|
2642
|
-
const twoPct = twoPlusBehind / known;
|
|
2643
|
-
const health = Math.round(Math.max(0, Math.min(100, currentPct * 100 - onePct * 10 - twoPct * 40)));
|
|
2644
|
-
const score = 100 - health;
|
|
2645
|
-
const riskLevel = score <= 30 ? "low" : score <= 60 ? "moderate" : "high";
|
|
2646
|
-
return { score, riskLevel };
|
|
2647
|
-
}
|
|
2648
|
-
function mapToolingToLayers(tooling, services, depsByLayer) {
|
|
2649
|
-
const layerTooling = /* @__PURE__ */ new Map();
|
|
2650
|
-
const layerServices = /* @__PURE__ */ new Map();
|
|
2651
|
-
const pkgLayerLookup = /* @__PURE__ */ new Map();
|
|
2652
|
-
for (const [layer, packages] of depsByLayer) {
|
|
2653
|
-
for (const pkg of packages) {
|
|
2654
|
-
pkgLayerLookup.set(pkg, layer);
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
if (tooling) {
|
|
2658
|
-
for (const [, items] of Object.entries(tooling)) {
|
|
2659
|
-
for (const item of items) {
|
|
2660
|
-
const layer = pkgLayerLookup.get(item.package) ?? PACKAGE_LAYER_MAP[item.package] ?? "shared";
|
|
2661
|
-
if (!layerTooling.has(layer)) layerTooling.set(layer, []);
|
|
2662
|
-
const existing = layerTooling.get(layer);
|
|
2663
|
-
if (!existing.some((t) => t.package === item.package)) {
|
|
2664
|
-
existing.push(item);
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
}
|
|
2668
|
-
}
|
|
2669
|
-
if (services) {
|
|
2670
|
-
for (const [, items] of Object.entries(services)) {
|
|
2671
|
-
for (const item of items) {
|
|
2672
|
-
const layer = pkgLayerLookup.get(item.package) ?? PACKAGE_LAYER_MAP[item.package] ?? "infrastructure";
|
|
2673
|
-
if (!layerServices.has(layer)) layerServices.set(layer, []);
|
|
2674
|
-
const existing = layerServices.get(layer);
|
|
2675
|
-
if (!existing.some((s) => s.package === item.package)) {
|
|
2676
|
-
existing.push(item);
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
return { layerTooling, layerServices };
|
|
2682
|
-
}
|
|
2683
|
-
function generateLayerFlowMermaid(layers) {
|
|
2684
|
-
const labels = {
|
|
2685
|
-
presentation: "Presentation",
|
|
2686
|
-
routing: "Routing",
|
|
2687
|
-
middleware: "Middleware",
|
|
2688
|
-
services: "Services",
|
|
2689
|
-
domain: "Domain",
|
|
2690
|
-
"data-access": "Data Access",
|
|
2691
|
-
infrastructure: "Infrastructure",
|
|
2692
|
-
config: "Config",
|
|
2693
|
-
shared: "Shared",
|
|
2694
|
-
testing: "Testing"
|
|
2695
|
-
};
|
|
2696
|
-
if (layers.length === 0) {
|
|
2697
|
-
return 'flowchart TD\n APP["Project"]';
|
|
2698
|
-
}
|
|
2699
|
-
const ordered = [...layers];
|
|
2700
|
-
const lines = ["flowchart TD"];
|
|
2701
|
-
for (let i = 0; i < ordered.length; i++) {
|
|
2702
|
-
const layer = ordered[i];
|
|
2703
|
-
lines.push(` L${i}["${labels[layer]}"]`);
|
|
2704
|
-
if (i > 0) lines.push(` L${i - 1} --> L${i}`);
|
|
2705
|
-
}
|
|
2706
|
-
return lines.join("\n");
|
|
2707
|
-
}
|
|
2708
|
-
async function buildProjectArchitectureMermaid(rootDir, project, archetype, cache) {
|
|
2709
|
-
const projectRoot = path3.resolve(rootDir, project.path || ".");
|
|
2710
|
-
const allFiles = await walkSourceFiles(projectRoot, cache);
|
|
2711
|
-
const layerSet = /* @__PURE__ */ new Set();
|
|
2712
|
-
for (const rel of allFiles) {
|
|
2713
|
-
const classification = classifyFile(rel, archetype);
|
|
2714
|
-
if (classification) {
|
|
2715
|
-
layerSet.add(classification.layer);
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
const layerOrder = [
|
|
2719
|
-
"presentation",
|
|
2720
|
-
"routing",
|
|
2721
|
-
"middleware",
|
|
2722
|
-
"services",
|
|
2723
|
-
"domain",
|
|
2724
|
-
"data-access",
|
|
2725
|
-
"infrastructure",
|
|
2726
|
-
"config",
|
|
2727
|
-
"shared",
|
|
2728
|
-
"testing"
|
|
2729
|
-
];
|
|
2730
|
-
const orderedLayers = layerOrder.filter((l) => layerSet.has(l));
|
|
2731
|
-
return generateLayerFlowMermaid(orderedLayers);
|
|
2732
|
-
}
|
|
2733
|
-
async function scanProjectArchitecture(rootDir, project, cache) {
|
|
2734
|
-
const projectRoot = path3.resolve(rootDir, project.path || ".");
|
|
2735
|
-
return scanArchitecture(projectRoot, [project], void 0, void 0, cache);
|
|
2736
|
-
}
|
|
2737
|
-
function aggregateSolutionArchitecture(projectResults) {
|
|
2738
|
-
if (projectResults.length === 0) {
|
|
2739
|
-
return { archetype: "unknown", archetypeConfidence: 0, layers: [], totalClassified: 0, unclassified: 0 };
|
|
2740
|
-
}
|
|
2741
|
-
if (projectResults.length === 1) {
|
|
2742
|
-
return projectResults[0];
|
|
2743
|
-
}
|
|
2744
|
-
let bestArchetype = "unknown";
|
|
2745
|
-
let bestConfidence = 0;
|
|
2746
|
-
for (const r of projectResults) {
|
|
2747
|
-
if (r.archetypeConfidence > bestConfidence || r.archetypeConfidence === bestConfidence && r.archetype !== "monorepo") {
|
|
2748
|
-
bestArchetype = r.archetype;
|
|
2749
|
-
bestConfidence = r.archetypeConfidence;
|
|
2750
|
-
}
|
|
2751
|
-
}
|
|
2752
|
-
const layerMap = /* @__PURE__ */ new Map();
|
|
2753
|
-
for (const r of projectResults) {
|
|
2754
|
-
for (const ls of r.layers) {
|
|
2755
|
-
const existing = layerMap.get(ls.layer);
|
|
2756
|
-
if (!existing) {
|
|
2757
|
-
layerMap.set(ls.layer, { ...ls, packages: [...ls.packages], techStack: [...ls.techStack], services: [...ls.services], files: [...ls.files] });
|
|
2758
|
-
} else {
|
|
2759
|
-
existing.fileCount += ls.fileCount;
|
|
2760
|
-
const pkgNames = new Set(existing.packages.map((p) => p.name));
|
|
2761
|
-
for (const pkg of ls.packages) {
|
|
2762
|
-
if (!pkgNames.has(pkg.name)) {
|
|
2763
|
-
existing.packages.push(pkg);
|
|
2764
|
-
pkgNames.add(pkg.name);
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
const techPkgs = new Set(existing.techStack.map((t) => t.package));
|
|
2768
|
-
for (const t of ls.techStack) {
|
|
2769
|
-
if (!techPkgs.has(t.package)) {
|
|
2770
|
-
existing.techStack.push(t);
|
|
2771
|
-
techPkgs.add(t.package);
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
const svcPkgs = new Set(existing.services.map((s) => s.package));
|
|
2775
|
-
for (const s of ls.services) {
|
|
2776
|
-
if (!svcPkgs.has(s.package)) {
|
|
2777
|
-
existing.services.push(s);
|
|
2778
|
-
svcPkgs.add(s.package);
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
const seenFiles = new Set(existing.files);
|
|
2782
|
-
for (const f of ls.files) {
|
|
2783
|
-
if (existing.files.length >= 40) break;
|
|
2784
|
-
if (!seenFiles.has(f)) {
|
|
2785
|
-
existing.files.push(f);
|
|
2786
|
-
seenFiles.add(f);
|
|
2787
|
-
}
|
|
2788
|
-
}
|
|
2789
|
-
const { score, riskLevel } = computeLayerDrift(existing.packages);
|
|
2790
|
-
existing.driftScore = score;
|
|
2791
|
-
existing.riskLevel = riskLevel;
|
|
2792
|
-
}
|
|
2793
|
-
}
|
|
2794
|
-
}
|
|
2795
|
-
const LAYER_ORDER = {
|
|
2796
|
-
"presentation": 0,
|
|
2797
|
-
"routing": 1,
|
|
2798
|
-
"middleware": 2,
|
|
2799
|
-
"services": 3,
|
|
2800
|
-
"domain": 4,
|
|
2801
|
-
"data-access": 5,
|
|
2802
|
-
"infrastructure": 6,
|
|
2803
|
-
"config": 7,
|
|
2804
|
-
"shared": 8,
|
|
2805
|
-
"testing": 9
|
|
2806
|
-
};
|
|
2807
|
-
const layers = [...layerMap.values()].sort((a, b) => (LAYER_ORDER[a.layer] ?? 99) - (LAYER_ORDER[b.layer] ?? 99));
|
|
2808
|
-
const totalClassified = projectResults.reduce((s, r) => s + r.totalClassified, 0);
|
|
2809
|
-
const unclassified = projectResults.reduce((s, r) => s + r.unclassified, 0);
|
|
2810
|
-
return { archetype: bestArchetype, archetypeConfidence: bestConfidence, layers, totalClassified, unclassified };
|
|
2811
|
-
}
|
|
2812
|
-
async function scanArchitecture(rootDir, projects, tooling, services, cache) {
|
|
2813
|
-
const { archetype, confidence: archetypeConfidence } = detectArchetype(projects);
|
|
2814
|
-
const sourceFiles = await walkSourceFiles(rootDir, cache);
|
|
2815
|
-
const classifications = [];
|
|
2816
|
-
let unclassified = 0;
|
|
2817
|
-
for (const file of sourceFiles) {
|
|
2818
|
-
const classification = classifyFile(file, archetype);
|
|
2819
|
-
if (classification) {
|
|
2820
|
-
classifications.push(classification);
|
|
2821
|
-
} else {
|
|
2822
|
-
unclassified++;
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
const allDeps = /* @__PURE__ */ new Map();
|
|
2826
|
-
for (const p of projects) {
|
|
2827
|
-
for (const d of p.dependencies) {
|
|
2828
|
-
if (!allDeps.has(d.package)) {
|
|
2829
|
-
allDeps.set(d.package, d);
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
}
|
|
2833
|
-
const depsByLayer = /* @__PURE__ */ new Map();
|
|
2834
|
-
for (const [pkg] of allDeps) {
|
|
2835
|
-
const layer = PACKAGE_LAYER_MAP[pkg];
|
|
2836
|
-
if (layer) {
|
|
2837
|
-
if (!depsByLayer.has(layer)) depsByLayer.set(layer, /* @__PURE__ */ new Set());
|
|
2838
|
-
depsByLayer.get(layer).add(pkg);
|
|
2839
|
-
}
|
|
2840
|
-
}
|
|
2841
|
-
const { layerTooling, layerServices } = mapToolingToLayers(tooling, services, depsByLayer);
|
|
2842
|
-
const ALL_LAYERS = [
|
|
2843
|
-
"routing",
|
|
2844
|
-
"middleware",
|
|
2845
|
-
"services",
|
|
2846
|
-
"domain",
|
|
2847
|
-
"data-access",
|
|
2848
|
-
"infrastructure",
|
|
2849
|
-
"presentation",
|
|
2850
|
-
"config",
|
|
2851
|
-
"testing",
|
|
2852
|
-
"shared"
|
|
2853
|
-
];
|
|
2854
|
-
const LAYER_FILES_CAP = 40;
|
|
2855
|
-
const layerFileCounts = /* @__PURE__ */ new Map();
|
|
2856
|
-
const layerFiles = /* @__PURE__ */ new Map();
|
|
2857
|
-
for (const c of classifications) {
|
|
2858
|
-
layerFileCounts.set(c.layer, (layerFileCounts.get(c.layer) ?? 0) + 1);
|
|
2859
|
-
const existing = layerFiles.get(c.layer);
|
|
2860
|
-
if (existing) {
|
|
2861
|
-
if (existing.length < LAYER_FILES_CAP) existing.push(c.filePath);
|
|
2862
|
-
} else {
|
|
2863
|
-
layerFiles.set(c.layer, [c.filePath]);
|
|
2864
|
-
}
|
|
2865
|
-
}
|
|
2866
|
-
const layers = [];
|
|
2867
|
-
for (const layer of ALL_LAYERS) {
|
|
2868
|
-
const fileCount = layerFileCounts.get(layer) ?? 0;
|
|
2869
|
-
const layerPkgs = depsByLayer.get(layer) ?? /* @__PURE__ */ new Set();
|
|
2870
|
-
const tech = layerTooling.get(layer) ?? [];
|
|
2871
|
-
const svc = layerServices.get(layer) ?? [];
|
|
2872
|
-
if (fileCount === 0 && layerPkgs.size === 0 && tech.length === 0 && svc.length === 0) {
|
|
2873
|
-
continue;
|
|
2874
|
-
}
|
|
2875
|
-
const packages = [];
|
|
2876
|
-
for (const pkg of layerPkgs) {
|
|
2877
|
-
const dep = allDeps.get(pkg);
|
|
2878
|
-
if (dep) {
|
|
2879
|
-
packages.push({
|
|
2880
|
-
name: dep.package,
|
|
2881
|
-
version: dep.resolvedVersion,
|
|
2882
|
-
latestStable: dep.latestStable,
|
|
2883
|
-
majorsBehind: dep.majorsBehind,
|
|
2884
|
-
drift: dep.drift
|
|
2885
|
-
});
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
const { score, riskLevel } = computeLayerDrift(packages);
|
|
2889
|
-
layers.push({
|
|
2890
|
-
layer,
|
|
2891
|
-
fileCount,
|
|
2892
|
-
driftScore: score,
|
|
2893
|
-
riskLevel,
|
|
2894
|
-
techStack: tech,
|
|
2895
|
-
services: svc,
|
|
2896
|
-
packages,
|
|
2897
|
-
files: layerFiles.get(layer) ?? []
|
|
2898
|
-
});
|
|
2899
|
-
}
|
|
2900
|
-
const LAYER_ORDER = {
|
|
2901
|
-
"presentation": 0,
|
|
2902
|
-
"routing": 1,
|
|
2903
|
-
"middleware": 2,
|
|
2904
|
-
"services": 3,
|
|
2905
|
-
"domain": 4,
|
|
2906
|
-
"data-access": 5,
|
|
2907
|
-
"infrastructure": 6,
|
|
2908
|
-
"config": 7,
|
|
2909
|
-
"shared": 8,
|
|
2910
|
-
"testing": 9
|
|
2911
|
-
};
|
|
2912
|
-
layers.sort((a, b) => (LAYER_ORDER[a.layer] ?? 99) - (LAYER_ORDER[b.layer] ?? 99));
|
|
2913
|
-
return {
|
|
2914
|
-
archetype,
|
|
2915
|
-
archetypeConfidence,
|
|
2916
|
-
layers,
|
|
2917
|
-
totalClassified: classifications.length,
|
|
2918
|
-
unclassified
|
|
2919
|
-
};
|
|
2920
|
-
}
|
|
2921
1966
|
var ts;
|
|
2922
1967
|
var tsLoading = null;
|
|
2923
1968
|
async function ensureTypeScript() {
|
|
@@ -2928,7 +1973,7 @@ async function ensureTypeScript() {
|
|
|
2928
1973
|
});
|
|
2929
1974
|
await tsLoading;
|
|
2930
1975
|
}
|
|
2931
|
-
var
|
|
1976
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
2932
1977
|
var DEFAULT_RESULT = {
|
|
2933
1978
|
filesAnalyzed: 0,
|
|
2934
1979
|
functionsAnalyzed: 0,
|
|
@@ -2994,9 +2039,9 @@ async function scanCodeQuality(rootDir, cache) {
|
|
|
2994
2039
|
async function findSourceFiles(rootDir, cache) {
|
|
2995
2040
|
if (cache) {
|
|
2996
2041
|
const entries = await cache.walkDir(rootDir);
|
|
2997
|
-
return entries.filter((entry) => entry.isFile &&
|
|
2042
|
+
return entries.filter((entry) => entry.isFile && SOURCE_EXTENSIONS.has(path3.extname(entry.name).toLowerCase())).map((entry) => entry.absPath);
|
|
2998
2043
|
}
|
|
2999
|
-
const files = await findFiles(rootDir, (name) =>
|
|
2044
|
+
const files = await findFiles(rootDir, (name) => SOURCE_EXTENSIONS.has(path3.extname(name).toLowerCase()));
|
|
3000
2045
|
return files;
|
|
3001
2046
|
}
|
|
3002
2047
|
function collectLocalImports(source, fileDir, rootDir) {
|
|
@@ -4272,6 +3317,11 @@ function archetypeCategory(archetype) {
|
|
|
4272
3317
|
case "hono":
|
|
4273
3318
|
case "koa":
|
|
4274
3319
|
case "serverless":
|
|
3320
|
+
case "spring":
|
|
3321
|
+
case "aspnet":
|
|
3322
|
+
case "django":
|
|
3323
|
+
case "fastapi":
|
|
3324
|
+
case "go-service":
|
|
4275
3325
|
return { category: "api", signal: `archetype:${archetype}` };
|
|
4276
3326
|
case "library":
|
|
4277
3327
|
return { category: "library", signal: "archetype:library" };
|
|
@@ -4281,6 +3331,41 @@ function archetypeCategory(archetype) {
|
|
|
4281
3331
|
return null;
|
|
4282
3332
|
}
|
|
4283
3333
|
}
|
|
3334
|
+
function projectKindCategory(kind) {
|
|
3335
|
+
switch (kind) {
|
|
3336
|
+
case "web-app":
|
|
3337
|
+
return { category: "web-app", signal: "projectKind:web-app" };
|
|
3338
|
+
case "web-api":
|
|
3339
|
+
return { category: "api", signal: "projectKind:web-api" };
|
|
3340
|
+
case "library":
|
|
3341
|
+
return { category: "library", signal: "projectKind:library" };
|
|
3342
|
+
case "cli":
|
|
3343
|
+
return { category: "cli", signal: "projectKind:cli" };
|
|
3344
|
+
case "iac":
|
|
3345
|
+
return { category: "infra", signal: "projectKind:iac" };
|
|
3346
|
+
case "database":
|
|
3347
|
+
return { category: "data", signal: "projectKind:database" };
|
|
3348
|
+
case "worker":
|
|
3349
|
+
return { category: "api", signal: "projectKind:worker" };
|
|
3350
|
+
default:
|
|
3351
|
+
return null;
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
var API_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
3355
|
+
"express",
|
|
3356
|
+
"nestjs",
|
|
3357
|
+
"fastify",
|
|
3358
|
+
"hono",
|
|
3359
|
+
"koa",
|
|
3360
|
+
"spring",
|
|
3361
|
+
"aspnet",
|
|
3362
|
+
"django",
|
|
3363
|
+
"fastapi",
|
|
3364
|
+
"laravel",
|
|
3365
|
+
"phoenix",
|
|
3366
|
+
"rails"
|
|
3367
|
+
]);
|
|
3368
|
+
var WEB_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs", "remix", "sveltekit", "nuxt"]);
|
|
4284
3369
|
function inferProjectPurpose(project, uiPurpose) {
|
|
4285
3370
|
const signals = [];
|
|
4286
3371
|
const votes = {};
|
|
@@ -4288,9 +3373,19 @@ function inferProjectPurpose(project, uiPurpose) {
|
|
|
4288
3373
|
votes[category] = (votes[category] ?? 0) + weight;
|
|
4289
3374
|
signals.push(signal);
|
|
4290
3375
|
};
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
3376
|
+
const pk = projectKindCategory(project.architecture?.projectKind);
|
|
3377
|
+
if (pk) vote(pk.category, 3, pk.signal);
|
|
3378
|
+
const fwHits = (project.architecture?.evidence ?? []).filter((e) => e.dimension === "framework").map((e) => e.value.toLowerCase());
|
|
3379
|
+
for (const fw of fwHits) {
|
|
3380
|
+
if (WEB_FRAMEWORKS.has(fw)) vote("web-app", 2, `framework:${fw}`);
|
|
3381
|
+
if (API_FRAMEWORKS.has(fw)) vote("api", 2, `framework:${fw}`);
|
|
3382
|
+
}
|
|
3383
|
+
const arch = archetypeCategory(project.architecture?.archetype);
|
|
3384
|
+
if (arch) {
|
|
3385
|
+
const nonJsArchetype = ["spring", "aspnet", "django", "fastapi", "go-service"].includes(project.architecture?.archetype ?? "");
|
|
3386
|
+
if (project.type === "node" || project.type === "typescript" || nonJsArchetype) {
|
|
3387
|
+
vote(arch.category, 3, arch.signal);
|
|
3388
|
+
}
|
|
4294
3389
|
}
|
|
4295
3390
|
const fwNames = (project.frameworks ?? []).map((f) => f.name.toLowerCase());
|
|
4296
3391
|
const uiFw = (uiPurpose?.detectedFrameworks ?? []).map((f) => f.toLowerCase());
|
|
@@ -4592,29 +3687,27 @@ async function runAdvancedAnalysis(ctx) {
|
|
|
4592
3687
|
}
|
|
4593
3688
|
if (scannerPolicy.architecture && scanners?.architecture?.enabled !== false) {
|
|
4594
3689
|
progress.startStep("architecture");
|
|
4595
|
-
|
|
3690
|
+
const { workspace, projectResults } = await scanArchitectureBundle(
|
|
4596
3691
|
rootDir,
|
|
4597
3692
|
allProjects,
|
|
4598
3693
|
extended.toolingInventory,
|
|
4599
3694
|
extended.serviceDependencies,
|
|
4600
3695
|
fileCache
|
|
4601
3696
|
);
|
|
3697
|
+
extended.architecture = workspace;
|
|
4602
3698
|
const arch = extended.architecture;
|
|
4603
3699
|
const layerCount = arch.layers.filter((l) => l.fileCount > 0).length;
|
|
4604
|
-
|
|
4605
|
-
project
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
);
|
|
4611
|
-
project.architecture = await scanProjectArchitecture(rootDir, project, fileCache);
|
|
4612
|
-
}));
|
|
3700
|
+
for (let i = 0; i < allProjects.length; i++) {
|
|
3701
|
+
const project = allProjects[i];
|
|
3702
|
+
const projectArch = projectResults[i];
|
|
3703
|
+
project.architecture = projectArch;
|
|
3704
|
+
project.architectureMermaid = mermaidFromArchitecture(projectArch);
|
|
3705
|
+
}
|
|
4613
3706
|
for (const solution of solutions) {
|
|
4614
3707
|
const memberProjects = solution.projectPaths.map((pp) => projectsByPath.get(pp) ?? projectsByPath.get(path3.dirname(pp).replace(/\\/g, "/"))).filter((p) => Boolean(p));
|
|
4615
3708
|
const memberArchResults = memberProjects.map((p) => p.architecture).filter((a) => Boolean(a));
|
|
4616
3709
|
if (memberArchResults.length > 0) {
|
|
4617
|
-
solution.architecture = aggregateSolutionArchitecture(memberArchResults);
|
|
3710
|
+
solution.architecture = aggregateSolutionArchitecture(memberArchResults, memberProjects);
|
|
4618
3711
|
}
|
|
4619
3712
|
}
|
|
4620
3713
|
progress.completeStep(
|
|
@@ -4664,5 +3757,5 @@ var baselineCommand = new Command("baseline").description("Create a drift baseli
|
|
|
4664
3757
|
});
|
|
4665
3758
|
|
|
4666
3759
|
export { baselineCommand, loadAdvancedScanHook, runBaseline };
|
|
4667
|
-
//# sourceMappingURL=chunk-
|
|
4668
|
-
//# sourceMappingURL=chunk-
|
|
3760
|
+
//# sourceMappingURL=chunk-6K3XK7C5.js.map
|
|
3761
|
+
//# sourceMappingURL=chunk-6K3XK7C5.js.map
|