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/.vscode/depgraph-output.json +979 -143
- package/depgraph-mcp.js +447 -36
- package/depgraph.js +517 -8
- package/package.json +2 -1
- package/scripts/benchmark.js +138 -0
package/depgraph-mcp.js
CHANGED
|
@@ -3263,8 +3263,8 @@ var require_utils = __commonJS({
|
|
|
3263
3263
|
}
|
|
3264
3264
|
return ind;
|
|
3265
3265
|
}
|
|
3266
|
-
function removeDotSegments(
|
|
3267
|
-
let input =
|
|
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
|
|
3677
|
-
wsComponent.path =
|
|
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:
|
|
7681
|
-
const fullPath = [...
|
|
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,
|
|
7797
|
+
constructor(parent, value, path9, key) {
|
|
7798
7798
|
this._cachedPath = [];
|
|
7799
7799
|
this.parent = parent;
|
|
7800
7800
|
this.data = value;
|
|
7801
|
-
this._path =
|
|
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,
|
|
11439
|
-
if (!
|
|
11438
|
+
function getElementAtPath(obj, path9) {
|
|
11439
|
+
if (!path9)
|
|
11440
11440
|
return obj;
|
|
11441
|
-
return
|
|
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(
|
|
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(
|
|
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(
|
|
15177
|
-
if (
|
|
15176
|
+
function getDotPath(path9) {
|
|
15177
|
+
if (path9.length === 0) {
|
|
15178
15178
|
return "object root";
|
|
15179
15179
|
}
|
|
15180
|
-
return
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ===
|
|
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:
|
|
23731
|
-
description: `${fromEntity.name}
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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) {
|