@launchsecure/launch-kit 0.0.29 → 0.0.30
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/beacon/beacon.mjs +2759 -1246
- package/dist/beacon/beacon.mjs.map +1 -1
- package/dist/beacon/beacon.umd.js +710 -95
- package/dist/beacon/beacon.umd.js.map +1 -1
- package/dist/beacon/types/core.d.ts +14 -0
- package/dist/beacon/types/core.d.ts.map +1 -0
- package/dist/beacon/types/ctx.d.ts +14 -0
- package/dist/beacon/types/ctx.d.ts.map +1 -0
- package/dist/beacon/types/element.d.ts +16 -48
- package/dist/beacon/types/element.d.ts.map +1 -1
- package/dist/beacon/types/index.d.ts +5 -4
- package/dist/beacon/types/index.d.ts.map +1 -1
- package/dist/beacon/types/internal/annotation-cache.d.ts +10 -0
- package/dist/beacon/types/internal/annotation-cache.d.ts.map +1 -0
- package/dist/beacon/types/internal/element-capture.d.ts +19 -0
- package/dist/beacon/types/internal/element-capture.d.ts.map +1 -0
- package/dist/beacon/types/internal/event-buffer.d.ts +16 -0
- package/dist/beacon/types/internal/event-buffer.d.ts.map +1 -0
- package/dist/beacon/types/internal/framework-detect.d.ts +6 -0
- package/dist/beacon/types/internal/framework-detect.d.ts.map +1 -0
- package/dist/beacon/types/internal/markers.d.ts +17 -0
- package/dist/beacon/types/internal/markers.d.ts.map +1 -0
- package/dist/beacon/types/internal/monitor/capture-dom.d.ts +14 -0
- package/dist/beacon/types/internal/monitor/capture-dom.d.ts.map +1 -0
- package/dist/beacon/types/internal/monitor/capture-network.d.ts +12 -0
- package/dist/beacon/types/internal/monitor/capture-network.d.ts.map +1 -0
- package/dist/beacon/types/internal/monitor/overlay.d.ts +16 -0
- package/dist/beacon/types/internal/monitor/overlay.d.ts.map +1 -0
- package/dist/beacon/types/internal/monitor/session.d.ts +41 -0
- package/dist/beacon/types/internal/monitor/session.d.ts.map +1 -0
- package/dist/beacon/types/{monitor → internal/monitor}/transport.d.ts +3 -3
- package/dist/beacon/types/internal/monitor/transport.d.ts.map +1 -0
- package/dist/beacon/types/{monitor/types.d.ts → internal/monitor/wire.d.ts} +69 -27
- package/dist/beacon/types/internal/monitor/wire.d.ts.map +1 -0
- package/dist/beacon/types/{ui → internal}/pick-mode-overlay.d.ts +4 -5
- package/dist/beacon/types/internal/pick-mode-overlay.d.ts.map +1 -0
- package/dist/beacon/types/{capture → internal}/picker.d.ts +0 -1
- package/dist/beacon/types/internal/picker.d.ts.map +1 -0
- package/dist/beacon/types/{ui → internal}/pin-popover.d.ts +1 -1
- package/dist/beacon/types/internal/pin-popover.d.ts.map +1 -0
- package/dist/beacon/types/{capture → internal}/screenshot.d.ts +1 -0
- package/dist/beacon/types/internal/screenshot.d.ts.map +1 -0
- package/dist/beacon/types/internal/selector.d.ts.map +1 -0
- package/dist/beacon/types/plugins/domEle.d.ts +14 -0
- package/dist/beacon/types/plugins/domEle.d.ts.map +1 -0
- package/dist/beacon/types/plugins/domSS.d.ts +8 -0
- package/dist/beacon/types/plugins/domSS.d.ts.map +1 -0
- package/dist/beacon/types/plugins/errors.d.ts +3 -0
- package/dist/beacon/types/plugins/errors.d.ts.map +1 -0
- package/dist/beacon/types/plugins/index.d.ts +8 -0
- package/dist/beacon/types/plugins/index.d.ts.map +1 -0
- package/dist/beacon/types/plugins/liveMonitor.d.ts +14 -0
- package/dist/beacon/types/plugins/liveMonitor.d.ts.map +1 -0
- package/dist/beacon/types/plugins/metadata.d.ts +3 -0
- package/dist/beacon/types/plugins/metadata.d.ts.map +1 -0
- package/dist/beacon/types/registry.d.ts +33 -0
- package/dist/beacon/types/registry.d.ts.map +1 -0
- package/dist/beacon/types/styles.d.ts +8 -0
- package/dist/beacon/types/styles.d.ts.map +1 -0
- package/dist/beacon/types/transport.d.ts +3 -0
- package/dist/beacon/types/transport.d.ts.map +1 -0
- package/dist/beacon/types/types.d.ts +152 -68
- package/dist/beacon/types/types.d.ts.map +1 -1
- package/dist/beacon/types/ui/dialog.d.ts +53 -0
- package/dist/beacon/types/ui/dialog.d.ts.map +1 -0
- package/dist/beacon/types/ui/form.d.ts +7 -0
- package/dist/beacon/types/ui/form.d.ts.map +1 -0
- package/dist/beacon/types/ui/overlay.d.ts +6 -0
- package/dist/beacon/types/ui/overlay.d.ts.map +1 -0
- package/dist/deck-client/assets/{_baseUniq-W2JQDmje.js → _baseUniq-DCt2IMRR.js} +1 -1
- package/dist/deck-client/assets/{arc-DIBWAId9.js → arc-h-ifqmNR.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-CAIRMvJK.js → architectureDiagram-Q4EWVU46-C9dITSPv.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-BeNaNiOi.js → blockDiagram-DXYQGD6D-BHuJT34t.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-B9Ozi62h.js → c4Diagram-AHTNJAMY-CpvMGtDG.js} +1 -1
- package/dist/deck-client/assets/channel-2PZVMiXf.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-D7AZ47dt.js → chunk-4BX2VUAB-B6md1VIm.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-DnVnNPcI.js → chunk-4TB4RGXK-BmEnX8ik.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-UKYs-YNd.js → chunk-55IACEB6-BZPUyZAZ.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-D43b-SKn.js → chunk-EDXVE4YY-BWwNUK-l.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-QzBAoyyW.js → chunk-FMBD7UC4-o7gSppGI.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-Cjif4r6W.js → chunk-OYMX7WX6-C4KoTL5p.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-CqLDirEI.js → chunk-QZHKN3VN-jkf68sDs.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-_FQvmMs4.js → chunk-YZCP3GAM-Cd4yBE7o.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-Bt8xBAof.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-Bt8xBAof.js +1 -0
- package/dist/deck-client/assets/clone-BHQryoDl.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-rfrocesE.js → cose-bilkent-S5V4N54A-DeGFUgAV.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-Bv_7DJat.js → dagre-KV5264BT-ekcYJuUV.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-4F1414G5.js → diagram-5BDNPKRD-YHPk4rV2.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-C4-Pszqm.js → diagram-G4DWMVQ6-DM-JCd_B.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-B647TIx9.js → diagram-MMDJMWI5-l5FK1ybk.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-BFAqpezd.js → diagram-TYMM5635-CIN4_1-j.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-BfBfrJOC.js → erDiagram-SMLLAGMA-MyinSkEl.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-DX9YAYes.js → flowDiagram-DWJPFMVM-Dk8nn42x.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DCuiy7wF.js → ganttDiagram-T4ZO3ILL-BU1ihicu.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-CGp1IXUh.js → gitGraphDiagram-UUTBAWPF-BjsTL13C.js} +1 -1
- package/dist/deck-client/assets/{graph-B7g8aoxv.js → graph-DJmh-xi7.js} +1 -1
- package/dist/deck-client/assets/{index-Dg1r-WSN.js → index-KsShfCV-.js} +3 -3
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-L3fahMkF.js → infoDiagram-42DDH7IO-Dxvy_RB4.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-aS_EjWBZ.js → ishikawaDiagram-UXIWVN3A-DPOaNF1l.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-djTSQZF9.js → journeyDiagram-VCZTEJTY-DMew3K5c.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-CcTHo4CM.js → kanban-definition-6JOO6SKY-csciJFuk.js} +1 -1
- package/dist/deck-client/assets/{layout-mEJiadb7.js → layout-Dg4yyms2.js} +1 -1
- package/dist/deck-client/assets/{linear-XgTKqyRu.js → linear-BA3zU6gq.js} +1 -1
- package/dist/deck-client/assets/{min-Ct9jZdpd.js → min-lz-Ird-p.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-BaFxCGNU.js → mindmap-definition-QFDTVHPH-CCEN8OQV.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-CIbYYjtw.js → pieDiagram-DEJITSTG-DM6n1HY7.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-D9EtCOvh.js → quadrantDiagram-34T5L4WZ-_ULoR66n.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-xeni9eVG.js → requirementDiagram-MS252O5E-BuwJs7Tn.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-LYeknz9h.js → sankeyDiagram-XADWPNL6-BEsuzkW4.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-RDbsKFZf.js → sequenceDiagram-FGHM5R23-CP2H0YWf.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-BH1Zjglk.js → stateDiagram-FHFEXIEX-B5Gw_NNL.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-4T4wMDXr.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-IFXxKptt.js → timeline-definition-GMOUNBTQ-DsoYydQa.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-D-sLkQs9.js → vennDiagram-DHZGUBPP-Dz8JT_ob.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-DGHQ_Ijv.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BTjjuDU3.js → wardleyDiagram-NUSXRM2D-DN1LJMB1.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-AYbv92n-.js → xychartDiagram-5P7HB3ND-nb0oSfrQ.js} +1 -1
- package/dist/deck-client/index.html +1 -1
- package/dist/server/beacon-monitor-entry.js +548 -6
- package/dist/server/chart-serve.js +917 -248
- package/dist/server/cli.js +1368 -374
- package/dist/server/council-entry.js +0 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/graph-mcp-entry.js +1326 -322
- package/dist/server/init-entry.js +16 -11
- package/dist/server/orbit-entry.js +135 -7
- package/dist/server/parse-worker-entry.js +918 -247
- package/package.json +22 -22
- package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-array.md +107 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-clear.md +94 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-pulse.md +82 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/beacon-scan.md +66 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/blast-radius.md +101 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/brief.md +112 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/course.md +84 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/debug.md +92 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/deploy-check.md +160 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/diagram.md +134 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/orbit.md +87 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/prototype.md +90 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/recall.md +83 -0
- package/scaffolds/ls-marketplace/plugins/kit/{commands → skills}/show-mcp-status.md +4 -4
- package/scaffolds/ls-marketplace/plugins/kit/skills/wireframe.md +70 -0
- package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
- package/scaffolds/statusline/statusline-mcp.sh +21 -9
- package/dist/beacon/types/capture/element.d.ts +0 -3
- package/dist/beacon/types/capture/element.d.ts.map +0 -1
- package/dist/beacon/types/capture/events.d.ts +0 -20
- package/dist/beacon/types/capture/events.d.ts.map +0 -1
- package/dist/beacon/types/capture/framework.d.ts +0 -3
- package/dist/beacon/types/capture/framework.d.ts.map +0 -1
- package/dist/beacon/types/capture/metadata.d.ts +0 -3
- package/dist/beacon/types/capture/metadata.d.ts.map +0 -1
- package/dist/beacon/types/capture/overlay.d.ts +0 -7
- package/dist/beacon/types/capture/overlay.d.ts.map +0 -1
- package/dist/beacon/types/capture/picker.d.ts.map +0 -1
- package/dist/beacon/types/capture/screenshot.d.ts.map +0 -1
- package/dist/beacon/types/capture/selector.d.ts.map +0 -1
- package/dist/beacon/types/monitor/dom.d.ts +0 -13
- package/dist/beacon/types/monitor/dom.d.ts.map +0 -1
- package/dist/beacon/types/monitor/index.d.ts +0 -19
- package/dist/beacon/types/monitor/index.d.ts.map +0 -1
- package/dist/beacon/types/monitor/network.d.ts +0 -12
- package/dist/beacon/types/monitor/network.d.ts.map +0 -1
- package/dist/beacon/types/monitor/transport.d.ts.map +0 -1
- package/dist/beacon/types/monitor/types.d.ts.map +0 -1
- package/dist/beacon/types/transport/submit.d.ts +0 -3
- package/dist/beacon/types/transport/submit.d.ts.map +0 -1
- package/dist/beacon/types/ui/button.d.ts +0 -2
- package/dist/beacon/types/ui/button.d.ts.map +0 -1
- package/dist/beacon/types/ui/drawer.d.ts +0 -33
- package/dist/beacon/types/ui/drawer.d.ts.map +0 -1
- package/dist/beacon/types/ui/icons.d.ts +0 -9
- package/dist/beacon/types/ui/icons.d.ts.map +0 -1
- package/dist/beacon/types/ui/monitor-panel.d.ts +0 -19
- package/dist/beacon/types/ui/monitor-panel.d.ts.map +0 -1
- package/dist/beacon/types/ui/pick-mode-overlay.d.ts.map +0 -1
- package/dist/beacon/types/ui/pin-popover.d.ts.map +0 -1
- package/dist/deck-client/assets/channel-CRdozqbp.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-lIZMp57W.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-lIZMp57W.js +0 -1
- package/dist/deck-client/assets/clone-BtWeSTyJ.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BrV78NDR.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-C010F8l4.js +0 -162
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-array.md +0 -92
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-clear.md +0 -68
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-pulse.md +0 -80
- package/scaffolds/ls-marketplace/plugins/kit/commands/beacon-scan.md +0 -62
- /package/dist/beacon/types/{capture → internal}/selector.d.ts +0 -0
|
@@ -1184,6 +1184,8 @@ function extractDeep(absPath) {
|
|
|
1184
1184
|
false
|
|
1185
1185
|
);
|
|
1186
1186
|
const hasEffects = Object.keys(fileEffects).length > 0;
|
|
1187
|
+
const uiLabels = collectUiLabels(root);
|
|
1188
|
+
const notes = collectNotes(root);
|
|
1187
1189
|
return {
|
|
1188
1190
|
elements,
|
|
1189
1191
|
stateVars,
|
|
@@ -1191,10 +1193,77 @@ function extractDeep(absPath) {
|
|
|
1191
1193
|
variables,
|
|
1192
1194
|
responses,
|
|
1193
1195
|
params,
|
|
1194
|
-
...hasEffects ? { effects: fileEffects } : {}
|
|
1196
|
+
...hasEffects ? { effects: fileEffects } : {},
|
|
1197
|
+
...uiLabels.length > 0 ? { ui_labels: uiLabels } : {},
|
|
1198
|
+
...notes.length > 0 ? { notes } : {}
|
|
1195
1199
|
};
|
|
1196
1200
|
}
|
|
1197
|
-
|
|
1201
|
+
function collectNotes(root) {
|
|
1202
|
+
const out = [];
|
|
1203
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1204
|
+
function visit(node) {
|
|
1205
|
+
if (out.length >= NOTES_MAX) return;
|
|
1206
|
+
if (node.type === "comment") {
|
|
1207
|
+
const text = node.text;
|
|
1208
|
+
const startRow = node.startPosition.row;
|
|
1209
|
+
NOTE_REGEX.lastIndex = 0;
|
|
1210
|
+
let m;
|
|
1211
|
+
while ((m = NOTE_REGEX.exec(text)) !== null) {
|
|
1212
|
+
const kind = m[1];
|
|
1213
|
+
const author = m[2];
|
|
1214
|
+
const body = m[3];
|
|
1215
|
+
if (!kind || !body) continue;
|
|
1216
|
+
const newlinesBefore = (text.slice(0, m.index).match(/\n/g) ?? []).length;
|
|
1217
|
+
const line = startRow + 1 + newlinesBefore;
|
|
1218
|
+
const key = `${line}:${kind}`;
|
|
1219
|
+
if (seen.has(key)) continue;
|
|
1220
|
+
seen.add(key);
|
|
1221
|
+
const note = {
|
|
1222
|
+
kind,
|
|
1223
|
+
text: body.length <= 200 ? body : body.slice(0, 200) + "...",
|
|
1224
|
+
line
|
|
1225
|
+
};
|
|
1226
|
+
if (author) note.author = author;
|
|
1227
|
+
out.push(note);
|
|
1228
|
+
if (out.length >= NOTES_MAX) return;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
for (const child of node.namedChildren) {
|
|
1232
|
+
visit(child);
|
|
1233
|
+
if (out.length >= NOTES_MAX) return;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
visit(root);
|
|
1237
|
+
return out;
|
|
1238
|
+
}
|
|
1239
|
+
function collectUiLabels(root) {
|
|
1240
|
+
const out = [];
|
|
1241
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1242
|
+
function visit(node) {
|
|
1243
|
+
if (out.length >= UI_LABELS_MAX) return;
|
|
1244
|
+
if (node.type === "pair") {
|
|
1245
|
+
const key = node.childForFieldName("key");
|
|
1246
|
+
const val = node.childForFieldName("value");
|
|
1247
|
+
if (key && val) {
|
|
1248
|
+
const keyText = key.type === "property_identifier" ? key.text : stringLiteralValue(key) ?? key.text;
|
|
1249
|
+
if (UI_LABEL_KEYS.has(keyText)) {
|
|
1250
|
+
const strVal = stringLiteralValue(val);
|
|
1251
|
+
if (strVal && strVal.length > 0 && strVal.length <= 200 && !seen.has(strVal)) {
|
|
1252
|
+
seen.add(strVal);
|
|
1253
|
+
out.push(strVal);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
for (const child of node.namedChildren) {
|
|
1259
|
+
visit(child);
|
|
1260
|
+
if (out.length >= UI_LABELS_MAX) return;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
visit(root);
|
|
1264
|
+
return out;
|
|
1265
|
+
}
|
|
1266
|
+
var import_node_fs5, import_node_path5, tsxLanguage, parserInstance, TreeSitterCtor, initPromise, initialized, queriesDir, queryCache, MAX_PARSEABLE_BYTES, MAX_CONSECUTIVE_PARSE_FAILURES, consecutiveParseFailures, ParseCascadeError, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS, EXEMPT_NAME_PATTERNS, PROTECT_NAME_PATTERNS, TRUST_AS_PROTECT_KEYS, TIMER_FNS, DOM_METHOD_NAMES, CLASSLIST_METHODS, STORAGE_OBJECTS, HISTORY_METHODS, LOCATION_METHODS, ASSIGN_DOM_PROPS, UI_LABEL_KEYS, UI_LABELS_MAX, NOTE_REGEX, NOTES_MAX;
|
|
1198
1267
|
var init_ts_extractor = __esm({
|
|
1199
1268
|
"src/server/graph/core/ts-extractor.ts"() {
|
|
1200
1269
|
"use strict";
|
|
@@ -1313,6 +1382,27 @@ var init_ts_extractor = __esm({
|
|
|
1313
1382
|
"selected",
|
|
1314
1383
|
"disabled"
|
|
1315
1384
|
]);
|
|
1385
|
+
UI_LABEL_KEYS = /* @__PURE__ */ new Set([
|
|
1386
|
+
"label",
|
|
1387
|
+
"title",
|
|
1388
|
+
"name",
|
|
1389
|
+
"text",
|
|
1390
|
+
"description",
|
|
1391
|
+
"placeholder",
|
|
1392
|
+
"tooltip",
|
|
1393
|
+
"heading",
|
|
1394
|
+
"subheading",
|
|
1395
|
+
"sheetTitle",
|
|
1396
|
+
"sheetDescription",
|
|
1397
|
+
"caption",
|
|
1398
|
+
"cta",
|
|
1399
|
+
"buttonText",
|
|
1400
|
+
"emptyText",
|
|
1401
|
+
"subtitle"
|
|
1402
|
+
]);
|
|
1403
|
+
UI_LABELS_MAX = 200;
|
|
1404
|
+
NOTE_REGEX = /^\s*(?:\/\/|\/\*+|\*)\s*([A-Z][A-Z0-9_]{1,15})(?:\(([^)]+)\))?:\s*(\S.*?)\s*(?:\*\/)?$/gm;
|
|
1405
|
+
NOTES_MAX = 100;
|
|
1316
1406
|
}
|
|
1317
1407
|
});
|
|
1318
1408
|
|
|
@@ -1320,6 +1410,7 @@ var init_ts_extractor = __esm({
|
|
|
1320
1410
|
var parse_worker_entry_exports = {};
|
|
1321
1411
|
module.exports = __toCommonJS(parse_worker_entry_exports);
|
|
1322
1412
|
var import_node_worker_threads = require("node:worker_threads");
|
|
1413
|
+
var import_pgsql_parser2 = require("pgsql-parser");
|
|
1323
1414
|
|
|
1324
1415
|
// src/server/graph/core/config.ts
|
|
1325
1416
|
var import_node_fs = require("node:fs");
|
|
@@ -1988,6 +2079,7 @@ function generate(rootDir) {
|
|
|
1988
2079
|
responses: deep.responses,
|
|
1989
2080
|
params: deep.params,
|
|
1990
2081
|
...deep.effects ? { effects: deep.effects } : {},
|
|
2082
|
+
...deep.notes ? { notes: deep.notes } : {},
|
|
1991
2083
|
_dbCalls: dbCalls
|
|
1992
2084
|
// temp: used for cross-ref building below
|
|
1993
2085
|
});
|
|
@@ -2008,6 +2100,8 @@ function generate(rootDir) {
|
|
|
2008
2100
|
conditions: deep.conditions,
|
|
2009
2101
|
variables: deep.variables,
|
|
2010
2102
|
...deep.effects ? { effects: deep.effects } : {},
|
|
2103
|
+
...deep.ui_labels ? { ui_labels: deep.ui_labels } : {},
|
|
2104
|
+
...deep.notes ? { notes: deep.notes } : {},
|
|
2011
2105
|
...authWrappers.length > 0 ? { auth: authWrappers } : {},
|
|
2012
2106
|
...dbCalls.length > 0 ? { _dbCalls: dbCalls } : {}
|
|
2013
2107
|
});
|
|
@@ -2608,6 +2702,7 @@ var prismaSchemaParser = {
|
|
|
2608
2702
|
// src/server/graph/parsers/db/sql-migrations.ts
|
|
2609
2703
|
var import_node_fs8 = require("node:fs");
|
|
2610
2704
|
var import_node_path7 = require("node:path");
|
|
2705
|
+
var import_pgsql_parser = require("pgsql-parser");
|
|
2611
2706
|
var PG_TO_PRISMA = {
|
|
2612
2707
|
"TEXT": "String",
|
|
2613
2708
|
"VARCHAR": "String",
|
|
@@ -2638,243 +2733,6 @@ function pgTypeToPrisma(pgType) {
|
|
|
2638
2733
|
const upper = pgType.toUpperCase().trim();
|
|
2639
2734
|
return PG_TO_PRISMA[upper] ?? upper;
|
|
2640
2735
|
}
|
|
2641
|
-
var ID = `(?:"[\\w$]+"|[\\w$]+)`;
|
|
2642
|
-
var QID = `(?:${ID}\\.)?${ID}`;
|
|
2643
|
-
function bareName(captured) {
|
|
2644
|
-
const parts = captured.split(".");
|
|
2645
|
-
const last = parts[parts.length - 1];
|
|
2646
|
-
return last.replace(/^"(.*)"$/, "$1").trim();
|
|
2647
|
-
}
|
|
2648
|
-
function parseCreateTable(sql, state) {
|
|
2649
|
-
const re = new RegExp(
|
|
2650
|
-
`CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s*\\(([\\s\\S]*?)\\);`,
|
|
2651
|
-
"gi"
|
|
2652
|
-
);
|
|
2653
|
-
let m;
|
|
2654
|
-
while ((m = re.exec(sql)) !== null) {
|
|
2655
|
-
const tableName = bareName(m[1]);
|
|
2656
|
-
const body = m[2];
|
|
2657
|
-
const columns = /* @__PURE__ */ new Map();
|
|
2658
|
-
let primaryCol = null;
|
|
2659
|
-
const inlineFks = [];
|
|
2660
|
-
const lines = splitTopLevelCommas(body);
|
|
2661
|
-
for (const raw of lines) {
|
|
2662
|
-
const trimmed = raw.trim().replace(/,\s*$/, "");
|
|
2663
|
-
if (!trimmed || trimmed.startsWith("--")) continue;
|
|
2664
|
-
const namedPk = trimmed.match(new RegExp(`^CONSTRAINT\\s+${ID}\\s+PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
|
|
2665
|
-
if (namedPk) {
|
|
2666
|
-
primaryCol = bareName(namedPk[1]);
|
|
2667
|
-
continue;
|
|
2668
|
-
}
|
|
2669
|
-
const tablePk = trimmed.match(new RegExp(`^PRIMARY\\s+KEY\\s*\\(\\s*(${QID})`, "i"));
|
|
2670
|
-
if (tablePk) {
|
|
2671
|
-
primaryCol = bareName(tablePk[1]);
|
|
2672
|
-
continue;
|
|
2673
|
-
}
|
|
2674
|
-
if (/^UNIQUE\s*\(/i.test(trimmed)) continue;
|
|
2675
|
-
const namedFk = trimmed.match(new RegExp(
|
|
2676
|
-
`^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+)?))?`,
|
|
2677
|
-
"i"
|
|
2678
|
-
));
|
|
2679
|
-
if (namedFk) {
|
|
2680
|
-
inlineFks.push({
|
|
2681
|
-
constraintName: bareName(namedFk[1]),
|
|
2682
|
-
sourceTable: tableName,
|
|
2683
|
-
sourceColumn: bareName(namedFk[2]),
|
|
2684
|
-
targetTable: bareName(namedFk[3]),
|
|
2685
|
-
targetColumn: bareName(namedFk[4]),
|
|
2686
|
-
onDelete: namedFk[5] ?? null
|
|
2687
|
-
});
|
|
2688
|
-
continue;
|
|
2689
|
-
}
|
|
2690
|
-
const bareFk = trimmed.match(new RegExp(
|
|
2691
|
-
`^FOREIGN\\s+KEY\\s*\\(\\s*(${QID})\\s*\\)\\s+REFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
2692
|
-
"i"
|
|
2693
|
-
));
|
|
2694
|
-
if (bareFk) {
|
|
2695
|
-
inlineFks.push({
|
|
2696
|
-
constraintName: `${tableName}_${bareName(bareFk[1])}_fkey`,
|
|
2697
|
-
sourceTable: tableName,
|
|
2698
|
-
sourceColumn: bareName(bareFk[1]),
|
|
2699
|
-
targetTable: bareName(bareFk[2]),
|
|
2700
|
-
targetColumn: bareName(bareFk[3]),
|
|
2701
|
-
onDelete: bareFk[4] ?? null
|
|
2702
|
-
});
|
|
2703
|
-
continue;
|
|
2704
|
-
}
|
|
2705
|
-
if (/^CONSTRAINT\s/i.test(trimmed)) continue;
|
|
2706
|
-
const colMatch = trimmed.match(new RegExp(`^(${ID})\\s+(.+)`, "i"));
|
|
2707
|
-
if (!colMatch) continue;
|
|
2708
|
-
const colName = bareName(colMatch[1]);
|
|
2709
|
-
let rest = colMatch[2];
|
|
2710
|
-
const inlineRefMatch = rest.match(new RegExp(
|
|
2711
|
-
`\\bREFERENCES\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)(?:\\s+ON\\s+DELETE\\s+(\\w+(?:\\s+\\w+)?))?`,
|
|
2712
|
-
"i"
|
|
2713
|
-
));
|
|
2714
|
-
if (inlineRefMatch) {
|
|
2715
|
-
inlineFks.push({
|
|
2716
|
-
constraintName: `${tableName}_${colName}_fkey`,
|
|
2717
|
-
sourceTable: tableName,
|
|
2718
|
-
sourceColumn: colName,
|
|
2719
|
-
targetTable: bareName(inlineRefMatch[1]),
|
|
2720
|
-
targetColumn: bareName(inlineRefMatch[2]),
|
|
2721
|
-
onDelete: inlineRefMatch[3] ?? null
|
|
2722
|
-
});
|
|
2723
|
-
rest = rest.replace(inlineRefMatch[0], "").trim();
|
|
2724
|
-
}
|
|
2725
|
-
const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
|
|
2726
|
-
const isPrimaryKey = /\bPRIMARY\s+KEY\b/i.test(rest);
|
|
2727
|
-
const isUnique = /\bUNIQUE\b/i.test(rest);
|
|
2728
|
-
const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)(?:\s*,?\s*$)/i);
|
|
2729
|
-
const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
|
|
2730
|
-
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();
|
|
2731
|
-
columns.set(colName, {
|
|
2732
|
-
name: colName,
|
|
2733
|
-
type: colType,
|
|
2734
|
-
nullable: !isNotNull && !isPrimaryKey,
|
|
2735
|
-
primary: isPrimaryKey,
|
|
2736
|
-
unique: isUnique,
|
|
2737
|
-
default: defaultVal
|
|
2738
|
-
});
|
|
2739
|
-
if (isPrimaryKey) primaryCol = colName;
|
|
2740
|
-
}
|
|
2741
|
-
if (primaryCol && columns.has(primaryCol)) {
|
|
2742
|
-
columns.get(primaryCol).primary = true;
|
|
2743
|
-
}
|
|
2744
|
-
state.tables.set(tableName, { name: tableName, columns });
|
|
2745
|
-
state.fks.push(...inlineFks);
|
|
2746
|
-
}
|
|
2747
|
-
}
|
|
2748
|
-
function splitTopLevelCommas(body) {
|
|
2749
|
-
const out = [];
|
|
2750
|
-
let depth = 0;
|
|
2751
|
-
let buf = "";
|
|
2752
|
-
let inString = null;
|
|
2753
|
-
for (const ch of body) {
|
|
2754
|
-
if (inString) {
|
|
2755
|
-
buf += ch;
|
|
2756
|
-
if (ch === inString) inString = null;
|
|
2757
|
-
continue;
|
|
2758
|
-
}
|
|
2759
|
-
if (ch === "'" || ch === '"') {
|
|
2760
|
-
inString = ch;
|
|
2761
|
-
buf += ch;
|
|
2762
|
-
continue;
|
|
2763
|
-
}
|
|
2764
|
-
if (ch === "(") depth++;
|
|
2765
|
-
else if (ch === ")") depth--;
|
|
2766
|
-
if (ch === "," && depth === 0) {
|
|
2767
|
-
out.push(buf);
|
|
2768
|
-
buf = "";
|
|
2769
|
-
continue;
|
|
2770
|
-
}
|
|
2771
|
-
buf += ch;
|
|
2772
|
-
}
|
|
2773
|
-
if (buf.trim()) out.push(buf);
|
|
2774
|
-
return out;
|
|
2775
|
-
}
|
|
2776
|
-
function parseCreateEnum(sql, state) {
|
|
2777
|
-
const re = new RegExp(
|
|
2778
|
-
`CREATE\\s+TYPE\\s+(${QID})\\s+AS\\s+ENUM\\s*\\(([^)]+)\\)`,
|
|
2779
|
-
"gi"
|
|
2780
|
-
);
|
|
2781
|
-
let m;
|
|
2782
|
-
while ((m = re.exec(sql)) !== null) {
|
|
2783
|
-
const enumName = bareName(m[1]);
|
|
2784
|
-
const valuesStr = m[2];
|
|
2785
|
-
const values = new Set(
|
|
2786
|
-
valuesStr.split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1")).filter(Boolean)
|
|
2787
|
-
);
|
|
2788
|
-
state.enums.set(enumName, { name: enumName, values });
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
function parseAlterTable(sql, state) {
|
|
2792
|
-
const addColRe = new RegExp(
|
|
2793
|
-
`ALTER\\s+TABLE\\s+(${QID})\\s+ADD\\s+COLUMN\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QID})\\s+(.+?);`,
|
|
2794
|
-
"gi"
|
|
2795
|
-
);
|
|
2796
|
-
let m;
|
|
2797
|
-
while ((m = addColRe.exec(sql)) !== null) {
|
|
2798
|
-
const tableName = bareName(m[1]);
|
|
2799
|
-
const colName = bareName(m[2]);
|
|
2800
|
-
let rest = m[3];
|
|
2801
|
-
const table = state.tables.get(tableName);
|
|
2802
|
-
if (!table) continue;
|
|
2803
|
-
const isNotNull = /\bNOT\s+NULL\b/i.test(rest);
|
|
2804
|
-
const defaultMatch = rest.match(/\bDEFAULT\s+(.+?)$/i);
|
|
2805
|
-
const defaultVal = defaultMatch ? defaultMatch[1].trim() : null;
|
|
2806
|
-
let colType = rest.replace(/\bNOT\s+NULL\b/gi, "").replace(/\bDEFAULT\s+.*/gi, "").trim();
|
|
2807
|
-
table.columns.set(colName, {
|
|
2808
|
-
name: colName,
|
|
2809
|
-
type: colType,
|
|
2810
|
-
nullable: !isNotNull,
|
|
2811
|
-
primary: false,
|
|
2812
|
-
unique: false,
|
|
2813
|
-
default: defaultVal
|
|
2814
|
-
});
|
|
2815
|
-
}
|
|
2816
|
-
const dropColRe = new RegExp(
|
|
2817
|
-
`ALTER\\s+TABLE\\s+(${QID})\\s+DROP\\s+COLUMN\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
|
|
2818
|
-
"gi"
|
|
2819
|
-
);
|
|
2820
|
-
while ((m = dropColRe.exec(sql)) !== null) {
|
|
2821
|
-
const table = state.tables.get(bareName(m[1]));
|
|
2822
|
-
if (table) table.columns.delete(bareName(m[2]));
|
|
2823
|
-
}
|
|
2824
|
-
const fkRe = new RegExp(
|
|
2825
|
-
`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+)?))?`,
|
|
2826
|
-
"gi"
|
|
2827
|
-
);
|
|
2828
|
-
while ((m = fkRe.exec(sql)) !== null) {
|
|
2829
|
-
state.fks.push({
|
|
2830
|
-
constraintName: bareName(m[2]),
|
|
2831
|
-
sourceTable: bareName(m[1]),
|
|
2832
|
-
sourceColumn: bareName(m[3]),
|
|
2833
|
-
targetTable: bareName(m[4]),
|
|
2834
|
-
targetColumn: bareName(m[5]),
|
|
2835
|
-
onDelete: m[6] ?? null
|
|
2836
|
-
});
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
function parseAlterEnum(sql, state) {
|
|
2840
|
-
const re = new RegExp(
|
|
2841
|
-
`ALTER\\s+TYPE\\s+(${QID})\\s+ADD\\s+VALUE\\s+'([^']+)'`,
|
|
2842
|
-
"gi"
|
|
2843
|
-
);
|
|
2844
|
-
let m;
|
|
2845
|
-
while ((m = re.exec(sql)) !== null) {
|
|
2846
|
-
const en = state.enums.get(bareName(m[1]));
|
|
2847
|
-
if (en) en.values.add(m[2]);
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
function parseDropTable(sql, state) {
|
|
2851
|
-
const re = new RegExp(
|
|
2852
|
-
`DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?(${QID})`,
|
|
2853
|
-
"gi"
|
|
2854
|
-
);
|
|
2855
|
-
let m;
|
|
2856
|
-
while ((m = re.exec(sql)) !== null) {
|
|
2857
|
-
const dropped = bareName(m[1]);
|
|
2858
|
-
state.tables.delete(dropped);
|
|
2859
|
-
state.fks = state.fks.filter((fk) => fk.sourceTable !== dropped && fk.targetTable !== dropped);
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
function parseUniqueIndex(sql, state) {
|
|
2863
|
-
const re = new RegExp(
|
|
2864
|
-
`CREATE\\s+UNIQUE\\s+INDEX\\s+(?:(?:IF\\s+NOT\\s+EXISTS\\s+)?(?:${ID}\\s+)?)?ON\\s+(${QID})\\s*\\(\\s*(${QID})\\s*\\)`,
|
|
2865
|
-
"gi"
|
|
2866
|
-
);
|
|
2867
|
-
let m;
|
|
2868
|
-
while ((m = re.exec(sql)) !== null) {
|
|
2869
|
-
const tableName = bareName(m[1]);
|
|
2870
|
-
const colName = bareName(m[2]);
|
|
2871
|
-
const table = state.tables.get(tableName);
|
|
2872
|
-
const col = table?.columns.get(colName);
|
|
2873
|
-
if (col) col.unique = true;
|
|
2874
|
-
if (!state.uniqueIndexes.has(tableName)) state.uniqueIndexes.set(tableName, /* @__PURE__ */ new Set());
|
|
2875
|
-
state.uniqueIndexes.get(tableName).add(colName);
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
2736
|
function discoverMigrationFiles(migrationsDir) {
|
|
2879
2737
|
if (!(0, import_node_fs8.existsSync)(migrationsDir)) return [];
|
|
2880
2738
|
const out = [];
|
|
@@ -2889,25 +2747,614 @@ function discoverMigrationFiles(migrationsDir) {
|
|
|
2889
2747
|
}
|
|
2890
2748
|
return out;
|
|
2891
2749
|
}
|
|
2892
|
-
|
|
2750
|
+
var postgresDialect = {
|
|
2751
|
+
parse(sql) {
|
|
2752
|
+
return (0, import_pgsql_parser.parseSync)(sql);
|
|
2753
|
+
},
|
|
2754
|
+
applyAll(ast, state, filepath) {
|
|
2755
|
+
const stmts = ast.stmts ?? [];
|
|
2756
|
+
extractTablesFromStmts(stmts, state);
|
|
2757
|
+
extractEnumsFromStmts(stmts, state);
|
|
2758
|
+
extractIndexesFromStmts(stmts, state, filepath);
|
|
2759
|
+
extractPoliciesFromStmts(stmts, state, filepath);
|
|
2760
|
+
extractExtensionsFromStmts(stmts, state, filepath);
|
|
2761
|
+
extractTriggersFromStmts(stmts, state, filepath);
|
|
2762
|
+
extractFunctionsFromStmts(stmts, state, filepath);
|
|
2763
|
+
extractViewsFromStmts(stmts, state, filepath);
|
|
2764
|
+
applyDropIndexes(stmts, state);
|
|
2765
|
+
applyDropPolicies(stmts, state);
|
|
2766
|
+
applyDropsForSchemaObjects(stmts, state);
|
|
2767
|
+
applyAstAlterEnums(stmts, state);
|
|
2768
|
+
applyAstAlterations(stmts, state);
|
|
2769
|
+
},
|
|
2770
|
+
extractMigrationInfo(ast, name, filepath) {
|
|
2771
|
+
const stmts = ast.stmts ?? [];
|
|
2772
|
+
return extractMigrationInfoFromStmts(stmts, name, filepath);
|
|
2773
|
+
}
|
|
2774
|
+
};
|
|
2775
|
+
function parseMigrations(migrationsDir, dialect = postgresDialect) {
|
|
2893
2776
|
const state = {
|
|
2894
2777
|
tables: /* @__PURE__ */ new Map(),
|
|
2895
2778
|
enums: /* @__PURE__ */ new Map(),
|
|
2896
2779
|
fks: [],
|
|
2897
|
-
uniqueIndexes: /* @__PURE__ */ new Map()
|
|
2780
|
+
uniqueIndexes: /* @__PURE__ */ new Map(),
|
|
2781
|
+
indexes: [],
|
|
2782
|
+
policies: [],
|
|
2783
|
+
extensions: [],
|
|
2784
|
+
triggers: [],
|
|
2785
|
+
functions: [],
|
|
2786
|
+
views: []
|
|
2898
2787
|
};
|
|
2899
2788
|
if (!migrationsDir) return state;
|
|
2900
2789
|
for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
|
|
2901
2790
|
const sql = (0, import_node_fs8.readFileSync)(sqlPath, "utf-8");
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2791
|
+
let ast;
|
|
2792
|
+
try {
|
|
2793
|
+
ast = dialect.parse(sql);
|
|
2794
|
+
} catch {
|
|
2795
|
+
continue;
|
|
2796
|
+
}
|
|
2797
|
+
dialect.applyAll(ast, state, sqlPath);
|
|
2908
2798
|
}
|
|
2909
2799
|
return state;
|
|
2910
2800
|
}
|
|
2801
|
+
function extractIndexesFromStmts(stmts, state, filepath) {
|
|
2802
|
+
for (const wrap of stmts) {
|
|
2803
|
+
const stmt = wrap.stmt ?? {};
|
|
2804
|
+
const ix = stmt.IndexStmt;
|
|
2805
|
+
if (!ix) continue;
|
|
2806
|
+
const name = ix.idxname ?? "";
|
|
2807
|
+
if (!name) continue;
|
|
2808
|
+
const table = ix.relation?.relname ?? "";
|
|
2809
|
+
const unique = !!ix.unique;
|
|
2810
|
+
const method = String(ix.accessMethod ?? "btree").toLowerCase();
|
|
2811
|
+
const params = ix.indexParams ?? [];
|
|
2812
|
+
const columns = [];
|
|
2813
|
+
let hasExpressions = false;
|
|
2814
|
+
for (const p of params) {
|
|
2815
|
+
const elem = p.IndexElem;
|
|
2816
|
+
if (!elem) continue;
|
|
2817
|
+
if (elem.name) columns.push(elem.name);
|
|
2818
|
+
else if (elem.expr) hasExpressions = true;
|
|
2819
|
+
}
|
|
2820
|
+
const hasPredicate = !!ix.whereClause;
|
|
2821
|
+
const existing = state.indexes.findIndex((i) => i.name === name);
|
|
2822
|
+
const next = { name, table, unique, method, columns, hasExpressions, hasPredicate, filepath };
|
|
2823
|
+
if (existing >= 0) state.indexes[existing] = next;
|
|
2824
|
+
else state.indexes.push(next);
|
|
2825
|
+
if (unique && columns.length === 1 && !hasPredicate && !hasExpressions) {
|
|
2826
|
+
const t = state.tables.get(table);
|
|
2827
|
+
const col = t?.columns.get(columns[0]);
|
|
2828
|
+
if (col) col.unique = true;
|
|
2829
|
+
if (!state.uniqueIndexes.has(table)) state.uniqueIndexes.set(table, /* @__PURE__ */ new Set());
|
|
2830
|
+
state.uniqueIndexes.get(table).add(columns[0]);
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
function applyDropIndexes(stmts, state) {
|
|
2835
|
+
for (const wrap of stmts) {
|
|
2836
|
+
const drop = wrap.stmt?.DropStmt;
|
|
2837
|
+
if (!drop || drop.removeType !== "OBJECT_INDEX") continue;
|
|
2838
|
+
const objects = drop.objects ?? [];
|
|
2839
|
+
const droppedNames = /* @__PURE__ */ new Set();
|
|
2840
|
+
for (const obj of objects) {
|
|
2841
|
+
const items = obj.List?.items ?? [];
|
|
2842
|
+
const last = items[items.length - 1]?.String?.sval;
|
|
2843
|
+
if (last) droppedNames.add(last);
|
|
2844
|
+
}
|
|
2845
|
+
if (droppedNames.size > 0) {
|
|
2846
|
+
state.indexes = state.indexes.filter((i) => !droppedNames.has(i.name));
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
function formatPgTypeName(typeName) {
|
|
2851
|
+
const names = (typeName?.names ?? []).map((n) => n.String?.sval ?? "").filter(Boolean);
|
|
2852
|
+
const base = (names[names.length - 1] ?? "").toLowerCase();
|
|
2853
|
+
const PG_INTERNAL_MAP = {
|
|
2854
|
+
int4: "INTEGER",
|
|
2855
|
+
int8: "BIGINT",
|
|
2856
|
+
int2: "SMALLINT",
|
|
2857
|
+
float8: "DOUBLE PRECISION",
|
|
2858
|
+
float4: "REAL",
|
|
2859
|
+
bool: "BOOLEAN",
|
|
2860
|
+
bpchar: "CHAR",
|
|
2861
|
+
timestamptz: "TIMESTAMPTZ",
|
|
2862
|
+
timestamp: "TIMESTAMP",
|
|
2863
|
+
numeric: "NUMERIC",
|
|
2864
|
+
text: "TEXT",
|
|
2865
|
+
varchar: "VARCHAR",
|
|
2866
|
+
jsonb: "JSONB",
|
|
2867
|
+
json: "JSON",
|
|
2868
|
+
uuid: "UUID",
|
|
2869
|
+
date: "DATE",
|
|
2870
|
+
bytea: "BYTEA"
|
|
2871
|
+
};
|
|
2872
|
+
return PG_INTERNAL_MAP[base] ?? base.toUpperCase();
|
|
2873
|
+
}
|
|
2874
|
+
function applyAstAlterations(stmts, state) {
|
|
2875
|
+
for (const wrap of stmts) {
|
|
2876
|
+
const stmt = wrap.stmt ?? {};
|
|
2877
|
+
const kind = Object.keys(stmt)[0];
|
|
2878
|
+
if (!kind) continue;
|
|
2879
|
+
if (kind === "AlterTableStmt") {
|
|
2880
|
+
const body = stmt.AlterTableStmt;
|
|
2881
|
+
const tableName = body.relation?.relname ?? "";
|
|
2882
|
+
const table = state.tables.get(tableName);
|
|
2883
|
+
if (!table) continue;
|
|
2884
|
+
const cmds = body.cmds ?? [];
|
|
2885
|
+
for (const c of cmds) {
|
|
2886
|
+
const cmd = c.AlterTableCmd;
|
|
2887
|
+
if (!cmd) continue;
|
|
2888
|
+
const subtype = cmd.subtype ?? "";
|
|
2889
|
+
const colName = cmd.name ?? "";
|
|
2890
|
+
const col = colName ? table.columns.get(colName) : void 0;
|
|
2891
|
+
switch (subtype) {
|
|
2892
|
+
case "AT_AlterColumnType": {
|
|
2893
|
+
if (!col) break;
|
|
2894
|
+
const typeName = cmd.def?.ColumnDef?.typeName ?? cmd.def?.typeName;
|
|
2895
|
+
if (typeName) col.type = formatPgTypeNameWithMods(typeName);
|
|
2896
|
+
break;
|
|
2897
|
+
}
|
|
2898
|
+
case "AT_SetNotNull":
|
|
2899
|
+
if (col) col.nullable = false;
|
|
2900
|
+
break;
|
|
2901
|
+
case "AT_DropNotNull":
|
|
2902
|
+
if (col) col.nullable = true;
|
|
2903
|
+
break;
|
|
2904
|
+
case "AT_AddColumn": {
|
|
2905
|
+
const cd = cmd.def?.ColumnDef;
|
|
2906
|
+
if (!cd) break;
|
|
2907
|
+
const newColName = cd.colname ?? "";
|
|
2908
|
+
if (!newColName) break;
|
|
2909
|
+
if (table.columns.has(newColName)) break;
|
|
2910
|
+
let nullable = true;
|
|
2911
|
+
let primary = false;
|
|
2912
|
+
let unique = false;
|
|
2913
|
+
let defaultVal = null;
|
|
2914
|
+
for (const c2 of cd.constraints ?? []) {
|
|
2915
|
+
const ct = c2.Constraint;
|
|
2916
|
+
if (!ct) continue;
|
|
2917
|
+
if (ct.contype === "CONSTR_NOTNULL") nullable = false;
|
|
2918
|
+
else if (ct.contype === "CONSTR_PRIMARY") {
|
|
2919
|
+
primary = true;
|
|
2920
|
+
nullable = false;
|
|
2921
|
+
} else if (ct.contype === "CONSTR_UNIQUE") unique = true;
|
|
2922
|
+
else if (ct.contype === "CONSTR_DEFAULT") defaultVal = "<expr>";
|
|
2923
|
+
}
|
|
2924
|
+
table.columns.set(newColName, {
|
|
2925
|
+
name: newColName,
|
|
2926
|
+
type: formatPgTypeNameWithMods(cd.typeName),
|
|
2927
|
+
nullable,
|
|
2928
|
+
primary,
|
|
2929
|
+
unique,
|
|
2930
|
+
default: defaultVal
|
|
2931
|
+
});
|
|
2932
|
+
break;
|
|
2933
|
+
}
|
|
2934
|
+
case "AT_DropColumn":
|
|
2935
|
+
if (colName) table.columns.delete(colName);
|
|
2936
|
+
break;
|
|
2937
|
+
case "AT_AddConstraint": {
|
|
2938
|
+
const ct = cmd.def?.Constraint;
|
|
2939
|
+
if (!ct) break;
|
|
2940
|
+
if (ct.contype !== "CONSTR_FOREIGN") break;
|
|
2941
|
+
const fkCols = (ct.fk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
2942
|
+
const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
2943
|
+
const pkTable = ct.pktable?.relname ?? "";
|
|
2944
|
+
if (fkCols.length && pkCols.length && pkTable) {
|
|
2945
|
+
state.fks.push({
|
|
2946
|
+
constraintName: ct.conname || `${tableName}_${fkCols[0]}_fkey`,
|
|
2947
|
+
sourceTable: tableName,
|
|
2948
|
+
sourceColumn: fkCols[0],
|
|
2949
|
+
targetTable: pkTable,
|
|
2950
|
+
targetColumn: pkCols[0],
|
|
2951
|
+
onDelete: mapFkAction(ct.fk_del_action)
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
break;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
} else if (kind === "RenameStmt") {
|
|
2959
|
+
const body = stmt.RenameStmt;
|
|
2960
|
+
const renameType = body.renameType ?? "";
|
|
2961
|
+
const newName = body.newname ?? "";
|
|
2962
|
+
if (renameType === "OBJECT_COLUMN") {
|
|
2963
|
+
const tableName = body.relation?.relname ?? "";
|
|
2964
|
+
const oldName = body.subname ?? "";
|
|
2965
|
+
const table = state.tables.get(tableName);
|
|
2966
|
+
if (!table || !oldName || !newName) continue;
|
|
2967
|
+
const col = table.columns.get(oldName);
|
|
2968
|
+
if (col) {
|
|
2969
|
+
col.name = newName;
|
|
2970
|
+
table.columns.delete(oldName);
|
|
2971
|
+
table.columns.set(newName, col);
|
|
2972
|
+
}
|
|
2973
|
+
} else if (renameType === "OBJECT_TABLE") {
|
|
2974
|
+
const oldName = body.relation?.relname ?? "";
|
|
2975
|
+
if (!oldName || !newName) continue;
|
|
2976
|
+
const t = state.tables.get(oldName);
|
|
2977
|
+
if (!t) continue;
|
|
2978
|
+
state.tables.delete(oldName);
|
|
2979
|
+
t.name = newName;
|
|
2980
|
+
state.tables.set(newName, t);
|
|
2981
|
+
for (const fk of state.fks) {
|
|
2982
|
+
if (fk.sourceTable === oldName) fk.sourceTable = newName;
|
|
2983
|
+
if (fk.targetTable === oldName) fk.targetTable = newName;
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
function extractPoliciesFromStmts(stmts, state, filepath) {
|
|
2990
|
+
for (const wrap of stmts) {
|
|
2991
|
+
const body = wrap.stmt?.CreatePolicyStmt;
|
|
2992
|
+
if (!body) continue;
|
|
2993
|
+
const name = body.policy_name ?? "";
|
|
2994
|
+
if (!name) continue;
|
|
2995
|
+
const table = body.table?.relname ?? "";
|
|
2996
|
+
const cmdRaw = String(body.cmd_name ?? "all").toUpperCase();
|
|
2997
|
+
const command = ["SELECT", "INSERT", "UPDATE", "DELETE", "ALL"].includes(cmdRaw) ? cmdRaw : "ALL";
|
|
2998
|
+
const permissive = body.permissive === true;
|
|
2999
|
+
const roles = (body.roles ?? []).map((r) => {
|
|
3000
|
+
const rs = r.RoleSpec;
|
|
3001
|
+
if (!rs) return "";
|
|
3002
|
+
if (rs.roletype === "ROLESPEC_PUBLIC") return "public";
|
|
3003
|
+
if (rs.roletype === "ROLESPEC_CURRENT_USER") return "current_user";
|
|
3004
|
+
if (rs.roletype === "ROLESPEC_CSTRING" && rs.rolename) return rs.rolename;
|
|
3005
|
+
return "";
|
|
3006
|
+
}).filter(Boolean);
|
|
3007
|
+
const hasUsing = !!body.qual;
|
|
3008
|
+
const hasWithCheck = !!body.with_check;
|
|
3009
|
+
const existing = state.policies.findIndex((p) => p.table === table && p.name === name);
|
|
3010
|
+
const next = { name, table, command, permissive, roles, hasUsing, hasWithCheck, filepath };
|
|
3011
|
+
if (existing >= 0) state.policies[existing] = next;
|
|
3012
|
+
else state.policies.push(next);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
function applyDropPolicies(stmts, state) {
|
|
3016
|
+
for (const wrap of stmts) {
|
|
3017
|
+
const drop = wrap.stmt?.DropStmt;
|
|
3018
|
+
if (!drop || drop.removeType !== "OBJECT_POLICY") continue;
|
|
3019
|
+
const objects = drop.objects ?? [];
|
|
3020
|
+
for (const obj of objects) {
|
|
3021
|
+
const items = obj.List?.items ?? [];
|
|
3022
|
+
if (items.length < 2) continue;
|
|
3023
|
+
const table = items[0]?.String?.sval ?? "";
|
|
3024
|
+
const policyName = items[items.length - 1]?.String?.sval ?? "";
|
|
3025
|
+
if (!table || !policyName) continue;
|
|
3026
|
+
state.policies = state.policies.filter((p) => !(p.table === table && p.name === policyName));
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
function mapFkAction(action) {
|
|
3031
|
+
if (!action) return null;
|
|
3032
|
+
const m = {
|
|
3033
|
+
r: "RESTRICT",
|
|
3034
|
+
c: "CASCADE",
|
|
3035
|
+
s: "SET NULL",
|
|
3036
|
+
d: "SET DEFAULT",
|
|
3037
|
+
a: "NO ACTION",
|
|
3038
|
+
// pgsql-parser may also emit FKCONSTR_ACTION_* enum strings:
|
|
3039
|
+
FKCONSTR_ACTION_RESTRICT: "RESTRICT",
|
|
3040
|
+
FKCONSTR_ACTION_CASCADE: "CASCADE",
|
|
3041
|
+
FKCONSTR_ACTION_SETNULL: "SET NULL",
|
|
3042
|
+
FKCONSTR_ACTION_SETDEFAULT: "SET DEFAULT",
|
|
3043
|
+
FKCONSTR_ACTION_NOACTION: "NO ACTION"
|
|
3044
|
+
};
|
|
3045
|
+
return m[action] ?? null;
|
|
3046
|
+
}
|
|
3047
|
+
function formatPgTypeNameWithMods(typeName) {
|
|
3048
|
+
const base = formatPgTypeName(typeName);
|
|
3049
|
+
if (base === "String" || base === "unknown") return base;
|
|
3050
|
+
const typmods = [];
|
|
3051
|
+
for (const m of typeName?.typmods ?? []) {
|
|
3052
|
+
const v = m.A_Const?.ival?.ival;
|
|
3053
|
+
if (typeof v === "number") typmods.push(v);
|
|
3054
|
+
}
|
|
3055
|
+
return typmods.length ? `${base}(${typmods.join(",")})` : base;
|
|
3056
|
+
}
|
|
3057
|
+
function extractTablesFromStmts(stmts, state) {
|
|
3058
|
+
for (const wrap of stmts) {
|
|
3059
|
+
const body = wrap.stmt?.CreateStmt;
|
|
3060
|
+
if (!body) continue;
|
|
3061
|
+
const tableName = body.relation?.relname ?? "";
|
|
3062
|
+
if (!tableName) continue;
|
|
3063
|
+
const columns = /* @__PURE__ */ new Map();
|
|
3064
|
+
const fks = [];
|
|
3065
|
+
let primaryCol = null;
|
|
3066
|
+
for (const elt of body.tableElts ?? []) {
|
|
3067
|
+
if (elt.ColumnDef) {
|
|
3068
|
+
const cd = elt.ColumnDef;
|
|
3069
|
+
const colName = cd.colname ?? "";
|
|
3070
|
+
if (!colName) continue;
|
|
3071
|
+
const colType = formatPgTypeNameWithMods(cd.typeName);
|
|
3072
|
+
let nullable = true;
|
|
3073
|
+
let primary = false;
|
|
3074
|
+
let unique = false;
|
|
3075
|
+
let defaultVal = null;
|
|
3076
|
+
for (const c of cd.constraints ?? []) {
|
|
3077
|
+
const ct = c.Constraint;
|
|
3078
|
+
if (!ct) continue;
|
|
3079
|
+
switch (ct.contype) {
|
|
3080
|
+
case "CONSTR_NOTNULL":
|
|
3081
|
+
nullable = false;
|
|
3082
|
+
break;
|
|
3083
|
+
case "CONSTR_PRIMARY":
|
|
3084
|
+
primary = true;
|
|
3085
|
+
nullable = false;
|
|
3086
|
+
primaryCol = colName;
|
|
3087
|
+
break;
|
|
3088
|
+
case "CONSTR_UNIQUE":
|
|
3089
|
+
unique = true;
|
|
3090
|
+
break;
|
|
3091
|
+
case "CONSTR_DEFAULT":
|
|
3092
|
+
defaultVal = "<expr>";
|
|
3093
|
+
break;
|
|
3094
|
+
case "CONSTR_FOREIGN": {
|
|
3095
|
+
const pkTable = ct.pktable?.relname ?? "";
|
|
3096
|
+
const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3097
|
+
if (pkTable && pkCols.length) {
|
|
3098
|
+
fks.push({
|
|
3099
|
+
constraintName: ct.conname || `${tableName}_${colName}_fkey`,
|
|
3100
|
+
sourceTable: tableName,
|
|
3101
|
+
sourceColumn: colName,
|
|
3102
|
+
targetTable: pkTable,
|
|
3103
|
+
targetColumn: pkCols[0],
|
|
3104
|
+
onDelete: mapFkAction(ct.fk_del_action)
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3107
|
+
break;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
columns.set(colName, {
|
|
3112
|
+
name: colName,
|
|
3113
|
+
type: colType,
|
|
3114
|
+
nullable,
|
|
3115
|
+
primary,
|
|
3116
|
+
unique,
|
|
3117
|
+
default: defaultVal
|
|
3118
|
+
});
|
|
3119
|
+
} else if (elt.Constraint) {
|
|
3120
|
+
const ct = elt.Constraint;
|
|
3121
|
+
switch (ct.contype) {
|
|
3122
|
+
case "CONSTR_PRIMARY": {
|
|
3123
|
+
const keys = (ct.keys ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3124
|
+
if (keys.length) primaryCol = keys[0];
|
|
3125
|
+
break;
|
|
3126
|
+
}
|
|
3127
|
+
case "CONSTR_FOREIGN": {
|
|
3128
|
+
const fkCols = (ct.fk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3129
|
+
const pkCols = (ct.pk_attrs ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3130
|
+
const pkTable = ct.pktable?.relname ?? "";
|
|
3131
|
+
if (fkCols.length && pkCols.length && pkTable) {
|
|
3132
|
+
fks.push({
|
|
3133
|
+
constraintName: ct.conname || `${tableName}_${fkCols[0]}_fkey`,
|
|
3134
|
+
sourceTable: tableName,
|
|
3135
|
+
sourceColumn: fkCols[0],
|
|
3136
|
+
targetTable: pkTable,
|
|
3137
|
+
targetColumn: pkCols[0],
|
|
3138
|
+
onDelete: mapFkAction(ct.fk_del_action)
|
|
3139
|
+
});
|
|
3140
|
+
}
|
|
3141
|
+
break;
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
if (primaryCol && columns.has(primaryCol)) {
|
|
3147
|
+
columns.get(primaryCol).primary = true;
|
|
3148
|
+
columns.get(primaryCol).nullable = false;
|
|
3149
|
+
}
|
|
3150
|
+
state.tables.set(tableName, { name: tableName, columns });
|
|
3151
|
+
state.fks.push(...fks);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
function extractEnumsFromStmts(stmts, state) {
|
|
3155
|
+
for (const wrap of stmts) {
|
|
3156
|
+
const body = wrap.stmt?.CreateEnumStmt;
|
|
3157
|
+
if (!body) continue;
|
|
3158
|
+
const names = (body.typeName ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3159
|
+
const enumName = names[names.length - 1] ?? "";
|
|
3160
|
+
if (!enumName) continue;
|
|
3161
|
+
const vals = new Set(
|
|
3162
|
+
(body.vals ?? []).map((s) => s.String?.sval ?? "").filter(Boolean)
|
|
3163
|
+
);
|
|
3164
|
+
state.enums.set(enumName, { name: enumName, values: vals });
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
function applyAstAlterEnums(stmts, state) {
|
|
3168
|
+
for (const wrap of stmts) {
|
|
3169
|
+
const body = wrap.stmt?.AlterEnumStmt;
|
|
3170
|
+
if (!body) continue;
|
|
3171
|
+
const names = (body.typeName ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3172
|
+
const enumName = names[names.length - 1] ?? "";
|
|
3173
|
+
const en = state.enums.get(enumName);
|
|
3174
|
+
if (!en) continue;
|
|
3175
|
+
if (body.newVal) en.values.add(String(body.newVal));
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
function extractExtensionsFromStmts(stmts, state, filepath) {
|
|
3179
|
+
for (const wrap of stmts) {
|
|
3180
|
+
const body = wrap.stmt?.CreateExtensionStmt;
|
|
3181
|
+
if (!body) continue;
|
|
3182
|
+
const name = body.extname ?? "";
|
|
3183
|
+
if (!name) continue;
|
|
3184
|
+
let schema = null;
|
|
3185
|
+
let version = null;
|
|
3186
|
+
for (const opt of body.options ?? []) {
|
|
3187
|
+
const de = opt.DefElem;
|
|
3188
|
+
if (!de) continue;
|
|
3189
|
+
if (de.defname === "schema" && de.arg?.String?.sval) schema = de.arg.String.sval;
|
|
3190
|
+
else if (de.defname === "new_version" && de.arg?.String?.sval) version = de.arg.String.sval;
|
|
3191
|
+
}
|
|
3192
|
+
const next = { name, schema, version, filepath };
|
|
3193
|
+
const existing = state.extensions.findIndex((e) => e.name === name);
|
|
3194
|
+
if (existing >= 0) state.extensions[existing] = next;
|
|
3195
|
+
else state.extensions.push(next);
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
function extractTriggersFromStmts(stmts, state, filepath) {
|
|
3199
|
+
for (const wrap of stmts) {
|
|
3200
|
+
const body = wrap.stmt?.CreateTrigStmt;
|
|
3201
|
+
if (!body) continue;
|
|
3202
|
+
const name = body.trigname ?? "";
|
|
3203
|
+
if (!name) continue;
|
|
3204
|
+
const table = body.relation?.relname ?? "";
|
|
3205
|
+
const timingVal = body.timing ?? 0;
|
|
3206
|
+
const eventsVal = body.events ?? 0;
|
|
3207
|
+
const timing = timingVal & 2 ? "BEFORE" : timingVal & 64 ? "INSTEAD OF" : "AFTER";
|
|
3208
|
+
const events = [];
|
|
3209
|
+
if (eventsVal & 4) events.push("INSERT");
|
|
3210
|
+
if (eventsVal & 8) events.push("DELETE");
|
|
3211
|
+
if (eventsVal & 16) events.push("UPDATE");
|
|
3212
|
+
if (eventsVal & 32) events.push("TRUNCATE");
|
|
3213
|
+
const funcname = body.funcname ?? [];
|
|
3214
|
+
const funcCall = funcname[funcname.length - 1]?.String?.sval ?? "";
|
|
3215
|
+
const forEach = body.row ? "ROW" : "STATEMENT";
|
|
3216
|
+
const hasWhen = !!body.whenClause;
|
|
3217
|
+
const next = { name, table, timing, events, function: funcCall, hasWhen, forEach, filepath };
|
|
3218
|
+
const existing = state.triggers.findIndex((t) => t.table === table && t.name === name);
|
|
3219
|
+
if (existing >= 0) state.triggers[existing] = next;
|
|
3220
|
+
else state.triggers.push(next);
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
function functionIdFor(name, schema) {
|
|
3224
|
+
return schema ? `${schema}.${name}` : name;
|
|
3225
|
+
}
|
|
3226
|
+
function extractFunctionsFromStmts(stmts, state, filepath) {
|
|
3227
|
+
for (const wrap of stmts) {
|
|
3228
|
+
const body = wrap.stmt?.CreateFunctionStmt;
|
|
3229
|
+
if (!body) continue;
|
|
3230
|
+
const fn = body.funcname ?? [];
|
|
3231
|
+
if (fn.length === 0) continue;
|
|
3232
|
+
const name = fn[fn.length - 1]?.String?.sval ?? "";
|
|
3233
|
+
if (!name) continue;
|
|
3234
|
+
const schema = fn.length > 1 ? fn[fn.length - 2]?.String?.sval ?? null : null;
|
|
3235
|
+
let language = "sql";
|
|
3236
|
+
for (const opt of body.options ?? []) {
|
|
3237
|
+
const de = opt.DefElem;
|
|
3238
|
+
if (de?.defname === "language" && de.arg?.String?.sval) language = de.arg.String.sval;
|
|
3239
|
+
}
|
|
3240
|
+
const returnType = body.returnType ? formatPgTypeName(body.returnType) : "";
|
|
3241
|
+
const isProcedure = !!body.is_procedure;
|
|
3242
|
+
const next = { name, schema, language, returnType, isProcedure, filepath };
|
|
3243
|
+
const id = functionIdFor(name, schema);
|
|
3244
|
+
const existing = state.functions.findIndex((f) => functionIdFor(f.name, f.schema) === id);
|
|
3245
|
+
if (existing >= 0) state.functions[existing] = next;
|
|
3246
|
+
else state.functions.push(next);
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
function extractViewsFromStmts(stmts, state, filepath) {
|
|
3250
|
+
for (const wrap of stmts) {
|
|
3251
|
+
const stmt = wrap.stmt ?? {};
|
|
3252
|
+
const view = stmt.ViewStmt;
|
|
3253
|
+
if (view) {
|
|
3254
|
+
const name = view.view?.relname ?? "";
|
|
3255
|
+
if (!name) continue;
|
|
3256
|
+
const schema = view.view?.schemaname ?? null;
|
|
3257
|
+
const next = {
|
|
3258
|
+
name,
|
|
3259
|
+
schema,
|
|
3260
|
+
isMaterialized: false,
|
|
3261
|
+
withCheckOption: String(view.withCheckOption ?? "NO_CHECK_OPTION"),
|
|
3262
|
+
filepath
|
|
3263
|
+
};
|
|
3264
|
+
const id = functionIdFor(name, schema);
|
|
3265
|
+
const existing = state.views.findIndex((v) => functionIdFor(v.name, v.schema) === id);
|
|
3266
|
+
if (existing >= 0) state.views[existing] = next;
|
|
3267
|
+
else state.views.push(next);
|
|
3268
|
+
}
|
|
3269
|
+
const ctas = stmt.CreateTableAsStmt;
|
|
3270
|
+
if (ctas && ctas.objtype === "OBJECT_MATVIEW") {
|
|
3271
|
+
const name = ctas.into?.rel?.relname ?? "";
|
|
3272
|
+
if (!name) continue;
|
|
3273
|
+
const schema = ctas.into?.rel?.schemaname ?? null;
|
|
3274
|
+
const next = {
|
|
3275
|
+
name,
|
|
3276
|
+
schema,
|
|
3277
|
+
isMaterialized: true,
|
|
3278
|
+
withCheckOption: "N/A",
|
|
3279
|
+
filepath
|
|
3280
|
+
};
|
|
3281
|
+
const id = functionIdFor(name, schema);
|
|
3282
|
+
const existing = state.views.findIndex((v) => functionIdFor(v.name, v.schema) === id);
|
|
3283
|
+
if (existing >= 0) state.views[existing] = next;
|
|
3284
|
+
else state.views.push(next);
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
function applyDropsForSchemaObjects(stmts, state) {
|
|
3289
|
+
for (const wrap of stmts) {
|
|
3290
|
+
const drop = wrap.stmt?.DropStmt;
|
|
3291
|
+
if (!drop) continue;
|
|
3292
|
+
const removeType = drop.removeType ?? "";
|
|
3293
|
+
const objects = drop.objects ?? [];
|
|
3294
|
+
if (removeType === "OBJECT_TABLE") {
|
|
3295
|
+
const droppedTables = /* @__PURE__ */ new Set();
|
|
3296
|
+
for (const obj of objects) {
|
|
3297
|
+
const items = obj.List?.items ?? [];
|
|
3298
|
+
const last = items[items.length - 1]?.String?.sval;
|
|
3299
|
+
if (last) droppedTables.add(last);
|
|
3300
|
+
}
|
|
3301
|
+
if (droppedTables.size > 0) {
|
|
3302
|
+
for (const t of droppedTables) state.tables.delete(t);
|
|
3303
|
+
state.fks = state.fks.filter((fk) => !droppedTables.has(fk.sourceTable) && !droppedTables.has(fk.targetTable));
|
|
3304
|
+
}
|
|
3305
|
+
} else if (removeType === "OBJECT_TYPE") {
|
|
3306
|
+
const droppedEnums = /* @__PURE__ */ new Set();
|
|
3307
|
+
for (const obj of objects) {
|
|
3308
|
+
const tn = obj.TypeName;
|
|
3309
|
+
if (!tn) continue;
|
|
3310
|
+
const names = (tn.names ?? []).map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3311
|
+
const last = names[names.length - 1];
|
|
3312
|
+
if (last) droppedEnums.add(last);
|
|
3313
|
+
}
|
|
3314
|
+
for (const e of droppedEnums) state.enums.delete(e);
|
|
3315
|
+
} else if (removeType === "OBJECT_EXTENSION") {
|
|
3316
|
+
const names = /* @__PURE__ */ new Set();
|
|
3317
|
+
for (const obj of objects) {
|
|
3318
|
+
const sval = obj.String?.sval;
|
|
3319
|
+
if (sval) names.add(sval);
|
|
3320
|
+
}
|
|
3321
|
+
if (names.size > 0) state.extensions = state.extensions.filter((e) => !names.has(e.name));
|
|
3322
|
+
} else if (removeType === "OBJECT_TRIGGER") {
|
|
3323
|
+
for (const obj of objects) {
|
|
3324
|
+
const items = obj.List?.items ?? [];
|
|
3325
|
+
if (items.length < 2) continue;
|
|
3326
|
+
const table = items[0]?.String?.sval ?? "";
|
|
3327
|
+
const trigName = items[items.length - 1]?.String?.sval ?? "";
|
|
3328
|
+
if (!table || !trigName) continue;
|
|
3329
|
+
state.triggers = state.triggers.filter((t) => !(t.table === table && t.name === trigName));
|
|
3330
|
+
}
|
|
3331
|
+
} else if (removeType === "OBJECT_FUNCTION" || removeType === "OBJECT_PROCEDURE") {
|
|
3332
|
+
for (const obj of objects) {
|
|
3333
|
+
const items = obj.ObjectWithArgs?.objname?.items ?? obj.ObjectWithArgs?.objname ?? obj.List?.items ?? [];
|
|
3334
|
+
if (!items.length) continue;
|
|
3335
|
+
const segs = items.map((s) => s.String?.sval ?? "").filter(Boolean);
|
|
3336
|
+
if (!segs.length) continue;
|
|
3337
|
+
const name = segs[segs.length - 1];
|
|
3338
|
+
const schema = segs.length > 1 ? segs[segs.length - 2] : null;
|
|
3339
|
+
const id = functionIdFor(name, schema);
|
|
3340
|
+
state.functions = state.functions.filter((f) => functionIdFor(f.name, f.schema) !== id);
|
|
3341
|
+
}
|
|
3342
|
+
} else if (removeType === "OBJECT_VIEW" || removeType === "OBJECT_MATVIEW") {
|
|
3343
|
+
for (const obj of objects) {
|
|
3344
|
+
const items = obj.List?.items ?? [];
|
|
3345
|
+
if (!items.length) continue;
|
|
3346
|
+
const name = items[items.length - 1]?.String?.sval ?? "";
|
|
3347
|
+
const schema = items.length > 1 ? items[items.length - 2]?.String?.sval ?? null : null;
|
|
3348
|
+
if (!name) continue;
|
|
3349
|
+
const id = functionIdFor(name, schema);
|
|
3350
|
+
state.views = state.views.filter((v) => functionIdFor(v.name, v.schema) !== id);
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
function indexIsPrismaUncoverable(idx) {
|
|
3356
|
+
return idx.hasPredicate || idx.hasExpressions || idx.method !== "btree";
|
|
3357
|
+
}
|
|
2911
3358
|
function loadPrismaState(schemaPath) {
|
|
2912
3359
|
if (!schemaPath || !(0, import_node_fs8.existsSync)(schemaPath)) return null;
|
|
2913
3360
|
const content = (0, import_node_fs8.readFileSync)(schemaPath, "utf-8");
|
|
@@ -3074,6 +3521,96 @@ function verify(sqlState, prisma) {
|
|
|
3074
3521
|
}
|
|
3075
3522
|
return { contradictions, flaggedEdges };
|
|
3076
3523
|
}
|
|
3524
|
+
function deriveMigrationName(sqlPath) {
|
|
3525
|
+
const segments = sqlPath.split(/[\\/]/);
|
|
3526
|
+
const last = segments[segments.length - 1];
|
|
3527
|
+
if (last === "migration.sql" && segments.length >= 2) {
|
|
3528
|
+
return segments[segments.length - 2];
|
|
3529
|
+
}
|
|
3530
|
+
return last.replace(/\.sql$/, "");
|
|
3531
|
+
}
|
|
3532
|
+
function extractMigrationInfoFromStmts(stmts, name, filepath) {
|
|
3533
|
+
let isDestructive = false;
|
|
3534
|
+
let hasOrphanCheck = false;
|
|
3535
|
+
let hasSidecarBackup = false;
|
|
3536
|
+
let hasPreFlightNotice = false;
|
|
3537
|
+
let containsBackfill = false;
|
|
3538
|
+
let containsDropColumn = false;
|
|
3539
|
+
let containsDropTable = false;
|
|
3540
|
+
for (const wrap of stmts) {
|
|
3541
|
+
const stmt = wrap.stmt ?? {};
|
|
3542
|
+
const kind = Object.keys(stmt)[0];
|
|
3543
|
+
if (!kind) continue;
|
|
3544
|
+
const body = stmt[kind] ?? {};
|
|
3545
|
+
switch (kind) {
|
|
3546
|
+
case "AlterTableStmt": {
|
|
3547
|
+
const cmds = body.cmds ?? [];
|
|
3548
|
+
for (const c of cmds) {
|
|
3549
|
+
const subtype = c.AlterTableCmd?.subtype;
|
|
3550
|
+
if (subtype === "AT_DropColumn") {
|
|
3551
|
+
containsDropColumn = true;
|
|
3552
|
+
isDestructive = true;
|
|
3553
|
+
} else if (subtype === "AT_AlterColumnType" || subtype === "AT_DropNotNull" || subtype === "AT_DropConstraint") {
|
|
3554
|
+
isDestructive = true;
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
break;
|
|
3558
|
+
}
|
|
3559
|
+
case "DropStmt": {
|
|
3560
|
+
const removeType = body.removeType ?? "";
|
|
3561
|
+
if (removeType === "OBJECT_TABLE") {
|
|
3562
|
+
containsDropTable = true;
|
|
3563
|
+
isDestructive = true;
|
|
3564
|
+
} else if (removeType === "OBJECT_TYPE" || removeType === "OBJECT_COLUMN" || removeType === "OBJECT_INDEX" || removeType === "OBJECT_POLICY") {
|
|
3565
|
+
isDestructive = true;
|
|
3566
|
+
}
|
|
3567
|
+
break;
|
|
3568
|
+
}
|
|
3569
|
+
case "CreateStmt": {
|
|
3570
|
+
const relname = body.relation?.relname ?? "";
|
|
3571
|
+
if (relname.startsWith("_backup_")) hasSidecarBackup = true;
|
|
3572
|
+
break;
|
|
3573
|
+
}
|
|
3574
|
+
case "CreateTableAsStmt": {
|
|
3575
|
+
const relname = body.into?.rel?.relname ?? "";
|
|
3576
|
+
if (relname.startsWith("_backup_")) hasSidecarBackup = true;
|
|
3577
|
+
break;
|
|
3578
|
+
}
|
|
3579
|
+
case "UpdateStmt":
|
|
3580
|
+
case "InsertStmt":
|
|
3581
|
+
case "DeleteStmt": {
|
|
3582
|
+
containsBackfill = true;
|
|
3583
|
+
break;
|
|
3584
|
+
}
|
|
3585
|
+
case "DoStmt": {
|
|
3586
|
+
const args = body.args ?? [];
|
|
3587
|
+
for (const arg of args) {
|
|
3588
|
+
const def = arg.DefElem;
|
|
3589
|
+
if (!def || def.defname !== "as") continue;
|
|
3590
|
+
const code = def.arg?.String?.sval ?? "";
|
|
3591
|
+
if (/\bRAISE\s+EXCEPTION\b/i.test(code)) hasOrphanCheck = true;
|
|
3592
|
+
if (/\bRAISE\s+NOTICE\b/i.test(code)) hasPreFlightNotice = true;
|
|
3593
|
+
}
|
|
3594
|
+
break;
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
const tsMatch = name.match(/^(\d{8,14})/);
|
|
3599
|
+
const timestamp = tsMatch ? tsMatch[1] : null;
|
|
3600
|
+
return {
|
|
3601
|
+
name,
|
|
3602
|
+
filepath,
|
|
3603
|
+
timestamp,
|
|
3604
|
+
isDestructive,
|
|
3605
|
+
hasOrphanCheck,
|
|
3606
|
+
hasSidecarBackup,
|
|
3607
|
+
hasPreFlightNotice,
|
|
3608
|
+
containsBackfill,
|
|
3609
|
+
containsDropColumn,
|
|
3610
|
+
containsDropTable,
|
|
3611
|
+
statementCount: stmts.length
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
3077
3614
|
function migrationsDirFor(rootDir) {
|
|
3078
3615
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
3079
3616
|
if (!paths) return null;
|
|
@@ -3128,6 +3665,132 @@ function generate3(rootDir) {
|
|
|
3128
3665
|
values: [...sqlEnum.values]
|
|
3129
3666
|
});
|
|
3130
3667
|
}
|
|
3668
|
+
let indexNodeCount = 0;
|
|
3669
|
+
for (const idx of sqlState.indexes) {
|
|
3670
|
+
if (!indexIsPrismaUncoverable(idx)) continue;
|
|
3671
|
+
nodes.push({
|
|
3672
|
+
id: `index:${idx.name}`,
|
|
3673
|
+
type: "index",
|
|
3674
|
+
name: idx.name,
|
|
3675
|
+
source: "sql",
|
|
3676
|
+
table: idx.table,
|
|
3677
|
+
unique: idx.unique,
|
|
3678
|
+
method: idx.method,
|
|
3679
|
+
columns: idx.columns,
|
|
3680
|
+
has_expressions: idx.hasExpressions,
|
|
3681
|
+
has_predicate: idx.hasPredicate,
|
|
3682
|
+
filepath: idx.filepath
|
|
3683
|
+
});
|
|
3684
|
+
indexNodeCount++;
|
|
3685
|
+
}
|
|
3686
|
+
let extensionNodeCount = 0;
|
|
3687
|
+
for (const ext of sqlState.extensions) {
|
|
3688
|
+
nodes.push({
|
|
3689
|
+
id: `extension:${ext.name}`,
|
|
3690
|
+
type: "extension",
|
|
3691
|
+
name: ext.name,
|
|
3692
|
+
source: "sql",
|
|
3693
|
+
schema: ext.schema,
|
|
3694
|
+
version: ext.version,
|
|
3695
|
+
filepath: ext.filepath
|
|
3696
|
+
});
|
|
3697
|
+
extensionNodeCount++;
|
|
3698
|
+
}
|
|
3699
|
+
let triggerNodeCount = 0;
|
|
3700
|
+
for (const trg of sqlState.triggers) {
|
|
3701
|
+
nodes.push({
|
|
3702
|
+
id: `trigger:${trg.table}:${trg.name}`,
|
|
3703
|
+
type: "trigger",
|
|
3704
|
+
name: trg.name,
|
|
3705
|
+
source: "sql",
|
|
3706
|
+
table: trg.table,
|
|
3707
|
+
timing: trg.timing,
|
|
3708
|
+
events: trg.events,
|
|
3709
|
+
function: trg.function,
|
|
3710
|
+
has_when: trg.hasWhen,
|
|
3711
|
+
for_each: trg.forEach,
|
|
3712
|
+
filepath: trg.filepath
|
|
3713
|
+
});
|
|
3714
|
+
triggerNodeCount++;
|
|
3715
|
+
}
|
|
3716
|
+
let functionNodeCount = 0;
|
|
3717
|
+
for (const fn of sqlState.functions) {
|
|
3718
|
+
const qualified = fn.schema ? `${fn.schema}.${fn.name}` : fn.name;
|
|
3719
|
+
nodes.push({
|
|
3720
|
+
id: `function:${qualified}`,
|
|
3721
|
+
type: "function",
|
|
3722
|
+
name: fn.name,
|
|
3723
|
+
source: "sql",
|
|
3724
|
+
schema: fn.schema,
|
|
3725
|
+
language: fn.language,
|
|
3726
|
+
return_type: fn.returnType,
|
|
3727
|
+
is_procedure: fn.isProcedure,
|
|
3728
|
+
filepath: fn.filepath
|
|
3729
|
+
});
|
|
3730
|
+
functionNodeCount++;
|
|
3731
|
+
}
|
|
3732
|
+
let viewNodeCount = 0;
|
|
3733
|
+
for (const vw of sqlState.views) {
|
|
3734
|
+
const qualified = vw.schema ? `${vw.schema}.${vw.name}` : vw.name;
|
|
3735
|
+
nodes.push({
|
|
3736
|
+
id: `${vw.isMaterialized ? "matview" : "view"}:${qualified}`,
|
|
3737
|
+
type: vw.isMaterialized ? "materialized_view" : "view",
|
|
3738
|
+
name: vw.name,
|
|
3739
|
+
source: "sql",
|
|
3740
|
+
schema: vw.schema,
|
|
3741
|
+
is_materialized: vw.isMaterialized,
|
|
3742
|
+
with_check_option: vw.withCheckOption,
|
|
3743
|
+
filepath: vw.filepath
|
|
3744
|
+
});
|
|
3745
|
+
viewNodeCount++;
|
|
3746
|
+
}
|
|
3747
|
+
let policyNodeCount = 0;
|
|
3748
|
+
for (const pol of sqlState.policies) {
|
|
3749
|
+
nodes.push({
|
|
3750
|
+
id: `policy:${pol.table}:${pol.name}`,
|
|
3751
|
+
type: "policy",
|
|
3752
|
+
name: pol.name,
|
|
3753
|
+
source: "sql",
|
|
3754
|
+
table: pol.table,
|
|
3755
|
+
command: pol.command,
|
|
3756
|
+
permissive: pol.permissive,
|
|
3757
|
+
roles: pol.roles,
|
|
3758
|
+
has_using: pol.hasUsing,
|
|
3759
|
+
has_with_check: pol.hasWithCheck,
|
|
3760
|
+
filepath: pol.filepath
|
|
3761
|
+
});
|
|
3762
|
+
policyNodeCount++;
|
|
3763
|
+
}
|
|
3764
|
+
const migrationFiles = migrationsDir ? discoverMigrationFiles(migrationsDir) : [];
|
|
3765
|
+
let migrationNodeCount = 0;
|
|
3766
|
+
for (const sqlPath of migrationFiles) {
|
|
3767
|
+
const sql = (0, import_node_fs8.readFileSync)(sqlPath, "utf-8");
|
|
3768
|
+
const name = deriveMigrationName(sqlPath);
|
|
3769
|
+
let ast;
|
|
3770
|
+
try {
|
|
3771
|
+
ast = postgresDialect.parse(sql);
|
|
3772
|
+
} catch {
|
|
3773
|
+
ast = { stmts: [] };
|
|
3774
|
+
}
|
|
3775
|
+
const info = postgresDialect.extractMigrationInfo(ast, name, sqlPath);
|
|
3776
|
+
nodes.push({
|
|
3777
|
+
id: `migration:${name}`,
|
|
3778
|
+
type: "migration",
|
|
3779
|
+
name,
|
|
3780
|
+
source: "sql",
|
|
3781
|
+
filepath: info.filepath,
|
|
3782
|
+
timestamp: info.timestamp,
|
|
3783
|
+
is_destructive: info.isDestructive,
|
|
3784
|
+
has_orphan_check: info.hasOrphanCheck,
|
|
3785
|
+
has_sidecar_backup: info.hasSidecarBackup,
|
|
3786
|
+
has_pre_flight_notice: info.hasPreFlightNotice,
|
|
3787
|
+
contains_backfill: info.containsBackfill,
|
|
3788
|
+
contains_drop_column: info.containsDropColumn,
|
|
3789
|
+
contains_drop_table: info.containsDropTable,
|
|
3790
|
+
statement_count: info.statementCount
|
|
3791
|
+
});
|
|
3792
|
+
migrationNodeCount++;
|
|
3793
|
+
}
|
|
3131
3794
|
const sqlOnlyTables = new Set(nodes.filter((n) => n.type === "table").map((n) => n.id));
|
|
3132
3795
|
const edges = sqlState.fks.filter((fk) => sqlOnlyTables.has(fk.sourceTable)).map((fk) => ({
|
|
3133
3796
|
source: fk.sourceTable,
|
|
@@ -3146,6 +3809,13 @@ function generate3(rootDir) {
|
|
|
3146
3809
|
sql_tables: sqlState.tables.size,
|
|
3147
3810
|
sql_enums: sqlState.enums.size,
|
|
3148
3811
|
sql_fks: sqlState.fks.length,
|
|
3812
|
+
sql_index_nodes: indexNodeCount,
|
|
3813
|
+
sql_policy_nodes: policyNodeCount,
|
|
3814
|
+
sql_extension_nodes: extensionNodeCount,
|
|
3815
|
+
sql_trigger_nodes: triggerNodeCount,
|
|
3816
|
+
sql_function_nodes: functionNodeCount,
|
|
3817
|
+
sql_view_nodes: viewNodeCount,
|
|
3818
|
+
sql_migration_nodes: migrationNodeCount,
|
|
3149
3819
|
additive_nodes: nodes.length,
|
|
3150
3820
|
contradictions_found: contradictions.length,
|
|
3151
3821
|
flagged_edges_found: flaggedEdges.length
|
|
@@ -4693,6 +5363,7 @@ if (!import_node_worker_threads.parentPort) {
|
|
|
4693
5363
|
async function run(req) {
|
|
4694
5364
|
try {
|
|
4695
5365
|
await initTreeSitter();
|
|
5366
|
+
await (0, import_pgsql_parser2.loadModule)();
|
|
4696
5367
|
const config = loadConfig(req.rootDir);
|
|
4697
5368
|
setExtractorConfig({
|
|
4698
5369
|
dbIdentifiers: config.parsers?.patterns?.dbIdentifiers,
|