@launchsecure/launch-kit 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart-client/assets/index-C8ANseEa.js +441 -0
- package/dist/chart-client/index.html +1 -1
- package/dist/deck-client/assets/{_baseUniq-2gclQXo7.js → _baseUniq-DsfOm3t_.js} +1 -1
- package/dist/deck-client/assets/{arc-DcMY5Wm0.js → arc-NJuvkBv1.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-B8iirmmJ.js → architectureDiagram-Q4EWVU46-BgrcgZs0.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-B4JBLjmJ.js → blockDiagram-DXYQGD6D-C3XoLi15.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CojrJAk8.js → c4Diagram-AHTNJAMY-FX2PjLfb.js} +1 -1
- package/dist/deck-client/assets/channel-ChQjD1T1.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-Bmb_BMDo.js → chunk-4BX2VUAB-D0aqsJV0.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-CumBy8qe.js → chunk-4TB4RGXK-7qRCCAgK.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-Ka8Hb1wD.js → chunk-55IACEB6-DfHG-iqb.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-B3sIPiQo.js → chunk-EDXVE4YY-DrR52j3B.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-C1tYkaqu.js → chunk-FMBD7UC4-D5KSGATB.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-D7Wacbky.js → chunk-OYMX7WX6-M7hsLRNU.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-ChXI0vO3.js → chunk-QZHKN3VN-1ynAWO2m.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-BXhiqf8u.js → chunk-YZCP3GAM-S2-nGw3D.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-B_9iqK1S.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-B_9iqK1S.js +1 -0
- package/dist/deck-client/assets/clone-BYt1AMfz.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bqp3p68D.js → cose-bilkent-S5V4N54A-BcMwozS2.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-BS-rtyhZ.js → dagre-KV5264BT-DtKMhl_1.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-BIrj9YGI.js → diagram-5BDNPKRD-1plH69us.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-noHWPIg4.js → diagram-G4DWMVQ6-D_o-BHO3.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-C2qHxvqV.js → diagram-MMDJMWI5-ClZ1LIx6.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-BytnGQr-.js → diagram-TYMM5635-B8dKHfRh.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfK5m2YQ.js → erDiagram-SMLLAGMA-CY2aCH7-.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-Cq925G1Z.js → flowDiagram-DWJPFMVM-DZZWHti8.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DhhHPAmj.js → ganttDiagram-T4ZO3ILL-OwGGa6Lu.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B3Lc0h9q.js → gitGraphDiagram-UUTBAWPF-GKyWD4Qt.js} +1 -1
- package/dist/deck-client/assets/{graph-RTawgVWm.js → graph-CORzYQdB.js} +1 -1
- package/dist/deck-client/assets/{index-BfIfJXmS.js → index-hiIpM7EP.js} +3 -3
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-BlR584kX.js → infoDiagram-42DDH7IO-DmgqJCcF.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DygKoNGY.js → ishikawaDiagram-UXIWVN3A-D-1v7knu.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-BnaiYp9N.js → journeyDiagram-VCZTEJTY-CYrGQE7b.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BQBUBzJC.js → kanban-definition-6JOO6SKY-BJFDWiH-.js} +1 -1
- package/dist/deck-client/assets/{layout-DeZ8HI1T.js → layout-BTFFcaxF.js} +1 -1
- package/dist/deck-client/assets/{linear-C6roLi_9.js → linear-DAbl6COS.js} +1 -1
- package/dist/deck-client/assets/{min-CbUksbuI.js → min-oWHBrFBm.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-iNxV62yN.js → mindmap-definition-QFDTVHPH-BTCB0VLO.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-DHVA0jaG.js → pieDiagram-DEJITSTG-CUZChWNA.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-DBeKKLUQ.js → quadrantDiagram-34T5L4WZ-4M1Um_e4.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CBwITx7p.js → requirementDiagram-MS252O5E-DLzQZ0B3.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BtE-1YTU.js → sankeyDiagram-XADWPNL6-DcNgzV3E.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-DN96yPP2.js → sequenceDiagram-FGHM5R23-CAcI2vC9.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-VUkKC2uJ.js → stateDiagram-FHFEXIEX-CntjTTm5.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-YiaphOU_.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-oUeZhRns.js → timeline-definition-GMOUNBTQ-D8zrit4U.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D87fK90n.js → vennDiagram-DHZGUBPP-C4SuFPgo.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-B3F-Olcq.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Ca_i0QRA.js → wardleyDiagram-NUSXRM2D-kj73r6f-.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CUOJVIvq.js → xychartDiagram-5P7HB3ND-CC_d_Ey3.js} +1 -1
- package/dist/deck-client/index.html +1 -1
- package/dist/server/chart-serve.js +549 -207
- package/dist/server/cli.js +541 -206
- package/dist/server/council-entry.js +0 -0
- package/dist/server/deck-server/deck-mcp-entry.js +0 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/graph-mcp-entry.js +587 -244
- package/dist/server/server/cli.js +0 -0
- package/dist/server/server/fb-wizard.js +0 -0
- package/dist/server/server/graph-mcp-entry.js +0 -0
- package/package.json +18 -17
- package/dist/chart-client/assets/index-D7x8nz-H.js +0 -441
- package/dist/deck-client/assets/channel-ERh5jKXV.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CMi1Gaev.js +0 -1
- package/dist/deck-client/assets/clone-DfWhlD4X.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CA0IjulK.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-DYbYcpDp.js +0 -162
|
@@ -602,19 +602,19 @@ __export(chart_serve_exports, {
|
|
|
602
602
|
module.exports = __toCommonJS(chart_serve_exports);
|
|
603
603
|
var import_node_http = __toESM(require("node:http"));
|
|
604
604
|
var import_node_fs18 = __toESM(require("node:fs"));
|
|
605
|
-
var
|
|
605
|
+
var import_node_path19 = __toESM(require("node:path"));
|
|
606
606
|
|
|
607
607
|
// src/server/graph/index.ts
|
|
608
608
|
var import_node_fs15 = require("node:fs");
|
|
609
|
-
var
|
|
609
|
+
var import_node_path16 = require("node:path");
|
|
610
610
|
|
|
611
611
|
// src/server/graph/core/graph-builder.ts
|
|
612
612
|
var import_node_fs12 = require("node:fs");
|
|
613
|
-
var
|
|
613
|
+
var import_node_path12 = require("node:path");
|
|
614
614
|
init_config();
|
|
615
615
|
|
|
616
616
|
// src/server/graph/core/parser-registry.ts
|
|
617
|
-
var
|
|
617
|
+
var import_node_path11 = require("node:path");
|
|
618
618
|
|
|
619
619
|
// src/server/graph/parsers/ts/typescript-project.ts
|
|
620
620
|
var import_node_fs5 = require("node:fs");
|
|
@@ -622,35 +622,12 @@ var import_node_path5 = require("node:path");
|
|
|
622
622
|
init_config();
|
|
623
623
|
|
|
624
624
|
// src/server/graph/core/resolve-paths.ts
|
|
625
|
-
var import_node_fs2 = require("node:fs");
|
|
626
|
-
var import_node_path2 = require("node:path");
|
|
627
|
-
function detectDbDir(rootDir, config) {
|
|
628
|
-
if (config.paths?.dbDir) return (0, import_node_path2.join)(rootDir, config.paths.dbDir);
|
|
629
|
-
const prismaDir = (0, import_node_path2.join)(rootDir, "prisma");
|
|
630
|
-
if ((0, import_node_fs2.existsSync)(prismaDir)) return prismaDir;
|
|
631
|
-
return null;
|
|
632
|
-
}
|
|
633
|
-
function resolveProjectPaths(rootDir, config) {
|
|
634
|
-
const dbDir = detectDbDir(rootDir, config);
|
|
635
|
-
if (config.paths?.appDir) {
|
|
636
|
-
const appDir = (0, import_node_path2.join)(rootDir, config.paths.appDir);
|
|
637
|
-
const srcDir = config.paths.srcDir ? (0, import_node_path2.join)(rootDir, config.paths.srcDir) : (0, import_node_path2.dirname)(appDir);
|
|
638
|
-
return { srcDir, appDir, apiDir: (0, import_node_path2.join)(appDir, "api"), dbDir };
|
|
639
|
-
}
|
|
640
|
-
const srcApp = (0, import_node_path2.join)(rootDir, "src", "app");
|
|
641
|
-
if ((0, import_node_fs2.existsSync)(srcApp)) {
|
|
642
|
-
return { srcDir: (0, import_node_path2.join)(rootDir, "src"), appDir: srcApp, apiDir: (0, import_node_path2.join)(srcApp, "api"), dbDir };
|
|
643
|
-
}
|
|
644
|
-
const rootApp = (0, import_node_path2.join)(rootDir, "app");
|
|
645
|
-
if ((0, import_node_fs2.existsSync)(rootApp)) {
|
|
646
|
-
return { srcDir: rootDir, appDir: rootApp, apiDir: (0, import_node_path2.join)(rootApp, "api"), dbDir };
|
|
647
|
-
}
|
|
648
|
-
return null;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// src/server/graph/core/walk.ts
|
|
652
625
|
var import_node_fs3 = require("node:fs");
|
|
653
626
|
var import_node_path3 = require("node:path");
|
|
627
|
+
|
|
628
|
+
// src/server/graph/core/walk.ts
|
|
629
|
+
var import_node_fs2 = require("node:fs");
|
|
630
|
+
var import_node_path2 = require("node:path");
|
|
654
631
|
var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
655
632
|
"node_modules",
|
|
656
633
|
".git",
|
|
@@ -666,12 +643,12 @@ var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
|
666
643
|
]);
|
|
667
644
|
function walk(dir, exts) {
|
|
668
645
|
const results = [];
|
|
669
|
-
if (!(0,
|
|
670
|
-
for (const entry of (0,
|
|
671
|
-
const full = (0,
|
|
646
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return results;
|
|
647
|
+
for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
|
|
648
|
+
const full = (0, import_node_path2.join)(dir, entry.name);
|
|
672
649
|
if (entry.isDirectory()) {
|
|
673
650
|
results.push(...walk(full, exts));
|
|
674
|
-
} else if (exts.includes((0,
|
|
651
|
+
} else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
|
|
675
652
|
results.push(full);
|
|
676
653
|
}
|
|
677
654
|
}
|
|
@@ -679,19 +656,205 @@ function walk(dir, exts) {
|
|
|
679
656
|
}
|
|
680
657
|
function walkWithIgnore(dir, exts, opts = {}) {
|
|
681
658
|
const results = [];
|
|
682
|
-
if (!(0,
|
|
659
|
+
if (!(0, import_node_fs2.existsSync)(dir)) return results;
|
|
683
660
|
const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
|
|
684
|
-
for (const entry of (0,
|
|
661
|
+
for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
|
|
685
662
|
if (entry.isDirectory()) {
|
|
686
663
|
if (skip.has(entry.name)) continue;
|
|
687
|
-
results.push(...walkWithIgnore((0,
|
|
688
|
-
} else if (exts.includes((0,
|
|
689
|
-
results.push((0,
|
|
664
|
+
results.push(...walkWithIgnore((0, import_node_path2.join)(dir, entry.name), exts, opts));
|
|
665
|
+
} else if (exts.includes((0, import_node_path2.extname)(entry.name))) {
|
|
666
|
+
results.push((0, import_node_path2.join)(dir, entry.name));
|
|
690
667
|
}
|
|
691
668
|
}
|
|
692
669
|
return results;
|
|
693
670
|
}
|
|
694
671
|
|
|
672
|
+
// src/server/graph/core/resolve-paths.ts
|
|
673
|
+
function hasSqlFiles(dir) {
|
|
674
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
675
|
+
try {
|
|
676
|
+
return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
|
|
677
|
+
(e) => e.isFile() && e.name.endsWith(".sql")
|
|
678
|
+
);
|
|
679
|
+
} catch {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function hasNestedMigrationSql(dir) {
|
|
684
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
685
|
+
try {
|
|
686
|
+
return (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true }).some(
|
|
687
|
+
(e) => e.isDirectory() && (0, import_node_fs3.existsSync)((0, import_node_path3.join)(dir, e.name, "migration.sql"))
|
|
688
|
+
);
|
|
689
|
+
} catch {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function resolveDbFromDir(dir) {
|
|
694
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
695
|
+
const schemaPath = (0, import_node_path3.join)(dir, "schema.prisma");
|
|
696
|
+
if ((0, import_node_fs3.existsSync)(schemaPath)) {
|
|
697
|
+
const migrationsDir2 = (0, import_node_path3.join)(dir, "migrations");
|
|
698
|
+
return {
|
|
699
|
+
kind: "prisma",
|
|
700
|
+
schemaPath,
|
|
701
|
+
migrationsDir: (0, import_node_fs3.existsSync)(migrationsDir2) ? migrationsDir2 : null
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
const migrationsDir = (0, import_node_path3.join)(dir, "migrations");
|
|
705
|
+
if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
|
|
706
|
+
return { kind: "sql-migrations", migrationsDir, schemaPath: null };
|
|
707
|
+
}
|
|
708
|
+
if (hasSqlFiles(dir) || hasNestedMigrationSql(dir)) {
|
|
709
|
+
return { kind: "sql-migrations", migrationsDir: dir, schemaPath: null };
|
|
710
|
+
}
|
|
711
|
+
return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
712
|
+
}
|
|
713
|
+
function detectDbConfig(rootDir, config) {
|
|
714
|
+
if (config.paths?.dbDir) {
|
|
715
|
+
return resolveDbFromDir((0, import_node_path3.join)(rootDir, config.paths.dbDir));
|
|
716
|
+
}
|
|
717
|
+
const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path3.join)("db", "migrations"), "migrations"];
|
|
718
|
+
for (const c of candidates) {
|
|
719
|
+
const dir = (0, import_node_path3.join)(rootDir, c);
|
|
720
|
+
const resolved = resolveDbFromDir(dir);
|
|
721
|
+
if (resolved.kind !== "none") return resolved;
|
|
722
|
+
}
|
|
723
|
+
return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
724
|
+
}
|
|
725
|
+
function detectDbDir(rootDir, config, dbConfig) {
|
|
726
|
+
if (config.paths?.dbDir) return (0, import_node_path3.join)(rootDir, config.paths.dbDir);
|
|
727
|
+
if (dbConfig.kind === "prisma") return (0, import_node_path3.dirname)(dbConfig.schemaPath);
|
|
728
|
+
if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
var NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
732
|
+
...DEFAULT_IGNORE_DIRS,
|
|
733
|
+
// DB conventions (handled by db parsers)
|
|
734
|
+
"prisma",
|
|
735
|
+
"supabase",
|
|
736
|
+
"drizzle",
|
|
737
|
+
"migrations",
|
|
738
|
+
// Web assets
|
|
739
|
+
"public",
|
|
740
|
+
"static",
|
|
741
|
+
"assets",
|
|
742
|
+
// Docs
|
|
743
|
+
"docs",
|
|
744
|
+
"documentation",
|
|
745
|
+
// Test dirs (project tests aren't part of the structural graph)
|
|
746
|
+
"tests",
|
|
747
|
+
"__tests__",
|
|
748
|
+
"e2e",
|
|
749
|
+
"playwright",
|
|
750
|
+
"cypress",
|
|
751
|
+
// Monorepo workspace roots — separate graph projects per .launchchart.json
|
|
752
|
+
"packages",
|
|
753
|
+
"apps",
|
|
754
|
+
"services",
|
|
755
|
+
"libs"
|
|
756
|
+
]);
|
|
757
|
+
function dirHasTSFiles(dir) {
|
|
758
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return false;
|
|
759
|
+
try {
|
|
760
|
+
const stack = [dir];
|
|
761
|
+
while (stack.length > 0) {
|
|
762
|
+
const cur = stack.pop();
|
|
763
|
+
const entries = (0, import_node_fs3.readdirSync)(cur, { withFileTypes: true });
|
|
764
|
+
for (const e of entries) {
|
|
765
|
+
if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
|
|
766
|
+
if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
|
|
767
|
+
stack.push((0, import_node_path3.join)(cur, e.name));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} catch {
|
|
772
|
+
}
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
function collectCodeBearingChildren(dir, extraSkip) {
|
|
776
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return [];
|
|
777
|
+
const out = [];
|
|
778
|
+
try {
|
|
779
|
+
for (const entry of (0, import_node_fs3.readdirSync)(dir, { withFileTypes: true })) {
|
|
780
|
+
if (!entry.isDirectory()) continue;
|
|
781
|
+
if (entry.name.startsWith(".")) continue;
|
|
782
|
+
if (NON_SOURCE_DIRS.has(entry.name)) continue;
|
|
783
|
+
if (extraSkip?.has(entry.name)) continue;
|
|
784
|
+
const full = (0, import_node_path3.join)(dir, entry.name);
|
|
785
|
+
if (dirHasTSFiles(full)) out.push(full);
|
|
786
|
+
}
|
|
787
|
+
} catch {
|
|
788
|
+
}
|
|
789
|
+
return out;
|
|
790
|
+
}
|
|
791
|
+
function detectSrcRoots(rootDir, srcDir, appDir, config) {
|
|
792
|
+
if (config.paths?.srcRoots && config.paths.srcRoots.length > 0) {
|
|
793
|
+
const roots2 = /* @__PURE__ */ new Set();
|
|
794
|
+
roots2.add(appDir);
|
|
795
|
+
for (const r of config.paths.srcRoots) {
|
|
796
|
+
const abs = (0, import_node_path3.isAbsolute)(r) ? r : (0, import_node_path3.resolve)(rootDir, r);
|
|
797
|
+
roots2.add(abs);
|
|
798
|
+
}
|
|
799
|
+
return [...roots2];
|
|
800
|
+
}
|
|
801
|
+
const roots = /* @__PURE__ */ new Set();
|
|
802
|
+
roots.add(appDir);
|
|
803
|
+
for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
|
|
804
|
+
if (srcDir !== rootDir) {
|
|
805
|
+
const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path3.basename)(srcDir)]);
|
|
806
|
+
for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
|
|
807
|
+
}
|
|
808
|
+
return [...roots];
|
|
809
|
+
}
|
|
810
|
+
var CONVENTION_NAMES = ["middleware.ts", "middleware.tsx", "instrumentation.ts", "instrumentation.tsx"];
|
|
811
|
+
function detectConventionFiles(rootDir, srcDir) {
|
|
812
|
+
const out = [];
|
|
813
|
+
const seen = /* @__PURE__ */ new Set();
|
|
814
|
+
const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
|
|
815
|
+
for (const dir of dirs) {
|
|
816
|
+
for (const name of CONVENTION_NAMES) {
|
|
817
|
+
const full = (0, import_node_path3.join)(dir, name);
|
|
818
|
+
if (!seen.has(full) && (0, import_node_fs3.existsSync)(full)) {
|
|
819
|
+
try {
|
|
820
|
+
if ((0, import_node_fs3.statSync)(full).isFile()) {
|
|
821
|
+
seen.add(full);
|
|
822
|
+
out.push(full);
|
|
823
|
+
}
|
|
824
|
+
} catch {
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return out;
|
|
830
|
+
}
|
|
831
|
+
function resolveProjectPaths(rootDir, config) {
|
|
832
|
+
let srcDir;
|
|
833
|
+
let appDir;
|
|
834
|
+
if (config.paths?.appDir) {
|
|
835
|
+
appDir = (0, import_node_path3.join)(rootDir, config.paths.appDir);
|
|
836
|
+
srcDir = config.paths.srcDir ? (0, import_node_path3.join)(rootDir, config.paths.srcDir) : (0, import_node_path3.dirname)(appDir);
|
|
837
|
+
} else {
|
|
838
|
+
const srcApp = (0, import_node_path3.join)(rootDir, "src", "app");
|
|
839
|
+
const rootApp = (0, import_node_path3.join)(rootDir, "app");
|
|
840
|
+
if ((0, import_node_fs3.existsSync)(srcApp)) {
|
|
841
|
+
srcDir = (0, import_node_path3.join)(rootDir, "src");
|
|
842
|
+
appDir = srcApp;
|
|
843
|
+
} else if ((0, import_node_fs3.existsSync)(rootApp)) {
|
|
844
|
+
srcDir = rootDir;
|
|
845
|
+
appDir = rootApp;
|
|
846
|
+
} else {
|
|
847
|
+
return null;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
const apiDir = (0, import_node_path3.join)(appDir, "api");
|
|
851
|
+
const dbConfig = detectDbConfig(rootDir, config);
|
|
852
|
+
const dbDir = detectDbDir(rootDir, config, dbConfig);
|
|
853
|
+
const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
|
|
854
|
+
const conventionFiles = detectConventionFiles(rootDir, srcDir);
|
|
855
|
+
return { srcDir, appDir, apiDir, dbDir, srcRoots, conventionFiles, dbConfig };
|
|
856
|
+
}
|
|
857
|
+
|
|
695
858
|
// src/server/graph/parsers/ts/typescript-project.ts
|
|
696
859
|
init_ts_extractor();
|
|
697
860
|
var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
|
|
@@ -708,8 +871,12 @@ var CLASSIFICATION_TO_LAYER = {
|
|
|
708
871
|
"mcp-tool": "ui",
|
|
709
872
|
external: "ui"
|
|
710
873
|
};
|
|
711
|
-
function toNodeId(srcDir, absPath) {
|
|
712
|
-
|
|
874
|
+
function toNodeId(srcDir, rootDir, absPath) {
|
|
875
|
+
const relFromSrc = (0, import_node_path5.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
876
|
+
if (relFromSrc.startsWith("..")) {
|
|
877
|
+
return (0, import_node_path5.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
878
|
+
}
|
|
879
|
+
return relFromSrc;
|
|
713
880
|
}
|
|
714
881
|
function resolveImport(srcDir, specifier) {
|
|
715
882
|
if (!specifier.startsWith("@/")) return null;
|
|
@@ -799,12 +966,13 @@ function extractRoute(id) {
|
|
|
799
966
|
function nameFromFilename(absPath) {
|
|
800
967
|
return (0, import_node_path5.basename)(absPath, (0, import_node_path5.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
|
|
801
968
|
}
|
|
802
|
-
function
|
|
803
|
-
let route = "/" + (0, import_node_path5.relative)(
|
|
969
|
+
function filePathToAppRoute(appDir, absPath) {
|
|
970
|
+
let route = ("/" + (0, import_node_path5.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
|
|
971
|
+
route = route.replace(/\/\([^)]+\)/g, "");
|
|
972
|
+
route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
|
|
804
973
|
route = route.replace(/\[([^\]]+)\]/g, ":$1");
|
|
805
974
|
route = route.replace(/\/+/g, "/");
|
|
806
|
-
|
|
807
|
-
return "/api" + route;
|
|
975
|
+
return route === "" ? "/" : route;
|
|
808
976
|
}
|
|
809
977
|
function camelToPascal(s) {
|
|
810
978
|
if (!s) return s;
|
|
@@ -889,7 +1057,7 @@ function matchRouteToPage(route, routeToNodeId) {
|
|
|
889
1057
|
if (routeToNodeId.has(normalized)) return routeToNodeId.get(normalized);
|
|
890
1058
|
return null;
|
|
891
1059
|
}
|
|
892
|
-
function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
|
|
1060
|
+
function extractEdges(srcDir, rootDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps, routeToNodeId) {
|
|
893
1061
|
const edges = [];
|
|
894
1062
|
const flagged = [];
|
|
895
1063
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -917,7 +1085,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
917
1085
|
for (const name of names) {
|
|
918
1086
|
const targetAbs = barrelMap.get(name);
|
|
919
1087
|
if (targetAbs) {
|
|
920
|
-
const targetId = toNodeId(srcDir, targetAbs);
|
|
1088
|
+
const targetId = toNodeId(srcDir, rootDir, targetAbs);
|
|
921
1089
|
if (nodeIdSet.has(targetId)) {
|
|
922
1090
|
if (!byTarget.has(targetId)) byTarget.set(targetId, []);
|
|
923
1091
|
byTarget.get(targetId).push(name);
|
|
@@ -931,7 +1099,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
931
1099
|
} else {
|
|
932
1100
|
const resolved = resolveImport(srcDir, specifier);
|
|
933
1101
|
if (resolved) {
|
|
934
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1102
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
935
1103
|
if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
|
|
936
1104
|
addEdge(targetId, edgeTypeFor(isTypeOnly, names));
|
|
937
1105
|
}
|
|
@@ -940,7 +1108,7 @@ function extractEdges(srcDir, absPath, sourceId, parsed, nodeIdSet, barrelMaps,
|
|
|
940
1108
|
} else if (specifier.startsWith(".")) {
|
|
941
1109
|
const resolved = resolveRelativeImport(absPath, specifier);
|
|
942
1110
|
if (resolved) {
|
|
943
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1111
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
944
1112
|
if (nodeIdSet.has(targetId) && !targetId.endsWith("/index.ts") && !targetId.endsWith("/index.tsx")) {
|
|
945
1113
|
addEdge(targetId, edgeTypeFor(isTypeOnly, names));
|
|
946
1114
|
}
|
|
@@ -992,13 +1160,22 @@ function generate(rootDir) {
|
|
|
992
1160
|
const config = loadConfig(rootDir);
|
|
993
1161
|
const paths = resolveProjectPaths(rootDir, config);
|
|
994
1162
|
const srcDir = paths.srcDir;
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1163
|
+
const allDiscovered = [];
|
|
1164
|
+
const discoveredSet = /* @__PURE__ */ new Set();
|
|
1165
|
+
for (const root of paths.srcRoots) {
|
|
1166
|
+
for (const f of walk(root, [".tsx", ".ts"])) {
|
|
1167
|
+
if (!discoveredSet.has(f)) {
|
|
1168
|
+
discoveredSet.add(f);
|
|
1169
|
+
allDiscovered.push(f);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
for (const conv of paths.conventionFiles) {
|
|
1174
|
+
if (!discoveredSet.has(conv)) {
|
|
1175
|
+
discoveredSet.add(conv);
|
|
1176
|
+
allDiscovered.push(conv);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1002
1179
|
const parsedByPath = /* @__PURE__ */ new Map();
|
|
1003
1180
|
for (const absPath of allDiscovered) {
|
|
1004
1181
|
parsedByPath.set(absPath, parseFileTS(absPath));
|
|
@@ -1010,7 +1187,7 @@ function generate(rootDir) {
|
|
|
1010
1187
|
const routeToNodeId = /* @__PURE__ */ new Map();
|
|
1011
1188
|
const fileSet = allDiscovered.filter((f) => !(0, import_node_path5.basename)(f).startsWith("index."));
|
|
1012
1189
|
for (const absPath of fileSet) {
|
|
1013
|
-
const id = toNodeId(srcDir, absPath);
|
|
1190
|
+
const id = toNodeId(srcDir, rootDir, absPath);
|
|
1014
1191
|
const type = classifyType(absPath, id);
|
|
1015
1192
|
if (type === "test" || type === "story") continue;
|
|
1016
1193
|
const parsed = parsedByPath.get(absPath);
|
|
@@ -1025,7 +1202,7 @@ function generate(rootDir) {
|
|
|
1025
1202
|
const dbCalls = extractDbCallsTS(absPath);
|
|
1026
1203
|
const authWrappers = extractAuthWrappersTS(absPath);
|
|
1027
1204
|
const deep = extractDeep(absPath);
|
|
1028
|
-
const routePath = (
|
|
1205
|
+
const routePath = filePathToAppRoute(paths.appDir, absPath);
|
|
1029
1206
|
const mutations = dbCalls.filter((c) => c.isMutation);
|
|
1030
1207
|
const mutates = mutations.length > 0;
|
|
1031
1208
|
const authStrategy = [...authWrappers];
|
|
@@ -1069,11 +1246,12 @@ function generate(rootDir) {
|
|
|
1069
1246
|
const uiEdges = [];
|
|
1070
1247
|
const uiFlagged = [];
|
|
1071
1248
|
for (const absPath of fileSet) {
|
|
1072
|
-
const id = toNodeId(srcDir, absPath);
|
|
1249
|
+
const id = toNodeId(srcDir, rootDir, absPath);
|
|
1073
1250
|
if (!nodeIdSet.has(id)) continue;
|
|
1074
1251
|
const parsed = parsedByPath.get(absPath);
|
|
1075
1252
|
const { edges, flagged } = extractEdges(
|
|
1076
1253
|
srcDir,
|
|
1254
|
+
rootDir,
|
|
1077
1255
|
absPath,
|
|
1078
1256
|
id,
|
|
1079
1257
|
parsed,
|
|
@@ -1086,7 +1264,7 @@ function generate(rootDir) {
|
|
|
1086
1264
|
}
|
|
1087
1265
|
const fetchCallEntries = [];
|
|
1088
1266
|
for (const absPath of fileSet) {
|
|
1089
|
-
const sourceId = toNodeId(srcDir, absPath);
|
|
1267
|
+
const sourceId = toNodeId(srcDir, rootDir, absPath);
|
|
1090
1268
|
if (!nodeIdSet.has(sourceId)) continue;
|
|
1091
1269
|
const parsed = parsedByPath.get(absPath);
|
|
1092
1270
|
if (parsed.fetchCalls.length === 0) continue;
|
|
@@ -1125,7 +1303,7 @@ function generate(rootDir) {
|
|
|
1125
1303
|
for (const name of names) {
|
|
1126
1304
|
const targetAbs = barrelMap.get(name);
|
|
1127
1305
|
if (!targetAbs) continue;
|
|
1128
|
-
const targetId2 = toNodeId(srcDir, targetAbs);
|
|
1306
|
+
const targetId2 = toNodeId(srcDir, rootDir, targetAbs);
|
|
1129
1307
|
if (!nodeIdSet.has(targetId2)) continue;
|
|
1130
1308
|
const key2 = `${externalId}\u2192${targetId2}`;
|
|
1131
1309
|
if (seen.has(key2)) continue;
|
|
@@ -1139,7 +1317,7 @@ function generate(rootDir) {
|
|
|
1139
1317
|
resolved = resolveRelativeImport(absPath, specifier);
|
|
1140
1318
|
}
|
|
1141
1319
|
if (!resolved) continue;
|
|
1142
|
-
const targetId = toNodeId(srcDir, resolved);
|
|
1320
|
+
const targetId = toNodeId(srcDir, rootDir, resolved);
|
|
1143
1321
|
if (!nodeIdSet.has(targetId)) continue;
|
|
1144
1322
|
if (targetId.endsWith("/index.ts") || targetId.endsWith("/index.tsx")) continue;
|
|
1145
1323
|
const key = `${externalId}\u2192${targetId}`;
|
|
@@ -1317,7 +1495,7 @@ var typescriptProjectParser = {
|
|
|
1317
1495
|
|
|
1318
1496
|
// src/server/graph/parsers/db/prisma-schema.ts
|
|
1319
1497
|
var import_node_fs6 = require("node:fs");
|
|
1320
|
-
|
|
1498
|
+
init_config();
|
|
1321
1499
|
function parseModels(content) {
|
|
1322
1500
|
const nodes = [];
|
|
1323
1501
|
const relations = [];
|
|
@@ -1408,10 +1586,24 @@ function parseEnums(content) {
|
|
|
1408
1586
|
return nodes;
|
|
1409
1587
|
}
|
|
1410
1588
|
function detect2(rootDir) {
|
|
1411
|
-
|
|
1589
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
1590
|
+
return paths?.dbConfig.kind === "prisma" && (0, import_node_fs6.existsSync)(paths.dbConfig.schemaPath);
|
|
1412
1591
|
}
|
|
1413
1592
|
function generate2(rootDir) {
|
|
1414
|
-
const
|
|
1593
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
1594
|
+
if (paths.dbConfig.kind !== "prisma") {
|
|
1595
|
+
return {
|
|
1596
|
+
metadata: { generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), layer: "db", source: "none" },
|
|
1597
|
+
nodes: [],
|
|
1598
|
+
edges: [],
|
|
1599
|
+
cross_refs: [],
|
|
1600
|
+
contradictions: [],
|
|
1601
|
+
warnings: [],
|
|
1602
|
+
flagged_edges: [],
|
|
1603
|
+
patterns: { total_tables: 0, total_enums: 0, total_relations: 0 }
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
const schemaPath = paths.dbConfig.schemaPath;
|
|
1415
1607
|
const content = (0, import_node_fs6.readFileSync)(schemaPath, "utf-8");
|
|
1416
1608
|
const { nodes: modelNodes, relations } = parseModels(content);
|
|
1417
1609
|
const enumNodes = parseEnums(content);
|
|
@@ -1432,7 +1624,7 @@ function generate2(rootDir) {
|
|
|
1432
1624
|
metadata: {
|
|
1433
1625
|
generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
1434
1626
|
scope: "prisma-schema",
|
|
1435
|
-
source:
|
|
1627
|
+
source: schemaPath,
|
|
1436
1628
|
provider: "postgresql",
|
|
1437
1629
|
layer: "db",
|
|
1438
1630
|
total_models: modelNodes.length,
|
|
@@ -1470,7 +1662,8 @@ var prismaSchemaParser = {
|
|
|
1470
1662
|
|
|
1471
1663
|
// src/server/graph/parsers/db/sql-migrations.ts
|
|
1472
1664
|
var import_node_fs7 = require("node:fs");
|
|
1473
|
-
var
|
|
1665
|
+
var import_node_path6 = require("node:path");
|
|
1666
|
+
init_config();
|
|
1474
1667
|
var PG_TO_PRISMA = {
|
|
1475
1668
|
"TEXT": "String",
|
|
1476
1669
|
"VARCHAR": "String",
|
|
@@ -1501,51 +1694,149 @@ function pgTypeToPrisma(pgType) {
|
|
|
1501
1694
|
const upper = pgType.toUpperCase().trim();
|
|
1502
1695
|
return PG_TO_PRISMA[upper] ?? upper;
|
|
1503
1696
|
}
|
|
1697
|
+
var ID = `(?:"[\\w$]+"|[\\w$]+)`;
|
|
1698
|
+
var QID = `(?:${ID}\\.)?${ID}`;
|
|
1699
|
+
function bareName(captured) {
|
|
1700
|
+
const parts = captured.split(".");
|
|
1701
|
+
const last = parts[parts.length - 1];
|
|
1702
|
+
return last.replace(/^"(.*)"$/, "$1").trim();
|
|
1703
|
+
}
|
|
1504
1704
|
function parseCreateTable(sql, state) {
|
|
1505
|
-
const re =
|
|
1705
|
+
const re = new RegExp(
|
|
1706
|
+
`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
|
|
1707
|
+
"gi"
|
|
1708
|
+
);
|
|
1506
1709
|
let m;
|
|
1507
1710
|
while ((m = re.exec(sql)) !== null) {
|
|
1508
|
-
const tableName = m[1];
|
|
1711
|
+
const tableName = bareName(m[1]);
|
|
1509
1712
|
const body = m[2];
|
|
1510
1713
|
const columns = /* @__PURE__ */ new Map();
|
|
1511
1714
|
let primaryCol = null;
|
|
1512
|
-
|
|
1513
|
-
|
|
1715
|
+
const inlineFks = [];
|
|
1716
|
+
const lines = splitTopLevelCommas(body);
|
|
1717
|
+
for (const raw of lines) {
|
|
1718
|
+
const trimmed = raw.trim().replace(/,\s*$/, "");
|
|
1514
1719
|
if (!trimmed || trimmed.startsWith("--")) continue;
|
|
1515
|
-
const
|
|
1516
|
-
if (
|
|
1517
|
-
primaryCol =
|
|
1720
|
+
const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
|
|
1721
|
+
if (namedPk) {
|
|
1722
|
+
primaryCol = bareName(namedPk[1]);
|
|
1723
|
+
continue;
|
|
1724
|
+
}
|
|
1725
|
+
const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
|
|
1726
|
+
if (tablePk) {
|
|
1727
|
+
primaryCol = bareName(tablePk[1]);
|
|
1728
|
+
continue;
|
|
1729
|
+
}
|
|
1730
|
+
if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
|
|
1731
|
+
const namedFk = trimmed.match(new RegExp(
|
|
1732
|
+
`^CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
1733
|
+
"i"
|
|
1734
|
+
));
|
|
1735
|
+
if (namedFk) {
|
|
1736
|
+
inlineFks.push({
|
|
1737
|
+
constraintName: bareName(namedFk[1]),
|
|
1738
|
+
sourceTable: tableName,
|
|
1739
|
+
sourceColumn: bareName(namedFk[2]),
|
|
1740
|
+
targetTable: bareName(namedFk[3]),
|
|
1741
|
+
targetColumn: bareName(namedFk[4]),
|
|
1742
|
+
onDelete: namedFk[5] ?? null
|
|
1743
|
+
});
|
|
1518
1744
|
continue;
|
|
1519
1745
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1746
|
+
const bareFk = trimmed.match(new RegExp(
|
|
1747
|
+
`^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
1748
|
+
"i"
|
|
1749
|
+
));
|
|
1750
|
+
if (bareFk) {
|
|
1751
|
+
inlineFks.push({
|
|
1752
|
+
constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
|
|
1753
|
+
sourceTable: tableName,
|
|
1754
|
+
sourceColumn: bareName(bareFk[1]),
|
|
1755
|
+
targetTable: bareName(bareFk[2]),
|
|
1756
|
+
targetColumn: bareName(bareFk[3]),
|
|
1757
|
+
onDelete: bareFk[4] ?? null
|
|
1758
|
+
});
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
if (/^CONSTRAINT\s/i.test(trimmed)) continue;
|
|
1762
|
+
const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
|
|
1522
1763
|
if (!colMatch) continue;
|
|
1523
|
-
const colName = colMatch[1];
|
|
1764
|
+
const colName = bareName(colMatch[1]);
|
|
1524
1765
|
let rest = colMatch[2];
|
|
1766
|
+
const inlineRefMatch = rest.match(new RegExp(
|
|
1767
|
+
`\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
1768
|
+
"i"
|
|
1769
|
+
));
|
|
1770
|
+
if (inlineRefMatch) {
|
|
1771
|
+
inlineFks.push({
|
|
1772
|
+
constraintName: `${tableName}_${colName}_fkey`,
|
|
1773
|
+
sourceTable: tableName,
|
|
1774
|
+
sourceColumn: colName,
|
|
1775
|
+
targetTable: bareName(inlineRefMatch[1]),
|
|
1776
|
+
targetColumn: bareName(inlineRefMatch[2]),
|
|
1777
|
+
onDelete: inlineRefMatch[3] ?? null
|
|
1778
|
+
});
|
|
1779
|
+
rest = rest.replace(inlineRefMatch[0], "").trim();
|
|
1780
|
+
}
|
|
1525
1781
|
const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
|
|
1782
|
+
const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
|
|
1783
|
+
const isUnique = /\bUNIQUE\b/i.test(rest);
|
|
1526
1784
|
const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
|
|
1527
1785
|
const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
|
|
1528
|
-
let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
|
|
1786
|
+
let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bPRIMARY\s+KEY\b/gi, "").replace(/\bUNIQUE\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim().replace(/,\s*$/, "").trim();
|
|
1529
1787
|
columns.set(colName, {
|
|
1530
1788
|
name: colName,
|
|
1531
1789
|
type: colType,
|
|
1532
|
-
nullable: !isNotNull,
|
|
1533
|
-
primary:
|
|
1534
|
-
unique:
|
|
1790
|
+
nullable: !isNotNull && !isPrimaryKey,
|
|
1791
|
+
primary: isPrimaryKey,
|
|
1792
|
+
unique: isUnique,
|
|
1535
1793
|
default: defaultVal
|
|
1536
1794
|
});
|
|
1795
|
+
if (isPrimaryKey) primaryCol = colName;
|
|
1537
1796
|
}
|
|
1538
1797
|
if (primaryCol && columns.has(primaryCol)) {
|
|
1539
1798
|
columns.get(primaryCol).primary = true;
|
|
1540
1799
|
}
|
|
1541
1800
|
state.tables.set(tableName, { name: tableName, columns });
|
|
1801
|
+
state.fks.push(...inlineFks);
|
|
1542
1802
|
}
|
|
1543
1803
|
}
|
|
1804
|
+
function splitTopLevelCommas(body) {
|
|
1805
|
+
const out = [];
|
|
1806
|
+
let depth = 0;
|
|
1807
|
+
let buf = "";
|
|
1808
|
+
let inString = null;
|
|
1809
|
+
for (const ch of body) {
|
|
1810
|
+
if (inString) {
|
|
1811
|
+
buf += ch;
|
|
1812
|
+
if (ch === inString) inString = null;
|
|
1813
|
+
continue;
|
|
1814
|
+
}
|
|
1815
|
+
if (ch === "'" || ch === '"') {
|
|
1816
|
+
inString = ch;
|
|
1817
|
+
buf += ch;
|
|
1818
|
+
continue;
|
|
1819
|
+
}
|
|
1820
|
+
if (ch === "(") depth++;
|
|
1821
|
+
else if (ch === ")") depth--;
|
|
1822
|
+
if (ch === "," && depth === 0) {
|
|
1823
|
+
out.push(buf);
|
|
1824
|
+
buf = "";
|
|
1825
|
+
continue;
|
|
1826
|
+
}
|
|
1827
|
+
buf += ch;
|
|
1828
|
+
}
|
|
1829
|
+
if (buf.trim()) out.push(buf);
|
|
1830
|
+
return out;
|
|
1831
|
+
}
|
|
1544
1832
|
function parseCreateEnum(sql, state) {
|
|
1545
|
-
const re =
|
|
1833
|
+
const re = new RegExp(
|
|
1834
|
+
`CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
|
|
1835
|
+
"gi"
|
|
1836
|
+
);
|
|
1546
1837
|
let m;
|
|
1547
1838
|
while ((m = re.exec(sql)) !== null) {
|
|
1548
|
-
const enumName = m[1];
|
|
1839
|
+
const enumName = bareName(m[1]);
|
|
1549
1840
|
const valuesStr = m[2];
|
|
1550
1841
|
const values = new Set(
|
|
1551
1842
|
valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
|
|
@@ -1554,11 +1845,14 @@ function parseCreateEnum(sql, state) {
|
|
|
1554
1845
|
}
|
|
1555
1846
|
}
|
|
1556
1847
|
function parseAlterTable(sql, state) {
|
|
1557
|
-
const addColRe =
|
|
1848
|
+
const addColRe = new RegExp(
|
|
1849
|
+
`ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
|
|
1850
|
+
"gi"
|
|
1851
|
+
);
|
|
1558
1852
|
let m;
|
|
1559
1853
|
while ((m = addColRe.exec(sql)) !== null) {
|
|
1560
|
-
const tableName = m[1];
|
|
1561
|
-
const colName = m[2];
|
|
1854
|
+
const tableName = bareName(m[1]);
|
|
1855
|
+
const colName = bareName(m[2]);
|
|
1562
1856
|
let rest = m[3];
|
|
1563
1857
|
const table = state.tables.get(tableName);
|
|
1564
1858
|
if (!table) continue;
|
|
@@ -1575,63 +1869,91 @@ function parseAlterTable(sql, state) {
|
|
|
1575
1869
|
default: defaultVal
|
|
1576
1870
|
});
|
|
1577
1871
|
}
|
|
1578
|
-
const dropColRe =
|
|
1872
|
+
const dropColRe = new RegExp(
|
|
1873
|
+
`ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
|
|
1874
|
+
"gi"
|
|
1875
|
+
);
|
|
1579
1876
|
while ((m = dropColRe.exec(sql)) !== null) {
|
|
1580
|
-
const table = state.tables.get(m[1]);
|
|
1581
|
-
if (table) table.columns.delete(m[2]);
|
|
1877
|
+
const table = state.tables.get(bareName(m[1]));
|
|
1878
|
+
if (table) table.columns.delete(bareName(m[2]));
|
|
1582
1879
|
}
|
|
1583
|
-
const fkRe =
|
|
1880
|
+
const fkRe = new RegExp(
|
|
1881
|
+
`ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+CONSTRAINT\\s+(${ID})\\s+FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
1882
|
+
"gi"
|
|
1883
|
+
);
|
|
1584
1884
|
while ((m = fkRe.exec(sql)) !== null) {
|
|
1585
1885
|
state.fks.push({
|
|
1586
|
-
constraintName: m[2],
|
|
1587
|
-
sourceTable: m[1],
|
|
1588
|
-
sourceColumn: m[3],
|
|
1589
|
-
targetTable: m[4],
|
|
1590
|
-
targetColumn: m[5],
|
|
1886
|
+
constraintName: bareName(m[2]),
|
|
1887
|
+
sourceTable: bareName(m[1]),
|
|
1888
|
+
sourceColumn: bareName(m[3]),
|
|
1889
|
+
targetTable: bareName(m[4]),
|
|
1890
|
+
targetColumn: bareName(m[5]),
|
|
1591
1891
|
onDelete: m[6] ?? null
|
|
1592
1892
|
});
|
|
1593
1893
|
}
|
|
1594
1894
|
}
|
|
1595
1895
|
function parseAlterEnum(sql, state) {
|
|
1596
|
-
const re =
|
|
1896
|
+
const re = new RegExp(
|
|
1897
|
+
`ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
|
|
1898
|
+
"gi"
|
|
1899
|
+
);
|
|
1597
1900
|
let m;
|
|
1598
1901
|
while ((m = re.exec(sql)) !== null) {
|
|
1599
|
-
const en = state.enums.get(m[1]);
|
|
1902
|
+
const en = state.enums.get(bareName(m[1]));
|
|
1600
1903
|
if (en) en.values.add(m[2]);
|
|
1601
1904
|
}
|
|
1602
1905
|
}
|
|
1603
1906
|
function parseDropTable(sql, state) {
|
|
1604
|
-
const re =
|
|
1907
|
+
const re = new RegExp(
|
|
1908
|
+
`DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
|
|
1909
|
+
"gi"
|
|
1910
|
+
);
|
|
1605
1911
|
let m;
|
|
1606
1912
|
while ((m = re.exec(sql)) !== null) {
|
|
1607
|
-
|
|
1608
|
-
state.
|
|
1913
|
+
const dropped = bareName(m[1]);
|
|
1914
|
+
state.tables.delete(dropped);
|
|
1915
|
+
state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
|
|
1609
1916
|
}
|
|
1610
1917
|
}
|
|
1611
1918
|
function parseUniqueIndex(sql, state) {
|
|
1612
|
-
const re =
|
|
1919
|
+
const re = new RegExp(
|
|
1920
|
+
`CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
|
|
1921
|
+
"gi"
|
|
1922
|
+
);
|
|
1613
1923
|
let m;
|
|
1614
1924
|
while ((m = re.exec(sql)) !== null) {
|
|
1615
|
-
const
|
|
1616
|
-
const
|
|
1925
|
+
const tableName = bareName(m[1]);
|
|
1926
|
+
const colName = bareName(m[2]);
|
|
1927
|
+
const table = state.tables.get(tableName);
|
|
1928
|
+
const col = table?.columns.get(colName);
|
|
1617
1929
|
if (col) col.unique = true;
|
|
1618
|
-
if (!state.uniqueIndexes.has(
|
|
1619
|
-
state.uniqueIndexes.get(
|
|
1930
|
+
if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
|
|
1931
|
+
state.uniqueIndexes.get(tableName).add(colName);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
function discoverMigrationFiles(migrationsDir) {
|
|
1935
|
+
if (!(0, import_node_fs7.existsSync)(migrationsDir)) return [];
|
|
1936
|
+
const out = [];
|
|
1937
|
+
const entries = (0, import_node_fs7.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1938
|
+
for (const entry of entries) {
|
|
1939
|
+
if (entry.isDirectory()) {
|
|
1940
|
+
const sqlPath = (0, import_node_path6.join)(migrationsDir, entry.name, "migration.sql");
|
|
1941
|
+
if ((0, import_node_fs7.existsSync)(sqlPath)) out.push(sqlPath);
|
|
1942
|
+
} else if (entry.isFile() && entry.name.endsWith(".sql")) {
|
|
1943
|
+
out.push((0, import_node_path6.join)(migrationsDir, entry.name));
|
|
1944
|
+
}
|
|
1620
1945
|
}
|
|
1946
|
+
return out;
|
|
1621
1947
|
}
|
|
1622
|
-
function parseMigrations(
|
|
1623
|
-
const migrationsDir = (0, import_node_path7.join)(rootDir, "prisma", "migrations");
|
|
1948
|
+
function parseMigrations(migrationsDir) {
|
|
1624
1949
|
const state = {
|
|
1625
1950
|
tables: /* @__PURE__ */ new Map(),
|
|
1626
1951
|
enums: /* @__PURE__ */ new Map(),
|
|
1627
1952
|
fks: [],
|
|
1628
1953
|
uniqueIndexes: /* @__PURE__ */ new Map()
|
|
1629
1954
|
};
|
|
1630
|
-
if (!
|
|
1631
|
-
const
|
|
1632
|
-
for (const dir of dirs) {
|
|
1633
|
-
const sqlPath = (0, import_node_path7.join)(migrationsDir, dir, "migration.sql");
|
|
1634
|
-
if (!(0, import_node_fs7.existsSync)(sqlPath)) continue;
|
|
1955
|
+
if (!migrationsDir) return state;
|
|
1956
|
+
for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
|
|
1635
1957
|
const sql = (0, import_node_fs7.readFileSync)(sqlPath, "utf-8");
|
|
1636
1958
|
parseCreateEnum(sql, state);
|
|
1637
1959
|
parseCreateTable(sql, state);
|
|
@@ -1642,9 +1964,8 @@ function parseMigrations(rootDir) {
|
|
|
1642
1964
|
}
|
|
1643
1965
|
return state;
|
|
1644
1966
|
}
|
|
1645
|
-
function loadPrismaState(
|
|
1646
|
-
|
|
1647
|
-
if (!(0, import_node_fs7.existsSync)(schemaPath)) return null;
|
|
1967
|
+
function loadPrismaState(schemaPath) {
|
|
1968
|
+
if (!schemaPath || !(0, import_node_fs7.existsSync)(schemaPath)) return null;
|
|
1648
1969
|
const content = (0, import_node_fs7.readFileSync)(schemaPath, "utf-8");
|
|
1649
1970
|
const tables = /* @__PURE__ */ new Map();
|
|
1650
1971
|
const enums = /* @__PURE__ */ new Map();
|
|
@@ -1809,14 +2130,28 @@ function verify(sqlState, prisma) {
|
|
|
1809
2130
|
}
|
|
1810
2131
|
return { contradictions, flaggedEdges };
|
|
1811
2132
|
}
|
|
2133
|
+
function migrationsDirFor(rootDir) {
|
|
2134
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2135
|
+
if (!paths) return null;
|
|
2136
|
+
if (paths.dbConfig.kind === "prisma" || paths.dbConfig.kind === "sql-migrations") {
|
|
2137
|
+
return paths.dbConfig.migrationsDir;
|
|
2138
|
+
}
|
|
2139
|
+
return null;
|
|
2140
|
+
}
|
|
2141
|
+
function schemaPathFor(rootDir) {
|
|
2142
|
+
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2143
|
+
if (!paths) return null;
|
|
2144
|
+
return paths.dbConfig.kind === "prisma" ? paths.dbConfig.schemaPath : null;
|
|
2145
|
+
}
|
|
1812
2146
|
function detect3(rootDir) {
|
|
1813
|
-
const
|
|
1814
|
-
if (!
|
|
1815
|
-
return (
|
|
2147
|
+
const dir = migrationsDirFor(rootDir);
|
|
2148
|
+
if (!dir) return false;
|
|
2149
|
+
return discoverMigrationFiles(dir).length > 0;
|
|
1816
2150
|
}
|
|
1817
2151
|
function generate3(rootDir) {
|
|
1818
|
-
const
|
|
1819
|
-
const
|
|
2152
|
+
const migrationsDir = migrationsDirFor(rootDir);
|
|
2153
|
+
const sqlState = parseMigrations(migrationsDir);
|
|
2154
|
+
const prisma = loadPrismaState(schemaPathFor(rootDir));
|
|
1820
2155
|
const prismaTableIds = prisma ? new Set(prisma.tables.keys()) : /* @__PURE__ */ new Set();
|
|
1821
2156
|
const prismaEnumIds = prisma ? new Set(prisma.enums.keys()) : /* @__PURE__ */ new Set();
|
|
1822
2157
|
const nodes = [];
|
|
@@ -1862,7 +2197,7 @@ function generate3(rootDir) {
|
|
|
1862
2197
|
metadata: {
|
|
1863
2198
|
generated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
1864
2199
|
scope: "sql-migrations",
|
|
1865
|
-
source: "
|
|
2200
|
+
source: migrationsDir ?? "none",
|
|
1866
2201
|
layer: "db",
|
|
1867
2202
|
sql_tables: sqlState.tables.size,
|
|
1868
2203
|
sql_enums: sqlState.enums.size,
|
|
@@ -2101,31 +2436,31 @@ var fetchResolverParser = {
|
|
|
2101
2436
|
|
|
2102
2437
|
// src/server/graph/parsers/crosslayer/api-annotations.ts
|
|
2103
2438
|
var import_node_fs8 = require("node:fs");
|
|
2104
|
-
var
|
|
2439
|
+
var import_node_path7 = require("node:path");
|
|
2105
2440
|
var API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
|
|
2106
2441
|
function walk2(dir, exts) {
|
|
2107
2442
|
if (!(0, import_node_fs8.existsSync)(dir)) return [];
|
|
2108
2443
|
const results = [];
|
|
2109
2444
|
for (const entry of (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true })) {
|
|
2110
2445
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2111
|
-
const full = (0,
|
|
2446
|
+
const full = (0, import_node_path7.join)(dir, entry.name);
|
|
2112
2447
|
if (entry.isDirectory()) {
|
|
2113
2448
|
results.push(...walk2(full, exts));
|
|
2114
|
-
} else if (exts.includes((0,
|
|
2449
|
+
} else if (exts.includes((0, import_node_path7.extname)(entry.name))) {
|
|
2115
2450
|
results.push(full);
|
|
2116
2451
|
}
|
|
2117
2452
|
}
|
|
2118
2453
|
return results;
|
|
2119
2454
|
}
|
|
2120
2455
|
function toNodeId2(srcDir, absPath) {
|
|
2121
|
-
return (0,
|
|
2456
|
+
return (0, import_node_path7.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2122
2457
|
}
|
|
2123
2458
|
var apiAnnotationsParser = {
|
|
2124
2459
|
id: "api-annotations",
|
|
2125
2460
|
layer: "crosslayer",
|
|
2126
2461
|
concern: "api-binding",
|
|
2127
2462
|
detect(rootDir) {
|
|
2128
|
-
return (0, import_node_fs8.existsSync)((0,
|
|
2463
|
+
return (0, import_node_fs8.existsSync)((0, import_node_path7.join)(rootDir, "src"));
|
|
2129
2464
|
},
|
|
2130
2465
|
generate(rootDir, layerOutputs) {
|
|
2131
2466
|
const apiOutput = layerOutputs.get("api");
|
|
@@ -2136,7 +2471,7 @@ var apiAnnotationsParser = {
|
|
|
2136
2471
|
const uiNodeIds = new Set(uiOutput?.nodes.map((n) => n.id) ?? []);
|
|
2137
2472
|
const apiRoutes = loadApiRoutesFromOutput(apiOutput);
|
|
2138
2473
|
const apiPathMap = buildApiPathMap(apiRoutes);
|
|
2139
|
-
const srcDir = (0,
|
|
2474
|
+
const srcDir = (0, import_node_path7.join)(rootDir, "src");
|
|
2140
2475
|
const files = walk2(srcDir, [".ts", ".tsx"]);
|
|
2141
2476
|
const crossRefs = [];
|
|
2142
2477
|
const flaggedEdges = [];
|
|
@@ -2187,7 +2522,7 @@ var apiAnnotationsParser = {
|
|
|
2187
2522
|
|
|
2188
2523
|
// src/server/graph/parsers/crosslayer/url-literal-scanner.ts
|
|
2189
2524
|
var import_node_fs9 = require("node:fs");
|
|
2190
|
-
var
|
|
2525
|
+
var import_node_path8 = require("node:path");
|
|
2191
2526
|
init_config();
|
|
2192
2527
|
var URL_LITERAL_RE = /['"`](\/api\/[^'"`\s]+?)['"`]/g;
|
|
2193
2528
|
function walk3(dir, exts) {
|
|
@@ -2195,17 +2530,17 @@ function walk3(dir, exts) {
|
|
|
2195
2530
|
const results = [];
|
|
2196
2531
|
for (const entry of (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true })) {
|
|
2197
2532
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2198
|
-
const full = (0,
|
|
2533
|
+
const full = (0, import_node_path8.join)(dir, entry.name);
|
|
2199
2534
|
if (entry.isDirectory()) {
|
|
2200
2535
|
results.push(...walk3(full, exts));
|
|
2201
|
-
} else if (exts.includes((0,
|
|
2536
|
+
} else if (exts.includes((0, import_node_path8.extname)(entry.name))) {
|
|
2202
2537
|
results.push(full);
|
|
2203
2538
|
}
|
|
2204
2539
|
}
|
|
2205
2540
|
return results;
|
|
2206
2541
|
}
|
|
2207
2542
|
function toNodeId3(srcDir, absPath) {
|
|
2208
|
-
return (0,
|
|
2543
|
+
return (0, import_node_path8.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2209
2544
|
}
|
|
2210
2545
|
var urlLiteralScannerParser = {
|
|
2211
2546
|
id: "url-literal-scanner",
|
|
@@ -2226,7 +2561,7 @@ var urlLiteralScannerParser = {
|
|
|
2226
2561
|
const apiPathMap = buildApiPathMap(apiRoutes);
|
|
2227
2562
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
2228
2563
|
const srcDir = paths.srcDir;
|
|
2229
|
-
const clientDir = (0,
|
|
2564
|
+
const clientDir = (0, import_node_path8.join)(srcDir, "client");
|
|
2230
2565
|
const files = [
|
|
2231
2566
|
...walk3(clientDir, [".ts", ".tsx"]),
|
|
2232
2567
|
...walk3(paths.appDir, [".ts", ".tsx"])
|
|
@@ -2268,7 +2603,7 @@ var urlLiteralScannerParser = {
|
|
|
2268
2603
|
|
|
2269
2604
|
// src/server/graph/parsers/static/static-values.ts
|
|
2270
2605
|
var import_node_fs10 = require("node:fs");
|
|
2271
|
-
var
|
|
2606
|
+
var import_node_path9 = require("node:path");
|
|
2272
2607
|
var parseCode = null;
|
|
2273
2608
|
function tryLoadTreeSitter() {
|
|
2274
2609
|
if (parseCode) return true;
|
|
@@ -2301,8 +2636,8 @@ function extractEnumValues(rootDir) {
|
|
|
2301
2636
|
const nodes = [];
|
|
2302
2637
|
const edges = [];
|
|
2303
2638
|
const schemaPaths = [
|
|
2304
|
-
(0,
|
|
2305
|
-
(0,
|
|
2639
|
+
(0, import_node_path9.join)(rootDir, "prisma", "schema.prisma"),
|
|
2640
|
+
(0, import_node_path9.join)(rootDir, "prisma", "schema")
|
|
2306
2641
|
];
|
|
2307
2642
|
let content = "";
|
|
2308
2643
|
for (const p of schemaPaths) {
|
|
@@ -2313,7 +2648,7 @@ function extractEnumValues(rootDir) {
|
|
|
2313
2648
|
content = (0, import_node_fs10.readFileSync)(p, "utf-8");
|
|
2314
2649
|
} else if (stat.isDirectory()) {
|
|
2315
2650
|
const files = (0, import_node_fs10.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
|
|
2316
|
-
content = files.map((f) => (0, import_node_fs10.readFileSync)((0,
|
|
2651
|
+
content = files.map((f) => (0, import_node_fs10.readFileSync)((0, import_node_path9.join)(p, f), "utf-8")).join("\n");
|
|
2317
2652
|
}
|
|
2318
2653
|
} catch {
|
|
2319
2654
|
continue;
|
|
@@ -2469,14 +2804,14 @@ function extractSeedData(rootDir) {
|
|
|
2469
2804
|
const nodes = [];
|
|
2470
2805
|
const edges = [];
|
|
2471
2806
|
const seedFiles = [
|
|
2472
|
-
(0,
|
|
2473
|
-
(0,
|
|
2474
|
-
(0,
|
|
2807
|
+
(0, import_node_path9.join)(rootDir, "prisma", "seed.ts"),
|
|
2808
|
+
(0, import_node_path9.join)(rootDir, "prisma", "seed.js"),
|
|
2809
|
+
(0, import_node_path9.join)(rootDir, "src", "server", "lib", "system-tags.ts")
|
|
2475
2810
|
].filter(import_node_fs10.existsSync);
|
|
2476
2811
|
const useTreeSitter = tryLoadTreeSitter();
|
|
2477
2812
|
for (const filePath of seedFiles) {
|
|
2478
2813
|
const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
|
|
2479
|
-
const relPath = (0,
|
|
2814
|
+
const relPath = (0, import_node_path9.relative)(rootDir, filePath);
|
|
2480
2815
|
const seeded = detectSeededArrays(content, relPath);
|
|
2481
2816
|
let astRoot = null;
|
|
2482
2817
|
if (useTreeSitter && parseCode) {
|
|
@@ -2574,7 +2909,7 @@ function walkDir(dir, exts) {
|
|
|
2574
2909
|
const results = [];
|
|
2575
2910
|
for (const entry of (0, import_node_fs10.readdirSync)(dir, { withFileTypes: true })) {
|
|
2576
2911
|
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
|
|
2577
|
-
const full = (0,
|
|
2912
|
+
const full = (0, import_node_path9.join)(dir, entry.name);
|
|
2578
2913
|
if (entry.isDirectory()) results.push(...walkDir(full, exts));
|
|
2579
2914
|
else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
|
|
2580
2915
|
}
|
|
@@ -2582,11 +2917,11 @@ function walkDir(dir, exts) {
|
|
|
2582
2917
|
}
|
|
2583
2918
|
function extractConstants(rootDir) {
|
|
2584
2919
|
const nodes = [];
|
|
2585
|
-
const srcDir = (0,
|
|
2920
|
+
const srcDir = (0, import_node_path9.join)(rootDir, "src");
|
|
2586
2921
|
if (!(0, import_node_fs10.existsSync)(srcDir)) return { nodes };
|
|
2587
2922
|
for (const filePath of walkDir(srcDir, [".ts", ".tsx"])) {
|
|
2588
2923
|
const content = (0, import_node_fs10.readFileSync)(filePath, "utf-8");
|
|
2589
|
-
const relPath = (0,
|
|
2924
|
+
const relPath = (0, import_node_path9.relative)(rootDir, filePath);
|
|
2590
2925
|
const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
|
|
2591
2926
|
let cm;
|
|
2592
2927
|
while ((cm = constArrayRe.exec(content)) !== null) {
|
|
@@ -2619,7 +2954,7 @@ function extractConstants(rootDir) {
|
|
|
2619
2954
|
return { nodes };
|
|
2620
2955
|
}
|
|
2621
2956
|
function detect4(rootDir) {
|
|
2622
|
-
return (0, import_node_fs10.existsSync)((0,
|
|
2957
|
+
return (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs10.existsSync)((0, import_node_path9.join)(rootDir, "prisma", "seed.ts"));
|
|
2623
2958
|
}
|
|
2624
2959
|
function generate4(rootDir) {
|
|
2625
2960
|
const enumResult = extractEnumValues(rootDir);
|
|
@@ -2695,7 +3030,7 @@ var staticValuesParser = {
|
|
|
2695
3030
|
|
|
2696
3031
|
// src/server/graph/parsers/crosslayer/static-ref-scanner.ts
|
|
2697
3032
|
var import_node_fs11 = require("node:fs");
|
|
2698
|
-
var
|
|
3033
|
+
var import_node_path10 = require("node:path");
|
|
2699
3034
|
init_config();
|
|
2700
3035
|
var MIN_VALUE_LENGTH = 4;
|
|
2701
3036
|
var SKIP_VALUES = /* @__PURE__ */ new Set([
|
|
@@ -2839,11 +3174,11 @@ var staticRefScannerParser = {
|
|
|
2839
3174
|
if (!paths) return { cross_refs: [], flagged_edges: [], warnings: [] };
|
|
2840
3175
|
const srcDir = paths.srcDir;
|
|
2841
3176
|
const files = [
|
|
2842
|
-
...walkWithIgnore((0,
|
|
3177
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "client"), [".ts", ".tsx"]),
|
|
2843
3178
|
...walkWithIgnore(paths.appDir, [".ts", ".tsx"]),
|
|
2844
|
-
...walkWithIgnore((0,
|
|
2845
|
-
...walkWithIgnore((0,
|
|
2846
|
-
...walkWithIgnore((0,
|
|
3179
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "server"), [".ts", ".tsx"]),
|
|
3180
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "lib"), [".ts", ".tsx"]),
|
|
3181
|
+
...walkWithIgnore((0, import_node_path10.join)(srcDir, "config"), [".ts", ".tsx"])
|
|
2847
3182
|
];
|
|
2848
3183
|
const uiOutput = layerOutputs.get("ui");
|
|
2849
3184
|
const apiOutput = layerOutputs.get("api");
|
|
@@ -2861,7 +3196,7 @@ var staticRefScannerParser = {
|
|
|
2861
3196
|
const seen = /* @__PURE__ */ new Set();
|
|
2862
3197
|
let filesScanned = 0;
|
|
2863
3198
|
for (const absPath of files) {
|
|
2864
|
-
const sourceId = (0,
|
|
3199
|
+
const sourceId = (0, import_node_path10.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
2865
3200
|
const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
|
|
2866
3201
|
if (!sourceLayer) continue;
|
|
2867
3202
|
const content = (0, import_node_fs11.readFileSync)(absPath, "utf-8");
|
|
@@ -2980,7 +3315,7 @@ function registerBuiltins(registry, disabled) {
|
|
|
2980
3315
|
function loadCustomParsers(registry, config, rootDir, disabled) {
|
|
2981
3316
|
for (const entry of config.parsers?.custom ?? []) {
|
|
2982
3317
|
try {
|
|
2983
|
-
const absPath = (0,
|
|
3318
|
+
const absPath = (0, import_node_path11.resolve)(rootDir, entry.path);
|
|
2984
3319
|
const mod = require(absPath);
|
|
2985
3320
|
const parser = "default" in mod ? mod.default : mod;
|
|
2986
3321
|
if (disabled.has(parser.id)) continue;
|
|
@@ -3110,7 +3445,7 @@ function applyCrossLayerResults(uiOutput, results) {
|
|
|
3110
3445
|
|
|
3111
3446
|
// src/server/graph/core/graph-builder.ts
|
|
3112
3447
|
function readGraphFromDisk(rootDir, layer) {
|
|
3113
|
-
const filePath = (0,
|
|
3448
|
+
const filePath = (0, import_node_path12.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
|
|
3114
3449
|
if (!(0, import_node_fs12.existsSync)(filePath)) return null;
|
|
3115
3450
|
try {
|
|
3116
3451
|
return JSON.parse((0, import_node_fs12.readFileSync)(filePath, "utf-8"));
|
|
@@ -3214,11 +3549,11 @@ function generateAll(rootDir) {
|
|
|
3214
3549
|
init_config();
|
|
3215
3550
|
|
|
3216
3551
|
// src/server/graph/core/tagger-registry.ts
|
|
3217
|
-
var
|
|
3552
|
+
var import_node_path14 = require("node:path");
|
|
3218
3553
|
|
|
3219
3554
|
// src/server/graph/taggers/module-tagger.ts
|
|
3220
3555
|
var import_node_fs13 = require("node:fs");
|
|
3221
|
-
var
|
|
3556
|
+
var import_node_path13 = require("node:path");
|
|
3222
3557
|
function matchGlob(pattern, id) {
|
|
3223
3558
|
const patParts = pattern.split("/");
|
|
3224
3559
|
const idParts = id.split("/");
|
|
@@ -3251,13 +3586,13 @@ function detectConventionDirs(rootDir, extraConventionDirs = []) {
|
|
|
3251
3586
|
const conventionDirs = [...CONVENTION_DIRS_BUILTIN, ...extraConventionDirs];
|
|
3252
3587
|
const searchDirs = [
|
|
3253
3588
|
rootDir,
|
|
3254
|
-
(0,
|
|
3255
|
-
(0,
|
|
3256
|
-
(0,
|
|
3589
|
+
(0, import_node_path13.join)(rootDir, "src"),
|
|
3590
|
+
(0, import_node_path13.join)(rootDir, "app"),
|
|
3591
|
+
(0, import_node_path13.join)(rootDir, "lib")
|
|
3257
3592
|
];
|
|
3258
3593
|
for (const base of searchDirs) {
|
|
3259
3594
|
for (const convention of conventionDirs) {
|
|
3260
|
-
const dir = (0,
|
|
3595
|
+
const dir = (0, import_node_path13.join)(base, convention);
|
|
3261
3596
|
if (!(0, import_node_fs13.existsSync)(dir)) continue;
|
|
3262
3597
|
try {
|
|
3263
3598
|
const stat = (0, import_node_fs13.statSync)(dir);
|
|
@@ -3556,7 +3891,7 @@ function loadCustomTaggers(registry, config, rootDir, disabled) {
|
|
|
3556
3891
|
for (const entry of config.taggers?.custom ?? []) {
|
|
3557
3892
|
if (disabled.has(entry.id)) continue;
|
|
3558
3893
|
try {
|
|
3559
|
-
const absPath = (0,
|
|
3894
|
+
const absPath = (0, import_node_path14.resolve)(rootDir, entry.path);
|
|
3560
3895
|
const mod = require(absPath);
|
|
3561
3896
|
const tagger = "default" in mod ? mod.default : mod;
|
|
3562
3897
|
const override = config.taggers?.trackUntagged?.[tagger.id];
|
|
@@ -3580,12 +3915,12 @@ function createTaggerRegistry(config, rootDir) {
|
|
|
3580
3915
|
|
|
3581
3916
|
// src/server/graph/core/tag-store.ts
|
|
3582
3917
|
var import_node_fs14 = require("node:fs");
|
|
3583
|
-
var
|
|
3918
|
+
var import_node_path15 = require("node:path");
|
|
3584
3919
|
var TAGS_FILENAME = "tags.json";
|
|
3585
3920
|
var GRAPHS_DIR = ".launchsecure/graphs";
|
|
3586
3921
|
var tagCache = /* @__PURE__ */ new Map();
|
|
3587
3922
|
function tagsFilePath(rootDir) {
|
|
3588
|
-
return (0,
|
|
3923
|
+
return (0, import_node_path15.join)(rootDir, GRAPHS_DIR, TAGS_FILENAME);
|
|
3589
3924
|
}
|
|
3590
3925
|
function readTagStore(rootDir) {
|
|
3591
3926
|
const filePath = tagsFilePath(rootDir);
|
|
@@ -3606,7 +3941,7 @@ function readTagStore(rootDir) {
|
|
|
3606
3941
|
}
|
|
3607
3942
|
function writeTagStore(rootDir, store) {
|
|
3608
3943
|
const filePath = tagsFilePath(rootDir);
|
|
3609
|
-
const dir = (0,
|
|
3944
|
+
const dir = (0, import_node_path15.dirname)(filePath);
|
|
3610
3945
|
(0, import_node_fs14.mkdirSync)(dir, { recursive: true });
|
|
3611
3946
|
const cleaned = {};
|
|
3612
3947
|
for (const [nodeId, tags] of Object.entries(store)) {
|
|
@@ -3637,20 +3972,20 @@ function removeTag(rootDir, nodeId, key) {
|
|
|
3637
3972
|
init_ts_extractor();
|
|
3638
3973
|
var GRAPHS_DIR2 = ".launchsecure/graphs";
|
|
3639
3974
|
function getAvailableLayers(rootDir) {
|
|
3640
|
-
const dir = (0,
|
|
3975
|
+
const dir = (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
|
|
3641
3976
|
if (!(0, import_node_fs15.existsSync)(dir)) return [];
|
|
3642
3977
|
return (0, import_node_fs15.readdirSync)(dir).filter((f) => f.endsWith(".json") && f !== "tags.json").map((f) => f.replace(".json", ""));
|
|
3643
3978
|
}
|
|
3644
3979
|
var graphCache = /* @__PURE__ */ new Map();
|
|
3645
3980
|
var taggedCache = /* @__PURE__ */ new Map();
|
|
3646
3981
|
function graphsDir(rootDir) {
|
|
3647
|
-
return (0,
|
|
3982
|
+
return (0, import_node_path16.join)(rootDir, GRAPHS_DIR2);
|
|
3648
3983
|
}
|
|
3649
3984
|
function graphFilePath(rootDir, layer) {
|
|
3650
|
-
return (0,
|
|
3985
|
+
return (0, import_node_path16.join)(graphsDir(rootDir), `${layer}.json`);
|
|
3651
3986
|
}
|
|
3652
3987
|
function tagsFilePath2(rootDir) {
|
|
3653
|
-
return (0,
|
|
3988
|
+
return (0, import_node_path16.join)(graphsDir(rootDir), "tags.json");
|
|
3654
3989
|
}
|
|
3655
3990
|
function getMtimeMs(filePath) {
|
|
3656
3991
|
if (!(0, import_node_fs15.existsSync)(filePath)) return 0;
|
|
@@ -3751,15 +4086,15 @@ async function generateGraph(rootDir, layer) {
|
|
|
3751
4086
|
var import_node_child_process = require("node:child_process");
|
|
3752
4087
|
var import_node_fs16 = require("node:fs");
|
|
3753
4088
|
var import_node_os = require("node:os");
|
|
3754
|
-
var
|
|
4089
|
+
var import_node_path17 = require("node:path");
|
|
3755
4090
|
function lockDir(projectRoot) {
|
|
3756
4091
|
if (projectRoot) {
|
|
3757
|
-
return (0,
|
|
4092
|
+
return (0, import_node_path17.join)(projectRoot, ".launchsecure");
|
|
3758
4093
|
}
|
|
3759
|
-
return (0,
|
|
4094
|
+
return (0, import_node_path17.join)((0, import_node_os.homedir)(), ".launchsecure");
|
|
3760
4095
|
}
|
|
3761
4096
|
function lockPath(projectRoot) {
|
|
3762
|
-
return (0,
|
|
4097
|
+
return (0, import_node_path17.join)(lockDir(projectRoot), "launch-chart.lock");
|
|
3763
4098
|
}
|
|
3764
4099
|
var _activeProjectRoot;
|
|
3765
4100
|
function readLock(projectRoot) {
|
|
@@ -3844,9 +4179,9 @@ init_config();
|
|
|
3844
4179
|
|
|
3845
4180
|
// src/server/graph/core/audit-core.ts
|
|
3846
4181
|
var import_node_fs17 = require("node:fs");
|
|
3847
|
-
var
|
|
4182
|
+
var import_node_path18 = require("node:path");
|
|
3848
4183
|
function readGraphFile(rootDir, layer) {
|
|
3849
|
-
const filePath = (0,
|
|
4184
|
+
const filePath = (0, import_node_path18.join)(rootDir, ".launchsecure", "graphs", `${layer}.json`);
|
|
3850
4185
|
if (!(0, import_node_fs17.existsSync)(filePath)) return null;
|
|
3851
4186
|
try {
|
|
3852
4187
|
return JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
|
|
@@ -3893,7 +4228,7 @@ function checkUnprotectedRoutes(rootDir) {
|
|
|
3893
4228
|
const api = readGraphFile(rootDir, "api");
|
|
3894
4229
|
const staticGraph = readGraphFile(rootDir, "static");
|
|
3895
4230
|
if (!api) return buildReport("api", "unprotected_routes", findings);
|
|
3896
|
-
const routePermsPath = (0,
|
|
4231
|
+
const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
3897
4232
|
let routePermsContent = "";
|
|
3898
4233
|
if ((0, import_node_fs17.existsSync)(routePermsPath)) {
|
|
3899
4234
|
routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
|
|
@@ -3973,7 +4308,7 @@ function checkUnenforcedPermissions(rootDir) {
|
|
|
3973
4308
|
const staticGraph = readGraphFile(rootDir, "static");
|
|
3974
4309
|
if (!staticGraph) return buildReport("static", "unenforced_permissions", findings);
|
|
3975
4310
|
const permissions = staticGraph.nodes.filter((n) => n.type === "seed_permission").map((n) => ({ id: n.id, key: n.value, name: n.name }));
|
|
3976
|
-
const routePermsPath = (0,
|
|
4311
|
+
const routePermsPath = (0, import_node_path18.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
3977
4312
|
let routePermsContent = "";
|
|
3978
4313
|
if ((0, import_node_fs17.existsSync)(routePermsPath)) {
|
|
3979
4314
|
routePermsContent = (0, import_node_fs17.readFileSync)(routePermsPath, "utf-8");
|
|
@@ -4006,7 +4341,7 @@ function checkHardcodedValues(rootDir) {
|
|
|
4006
4341
|
const seen = /* @__PURE__ */ new Set();
|
|
4007
4342
|
for (const node of api.nodes) {
|
|
4008
4343
|
if (node.type !== "endpoint") continue;
|
|
4009
|
-
const filePath = (0,
|
|
4344
|
+
const filePath = (0, import_node_path18.join)(rootDir, "src", node.id);
|
|
4010
4345
|
if (!(0, import_node_fs17.existsSync)(filePath)) continue;
|
|
4011
4346
|
const content = (0, import_node_fs17.readFileSync)(filePath, "utf-8");
|
|
4012
4347
|
let m;
|
|
@@ -4138,16 +4473,16 @@ var MIME_TYPES = {
|
|
|
4138
4473
|
function findProjectRoot(startDir) {
|
|
4139
4474
|
let dir = startDir;
|
|
4140
4475
|
for (let i = 0; i < 8; i++) {
|
|
4141
|
-
const graphsDir2 =
|
|
4142
|
-
if (import_node_fs18.default.existsSync(
|
|
4143
|
-
const parent =
|
|
4476
|
+
const graphsDir2 = import_node_path19.default.join(dir, ".launchsecure", "graphs");
|
|
4477
|
+
if (import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "ui.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "api.json")) || import_node_fs18.default.existsSync(import_node_path19.default.join(graphsDir2, "db.json"))) return dir;
|
|
4478
|
+
const parent = import_node_path19.default.dirname(dir);
|
|
4144
4479
|
if (parent === dir) break;
|
|
4145
4480
|
dir = parent;
|
|
4146
4481
|
}
|
|
4147
4482
|
dir = startDir;
|
|
4148
4483
|
for (let i = 0; i < 8; i++) {
|
|
4149
|
-
if (import_node_fs18.default.existsSync(
|
|
4150
|
-
const parent =
|
|
4484
|
+
if (import_node_fs18.default.existsSync(import_node_path19.default.join(dir, ".git"))) return dir;
|
|
4485
|
+
const parent = import_node_path19.default.dirname(dir);
|
|
4151
4486
|
if (parent === dir) break;
|
|
4152
4487
|
dir = parent;
|
|
4153
4488
|
}
|
|
@@ -4156,7 +4491,7 @@ function findProjectRoot(startDir) {
|
|
|
4156
4491
|
function resolveRequestRoot(url, monorepoRoot, projects) {
|
|
4157
4492
|
const projectParam = url.searchParams.get("project");
|
|
4158
4493
|
if (!projectParam || projects.length === 0) return monorepoRoot;
|
|
4159
|
-
const resolved =
|
|
4494
|
+
const resolved = import_node_path19.default.resolve(monorepoRoot, projectParam);
|
|
4160
4495
|
if (!resolved.startsWith(monorepoRoot)) {
|
|
4161
4496
|
throw new Error("Project path outside monorepo root");
|
|
4162
4497
|
}
|
|
@@ -4208,14 +4543,14 @@ async function buildMergedGraph(root) {
|
|
|
4208
4543
|
}
|
|
4209
4544
|
function serveStatic(res, filePath) {
|
|
4210
4545
|
if (!import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) return false;
|
|
4211
|
-
const ext =
|
|
4546
|
+
const ext = import_node_path19.default.extname(filePath).toLowerCase();
|
|
4212
4547
|
const mime = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
4213
4548
|
res.writeHead(200, { "Content-Type": mime, "Cache-Control": "no-cache" });
|
|
4214
4549
|
import_node_fs18.default.createReadStream(filePath).pipe(res);
|
|
4215
4550
|
return true;
|
|
4216
4551
|
}
|
|
4217
4552
|
function serveIndex(res, clientDir) {
|
|
4218
|
-
const indexPath =
|
|
4553
|
+
const indexPath = import_node_path19.default.join(clientDir, "index.html");
|
|
4219
4554
|
if (!import_node_fs18.default.existsSync(indexPath)) {
|
|
4220
4555
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
4221
4556
|
res.end(`LaunchChart client bundle not found at ${clientDir}. Run 'npm run build:chart-client'.`);
|
|
@@ -4224,14 +4559,14 @@ function serveIndex(res, clientDir) {
|
|
|
4224
4559
|
serveStatic(res, indexPath);
|
|
4225
4560
|
}
|
|
4226
4561
|
function tryListen(server, port) {
|
|
4227
|
-
return new Promise((
|
|
4562
|
+
return new Promise((resolve4, reject) => {
|
|
4228
4563
|
const onError = (err) => {
|
|
4229
4564
|
server.off("listening", onListening);
|
|
4230
4565
|
reject(err);
|
|
4231
4566
|
};
|
|
4232
4567
|
const onListening = () => {
|
|
4233
4568
|
server.off("error", onError);
|
|
4234
|
-
|
|
4569
|
+
resolve4(port);
|
|
4235
4570
|
};
|
|
4236
4571
|
server.once("error", onError);
|
|
4237
4572
|
server.once("listening", onListening);
|
|
@@ -4268,7 +4603,7 @@ async function startChartServer(opts = {}) {
|
|
|
4268
4603
|
}
|
|
4269
4604
|
return { port: existing.port, url: existing.url };
|
|
4270
4605
|
}
|
|
4271
|
-
const clientDir = opts.clientDir ??
|
|
4606
|
+
const clientDir = opts.clientDir ?? import_node_path19.default.join(__dirname, "..", "chart-client");
|
|
4272
4607
|
const rootConfig = loadConfig(projectRoot);
|
|
4273
4608
|
const projects = rootConfig.projects ?? [];
|
|
4274
4609
|
const server = import_node_http.default.createServer((req, res) => {
|
|
@@ -4284,11 +4619,11 @@ async function startChartServer(opts = {}) {
|
|
|
4284
4619
|
}
|
|
4285
4620
|
if (req.method === "GET" && url2.pathname === "/api/projects") {
|
|
4286
4621
|
const projectList = projects.length > 0 ? projects.map((p) => {
|
|
4287
|
-
const absRoot =
|
|
4288
|
-
const hasGraphs = import_node_fs18.default.existsSync(
|
|
4289
|
-
const hasNextConfig = import_node_fs18.default.existsSync(
|
|
4622
|
+
const absRoot = import_node_path19.default.resolve(projectRoot, p.root);
|
|
4623
|
+
const hasGraphs = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, ".launchsecure", "graphs"));
|
|
4624
|
+
const hasNextConfig = import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.ts")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.js")) || import_node_fs18.default.existsSync(import_node_path19.default.join(absRoot, "next.config.mjs"));
|
|
4290
4625
|
return { name: p.name, root: p.root, hasGraphs, hasNextConfig };
|
|
4291
|
-
}) : [{ name:
|
|
4626
|
+
}) : [{ name: import_node_path19.default.basename(projectRoot), root: ".", hasGraphs: import_node_fs18.default.existsSync(import_node_path19.default.join(projectRoot, ".launchsecure", "graphs")), hasNextConfig: true }];
|
|
4292
4627
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4293
4628
|
res.end(JSON.stringify({ projects: projectList, monorepoRoot: projectRoot }));
|
|
4294
4629
|
return;
|
|
@@ -4334,18 +4669,18 @@ async function startChartServer(opts = {}) {
|
|
|
4334
4669
|
}
|
|
4335
4670
|
if (req.method === "GET" && url2.pathname === "/api/file-content") {
|
|
4336
4671
|
const relPath = url2.searchParams.get("path");
|
|
4337
|
-
if (!relPath || relPath.includes("..") ||
|
|
4672
|
+
if (!relPath || relPath.includes("..") || import_node_path19.default.isAbsolute(relPath)) {
|
|
4338
4673
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
4339
4674
|
res.end(JSON.stringify({ error: "Invalid path" }));
|
|
4340
4675
|
return;
|
|
4341
4676
|
}
|
|
4342
|
-
const filePath =
|
|
4677
|
+
const filePath = import_node_path19.default.join(reqRoot, relPath);
|
|
4343
4678
|
if (!filePath.startsWith(reqRoot) || !import_node_fs18.default.existsSync(filePath) || !import_node_fs18.default.statSync(filePath).isFile()) {
|
|
4344
4679
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
4345
4680
|
res.end(JSON.stringify({ error: "File not found" }));
|
|
4346
4681
|
return;
|
|
4347
4682
|
}
|
|
4348
|
-
const ext =
|
|
4683
|
+
const ext = import_node_path19.default.extname(filePath).toLowerCase();
|
|
4349
4684
|
const langMap = { ".ts": "typescript", ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", ".prisma": "prisma", ".json": "json", ".css": "css" };
|
|
4350
4685
|
const content = import_node_fs18.default.readFileSync(filePath, "utf-8");
|
|
4351
4686
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -4389,7 +4724,7 @@ async function startChartServer(opts = {}) {
|
|
|
4389
4724
|
req.on("end", () => {
|
|
4390
4725
|
try {
|
|
4391
4726
|
const newConfig = JSON.parse(body);
|
|
4392
|
-
const configPath =
|
|
4727
|
+
const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
|
|
4393
4728
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(newConfig, null, 2) + "\n", "utf-8");
|
|
4394
4729
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4395
4730
|
res.end(JSON.stringify({ ok: true }));
|
|
@@ -4423,7 +4758,7 @@ async function startChartServer(opts = {}) {
|
|
|
4423
4758
|
const taggerConfig = JSON.parse(body);
|
|
4424
4759
|
const config2 = loadConfig(reqRoot);
|
|
4425
4760
|
config2.taggers = taggerConfig;
|
|
4426
|
-
const configPath =
|
|
4761
|
+
const configPath = import_node_path19.default.join(reqRoot, ".launchchart.json");
|
|
4427
4762
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
4428
4763
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4429
4764
|
res.end(JSON.stringify({ ok: true }));
|
|
@@ -4491,16 +4826,23 @@ async function startChartServer(opts = {}) {
|
|
|
4491
4826
|
const paths = resolveProjectPaths(reqRoot, config2);
|
|
4492
4827
|
const overrides = {
|
|
4493
4828
|
appDir: !!config2.paths?.appDir,
|
|
4494
|
-
dbDir: !!config2.paths?.dbDir
|
|
4829
|
+
dbDir: !!config2.paths?.dbDir,
|
|
4830
|
+
srcRoots: !!(config2.paths?.srcRoots && config2.paths.srcRoots.length > 0)
|
|
4495
4831
|
};
|
|
4832
|
+
const relFromRoot = (abs) => import_node_path19.default.relative(reqRoot, abs) || ".";
|
|
4496
4833
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4497
4834
|
res.end(JSON.stringify({
|
|
4498
4835
|
projectRoot: reqRoot,
|
|
4499
4836
|
detected: paths ? {
|
|
4500
|
-
srcDir:
|
|
4501
|
-
appDir:
|
|
4502
|
-
apiDir:
|
|
4503
|
-
dbDir: paths.dbDir ?
|
|
4837
|
+
srcDir: relFromRoot(paths.srcDir),
|
|
4838
|
+
appDir: relFromRoot(paths.appDir),
|
|
4839
|
+
apiDir: relFromRoot(paths.apiDir),
|
|
4840
|
+
dbDir: paths.dbDir ? relFromRoot(paths.dbDir) : null,
|
|
4841
|
+
dbKind: paths.dbConfig.kind,
|
|
4842
|
+
dbSchemaPath: paths.dbConfig.schemaPath ? relFromRoot(paths.dbConfig.schemaPath) : null,
|
|
4843
|
+
dbMigrationsDir: paths.dbConfig.migrationsDir ? relFromRoot(paths.dbConfig.migrationsDir) : null,
|
|
4844
|
+
srcRoots: paths.srcRoots.map(relFromRoot),
|
|
4845
|
+
conventionFiles: paths.conventionFiles.map(relFromRoot)
|
|
4504
4846
|
} : null,
|
|
4505
4847
|
overrides,
|
|
4506
4848
|
isOverride: overrides.appDir
|
|
@@ -4509,8 +4851,8 @@ async function startChartServer(opts = {}) {
|
|
|
4509
4851
|
}
|
|
4510
4852
|
if (req.method === "GET" && url2.pathname === "/api/browse-dir") {
|
|
4511
4853
|
const browsePath = url2.searchParams.get("path") || projectRoot;
|
|
4512
|
-
const abs =
|
|
4513
|
-
const twoUp =
|
|
4854
|
+
const abs = import_node_path19.default.resolve(browsePath);
|
|
4855
|
+
const twoUp = import_node_path19.default.resolve(projectRoot, "..", "..");
|
|
4514
4856
|
if (!abs.startsWith(twoUp)) {
|
|
4515
4857
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
4516
4858
|
res.end(JSON.stringify({ ok: false, error: "Path outside allowed range" }));
|
|
@@ -4519,9 +4861,9 @@ async function startChartServer(opts = {}) {
|
|
|
4519
4861
|
try {
|
|
4520
4862
|
const entries = import_node_fs18.default.readdirSync(abs, { withFileTypes: true });
|
|
4521
4863
|
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist" && e.name !== ".next").map((e) => e.name).sort();
|
|
4522
|
-
const parent = abs !== twoUp ?
|
|
4864
|
+
const parent = abs !== twoUp ? import_node_path19.default.dirname(abs) : null;
|
|
4523
4865
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4524
|
-
res.end(JSON.stringify({ current: abs, parent, dirs, relative:
|
|
4866
|
+
res.end(JSON.stringify({ current: abs, parent, dirs, relative: import_node_path19.default.relative(projectRoot, abs) || "." }));
|
|
4525
4867
|
} catch (err) {
|
|
4526
4868
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
4527
4869
|
res.end(JSON.stringify({ ok: false, error: String(err) }));
|
|
@@ -4547,7 +4889,7 @@ async function startChartServer(opts = {}) {
|
|
|
4547
4889
|
const { projects: newProjects } = JSON.parse(body);
|
|
4548
4890
|
const config2 = loadConfig(projectRoot);
|
|
4549
4891
|
config2.projects = newProjects.length > 0 ? newProjects : void 0;
|
|
4550
|
-
const configPath =
|
|
4892
|
+
const configPath = import_node_path19.default.join(projectRoot, ".launchchart.json");
|
|
4551
4893
|
import_node_fs18.default.writeFileSync(configPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
4552
4894
|
projects.length = 0;
|
|
4553
4895
|
if (config2.projects) projects.push(...config2.projects);
|
|
@@ -4561,7 +4903,7 @@ async function startChartServer(opts = {}) {
|
|
|
4561
4903
|
return;
|
|
4562
4904
|
}
|
|
4563
4905
|
if (url2.pathname !== "/") {
|
|
4564
|
-
const staticPath =
|
|
4906
|
+
const staticPath = import_node_path19.default.join(clientDir, url2.pathname);
|
|
4565
4907
|
if (serveStatic(res, staticPath)) return;
|
|
4566
4908
|
}
|
|
4567
4909
|
serveIndex(res, clientDir);
|