@vibgrate/cli 2026.817.1 → 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-CUYQKC6S.js.map → agent-UQC7QN77.js.map} +1 -1
- package/dist/{approvals-IPMUDEDV.js → approvals-ASPJQUZK.js} +6 -5
- package/dist/{approvals-IPMUDEDV.js.map → approvals-ASPJQUZK.js.map} +1 -1
- package/dist/baseline-FIV6PR2M.js +9 -0
- package/dist/{baseline-NZFGLMER.js.map → baseline-FIV6PR2M.js.map} +1 -1
- package/dist/{chunk-4W5SYK2M.js → chunk-2FEB5KJS.js} +3 -3
- package/dist/{chunk-4W5SYK2M.js.map → chunk-2FEB5KJS.js.map} +1 -1
- package/dist/{chunk-MIYXVY57.js → chunk-3FMRFECC.js} +4 -4
- package/dist/{chunk-MIYXVY57.js.map → chunk-3FMRFECC.js.map} +1 -1
- package/dist/{chunk-NQUWC2IA.js → chunk-3H3SVJUY.js} +4 -4
- package/dist/{chunk-NQUWC2IA.js.map → chunk-3H3SVJUY.js.map} +1 -1
- package/dist/{chunk-UBEVY5UT.js → chunk-3NJUOIZQ.js} +5 -5
- package/dist/{chunk-UBEVY5UT.js.map → chunk-3NJUOIZQ.js.map} +1 -1
- package/dist/{chunk-3GZSDY35.js → chunk-5OL2TSHK.js} +4 -4
- package/dist/{chunk-3GZSDY35.js.map → chunk-5OL2TSHK.js.map} +1 -1
- package/dist/{chunk-2BURPMYA.js → chunk-6K3XK7C5.js} +69 -976
- package/dist/chunk-6K3XK7C5.js.map +1 -0
- package/dist/{chunk-2GSMCOIC.js → chunk-AXZZ5CCG.js} +4 -4
- package/dist/{chunk-2GSMCOIC.js.map → chunk-AXZZ5CCG.js.map} +1 -1
- package/dist/{chunk-NHB53JTV.js → chunk-C3LMWZKF.js} +3 -3
- package/dist/{chunk-NHB53JTV.js.map → chunk-C3LMWZKF.js.map} +1 -1
- package/dist/{chunk-FD2HPGX2.js → chunk-DVW3SVCW.js} +9 -8
- package/dist/chunk-DVW3SVCW.js.map +1 -0
- package/dist/{chunk-RJCRWQNS.js → chunk-E2FAQREZ.js} +164 -221
- package/dist/chunk-E2FAQREZ.js.map +1 -0
- package/dist/{chunk-45AKSS4A.js → chunk-EXV4QSAD.js} +4 -4
- package/dist/{chunk-45AKSS4A.js.map → chunk-EXV4QSAD.js.map} +1 -1
- package/dist/{chunk-OWSXI3PJ.js → chunk-GOGMS3ST.js} +5 -5
- package/dist/{chunk-OWSXI3PJ.js.map → chunk-GOGMS3ST.js.map} +1 -1
- package/dist/{chunk-YL4OIUA5.js → chunk-K6DXETMC.js} +11 -11
- package/dist/{chunk-YL4OIUA5.js.map → chunk-K6DXETMC.js.map} +1 -1
- package/dist/{chunk-NKRWKCME.js → chunk-KJT2R6WW.js} +4 -4
- package/dist/{chunk-NKRWKCME.js.map → chunk-KJT2R6WW.js.map} +1 -1
- package/dist/{chunk-FMS6G67U.js → chunk-KNGAZDGF.js} +5 -5
- package/dist/{chunk-FMS6G67U.js.map → chunk-KNGAZDGF.js.map} +1 -1
- package/dist/{chunk-JHLCKMKF.js → chunk-LHKQGVRF.js} +9 -8
- package/dist/chunk-LHKQGVRF.js.map +1 -0
- package/dist/{chunk-A7EKFLAN.js → chunk-M7IO3DXH.js} +9 -8
- package/dist/chunk-M7IO3DXH.js.map +1 -0
- package/dist/{chunk-QPXVTQ7O.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-K267DHCF.js → chunk-O2DL2Q55.js} +6 -6
- package/dist/{chunk-K267DHCF.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-PRG2ULPK.js +6 -0
- package/dist/{chunk-PV76EO4G.js.map → chunk-PRG2ULPK.js.map} +1 -1
- package/dist/{chunk-ZSECAGSU.js → chunk-Q3M6K3HY.js} +3 -3
- package/dist/{chunk-ZSECAGSU.js.map → chunk-Q3M6K3HY.js.map} +1 -1
- package/dist/{chunk-2TJ5EY4I.js → chunk-Q4G2BWE3.js} +4 -4
- package/dist/{chunk-2TJ5EY4I.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-RQAKBRAV.js → chunk-TVDMNIUT.js} +3 -3
- package/dist/{chunk-RQAKBRAV.js.map → chunk-TVDMNIUT.js.map} +1 -1
- package/dist/{chunk-ANYL7SUI.js → chunk-WAKP7SK7.js} +4584 -976
- package/dist/chunk-WAKP7SK7.js.map +1 -0
- package/dist/{chunk-ENFSSUNK.js → chunk-WVMOGIPC.js} +5 -43
- package/dist/chunk-WVMOGIPC.js.map +1 -0
- package/dist/{chunk-6NOGNOE4.js → chunk-XLXJC7H3.js} +141 -13
- package/dist/chunk-XLXJC7H3.js.map +1 -0
- package/dist/cli.js +1476 -575
- package/dist/cli.js.map +1 -1
- package/dist/{daemon-J2HX4GY3.js → daemon-FPTRHO5N.js} +11 -10
- package/dist/{daemon-J2HX4GY3.js.map → daemon-FPTRHO5N.js.map} +1 -1
- 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-5C6KG66X.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-HH5IIQ55.js.map → graph-backend-RNWQBT3P.js.map} +1 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.js +18 -17
- package/dist/index.js.map +1 -1
- package/dist/{interactive-FXPAZAUJ.js → interactive-SR7TMF6M.js} +28 -27
- package/dist/interactive-SR7TMF6M.js.map +1 -0
- package/dist/load-AYFECIQB.js +11 -0
- package/dist/{load-OR2XVGAV.js.map → load-AYFECIQB.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-M4546HLJ.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-6KKMFS6Q.js.map → runtime-session-CNJ4DAV5.js.map} +1 -1
- package/dist/session-H34HUV2Y.js +17 -0
- package/dist/{session-HCFJUSKN.js.map → session-H34HUV2Y.js.map} +1 -1
- package/dist/{stream-json-4DL65D6U.js → stream-json-55YDNAFX.js} +15 -14
- package/dist/stream-json-55YDNAFX.js.map +1 -0
- package/dist/{types-8SYlXhzm.d.ts → types-DHqH0XIE.d.ts} +11 -0
- package/dist/version-WSE3QOPK.js +4 -0
- package/dist/{version-UPIC3F4P.js.map → version-WSE3QOPK.js.map} +1 -1
- package/dist/{vg-mcp-bridge-FZGX6DYO.js → vg-mcp-bridge-2CNLHNEL.js} +13 -12
- package/dist/vg-mcp-bridge-2CNLHNEL.js.map +1 -0
- package/dist/{vgd-QR26FAZD.js → vgd-URUZQORN.js} +10 -9
- package/dist/vgd-URUZQORN.js.map +1 -0
- package/package.json +7 -7
- package/dist/agent-CUYQKC6S.js +0 -26
- package/dist/baseline-NZFGLMER.js +0 -9
- package/dist/chunk-2BURPMYA.js.map +0 -1
- package/dist/chunk-6NOGNOE4.js.map +0 -1
- package/dist/chunk-A7EKFLAN.js.map +0 -1
- package/dist/chunk-ANYL7SUI.js.map +0 -1
- package/dist/chunk-DT4KIVRI.js.map +0 -1
- package/dist/chunk-ENFSSUNK.js.map +0 -1
- package/dist/chunk-FD2HPGX2.js.map +0 -1
- package/dist/chunk-JHLCKMKF.js.map +0 -1
- package/dist/chunk-PV76EO4G.js +0 -6
- package/dist/chunk-QPXVTQ7O.js.map +0 -1
- package/dist/chunk-RJCRWQNS.js.map +0 -1
- package/dist/chunk-RXP66R2E.js +0 -39
- package/dist/chunk-RXP66R2E.js.map +0 -1
- package/dist/ensure-map-5C6KG66X.js +0 -32
- package/dist/fs-NTQUFCXV.js.map +0 -1
- package/dist/graph-backend-HH5IIQ55.js +0 -14
- package/dist/interactive-FXPAZAUJ.js.map +0 -1
- package/dist/load-OR2XVGAV.js +0 -10
- package/dist/run-outcome-M4546HLJ.js.map +0 -1
- package/dist/runtime-session-6KKMFS6Q.js +0 -21
- package/dist/session-HCFJUSKN.js +0 -16
- package/dist/stream-json-4DL65D6U.js.map +0 -1
- package/dist/version-UPIC3F4P.js +0 -4
- package/dist/vg-mcp-bridge-FZGX6DYO.js.map +0 -1
- package/dist/vgd-QR26FAZD.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
|