@vibgrate/cli 2026.817.1 → 2026.818.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +61 -0
- package/README.md +1 -0
- package/dist/activity-MF2GNYAI.js +5 -0
- package/dist/activity-MF2GNYAI.js.map +1 -0
- package/dist/agent-CUK24AWF.js +30 -0
- package/dist/{agent-CUYQKC6S.js.map → agent-CUK24AWF.js.map} +1 -1
- package/dist/{approvals-IPMUDEDV.js → approvals-YFOU6GVB.js} +6 -5
- package/dist/{approvals-IPMUDEDV.js.map → approvals-YFOU6GVB.js.map} +1 -1
- package/dist/attach-6S3XS7VO.js +9 -0
- package/dist/attach-6S3XS7VO.js.map +1 -0
- package/dist/baseline-OBZJRCCP.js +9 -0
- package/dist/{baseline-NZFGLMER.js.map → baseline-OBZJRCCP.js.map} +1 -1
- package/dist/{chunk-RJCRWQNS.js → chunk-43ESHUM5.js} +179 -463
- package/dist/chunk-43ESHUM5.js.map +1 -0
- package/dist/{chunk-YL4OIUA5.js → chunk-4QAMUBAC.js} +13 -12
- package/dist/chunk-4QAMUBAC.js.map +1 -0
- package/dist/{chunk-2BURPMYA.js → chunk-6ABMV74F.js} +72 -976
- package/dist/chunk-6ABMV74F.js.map +1 -0
- package/dist/chunk-6BEBJCK4.js +467 -0
- package/dist/chunk-6BEBJCK4.js.map +1 -0
- package/dist/{chunk-NKRWKCME.js → chunk-6LY3JH6S.js} +4 -4
- package/dist/{chunk-NKRWKCME.js.map → chunk-6LY3JH6S.js.map} +1 -1
- package/dist/chunk-6WRG7VDO.js +118 -0
- package/dist/chunk-6WRG7VDO.js.map +1 -0
- package/dist/chunk-DBX3DL27.js +26 -0
- package/dist/chunk-DBX3DL27.js.map +1 -0
- package/dist/{chunk-ZSECAGSU.js → chunk-DH6EDSQP.js} +3 -3
- package/dist/{chunk-ZSECAGSU.js.map → chunk-DH6EDSQP.js.map} +1 -1
- package/dist/{chunk-3GZSDY35.js → chunk-DM6MJ7IF.js} +4 -4
- package/dist/{chunk-3GZSDY35.js.map → chunk-DM6MJ7IF.js.map} +1 -1
- package/dist/{chunk-2TJ5EY4I.js → chunk-DUCEKH7Q.js} +12 -6
- package/dist/chunk-DUCEKH7Q.js.map +1 -0
- package/dist/{chunk-45AKSS4A.js → chunk-E7RVA2ZI.js} +4 -4
- package/dist/{chunk-45AKSS4A.js.map → chunk-E7RVA2ZI.js.map} +1 -1
- package/dist/{chunk-NHB53JTV.js → chunk-FFYO7G3T.js} +4 -4
- package/dist/{chunk-NHB53JTV.js.map → chunk-FFYO7G3T.js.map} +1 -1
- package/dist/chunk-G7ZFSH5J.js +132 -0
- package/dist/chunk-G7ZFSH5J.js.map +1 -0
- package/dist/{chunk-A7EKFLAN.js → chunk-GKZU6MII.js} +166 -31
- package/dist/chunk-GKZU6MII.js.map +1 -0
- package/dist/chunk-H5Q4JUY4.js +47 -0
- package/dist/chunk-H5Q4JUY4.js.map +1 -0
- package/dist/{chunk-JHLCKMKF.js → chunk-H6RV2OAX.js} +32 -10
- package/dist/chunk-H6RV2OAX.js.map +1 -0
- package/dist/{chunk-4W5SYK2M.js → chunk-I3PKYYRP.js} +5 -4
- package/dist/chunk-I3PKYYRP.js.map +1 -0
- package/dist/{chunk-6NOGNOE4.js → chunk-J3A3O4IA.js} +142 -127
- package/dist/chunk-J3A3O4IA.js.map +1 -0
- package/dist/{chunk-K267DHCF.js → chunk-J7CVFTLG.js} +6 -6
- package/dist/{chunk-K267DHCF.js.map → chunk-J7CVFTLG.js.map} +1 -1
- package/dist/{chunk-UBEVY5UT.js → chunk-LHQYYBCH.js} +5 -5
- package/dist/{chunk-UBEVY5UT.js.map → chunk-LHQYYBCH.js.map} +1 -1
- package/dist/{chunk-OWSXI3PJ.js → chunk-MHJBIGWV.js} +752 -51
- package/dist/chunk-MHJBIGWV.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-NDNNOAS6.js +16 -0
- package/dist/chunk-NDNNOAS6.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-RBIRXQR6.js → chunk-NO4BMW7M.js} +4 -14
- package/dist/chunk-NO4BMW7M.js.map +1 -0
- package/dist/chunk-O3LABX6I.js +43 -0
- package/dist/chunk-O3LABX6I.js.map +1 -0
- package/dist/{chunk-FD2HPGX2.js → chunk-OS4YFOFJ.js} +31 -10
- package/dist/chunk-OS4YFOFJ.js.map +1 -0
- package/dist/{chunk-NQUWC2IA.js → chunk-OVUZWR67.js} +108 -543
- package/dist/chunk-OVUZWR67.js.map +1 -0
- package/dist/chunk-POOL355F.js +237 -0
- package/dist/chunk-POOL355F.js.map +1 -0
- package/dist/{chunk-ENFSSUNK.js → chunk-Q7TWHJJ6.js} +5 -43
- package/dist/chunk-Q7TWHJJ6.js.map +1 -0
- package/dist/{chunk-MIYXVY57.js → chunk-SBHK4ECM.js} +4 -4
- package/dist/{chunk-MIYXVY57.js.map → chunk-SBHK4ECM.js.map} +1 -1
- package/dist/chunk-SUD54UGN.js +6 -0
- package/dist/{chunk-PV76EO4G.js.map → chunk-SUD54UGN.js.map} +1 -1
- package/dist/chunk-T7RSQ5WD.js +227 -0
- package/dist/chunk-T7RSQ5WD.js.map +1 -0
- package/dist/{chunk-ANYL7SUI.js → chunk-V2UGRUTL.js} +4761 -976
- package/dist/chunk-V2UGRUTL.js.map +1 -0
- package/dist/{chunk-2GSMCOIC.js → chunk-WVTGF2MP.js} +39 -20
- package/dist/chunk-WVTGF2MP.js.map +1 -0
- package/dist/{chunk-RQAKBRAV.js → chunk-X4DECFUG.js} +4 -4
- package/dist/{chunk-RQAKBRAV.js.map → chunk-X4DECFUG.js.map} +1 -1
- package/dist/{chunk-OZ3IFXRD.js → chunk-YENM3HT7.js} +5 -4
- package/dist/chunk-YENM3HT7.js.map +1 -0
- package/dist/{chunk-FMS6G67U.js → chunk-ZWFMJUXC.js} +151 -42
- package/dist/chunk-ZWFMJUXC.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +1895 -872
- package/dist/cli.js.map +1 -1
- package/dist/daemon-4Q5QBBAF.js +31 -0
- package/dist/{daemon-J2HX4GY3.js.map → daemon-4Q5QBBAF.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-B2PS5ALS.js +40 -0
- package/dist/{ensure-map-5C6KG66X.js.map → ensure-map-B2PS5ALS.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-EEXMD6XY.js +16 -0
- package/dist/{graph-backend-HH5IIQ55.js.map → graph-backend-EEXMD6XY.js.map} +1 -1
- package/dist/index.d.ts +627 -6
- package/dist/index.js +28 -20
- package/dist/index.js.map +1 -1
- package/dist/{interactive-FXPAZAUJ.js → interactive-KEPGE5HD.js} +44 -36
- package/dist/interactive-KEPGE5HD.js.map +1 -0
- package/dist/load-H5HAME25.js +11 -0
- package/dist/{load-OR2XVGAV.js.map → load-H5HAME25.js.map} +1 -1
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +6 -2
- package/dist/parse-worker.js.map +1 -1
- package/dist/{run-outcome-M4546HLJ.js → run-outcome-V3L4GAN4.js} +7 -6
- package/dist/run-outcome-V3L4GAN4.js.map +1 -0
- package/dist/runtime-session-M2FRGTDS.js +27 -0
- package/dist/{runtime-session-6KKMFS6Q.js.map → runtime-session-M2FRGTDS.js.map} +1 -1
- package/dist/session-77YXFUC7.js +17 -0
- package/dist/{session-HCFJUSKN.js.map → session-77YXFUC7.js.map} +1 -1
- package/dist/slot-subscription-25GOARW5.js +95 -0
- package/dist/slot-subscription-25GOARW5.js.map +1 -0
- package/dist/{stream-json-4DL65D6U.js → stream-json-S6E3W2US.js} +21 -17
- package/dist/stream-json-S6E3W2US.js.map +1 -0
- package/dist/{types-8SYlXhzm.d.ts → types-DHqH0XIE.d.ts} +11 -0
- package/dist/version-VRZT5G4T.js +4 -0
- package/dist/{version-UPIC3F4P.js.map → version-VRZT5G4T.js.map} +1 -1
- package/dist/{vg-mcp-bridge-FZGX6DYO.js → vg-mcp-bridge-HCPJWJKJ.js} +16 -14
- package/dist/vg-mcp-bridge-HCPJWJKJ.js.map +1 -0
- package/dist/{vgd-QR26FAZD.js → vgd-R2PNIDEP.js} +17 -11
- package/dist/vgd-R2PNIDEP.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-2GSMCOIC.js.map +0 -1
- package/dist/chunk-2TJ5EY4I.js.map +0 -1
- package/dist/chunk-4W5SYK2M.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-FMS6G67U.js.map +0 -1
- package/dist/chunk-JHLCKMKF.js.map +0 -1
- package/dist/chunk-NQUWC2IA.js.map +0 -1
- package/dist/chunk-OWSXI3PJ.js.map +0 -1
- package/dist/chunk-OZ3IFXRD.js.map +0 -1
- package/dist/chunk-PV76EO4G.js +0 -6
- package/dist/chunk-QPXVTQ7O.js.map +0 -1
- package/dist/chunk-RBIRXQR6.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/chunk-YL4OIUA5.js.map +0 -1
- package/dist/daemon-J2HX4GY3.js +0 -25
- 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-V2UGRUTL.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) {
|
|
@@ -4265,6 +3310,8 @@ function archetypeCategory(archetype) {
|
|
|
4265
3310
|
case "remix":
|
|
4266
3311
|
case "sveltekit":
|
|
4267
3312
|
case "nuxt":
|
|
3313
|
+
case "rails":
|
|
3314
|
+
case "phoenix":
|
|
4268
3315
|
return { category: "web-app", signal: `archetype:${archetype}` };
|
|
4269
3316
|
case "nestjs":
|
|
4270
3317
|
case "express":
|
|
@@ -4272,6 +3319,12 @@ function archetypeCategory(archetype) {
|
|
|
4272
3319
|
case "hono":
|
|
4273
3320
|
case "koa":
|
|
4274
3321
|
case "serverless":
|
|
3322
|
+
case "spring":
|
|
3323
|
+
case "aspnet":
|
|
3324
|
+
case "django":
|
|
3325
|
+
case "fastapi":
|
|
3326
|
+
case "laravel":
|
|
3327
|
+
case "go-service":
|
|
4275
3328
|
return { category: "api", signal: `archetype:${archetype}` };
|
|
4276
3329
|
case "library":
|
|
4277
3330
|
return { category: "library", signal: "archetype:library" };
|
|
@@ -4281,6 +3334,41 @@ function archetypeCategory(archetype) {
|
|
|
4281
3334
|
return null;
|
|
4282
3335
|
}
|
|
4283
3336
|
}
|
|
3337
|
+
function projectKindCategory(kind) {
|
|
3338
|
+
switch (kind) {
|
|
3339
|
+
case "web-app":
|
|
3340
|
+
return { category: "web-app", signal: "projectKind:web-app" };
|
|
3341
|
+
case "web-api":
|
|
3342
|
+
return { category: "api", signal: "projectKind:web-api" };
|
|
3343
|
+
case "library":
|
|
3344
|
+
return { category: "library", signal: "projectKind:library" };
|
|
3345
|
+
case "cli":
|
|
3346
|
+
return { category: "cli", signal: "projectKind:cli" };
|
|
3347
|
+
case "iac":
|
|
3348
|
+
return { category: "infra", signal: "projectKind:iac" };
|
|
3349
|
+
case "database":
|
|
3350
|
+
return { category: "data", signal: "projectKind:database" };
|
|
3351
|
+
case "worker":
|
|
3352
|
+
return { category: "api", signal: "projectKind:worker" };
|
|
3353
|
+
default:
|
|
3354
|
+
return null;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
var API_FRAMEWORKS = /* @__PURE__ */ new Set([
|
|
3358
|
+
"express",
|
|
3359
|
+
"nestjs",
|
|
3360
|
+
"fastify",
|
|
3361
|
+
"hono",
|
|
3362
|
+
"koa",
|
|
3363
|
+
"spring",
|
|
3364
|
+
"aspnet",
|
|
3365
|
+
"django",
|
|
3366
|
+
"fastapi",
|
|
3367
|
+
"laravel",
|
|
3368
|
+
"phoenix",
|
|
3369
|
+
"rails"
|
|
3370
|
+
]);
|
|
3371
|
+
var WEB_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs", "remix", "sveltekit", "nuxt"]);
|
|
4284
3372
|
function inferProjectPurpose(project, uiPurpose) {
|
|
4285
3373
|
const signals = [];
|
|
4286
3374
|
const votes = {};
|
|
@@ -4288,9 +3376,19 @@ function inferProjectPurpose(project, uiPurpose) {
|
|
|
4288
3376
|
votes[category] = (votes[category] ?? 0) + weight;
|
|
4289
3377
|
signals.push(signal);
|
|
4290
3378
|
};
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
3379
|
+
const pk = projectKindCategory(project.architecture?.projectKind);
|
|
3380
|
+
if (pk) vote(pk.category, 3, pk.signal);
|
|
3381
|
+
const fwHits = (project.architecture?.evidence ?? []).filter((e) => e.dimension === "framework").map((e) => e.value.toLowerCase());
|
|
3382
|
+
for (const fw of fwHits) {
|
|
3383
|
+
if (WEB_FRAMEWORKS.has(fw)) vote("web-app", 2, `framework:${fw}`);
|
|
3384
|
+
if (API_FRAMEWORKS.has(fw)) vote("api", 2, `framework:${fw}`);
|
|
3385
|
+
}
|
|
3386
|
+
const arch = archetypeCategory(project.architecture?.archetype);
|
|
3387
|
+
if (arch) {
|
|
3388
|
+
const nonJsArchetype = ["spring", "aspnet", "django", "fastapi", "go-service"].includes(project.architecture?.archetype ?? "");
|
|
3389
|
+
if (project.type === "node" || project.type === "typescript" || nonJsArchetype) {
|
|
3390
|
+
vote(arch.category, 3, arch.signal);
|
|
3391
|
+
}
|
|
4294
3392
|
}
|
|
4295
3393
|
const fwNames = (project.frameworks ?? []).map((f) => f.name.toLowerCase());
|
|
4296
3394
|
const uiFw = (uiPurpose?.detectedFrameworks ?? []).map((f) => f.toLowerCase());
|
|
@@ -4592,29 +3690,27 @@ async function runAdvancedAnalysis(ctx) {
|
|
|
4592
3690
|
}
|
|
4593
3691
|
if (scannerPolicy.architecture && scanners?.architecture?.enabled !== false) {
|
|
4594
3692
|
progress.startStep("architecture");
|
|
4595
|
-
|
|
3693
|
+
const { workspace, projectResults } = await scanArchitectureBundle(
|
|
4596
3694
|
rootDir,
|
|
4597
3695
|
allProjects,
|
|
4598
3696
|
extended.toolingInventory,
|
|
4599
3697
|
extended.serviceDependencies,
|
|
4600
3698
|
fileCache
|
|
4601
3699
|
);
|
|
3700
|
+
extended.architecture = workspace;
|
|
4602
3701
|
const arch = extended.architecture;
|
|
4603
3702
|
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
|
-
}));
|
|
3703
|
+
for (let i = 0; i < allProjects.length; i++) {
|
|
3704
|
+
const project = allProjects[i];
|
|
3705
|
+
const projectArch = projectResults[i];
|
|
3706
|
+
project.architecture = projectArch;
|
|
3707
|
+
project.architectureMermaid = mermaidFromArchitecture(projectArch);
|
|
3708
|
+
}
|
|
4613
3709
|
for (const solution of solutions) {
|
|
4614
3710
|
const memberProjects = solution.projectPaths.map((pp) => projectsByPath.get(pp) ?? projectsByPath.get(path3.dirname(pp).replace(/\\/g, "/"))).filter((p) => Boolean(p));
|
|
4615
3711
|
const memberArchResults = memberProjects.map((p) => p.architecture).filter((a) => Boolean(a));
|
|
4616
3712
|
if (memberArchResults.length > 0) {
|
|
4617
|
-
solution.architecture = aggregateSolutionArchitecture(memberArchResults);
|
|
3713
|
+
solution.architecture = aggregateSolutionArchitecture(memberArchResults, memberProjects);
|
|
4618
3714
|
}
|
|
4619
3715
|
}
|
|
4620
3716
|
progress.completeStep(
|
|
@@ -4664,5 +3760,5 @@ var baselineCommand = new Command("baseline").description("Create a drift baseli
|
|
|
4664
3760
|
});
|
|
4665
3761
|
|
|
4666
3762
|
export { baselineCommand, loadAdvancedScanHook, runBaseline };
|
|
4667
|
-
//# sourceMappingURL=chunk-
|
|
4668
|
-
//# sourceMappingURL=chunk-
|
|
3763
|
+
//# sourceMappingURL=chunk-6ABMV74F.js.map
|
|
3764
|
+
//# sourceMappingURL=chunk-6ABMV74F.js.map
|