depgraph-core 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/depgraph-mcp.js CHANGED
@@ -3263,8 +3263,8 @@ var require_utils = __commonJS({
3263
3263
  }
3264
3264
  return ind;
3265
3265
  }
3266
- function removeDotSegments(path7) {
3267
- let input = path7;
3266
+ function removeDotSegments(path9) {
3267
+ let input = path9;
3268
3268
  const output = [];
3269
3269
  let nextSlash = -1;
3270
3270
  let len = 0;
@@ -3673,8 +3673,8 @@ var require_schemes = __commonJS({
3673
3673
  }
3674
3674
  if (wsComponent.resourceName) {
3675
3675
  const queryIndex = wsComponent.resourceName.indexOf("?");
3676
- const path7 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3677
- wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
3676
+ const path9 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3677
+ wsComponent.path = path9 && path9 !== "/" ? path9 : void 0;
3678
3678
  wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
3679
3679
  wsComponent.resourceName = void 0;
3680
3680
  }
@@ -7677,8 +7677,8 @@ function getErrorMap() {
7677
7677
 
7678
7678
  // node_modules/zod/v3/helpers/parseUtil.js
7679
7679
  var makeIssue = (params) => {
7680
- const { data, path: path7, errorMaps, issueData } = params;
7681
- const fullPath = [...path7, ...issueData.path || []];
7680
+ const { data, path: path9, errorMaps, issueData } = params;
7681
+ const fullPath = [...path9, ...issueData.path || []];
7682
7682
  const fullIssue = {
7683
7683
  ...issueData,
7684
7684
  path: fullPath
@@ -7794,11 +7794,11 @@ var errorUtil;
7794
7794
 
7795
7795
  // node_modules/zod/v3/types.js
7796
7796
  var ParseInputLazyPath = class {
7797
- constructor(parent, value, path7, key) {
7797
+ constructor(parent, value, path9, key) {
7798
7798
  this._cachedPath = [];
7799
7799
  this.parent = parent;
7800
7800
  this.data = value;
7801
- this._path = path7;
7801
+ this._path = path9;
7802
7802
  this._key = key;
7803
7803
  }
7804
7804
  get path() {
@@ -11435,10 +11435,10 @@ function assignProp(target, prop, value) {
11435
11435
  configurable: true
11436
11436
  });
11437
11437
  }
11438
- function getElementAtPath(obj, path7) {
11439
- if (!path7)
11438
+ function getElementAtPath(obj, path9) {
11439
+ if (!path9)
11440
11440
  return obj;
11441
- return path7.reduce((acc, key) => acc?.[key], obj);
11441
+ return path9.reduce((acc, key) => acc?.[key], obj);
11442
11442
  }
11443
11443
  function promiseAllObject(promisesObj) {
11444
11444
  const keys = Object.keys(promisesObj);
@@ -11758,11 +11758,11 @@ function aborted(x, startIndex = 0) {
11758
11758
  }
11759
11759
  return false;
11760
11760
  }
11761
- function prefixIssues(path7, issues) {
11761
+ function prefixIssues(path9, issues) {
11762
11762
  return issues.map((iss) => {
11763
11763
  var _a;
11764
11764
  (_a = iss).path ?? (_a.path = []);
11765
- iss.path.unshift(path7);
11765
+ iss.path.unshift(path9);
11766
11766
  return iss;
11767
11767
  });
11768
11768
  }
@@ -15173,11 +15173,11 @@ function normalizeObjectSchema(schema) {
15173
15173
  }
15174
15174
  return void 0;
15175
15175
  }
15176
- function getDotPath(path7) {
15177
- if (path7.length === 0) {
15176
+ function getDotPath(path9) {
15177
+ if (path9.length === 0) {
15178
15178
  return "object root";
15179
15179
  }
15180
- return path7.reduce((acc, seg, index) => {
15180
+ return path9.reduce((acc, seg, index) => {
15181
15181
  if (index === 0) {
15182
15182
  return String(seg);
15183
15183
  }
@@ -21545,7 +21545,9 @@ var SUPPORTED_EXTS = /* @__PURE__ */ new Set([
21545
21545
  ".vue",
21546
21546
  ".svelte",
21547
21547
  ".dart",
21548
- ".rs"
21548
+ ".rs",
21549
+ ".sql",
21550
+ ".prisma"
21549
21551
  ]);
21550
21552
  var MAX_FILE_SIZE = 3e5;
21551
21553
  var MAX_BFS_DEPTH = 10;
@@ -23592,9 +23594,415 @@ var RustParser = {
23592
23594
  };
23593
23595
  registerParser(RustParser);
23594
23596
 
23597
+ // src/languages/sql/helpers.ts
23598
+ var NAME_PART = '(?:"(?:[^"\\n]|"")*"|`(?:[^`\\n]|``)*`|\\[(?:[^\\]\\n]|\\]\\])*\\]|[\\w$]+)';
23599
+ var QUAL_NAME = `${NAME_PART}(?:\\s*\\.\\s*${NAME_PART})*`;
23600
+ var ROUTINE_RECOVERY_RX = new RegExp(
23601
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?(?:FUNCTION|PROC(?:EDURE)?)\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23602
+ "gi"
23603
+ );
23604
+ function lineOf(text, offset) {
23605
+ return text.slice(0, offset).split("\n").length;
23606
+ }
23607
+ function normIdent(name) {
23608
+ return name.split(".").map((p) => {
23609
+ const s = p.trim();
23610
+ if (s.length >= 2 && (s[0] === s[s.length - 1] && (s[0] === '"' || s[0] === "`") || s[0] === "[" && s[s.length - 1] === "]")) {
23611
+ return s.slice(1, -1).toLowerCase();
23612
+ }
23613
+ return s.toLowerCase();
23614
+ }).join(".");
23615
+ }
23616
+ function maskSqlComments(text) {
23617
+ const out = [];
23618
+ let i = 0;
23619
+ const n = text.length;
23620
+ function blank(upto) {
23621
+ for (const ch of text.slice(i, upto)) out.push(ch === "\n" ? "\n" : " ");
23622
+ return upto;
23623
+ }
23624
+ while (i < n) {
23625
+ const c = text[i];
23626
+ if (c === "'") {
23627
+ let j = i + 1;
23628
+ while (j < n && text[j] !== "\n") {
23629
+ if (text[j] === "'") {
23630
+ if (j + 1 < n && text[j + 1] === "'") {
23631
+ j += 2;
23632
+ continue;
23633
+ }
23634
+ j++;
23635
+ break;
23636
+ }
23637
+ j++;
23638
+ }
23639
+ i = blank(j);
23640
+ } else if (c === '"' || c === "`" || c === "[") {
23641
+ const closer = c === "[" ? "]" : c;
23642
+ let j = i + 1;
23643
+ let closed = false;
23644
+ while (j < n && text[j] !== "\n") {
23645
+ if (text[j] === closer) {
23646
+ if (j + 1 < n && text[j + 1] === closer) {
23647
+ j += 2;
23648
+ continue;
23649
+ }
23650
+ j++;
23651
+ closed = true;
23652
+ break;
23653
+ }
23654
+ j++;
23655
+ }
23656
+ const span = text.slice(i, j);
23657
+ if (closed && !span.includes("--") && !span.includes("/*")) {
23658
+ out.push(span);
23659
+ i = j;
23660
+ } else {
23661
+ let eol = text.indexOf("\n", i);
23662
+ if (eol === -1) eol = n;
23663
+ i = blank(eol);
23664
+ }
23665
+ } else if (c === "-" && i + 1 < n && text[i + 1] === "-") {
23666
+ let j = i;
23667
+ while (j < n && text[j] !== "\n") j++;
23668
+ i = blank(j);
23669
+ } else if (c === "/" && i + 1 < n && text[i + 1] === "*") {
23670
+ let depth = 1;
23671
+ let j = i + 2;
23672
+ while (j < n && depth > 0) {
23673
+ if (text[j] === "/" && j + 1 < n && text[j + 1] === "*") {
23674
+ depth++;
23675
+ j += 2;
23676
+ } else if (text[j] === "*" && j + 1 < n && text[j + 1] === "/") {
23677
+ depth--;
23678
+ j += 2;
23679
+ } else j++;
23680
+ }
23681
+ i = blank(j);
23682
+ } else {
23683
+ out.push(c);
23684
+ i++;
23685
+ }
23686
+ }
23687
+ return out.join("");
23688
+ }
23689
+ var NON_TABLES = /* @__PURE__ */ new Set([
23690
+ "select",
23691
+ "where",
23692
+ "set",
23693
+ "dual",
23694
+ "null",
23695
+ "true",
23696
+ "false",
23697
+ "first",
23698
+ "skip",
23699
+ "rows",
23700
+ "next",
23701
+ "only",
23702
+ "lateral",
23703
+ "values",
23704
+ "inserted",
23705
+ "deleted",
23706
+ "new",
23707
+ "old"
23708
+ ]);
23709
+ function collectCteNames(text) {
23710
+ const ctes = /* @__PURE__ */ new Set();
23711
+ const rx = /\bWITH\s+(?:RECURSIVE\s+)?([\w$]+)\s*(?:\([^()]*\))?\s+AS\s*\(/gi;
23712
+ for (const m of text.matchAll(rx)) ctes.add(normIdent(m[1]));
23713
+ return ctes;
23714
+ }
23715
+ function findMatchingParen(text, openIdx) {
23716
+ let depth = 0;
23717
+ for (let i = openIdx; i < text.length; i++) {
23718
+ if (text[i] === "(") depth++;
23719
+ else if (text[i] === ")") {
23720
+ depth--;
23721
+ if (depth === 0) return i;
23722
+ }
23723
+ }
23724
+ return text.length;
23725
+ }
23726
+ function findStatementEnd(text, start) {
23727
+ const slice = text.slice(start);
23728
+ const match = slice.match(/(?:^|\n)\s*CREATE\s/i);
23729
+ if (!match || match.index == null) return text.length;
23730
+ const offset = match.index === 0 ? 0 : match.index + 1;
23731
+ return start + offset;
23732
+ }
23733
+ function collectTableRefs(masked, extraNonTables = /* @__PURE__ */ new Set()) {
23734
+ const skip = /* @__PURE__ */ new Set([...NON_TABLES, ...extraNonTables]);
23735
+ const refs = [];
23736
+ const seen = /* @__PURE__ */ new Set();
23737
+ const rx = new RegExp(
23738
+ `\\b(?:FROM|JOIN|INTO|UPDATE)\\s+(${QUAL_NAME})`,
23739
+ "gi"
23740
+ );
23741
+ for (const m of masked.matchAll(rx)) {
23742
+ const raw = m[1];
23743
+ const key = normIdent(raw);
23744
+ if (skip.has(key) || seen.has(key)) continue;
23745
+ seen.add(key);
23746
+ refs.push({ name: raw, line: lineOf(masked, m.index ?? 0) });
23747
+ }
23748
+ return refs;
23749
+ }
23750
+ function collectFkRefs(masked) {
23751
+ const refs = [];
23752
+ const seen = /* @__PURE__ */ new Set();
23753
+ const rx = new RegExp(`\\bREFERENCES\\s+(${QUAL_NAME})`, "gi");
23754
+ for (const m of masked.matchAll(rx)) {
23755
+ const raw = m[1];
23756
+ const key = normIdent(raw);
23757
+ if (seen.has(key)) continue;
23758
+ seen.add(key);
23759
+ refs.push({ name: raw, line: lineOf(masked, m.index ?? 0) });
23760
+ }
23761
+ return refs;
23762
+ }
23763
+
23764
+ // src/languages/sql/patterns.ts
23765
+ var sqlEntityPatterns = [
23766
+ {
23767
+ regex: new RegExp(
23768
+ `\\bCREATE\\s+(?:TEMP(?:ORARY)?\\s+)?TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23769
+ "gi"
23770
+ ),
23771
+ type: "table"
23772
+ },
23773
+ {
23774
+ regex: new RegExp(
23775
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?(?:MATERIALIZED\\s+)?VIEW\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23776
+ "gi"
23777
+ ),
23778
+ type: "view"
23779
+ },
23780
+ {
23781
+ regex: new RegExp(
23782
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?FUNCTION\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23783
+ "gi"
23784
+ ),
23785
+ type: "function"
23786
+ },
23787
+ {
23788
+ regex: new RegExp(
23789
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?PROC(?:EDURE)?\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23790
+ "gi"
23791
+ ),
23792
+ type: "procedure"
23793
+ },
23794
+ {
23795
+ regex: new RegExp(
23796
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?TRIGGER\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23797
+ "gi"
23798
+ ),
23799
+ type: "trigger"
23800
+ },
23801
+ {
23802
+ regex: new RegExp(
23803
+ `\\bCREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:CONCURRENTLY\\s+)?(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})\\s+ON\\b`,
23804
+ "gi"
23805
+ ),
23806
+ type: "index"
23807
+ }
23808
+ ];
23809
+
23810
+ // src/languages/sql/extractor.ts
23811
+ var import_path3 = __toESM(require("path"));
23812
+ var _currentFile = "";
23813
+ function extractEntities12(code, filePath) {
23814
+ _currentFile = filePath;
23815
+ const masked = maskSqlComments(code);
23816
+ const entities = [];
23817
+ const seenNames = /* @__PURE__ */ new Set();
23818
+ for (const { regex, type } of sqlEntityPatterns) {
23819
+ regex.lastIndex = 0;
23820
+ for (const m of masked.matchAll(regex)) {
23821
+ const raw = m[1].trim();
23822
+ const key = normIdent(raw);
23823
+ if (seenNames.has(key)) continue;
23824
+ seenNames.add(key);
23825
+ entities.push({ name: raw, type, line: lineOf(code, m.index ?? 0), complexity: "low" });
23826
+ }
23827
+ }
23828
+ ROUTINE_RECOVERY_RX.lastIndex = 0;
23829
+ for (const m of masked.matchAll(ROUTINE_RECOVERY_RX)) {
23830
+ const raw = m[1].trim();
23831
+ const key = normIdent(raw);
23832
+ if (seenNames.has(key)) continue;
23833
+ seenNames.add(key);
23834
+ entities.push({ name: `${raw}()`, type: "procedure", line: lineOf(code, m.index ?? 0), complexity: "low" });
23835
+ }
23836
+ return entities;
23837
+ }
23838
+ var TABLE_HEADER_RX = new RegExp(
23839
+ `\\bCREATE\\s+(?:TEMP(?:ORARY)?\\s+)?TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23840
+ "gi"
23841
+ );
23842
+ var VIEW_HEADER_RX = new RegExp(
23843
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?(?:MATERIALIZED\\s+)?VIEW\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23844
+ "gi"
23845
+ );
23846
+ var ROUTINE_HEADER_RX = new RegExp(
23847
+ `\\bCREATE\\s+(?:OR\\s+(?:REPLACE|ALTER)\\s+)?(?:FUNCTION|PROC(?:EDURE)?)\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(${QUAL_NAME})`,
23848
+ "gi"
23849
+ );
23850
+ function extractImports12(code) {
23851
+ const masked = maskSqlComments(code);
23852
+ const fileBase = import_path3.default.basename(_currentFile, import_path3.default.extname(_currentFile));
23853
+ if (!fileBase) return [];
23854
+ const imports = [];
23855
+ function emit(fromEntity, name, relationType) {
23856
+ if (normIdent(name) === normIdent(fromEntity)) return;
23857
+ imports.push({ source: fileBase, names: [name], isLocal: true, fromEntity, relationType });
23858
+ }
23859
+ TABLE_HEADER_RX.lastIndex = 0;
23860
+ for (const m of masked.matchAll(TABLE_HEADER_RX)) {
23861
+ const tableName = m[1].trim();
23862
+ const afterHeader = m.index + m[0].length;
23863
+ let pi = afterHeader;
23864
+ while (pi < masked.length && masked[pi] !== "(" && masked[pi] !== ";") pi++;
23865
+ if (masked[pi] !== "(") continue;
23866
+ const bodyEnd = findMatchingParen(masked, pi);
23867
+ const body = masked.slice(pi + 1, bodyEnd);
23868
+ for (const ref of collectFkRefs(body)) emit(tableName, ref.name, "references");
23869
+ }
23870
+ VIEW_HEADER_RX.lastIndex = 0;
23871
+ for (const m of masked.matchAll(VIEW_HEADER_RX)) {
23872
+ const viewName = m[1].trim();
23873
+ const afterHeader = m.index + m[0].length;
23874
+ const bodyEnd = findStatementEnd(masked, afterHeader);
23875
+ const body = masked.slice(afterHeader, bodyEnd);
23876
+ const ctes = collectCteNames(body);
23877
+ for (const ref of collectTableRefs(body, ctes)) emit(viewName, ref.name, "reads_from");
23878
+ }
23879
+ ROUTINE_HEADER_RX.lastIndex = 0;
23880
+ for (const m of masked.matchAll(ROUTINE_HEADER_RX)) {
23881
+ const routineName = m[1].trim();
23882
+ const afterHeader = m.index + m[0].length;
23883
+ const bodyEnd = findStatementEnd(masked, afterHeader);
23884
+ const body = masked.slice(afterHeader, bodyEnd);
23885
+ const ctes = collectCteNames(body);
23886
+ for (const ref of collectTableRefs(body, ctes)) emit(routineName, ref.name, "reads_from");
23887
+ }
23888
+ return imports;
23889
+ }
23890
+ function extractExports12(code) {
23891
+ const masked = maskSqlComments(code);
23892
+ const names = [];
23893
+ const seen = /* @__PURE__ */ new Set();
23894
+ for (const { regex } of sqlEntityPatterns) {
23895
+ regex.lastIndex = 0;
23896
+ for (const m of masked.matchAll(regex)) {
23897
+ const key = normIdent(m[1].trim());
23898
+ if (!seen.has(key)) {
23899
+ seen.add(key);
23900
+ names.push(m[1].trim());
23901
+ }
23902
+ }
23903
+ }
23904
+ return names;
23905
+ }
23906
+
23907
+ // src/languages/sql/index.ts
23908
+ var SqlParser = {
23909
+ lang: "sql",
23910
+ extensions: [".sql"],
23911
+ extractEntities: extractEntities12,
23912
+ extractImports: extractImports12,
23913
+ extractExports: extractExports12,
23914
+ entityPatterns: sqlEntityPatterns
23915
+ };
23916
+ registerParser(SqlParser);
23917
+
23918
+ // src/languages/prisma/extractor.ts
23919
+ var import_path4 = __toESM(require("path"));
23920
+ var PRISMA_SCALARS = /* @__PURE__ */ new Set([
23921
+ "string",
23922
+ "int",
23923
+ "float",
23924
+ "boolean",
23925
+ "datetime",
23926
+ "json",
23927
+ "bytes",
23928
+ "decimal",
23929
+ "bigint",
23930
+ "unsupported"
23931
+ ]);
23932
+ function isScalar(typeName) {
23933
+ return PRISMA_SCALARS.has(typeName.toLowerCase());
23934
+ }
23935
+ function baseType(t) {
23936
+ return t.replace(/[\[\]?]/g, "").trim();
23937
+ }
23938
+ var _currentFile2 = "";
23939
+ function extractEntities13(code, filePath) {
23940
+ _currentFile2 = filePath;
23941
+ const entities = [];
23942
+ const modelRx = /^model\s+(\w+)\s*\{/gm;
23943
+ for (const m of code.matchAll(modelRx)) {
23944
+ const line = code.slice(0, m.index).split("\n").length;
23945
+ entities.push({ name: m[1], type: "model", line, complexity: "low" });
23946
+ }
23947
+ const enumRx = /^enum\s+(\w+)\s*\{/gm;
23948
+ for (const m of code.matchAll(enumRx)) {
23949
+ const line = code.slice(0, m.index).split("\n").length;
23950
+ entities.push({ name: m[1], type: "enum", line, complexity: "low" });
23951
+ }
23952
+ return entities;
23953
+ }
23954
+ function extractImports13(code) {
23955
+ const fileBase = import_path4.default.basename(_currentFile2, import_path4.default.extname(_currentFile2));
23956
+ if (!fileBase) return [];
23957
+ const imports = [];
23958
+ const modelBlockRx = /^model\s+(\w+)\s*\{([^}]*)\}/gms;
23959
+ for (const block of code.matchAll(modelBlockRx)) {
23960
+ const modelName = block[1];
23961
+ const body = block[2];
23962
+ const fieldRx = /^\s*(\w+)\s+(\w[\w[\]?]*)/gm;
23963
+ const seen = /* @__PURE__ */ new Set();
23964
+ for (const field of body.matchAll(fieldRx)) {
23965
+ const rawType = field[2];
23966
+ const typeName = baseType(rawType);
23967
+ if (isScalar(typeName)) continue;
23968
+ if (typeName === modelName) continue;
23969
+ if (seen.has(typeName)) continue;
23970
+ seen.add(typeName);
23971
+ imports.push({
23972
+ source: fileBase,
23973
+ names: [typeName],
23974
+ isLocal: true,
23975
+ fromEntity: modelName,
23976
+ relationType: "relation"
23977
+ });
23978
+ }
23979
+ }
23980
+ return imports;
23981
+ }
23982
+ function extractExports13(code) {
23983
+ const names = [];
23984
+ for (const m of code.matchAll(/^(?:model|enum)\s+(\w+)/gm)) names.push(m[1]);
23985
+ return names;
23986
+ }
23987
+
23988
+ // src/languages/prisma/index.ts
23989
+ var prismaEntityPatterns = [
23990
+ { regex: /^model\s+(\w+)\s*\{/gm, type: "model" },
23991
+ { regex: /^enum\s+(\w+)\s*\{/gm, type: "enum" }
23992
+ ];
23993
+ var PrismaParser = {
23994
+ lang: "prisma",
23995
+ extensions: [".prisma"],
23996
+ extractEntities: extractEntities13,
23997
+ extractImports: extractImports13,
23998
+ extractExports: extractExports13,
23999
+ entityPatterns: prismaEntityPatterns
24000
+ };
24001
+ registerParser(PrismaParser);
24002
+
23595
24003
  // src/stages/collector.ts
23596
24004
  var import_fs = __toESM(require("fs"));
23597
- var import_path3 = __toESM(require("path"));
24005
+ var import_path5 = __toESM(require("path"));
23598
24006
  function collectFiles(dir) {
23599
24007
  const results = [];
23600
24008
  function walk(currentDir) {
@@ -23606,7 +24014,7 @@ function collectFiles(dir) {
23606
24014
  return;
23607
24015
  }
23608
24016
  for (const entry of entries) {
23609
- const fullPath = import_path3.default.join(currentDir, entry);
24017
+ const fullPath = import_path5.default.join(currentDir, entry);
23610
24018
  let stat;
23611
24019
  try {
23612
24020
  stat = import_fs.default.statSync(fullPath);
@@ -23620,7 +24028,7 @@ function collectFiles(dir) {
23620
24028
  }
23621
24029
  continue;
23622
24030
  }
23623
- const ext = import_path3.default.extname(entry);
24031
+ const ext = import_path5.default.extname(entry);
23624
24032
  if (SUPPORTED_EXTS.has(ext) && stat.size < MAX_FILE_SIZE) {
23625
24033
  results.push(fullPath);
23626
24034
  }
@@ -23632,7 +24040,7 @@ function collectFiles(dir) {
23632
24040
 
23633
24041
  // src/stages/parser.ts
23634
24042
  var import_fs2 = __toESM(require("fs"));
23635
- var import_path4 = __toESM(require("path"));
24043
+ var import_path6 = __toESM(require("path"));
23636
24044
  function parseFile(filePath) {
23637
24045
  let code;
23638
24046
  try {
@@ -23641,7 +24049,7 @@ function parseFile(filePath) {
23641
24049
  console.warn(`\u26A0 Cannot read file: ${filePath}`);
23642
24050
  return null;
23643
24051
  }
23644
- const ext = import_path4.default.extname(filePath).toLowerCase();
24052
+ const ext = import_path6.default.extname(filePath).toLowerCase();
23645
24053
  const parser = getLanguageParser(ext);
23646
24054
  if (!parser) return null;
23647
24055
  const isHashCommentLang = [".py", ".rb", ".sh", ".bash", ".ps1"].includes(ext);
@@ -23673,12 +24081,12 @@ function parseFiles(filePaths) {
23673
24081
  }
23674
24082
 
23675
24083
  // src/stages/graph.ts
23676
- var import_path5 = __toESM(require("path"));
24084
+ var import_path7 = __toESM(require("path"));
23677
24085
  function buildGraph(parsedFiles) {
23678
24086
  const nodes = /* @__PURE__ */ new Map();
23679
24087
  const edges = [];
23680
24088
  for (const file of parsedFiles) {
23681
- const fileBase = import_path5.default.basename(file.filePath, import_path5.default.extname(file.filePath));
24089
+ const fileBase = import_path7.default.basename(file.filePath, import_path7.default.extname(file.filePath));
23682
24090
  for (const entity of file.entities) {
23683
24091
  const id = makeId(entity.name, fileBase);
23684
24092
  if (nodes.has(id)) continue;
@@ -23702,7 +24110,7 @@ function buildGraph(parsedFiles) {
23702
24110
  fileMap.set(file.filePath, file);
23703
24111
  }
23704
24112
  for (const file of parsedFiles) {
23705
- const fileBase = import_path5.default.basename(file.filePath, import_path5.default.extname(file.filePath));
24113
+ const fileBase = import_path7.default.basename(file.filePath, import_path7.default.extname(file.filePath));
23706
24114
  for (const imp of file.imports) {
23707
24115
  if (!imp.isLocal) continue;
23708
24116
  const resolvedPath = resolvePath(file.filePath, imp.source, parsedFiles);
@@ -23712,23 +24120,24 @@ function buildGraph(parsedFiles) {
23712
24120
  for (const importedName of imp.names) {
23713
24121
  const targetEntity = targetFile.entities.find((e) => e.name === importedName);
23714
24122
  if (!targetEntity) continue;
23715
- const targetBase = import_path5.default.basename(resolvedPath, import_path5.default.extname(resolvedPath));
24123
+ const targetBase = import_path7.default.basename(resolvedPath, import_path7.default.extname(resolvedPath));
23716
24124
  const toId = makeId(importedName, targetBase);
23717
24125
  if (!nodes.has(toId)) continue;
23718
- const fromEntities = file.entities.length > 0 ? file.entities : [{ name: fileBase, type: "file", line: 0, complexity: "low" }];
24126
+ const edgeType = imp.relationType ?? "imports";
24127
+ const fromEntities = imp.fromEntity ? file.entities.filter((e) => e.name === imp.fromEntity) : file.entities.length > 0 ? file.entities : [{ name: fileBase, type: "file", line: 0, complexity: "low" }];
23719
24128
  for (const fromEntity of fromEntities) {
23720
24129
  const fromId = makeId(fromEntity.name, fileBase);
23721
24130
  if (!nodes.has(fromId)) continue;
23722
24131
  if (fromId === toId) continue;
23723
24132
  const alreadyExists = edges.some(
23724
- (e) => e.from === fromId && e.to === toId && e.type === "imports"
24133
+ (e) => e.from === fromId && e.to === toId && e.type === edgeType
23725
24134
  );
23726
24135
  if (alreadyExists) continue;
23727
24136
  edges.push({
23728
24137
  from: fromId,
23729
24138
  to: toId,
23730
- type: "imports",
23731
- description: `${fromEntity.name} imports ${importedName} from ${import_path5.default.basename(resolvedPath)}`
24139
+ type: edgeType,
24140
+ description: `${fromEntity.name} ${edgeType} ${importedName}`
23732
24141
  });
23733
24142
  const fromNode = nodes.get(fromId);
23734
24143
  const toNode = nodes.get(toId);
@@ -23750,7 +24159,7 @@ function makeId(name, fileBase) {
23750
24159
  return `${cleanName}__${cleanBase}`;
23751
24160
  }
23752
24161
  function resolvePath(fromFile, importSource, allFiles) {
23753
- const fromDir = import_path5.default.dirname(fromFile);
24162
+ const fromDir = import_path7.default.dirname(fromFile);
23754
24163
  let normalizedSource = importSource;
23755
24164
  if (normalizedSource.startsWith("crate::")) {
23756
24165
  normalizedSource = normalizedSource.slice(7).replace(/::/g, "/");
@@ -23759,7 +24168,7 @@ function resolvePath(fromFile, importSource, allFiles) {
23759
24168
  } else if (normalizedSource.startsWith("self::")) {
23760
24169
  normalizedSource = "./" + normalizedSource.slice(6).replace(/::/g, "/");
23761
24170
  }
23762
- const base = import_path5.default.join(fromDir, normalizedSource);
24171
+ const base = import_path7.default.join(fromDir, normalizedSource);
23763
24172
  const candidates = [
23764
24173
  base,
23765
24174
  `${base}.ts`,
@@ -23769,14 +24178,16 @@ function resolvePath(fromFile, importSource, allFiles) {
23769
24178
  `${base}/index.ts`,
23770
24179
  `${base}/index.js`,
23771
24180
  `${base}.dart`,
23772
- `${base}.rs`
24181
+ `${base}.rs`,
24182
+ `${base}.sql`,
24183
+ `${base}.prisma`
23773
24184
  ];
23774
24185
  for (const candidate of candidates) {
23775
24186
  const normalized = candidate.replace(/\\/g, "/");
23776
24187
  const found = allFiles.find((f) => f.filePath.replace(/\\/g, "/") === normalized);
23777
24188
  if (found) return found.filePath;
23778
24189
  }
23779
- const parentBase = import_path5.default.dirname(base);
24190
+ const parentBase = import_path7.default.dirname(base);
23780
24191
  if (parentBase && parentBase !== base) {
23781
24192
  const parentCandidates = [
23782
24193
  `${parentBase}.rs`,
@@ -23966,7 +24377,7 @@ function emptyReport(targetName, changeDescription, reason) {
23966
24377
 
23967
24378
  // src/stages/gitdiff.ts
23968
24379
  var import_child_process = require("child_process");
23969
- var import_path6 = __toESM(require("path"));
24380
+ var import_path8 = __toESM(require("path"));
23970
24381
  function getChangedEntities(options) {
23971
24382
  const diff = runGitDiff(options);
23972
24383
  if (!diff) return [];
@@ -24058,7 +24469,7 @@ function parseDiff(diff, projectDir) {
24058
24469
  return entities;
24059
24470
  }
24060
24471
  function extractEntityFromContext(context, file) {
24061
- const ext = import_path6.default.extname(file).toLowerCase();
24472
+ const ext = import_path8.default.extname(file).toLowerCase();
24062
24473
  const parser = getLanguageParser(ext);
24063
24474
  if (parser?.entityPatterns) {
24064
24475
  for (const { regex, type } of parser.entityPatterns) {