depgraph-core 1.0.3 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/depgraph.js CHANGED
@@ -87,12 +87,37 @@ var require_javascript = __commonJS({
87
87
  var registry_1 = require_registry();
88
88
  var constants_1 = require_constants();
89
89
  function estimateComplexity(code, name) {
90
- const bodyMatch = code.match(new RegExp(`function\\s+${name}[^{]*{([\\s\\S]*?)
91
- }`, "m"));
92
- if (!bodyMatch)
90
+ const lines = code.split("\n");
91
+ const nameRegex = new RegExp(`(?:(?:async\\s+)?function(?:\\s*\\*|\\s+)|(?:const|let|var)\\s+)${name}\\b|\\b${name}\\s*(?:<[^>]*>)?\\s*\\(`, "m");
92
+ const defLineIdx = lines.findIndex((l) => nameRegex.test(l));
93
+ if (defLineIdx === -1)
94
+ return "low";
95
+ let startLine = defLineIdx;
96
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
97
+ startLine++;
98
+ }
99
+ if (startLine >= lines.length)
93
100
  return "low";
94
- const body = bodyMatch[1];
95
- const branches = (body.match(/\b(if|else|for|while|switch|catch|&&|\|\|)\b/g) || []).length;
101
+ let braceCount = 0;
102
+ let started = false;
103
+ const bodyLines = [];
104
+ for (let i = startLine; i < lines.length; i++) {
105
+ const line = lines[i];
106
+ for (const char of line) {
107
+ if (char === "{") {
108
+ braceCount++;
109
+ started = true;
110
+ } else if (char === "}") {
111
+ braceCount--;
112
+ }
113
+ }
114
+ bodyLines.push(line);
115
+ if (started && braceCount <= 0) {
116
+ break;
117
+ }
118
+ }
119
+ const body = bodyLines.join("\n");
120
+ const branches = (body.match(/\b(if|else\s+if|for|while|switch|case|catch|&&|\|\||\?\?)\b|\?[^:]*:/g) || []).length;
96
121
  if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
97
122
  return "low";
98
123
  if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
@@ -100,44 +125,69 @@ var require_javascript = __commonJS({
100
125
  return "high";
101
126
  }
102
127
  exports2.jsEntityPatterns = [
103
- // React components (PascalCase arrow functions)
128
+ // React components: wrapped in memo/forwardRef
129
+ {
130
+ regex: /^(?:export\s+)?(?:default\s+)?(?:const|let|var)\s+([A-Z]\w*)\s*=\s*(?:React\.)?(?:memo|forwardRef)\(/gm,
131
+ type: "component"
132
+ },
133
+ // React components: PascalCase arrow functions
134
+ {
135
+ regex: /^(?:export\s+)?(?:default\s+)?(?:const|let|var)\s+([A-Z]\w*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_]\w*)\s*=>/gm,
136
+ type: "component"
137
+ },
138
+ // React components: PascalCase function declarations
104
139
  {
105
- regex: /^(?:export\s+)?const\s+([A-Z]\w+)\s*=\s*(?:\([^)]*\)|[^=])\s*=>/gm,
140
+ regex: /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+([A-Z]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
106
141
  type: "component"
107
142
  },
108
- // React hooks (camelCase starting with "use")
143
+ // React hooks: camelCase starting with "use" (arrow functions or const assignments)
144
+ {
145
+ regex: /^(?:export\s+)?(?:default\s+)?(?:const|let|var)\s+(use[A-Z]\w*)\s*=/gm,
146
+ type: "hook"
147
+ },
148
+ // React hooks: camelCase starting with "use" (function declarations)
109
149
  {
110
- regex: /^(?:export\s+)?(?:const\s+)?(use[A-Z]\w+)\s*=/gm,
150
+ regex: /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+(use[A-Z]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
111
151
  type: "hook"
112
152
  },
113
- // regular functions
153
+ // regular and async function declarations (including generator functions)
154
+ {
155
+ regex: /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function(?:\s*\*\s*|\s+)([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
156
+ type: "function"
157
+ },
158
+ // arrow functions assigned to const / let / var
114
159
  {
115
- regex: /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+(\w+)\s*\(/gm,
160
+ regex: /^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_]\w*)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_]\w*)\s*=>/gm,
116
161
  type: "function"
117
162
  },
118
- // arrow functions assigned to const
163
+ // function expressions assigned to const / let / var
119
164
  {
120
- regex: /^(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/gm,
165
+ regex: /^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_]\w*)\s*=\s*(?:async\s*)?function/gm,
121
166
  type: "function"
122
167
  },
123
- // classes
168
+ // classes (regular, exported, abstract)
124
169
  {
125
- regex: /^(?:export\s+)?(?:default\s+)?class\s+(\w+)/gm,
170
+ regex: /^(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+([A-Za-z_]\w*)/gm,
126
171
  type: "class"
127
172
  },
128
173
  // TypeScript interfaces
129
174
  {
130
- regex: /^(?:export\s+)?interface\s+(\w+)/gm,
175
+ regex: /^(?:export\s+)?(?:default\s+)?interface\s+([A-Za-z_]\w*)/gm,
131
176
  type: "interface"
132
177
  },
133
178
  // TypeScript types
134
179
  {
135
- regex: /^(?:export\s+)?type\s+(\w+)\s*=/gm,
180
+ regex: /^(?:export\s+)?(?:default\s+)?type\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*=/gm,
136
181
  type: "type"
137
182
  },
138
- // Express routes (capture group 1 = method, group 2 = path — skipped in gitdiff context matching)
183
+ // TypeScript enums (regular or const enum)
139
184
  {
140
- regex: /(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/gm,
185
+ regex: /^(?:export\s+)?(?:const\s+)?enum\s+([A-Za-z_]\w*)/gm,
186
+ type: "class"
187
+ },
188
+ // Express / router routes (capture group 1 = method, group 2 = path — skipped in gitdiff context matching)
189
+ {
190
+ regex: /(?:app|router|server)\.(get|post|put|delete|patch|options|head)\s*\(\s*['"]([^'"]+)['"]/gm,
141
191
  type: "api"
142
192
  }
143
193
  ];
@@ -173,46 +223,114 @@ var require_javascript = __commonJS({
173
223
  }
174
224
  function extractImports(code) {
175
225
  const imports = [];
176
- const namedPattern = /^import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/gm;
226
+ const combinedPattern = /^import\s+(?:type\s+)?([A-Za-z_$]\w*)\s*,\s*(?:\{([^}]+)\}|\*\s+as\s+([A-Za-z_$]\w*))\s+from\s+['"]([^'"]+)['"]/gm;
177
227
  let match;
228
+ while ((match = combinedPattern.exec(code)) !== null) {
229
+ const defaultName = match[1];
230
+ const namedClause = match[2];
231
+ const nsName = match[3];
232
+ const source = match[4];
233
+ const names = [defaultName];
234
+ if (namedClause) {
235
+ const parsedNamed = namedClause.split(",").map((n) => n.trim().replace(/^type\s+/, "").replace(/\s+as\s+\w+$/, "").trim()).filter((n) => n.length > 0);
236
+ names.push(...parsedNamed);
237
+ }
238
+ if (nsName) {
239
+ names.push(nsName);
240
+ }
241
+ imports.push({
242
+ source,
243
+ names: [...new Set(names)],
244
+ isLocal: source.startsWith(".") || source.startsWith("/")
245
+ });
246
+ }
247
+ const namedPattern = /^import\s+(?:type\s+)?\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/gm;
178
248
  while ((match = namedPattern.exec(code)) !== null) {
179
- const names = match[1].split(",").map((n) => n.trim().replace(/\s+as\s+\w+/, ""));
180
249
  const source = match[2];
250
+ if (imports.some((i) => i.source === source))
251
+ continue;
252
+ const names = match[1].split(",").map((n) => n.trim().replace(/^type\s+/, "").replace(/\s+as\s+\w+$/, "").trim()).filter((n) => n.length > 0);
181
253
  imports.push({
182
254
  source,
183
- names,
184
- isLocal: source.startsWith(".")
255
+ names: [...new Set(names)],
256
+ isLocal: source.startsWith(".") || source.startsWith("/")
185
257
  });
186
258
  }
187
- const defaultPattern = /^import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/gm;
259
+ const defaultPattern = /^import\s+(?:type\s+)?([A-Za-z_$]\w*)\s+from\s+['"]([^'"]+)['"]/gm;
188
260
  while ((match = defaultPattern.exec(code)) !== null) {
261
+ const source = match[2];
262
+ if (imports.some((i) => i.source === source))
263
+ continue;
264
+ imports.push({
265
+ source,
266
+ names: [match[1]],
267
+ isLocal: source.startsWith(".") || source.startsWith("/")
268
+ });
269
+ }
270
+ const nsPattern = /^import\s+\*\s+as\s+([A-Za-z_$]\w*)\s+from\s+['"]([^'"]+)['"]/gm;
271
+ while ((match = nsPattern.exec(code)) !== null) {
272
+ const source = match[2];
273
+ if (imports.some((i) => i.source === source))
274
+ continue;
189
275
  imports.push({
190
- source: match[2],
276
+ source,
191
277
  names: [match[1]],
192
- isLocal: match[2].startsWith(".")
278
+ isLocal: source.startsWith(".") || source.startsWith("/")
193
279
  });
194
280
  }
195
281
  const requirePattern = /(?:const|let|var)\s+\{?([^}=]+)\}?\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)/gm;
196
282
  while ((match = requirePattern.exec(code)) !== null) {
197
- const names = match[1].split(",").map((n) => n.trim());
283
+ const rawNames = match[1];
284
+ const source = match[2];
285
+ const names = rawNames.split(",").map((n) => n.trim().replace(/^\w+:\s*/, "").trim()).filter((n) => n.length > 0);
286
+ imports.push({
287
+ source,
288
+ names: [...new Set(names)],
289
+ isLocal: source.startsWith(".") || source.startsWith("/")
290
+ });
291
+ }
292
+ const reexportPattern = /^export\s+(?:\{([^}]+)\}|\*\s+as\s+([A-Za-z_$]\w*)|\*)\s+from\s+['"]([^'"]+)['"]/gm;
293
+ while ((match = reexportPattern.exec(code)) !== null) {
294
+ const namedClause = match[1];
295
+ const nsAlias = match[2];
296
+ const source = match[3];
297
+ let names = [];
298
+ if (namedClause) {
299
+ names = namedClause.split(",").map((n) => n.trim().replace(/^type\s+/, "").replace(/\s+as\s+\w+$/, "").trim()).filter((n) => n.length > 0);
300
+ } else if (nsAlias) {
301
+ names = [nsAlias];
302
+ } else {
303
+ names = ["*"];
304
+ }
198
305
  imports.push({
199
- source: match[2],
200
- names,
201
- isLocal: match[2].startsWith(".")
306
+ source,
307
+ names: [...new Set(names)],
308
+ isLocal: source.startsWith(".") || source.startsWith("/")
202
309
  });
203
310
  }
204
311
  return imports;
205
312
  }
206
313
  function extractExports(code) {
207
314
  const exports3 = [];
208
- const namedPattern = /^export\s+(?:default\s+)?(?:async\s+)?(?:function|class|const|let|var|type|interface)\s+(\w+)/gm;
315
+ const namedPattern = /^export\s+(?:default\s+)?(?:async\s+|abstract\s+)?(?:function(?:\s*\*|\s+)|class|const|let|var|type|interface|enum)\s+([A-Za-z_$]\w*)/gm;
209
316
  let match;
210
317
  while ((match = namedPattern.exec(code)) !== null) {
211
318
  exports3.push(match[1]);
212
319
  }
213
- const listPattern = /^export\s+\{([^}]+)\}/gm;
320
+ const defaultIdentPattern = /^export\s+default\s+([A-Za-z_$]\w*)\s*(?:;|$)/gm;
321
+ while ((match = defaultIdentPattern.exec(code)) !== null) {
322
+ if (!["function", "class", "interface", "abstract"].includes(match[1])) {
323
+ exports3.push(match[1]);
324
+ }
325
+ }
326
+ const listPattern = /^export\s+\{([^}]+)\}(?!\s*from)/gm;
214
327
  while ((match = listPattern.exec(code)) !== null) {
215
- const names = match[1].split(",").map((n) => n.trim());
328
+ const names = match[1].split(",").map((n) => n.trim().replace(/^type\s+/, "").replace(/^\w+\s+as\s+/, "").trim()).filter((n) => n.length > 0);
329
+ exports3.push(...names);
330
+ }
331
+ const reexportPattern = /^export\s+\{([^}]+)\}\s+from/gm;
332
+ while ((match = reexportPattern.exec(code)) !== null) {
333
+ const names = match[1].split(",").map((n) => n.trim().replace(/^type\s+/, "").replace(/^\w+\s+as\s+/, "").trim()).filter((n) => n.length > 0);
216
334
  exports3.push(...names);
217
335
  }
218
336
  return [...new Set(exports3)];
@@ -237,13 +355,22 @@ var require_python = __commonJS({
237
355
  exports2.pyEntityPatterns = void 0;
238
356
  var registry_1 = require_registry();
239
357
  var constants_1 = require_constants();
358
+ function escapeRegex(s) {
359
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
360
+ }
240
361
  function estimateComplexity(code, name) {
241
362
  const lines = code.split("\n");
242
- const defLine = lines.findIndex((l) => l.match(new RegExp(`def\\s+${name}\\s*\\(`)));
363
+ const defRegex = new RegExp(`^[ \\t]*(?:async\\s+)?def\\s+${escapeRegex(name)}\\s*\\(`, "m");
364
+ const defLine = lines.findIndex((l) => defRegex.test(l));
243
365
  if (defLine === -1)
244
366
  return "low";
367
+ let bodyStart = defLine;
368
+ while (bodyStart < lines.length && !lines[bodyStart].includes(":")) {
369
+ bodyStart++;
370
+ }
371
+ bodyStart++;
245
372
  const bodyLines = [];
246
- for (let i = defLine + 1; i < lines.length; i++) {
373
+ for (let i = bodyStart; i < lines.length; i++) {
247
374
  const line = lines[i];
248
375
  if (line.trim() === "")
249
376
  continue;
@@ -251,8 +378,7 @@ var require_python = __commonJS({
251
378
  break;
252
379
  bodyLines.push(line);
253
380
  }
254
- const body = bodyLines.join("\n");
255
- const branches = (body.match(/\b(if|elif|else|for|while|except|and|or)\b/g) || []).length;
381
+ const branches = (bodyLines.join("\n").match(/\b(if|elif|else|for|while|except|and|or|match|case)\b/g) || []).length;
256
382
  if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
257
383
  return "low";
258
384
  if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
@@ -260,14 +386,14 @@ var require_python = __commonJS({
260
386
  return "high";
261
387
  }
262
388
  exports2.pyEntityPatterns = [
263
- // regular functions
389
+ // functions and methods (including async def)
264
390
  {
265
- regex: /^(?:async\s+)?def\s+(\w+)\s*\(/gm,
391
+ regex: /^[ \t]*(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/gm,
266
392
  type: "function"
267
393
  },
268
- // classes
394
+ // classes (with optional generic parameters [T] and base classes (Base))
269
395
  {
270
- regex: /^class\s+(\w+)(?:\s*\([^)]*\))?\s*:/gm,
396
+ regex: /^[ \t]*class\s+([A-Za-z_]\w*)(?:\s*\[[^\]]*\])?(?:\s*\([^)]*\))?\s*:/gm,
271
397
  type: "class"
272
398
  }
273
399
  ];
@@ -280,10 +406,10 @@ var require_python = __commonJS({
280
406
  const name = match[1];
281
407
  if (type === "function" && name.startsWith("__") && name.endsWith("__"))
282
408
  continue;
283
- if (entities.some((e) => e.name === name))
284
- continue;
285
409
  const upToMatch = code.slice(0, match.index);
286
410
  const line = upToMatch.split("\n").length;
411
+ if (entities.some((e) => e.name === name && e.line === line))
412
+ continue;
287
413
  entities.push({
288
414
  name,
289
415
  type,
@@ -294,33 +420,43 @@ var require_python = __commonJS({
294
420
  }
295
421
  return entities;
296
422
  }
423
+ function stripAlias(name) {
424
+ return name.replace(/\s+as\s+[A-Za-z_]\w*$/, "").trim();
425
+ }
297
426
  function extractImports(code) {
298
427
  const imports = [];
428
+ const normalised = code.replace(/^(from\s+[\w.]+\s+import\s*)\(\s*([\s\S]*?)\)/gm, (_, prefix, body) => prefix + body.replace(/\s*\n\s*/g, ", "));
299
429
  const fromPattern = /^from\s+([\w.]+)\s+import\s+(.+)$/gm;
300
430
  let match;
301
- while ((match = fromPattern.exec(code)) !== null) {
431
+ while ((match = fromPattern.exec(normalised)) !== null) {
302
432
  const source = match[1];
303
- const names = match[2].split(",").map((n) => n.trim()).filter((n) => n.length > 0);
304
- const isLocal = source.startsWith(".");
305
- imports.push({ source, names, isLocal });
433
+ const rawNames = match[2].replace(/#.*$/, "");
434
+ const names = rawNames.split(",").map((n) => stripAlias(n.trim())).filter((n) => n.length > 0 && n !== "*");
435
+ imports.push({ source, names, isLocal: source.startsWith(".") });
306
436
  }
307
- const importPattern = /^import\s+([\w.]+)/gm;
308
- while ((match = importPattern.exec(code)) !== null) {
309
- const source = match[1];
310
- imports.push({
311
- source,
312
- names: [source],
313
- isLocal: false
314
- // bare imports are always external
315
- });
437
+ const importPattern = /^import\s+([^#\n]+)/gm;
438
+ while ((match = importPattern.exec(normalised)) !== null) {
439
+ const modules = match[1].split(",").map((m) => m.trim());
440
+ for (const mod of modules) {
441
+ if (!mod)
442
+ continue;
443
+ const cleanMod = stripAlias(mod);
444
+ if (!cleanMod)
445
+ continue;
446
+ imports.push({
447
+ source: cleanMod,
448
+ names: [cleanMod],
449
+ isLocal: cleanMod.startsWith(".")
450
+ });
451
+ }
316
452
  }
317
453
  return imports;
318
454
  }
319
455
  function extractExports(code) {
320
- const allMatch = code.match(/__all__\s*=\s*\[([^\]]+)\]/);
456
+ const allMatch = code.match(/__all__\s*=\s*[\[\(]([\s\S]*?)[\]\)]/);
321
457
  if (!allMatch)
322
458
  return [];
323
- return allMatch[1].split(",").map((n) => n.trim().replace(/['"]/g, "")).filter((n) => n.length > 0);
459
+ return allMatch[1].split(",").map((n) => n.trim().replace(/['"]/g, "").replace(/#.*$/, "").trim()).filter((n) => n.length > 0);
324
460
  }
325
461
  var PythonParser = {
326
462
  lang: "py",
@@ -341,16 +477,60 @@ var require_go = __commonJS({
341
477
  Object.defineProperty(exports2, "__esModule", { value: true });
342
478
  exports2.goEntityPatterns = void 0;
343
479
  var registry_1 = require_registry();
480
+ var constants_1 = require_constants();
481
+ function estimateComplexity(code, name) {
482
+ const lines = code.split("\n");
483
+ const funcRegex = new RegExp(`func\\s+(?:\\([^)]*\\)\\s+)?${name}\\s*(?:\\[[^\\]]*\\])?\\s*\\(`, "m");
484
+ const defLineIdx = lines.findIndex((l) => funcRegex.test(l));
485
+ if (defLineIdx === -1)
486
+ return "low";
487
+ let startLine = defLineIdx;
488
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
489
+ startLine++;
490
+ }
491
+ if (startLine >= lines.length)
492
+ return "low";
493
+ let braceCount = 0;
494
+ let started = false;
495
+ const bodyLines = [];
496
+ for (let i = startLine; i < lines.length; i++) {
497
+ const line = lines[i];
498
+ for (const char of line) {
499
+ if (char === "{") {
500
+ braceCount++;
501
+ started = true;
502
+ } else if (char === "}") {
503
+ braceCount--;
504
+ }
505
+ }
506
+ bodyLines.push(line);
507
+ if (started && braceCount <= 0) {
508
+ break;
509
+ }
510
+ }
511
+ const body = bodyLines.join("\n");
512
+ const branches = (body.match(/\b(if|else\s+if|for|switch|case|select|&&|\|\|)\b/g) || []).length;
513
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
514
+ return "low";
515
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
516
+ return "medium";
517
+ return "high";
518
+ }
344
519
  exports2.goEntityPatterns = [
345
- // functions (including methods: func (r *Receiver) Name(...))
520
+ // functions and methods with optional receiver and type parameters (generics)
346
521
  {
347
- regex: /^func\s+(?:\(\w+\s+\*?\w+\)\s+)?(\w+)\s*\(/gm,
522
+ regex: /^func\s+(?:\([^)]*\)\s+)?([A-Za-z_]\w*)\s*(?:\[[^\]]*\])?\s*\(/gm,
348
523
  type: "function"
349
524
  },
350
- // type declarations (structs, interfaces, type aliases)
525
+ // type declarations (structs, interfaces) with optional type parameters
351
526
  {
352
- regex: /^type\s+(\w+)\s+(?:struct|interface)/gm,
527
+ regex: /^type\s+([A-Za-z_]\w*)\s*(?:\[[^\]]*\])?\s+(?:struct|interface)/gm,
353
528
  type: "class"
529
+ },
530
+ // type aliases and custom types (e.g. type HandlerFunc func(...), type MyInt int)
531
+ {
532
+ regex: /^type\s+([A-Za-z_]\w*)\s*(?:\[[^\]]*\])?\s+(?!(?:struct|interface)\b)[A-Za-z_\[\]\*]/gm,
533
+ type: "type"
354
534
  }
355
535
  ];
356
536
  function extractEntities(code, filePath) {
@@ -364,25 +544,89 @@ var require_go = __commonJS({
364
544
  continue;
365
545
  const upToMatch = code.slice(0, match.index);
366
546
  const line = upToMatch.split("\n").length;
367
- entities.push({ name, type, line, complexity: "low" });
547
+ entities.push({
548
+ name,
549
+ type,
550
+ line,
551
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
552
+ });
553
+ }
554
+ }
555
+ const blockTypePattern = /^type\s*\(\s*\n?([\s\S]*?)\n\s*\)/gm;
556
+ let blockMatch;
557
+ while ((blockMatch = blockTypePattern.exec(code)) !== null) {
558
+ const blockContent = blockMatch[1];
559
+ const blockStartLine = code.slice(0, blockMatch.index).split("\n").length;
560
+ const lines = blockContent.split("\n");
561
+ let braceDepth = 0;
562
+ for (let i = 0; i < lines.length; i++) {
563
+ const line = lines[i].trim();
564
+ if (braceDepth === 0 && line.length > 0 && !line.startsWith("//")) {
565
+ const structInterfaceMatch = line.match(/^([A-Za-z_]\w*)\s*(?:\[[^\]]*\])?\s+(struct|interface)/);
566
+ if (structInterfaceMatch) {
567
+ const name = structInterfaceMatch[1];
568
+ if (!entities.some((e) => e.name === name)) {
569
+ entities.push({
570
+ name,
571
+ type: "class",
572
+ line: blockStartLine + i + 1,
573
+ complexity: "low"
574
+ });
575
+ }
576
+ } else {
577
+ const aliasMatch = line.match(/^([A-Za-z_]\w*)\s*(?:\[[^\]]*\])?\s+(?:=\s*)?(?!(?:struct|interface)\b)[A-Za-z_\[\]\*]/);
578
+ if (aliasMatch) {
579
+ const name = aliasMatch[1];
580
+ if (!entities.some((e) => e.name === name)) {
581
+ entities.push({
582
+ name,
583
+ type: "type",
584
+ line: blockStartLine + i + 1,
585
+ complexity: "low"
586
+ });
587
+ }
588
+ }
589
+ }
590
+ }
591
+ for (const ch of line) {
592
+ if (ch === "{")
593
+ braceDepth++;
594
+ else if (ch === "}")
595
+ braceDepth--;
596
+ }
368
597
  }
369
598
  }
370
599
  return entities;
371
600
  }
372
601
  function extractImports(code) {
373
602
  const imports = [];
374
- const singlePattern = /^import\s+(?:\w+\s+)?["']([^"']+)["']/gm;
603
+ const singlePattern = /^import\s+(?:([A-Za-z_.\w]+)\s+)?["']([^"']+)["']/gm;
375
604
  let match;
376
605
  while ((match = singlePattern.exec(code)) !== null) {
377
- imports.push({ source: match[1], names: [match[1]], isLocal: match[1].startsWith(".") });
606
+ const alias = match[1];
607
+ const source = match[2];
608
+ const pkgName = alias && alias !== "_" && alias !== "." ? alias : source.split("/").pop() || source;
609
+ imports.push({
610
+ source,
611
+ names: [pkgName],
612
+ isLocal: source.startsWith(".") || source.startsWith("/")
613
+ });
378
614
  }
379
- const blockPattern = /import\s+\(([^)]+)\)/gs;
615
+ const blockPattern = /import\s*\(\s*([\s\S]*?)\s*\)/gm;
380
616
  while ((match = blockPattern.exec(code)) !== null) {
381
617
  const lines = match[1].split("\n");
382
618
  for (const line of lines) {
383
- const pkgMatch = line.match(/(?:\w+\s+)?["']([^"']+)["']/);
619
+ const cleanLine = line.replace(/\/\/.*$/, "").trim();
620
+ const pkgMatch = cleanLine.match(/^(?:([A-Za-z_.\w]+)\s+)?["']([^"']+)["']/);
384
621
  if (pkgMatch) {
385
- imports.push({ source: pkgMatch[1], names: [pkgMatch[1]], isLocal: pkgMatch[1].startsWith(".") });
622
+ const alias = pkgMatch[1];
623
+ const source = pkgMatch[2];
624
+ const pkgName = alias && alias !== "_" && alias !== "." ? alias : source.split("/").pop() || source;
625
+ imports.push({
626
+ source,
627
+ names: [pkgName],
628
+ isLocal: source.startsWith(".") || source.startsWith("/")
629
+ });
386
630
  }
387
631
  }
388
632
  }
@@ -390,11 +634,51 @@ var require_go = __commonJS({
390
634
  }
391
635
  function extractExports(code) {
392
636
  const exports3 = [];
393
- const pattern = /^func\s+(?:\(\w+\s+\*?\w+\)\s+)?([A-Z]\w*)\s*\(/gm;
637
+ const funcPattern = /^func\s+(?:\([^)]*\)\s+)?([A-Z]\w*)\s*(?:\[[^\]]*\])?\s*\(/gm;
394
638
  let match;
395
- while ((match = pattern.exec(code)) !== null) {
639
+ while ((match = funcPattern.exec(code)) !== null) {
640
+ exports3.push(match[1]);
641
+ }
642
+ const typePattern = /^type\s+([A-Z]\w*)/gm;
643
+ while ((match = typePattern.exec(code)) !== null) {
644
+ exports3.push(match[1]);
645
+ }
646
+ const blockTypePattern = /^type\s*\(\s*\n?([\s\S]*?)\n\s*\)/gm;
647
+ let blockTypeMatch;
648
+ while ((blockTypeMatch = blockTypePattern.exec(code)) !== null) {
649
+ const lines = blockTypeMatch[1].split("\n");
650
+ let braceDepth = 0;
651
+ for (const line of lines) {
652
+ const trimmed = line.trim();
653
+ if (braceDepth === 0 && trimmed.length > 0 && !trimmed.startsWith("//")) {
654
+ const m = trimmed.match(/^([A-Z]\w*)/);
655
+ if (m)
656
+ exports3.push(m[1]);
657
+ }
658
+ for (const ch of trimmed) {
659
+ if (ch === "{")
660
+ braceDepth++;
661
+ else if (ch === "}")
662
+ braceDepth--;
663
+ }
664
+ }
665
+ }
666
+ const constVarPattern = /^(?:const|var)\s+([A-Z]\w*)/gm;
667
+ while ((match = constVarPattern.exec(code)) !== null) {
396
668
  exports3.push(match[1]);
397
669
  }
670
+ const blockConstVarPattern = /^(?:const|var)\s*\(\s*\n?([\s\S]*?)\n\s*\)/gm;
671
+ while ((match = blockConstVarPattern.exec(code)) !== null) {
672
+ const lines = match[1].split("\n");
673
+ for (const line of lines) {
674
+ const trimmed = line.trim();
675
+ if (!trimmed.startsWith("//")) {
676
+ const m = trimmed.match(/^([A-Z]\w*)/);
677
+ if (m)
678
+ exports3.push(m[1]);
679
+ }
680
+ }
681
+ }
398
682
  return [...new Set(exports3)];
399
683
  }
400
684
  var GoParser = {
@@ -409,6 +693,933 @@ var require_go = __commonJS({
409
693
  }
410
694
  });
411
695
 
696
+ // dist/languages/csharp.js
697
+ var require_csharp = __commonJS({
698
+ "dist/languages/csharp.js"(exports2) {
699
+ "use strict";
700
+ Object.defineProperty(exports2, "__esModule", { value: true });
701
+ exports2.csharpEntityPatterns = void 0;
702
+ var registry_1 = require_registry();
703
+ var constants_1 = require_constants();
704
+ function estimateComplexity(code, name) {
705
+ const lines = code.split("\n");
706
+ const methodRegex = new RegExp(`(?:(?:public|private|protected|internal|static|async|virtual|override|abstract|sealed|partial)\\s+)+[\\w<>\\[\\],?]+\\s+${name}\\s*(?:<[^>]*>)?\\s*\\(`, "m");
707
+ const defLineIdx = lines.findIndex((l) => methodRegex.test(l) || new RegExp(`\\b${name}\\s*\\(`, "m").test(l));
708
+ if (defLineIdx === -1)
709
+ return "low";
710
+ let startLine = defLineIdx;
711
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
712
+ startLine++;
713
+ }
714
+ if (startLine >= lines.length)
715
+ return "low";
716
+ let braceCount = 0;
717
+ let started = false;
718
+ const bodyLines = [];
719
+ for (let i = startLine; i < lines.length; i++) {
720
+ const line = lines[i];
721
+ for (const char of line) {
722
+ if (char === "{") {
723
+ braceCount++;
724
+ started = true;
725
+ } else if (char === "}") {
726
+ braceCount--;
727
+ }
728
+ }
729
+ bodyLines.push(line);
730
+ if (started && braceCount <= 0) {
731
+ break;
732
+ }
733
+ }
734
+ const body = bodyLines.join("\n");
735
+ const branches = (body.match(/\b(if|else\s+if|for|foreach|while|do|switch|case|catch|&&|\|\||\?\?)\b|\?[^:]*:/g) || []).length;
736
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
737
+ return "low";
738
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
739
+ return "medium";
740
+ return "high";
741
+ }
742
+ exports2.csharpEntityPatterns = [
743
+ // Classes, structs, records, interfaces, enums
744
+ {
745
+ regex: /^[ \t]*(?:(?:public|private|protected|internal|static|abstract|sealed|partial)\s+)*(?:class|interface|enum|struct|record(?:\s+(?:class|struct))?)\s+([A-Za-z_]\w*)/gm,
746
+ type: "class"
747
+ },
748
+ // Methods (constructors, instance methods, async/static methods)
749
+ {
750
+ regex: /^[ \t]*(?:(?:public|private|protected|internal|static|async|virtual|override|abstract|sealed|partial)\s+)+(?:(?:async\s+)?[\w<>[\]?,]+\s+)?([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
751
+ type: "function"
752
+ }
753
+ ];
754
+ function extractEntities(code, filePath) {
755
+ const entities = [];
756
+ for (const { regex, type } of exports2.csharpEntityPatterns) {
757
+ regex.lastIndex = 0;
758
+ let match;
759
+ while ((match = regex.exec(code)) !== null) {
760
+ const name = match[1];
761
+ if (["if", "for", "foreach", "while", "switch", "catch", "lock", "using", "get", "set"].includes(name)) {
762
+ continue;
763
+ }
764
+ const upToMatch = code.slice(0, match.index);
765
+ const line = upToMatch.split("\n").length;
766
+ if (entities.some((e) => e.name === name && e.line === line))
767
+ continue;
768
+ entities.push({
769
+ name,
770
+ type,
771
+ line,
772
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
773
+ });
774
+ }
775
+ }
776
+ return entities;
777
+ }
778
+ function extractImports(code) {
779
+ const imports = [];
780
+ const usingPattern = /^[ \t]*(?:global\s+)?using\s+(?:static\s+)?(?:([A-Za-z_]\w*)\s*=\s*)?([A-Za-z_][\w.]*(?:<[^>]*>)?)\s*;/gm;
781
+ let match;
782
+ while ((match = usingPattern.exec(code)) !== null) {
783
+ const alias = match[1];
784
+ const targetFqn = match[2].trim();
785
+ const simpleName = alias || targetFqn.split(".").pop() || targetFqn;
786
+ const isLocal = !targetFqn.startsWith("System") && !targetFqn.startsWith("Microsoft");
787
+ imports.push({
788
+ source: targetFqn,
789
+ names: [simpleName],
790
+ isLocal
791
+ });
792
+ }
793
+ return imports;
794
+ }
795
+ function extractExports(code) {
796
+ const exports3 = [];
797
+ const typePattern = /^[ \t]*(?:public|internal)\s+(?:(?:static|abstract|sealed|partial)\s+)*(?:class|interface|enum|struct|record(?:\s+(?:class|struct))?)\s+([A-Za-z_]\w*)/gm;
798
+ let match;
799
+ while ((match = typePattern.exec(code)) !== null) {
800
+ exports3.push(match[1]);
801
+ }
802
+ const methodPattern = /^[ \t]*(?:public|internal)\s+(?:(?:static|async|virtual|override|abstract|sealed|partial)\s+)*(?:[\w<>[\]?,]+\s+)?([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm;
803
+ while ((match = methodPattern.exec(code)) !== null) {
804
+ const name = match[1];
805
+ if (!["if", "for", "foreach", "while", "switch", "catch", "lock", "using", "get", "set"].includes(name)) {
806
+ exports3.push(name);
807
+ }
808
+ }
809
+ return [...new Set(exports3)];
810
+ }
811
+ var CSharpParser = {
812
+ lang: "cs",
813
+ extensions: [".cs"],
814
+ extractEntities,
815
+ extractImports,
816
+ extractExports,
817
+ entityPatterns: exports2.csharpEntityPatterns
818
+ };
819
+ (0, registry_1.registerParser)(CSharpParser);
820
+ }
821
+ });
822
+
823
+ // dist/languages/java.js
824
+ var require_java = __commonJS({
825
+ "dist/languages/java.js"(exports2) {
826
+ "use strict";
827
+ Object.defineProperty(exports2, "__esModule", { value: true });
828
+ exports2.javaEntityPatterns = void 0;
829
+ var registry_1 = require_registry();
830
+ var constants_1 = require_constants();
831
+ function escapeRegex(s) {
832
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
833
+ }
834
+ function estimateComplexity(code, name) {
835
+ const lines = code.split("\n");
836
+ const defRegex = new RegExp(`(?:^|\\s)${escapeRegex(name)}\\s*\\(`, "m");
837
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
838
+ if (defLineIdx === -1)
839
+ return "low";
840
+ let startLine = defLineIdx;
841
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
842
+ startLine++;
843
+ }
844
+ if (startLine >= lines.length)
845
+ return "low";
846
+ let braceCount = 0;
847
+ let started = false;
848
+ const bodyLines = [];
849
+ for (let i = startLine; i < lines.length; i++) {
850
+ const line = lines[i];
851
+ for (const ch of line) {
852
+ if (ch === "{") {
853
+ braceCount++;
854
+ started = true;
855
+ } else if (ch === "}") {
856
+ braceCount--;
857
+ }
858
+ }
859
+ bodyLines.push(line);
860
+ if (started && braceCount <= 0)
861
+ break;
862
+ }
863
+ const body = bodyLines.join("\n");
864
+ const branches = (body.match(/\b(if|else\s+if|else|for|while|do|switch|case|catch|&&|\|\|)\b/g) || []).length;
865
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
866
+ return "low";
867
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
868
+ return "medium";
869
+ return "high";
870
+ }
871
+ exports2.javaEntityPatterns = [
872
+ // class / abstract class / final class
873
+ {
874
+ regex: /^[ \t]*(?:(?:public|protected|private|abstract|final|static)\s+)*class\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?:extends\s+\S+\s*)?(?:implements\s+[^{]+)?\s*\{/gm,
875
+ type: "class"
876
+ },
877
+ // interface
878
+ {
879
+ regex: /^[ \t]*(?:(?:public|protected|private|abstract|static)\s+)*interface\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?:extends\s+[^{]+)?\s*\{/gm,
880
+ type: "interface"
881
+ },
882
+ // record (Java 14+)
883
+ {
884
+ regex: /^[ \t]*(?:(?:public|protected|private|final|static)\s+)*record\s+([A-Za-z_]\w*)\s*\(/gm,
885
+ type: "class"
886
+ },
887
+ // enum
888
+ {
889
+ regex: /^[ \t]*(?:(?:public|protected|private|static)\s+)*enum\s+([A-Za-z_]\w*)\s*(?:implements\s+[^{]+)?\s*\{/gm,
890
+ type: "class"
891
+ },
892
+ // annotation type
893
+ {
894
+ regex: /^[ \t]*(?:(?:public|protected|private|abstract|static)\s+)*@interface\s+([A-Za-z_]\w*)\s*\{/gm,
895
+ type: "interface"
896
+ },
897
+ // method declarations (with return type before the name)
898
+ {
899
+ regex: /^[ \t]*(?:(?:public|protected|private|static|final|abstract|synchronized|native|default|override)\s+)*(?:<[^>]*>\s+)?(?:[\w.<>\[\]]+\s+)+([A-Za-z_]\w*)\s*\([^)]*\)\s*(?:throws\s+[\w,\s]+)?\s*\{/gm,
900
+ type: "function"
901
+ }
902
+ ];
903
+ function extractEntities(code, _filePath) {
904
+ const entities = [];
905
+ for (const { regex, type } of exports2.javaEntityPatterns) {
906
+ regex.lastIndex = 0;
907
+ let match;
908
+ while ((match = regex.exec(code)) !== null) {
909
+ const name = match[1];
910
+ if (["if", "else", "for", "while", "do", "switch", "try", "catch", "return", "new", "void", "this", "super"].includes(name))
911
+ continue;
912
+ const upToMatch = code.slice(0, match.index);
913
+ const line = upToMatch.split("\n").length;
914
+ if (entities.some((e) => e.name === name && e.line === line))
915
+ continue;
916
+ entities.push({
917
+ name,
918
+ type,
919
+ line,
920
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
921
+ });
922
+ }
923
+ }
924
+ return entities;
925
+ }
926
+ function extractImports(code) {
927
+ const imports = [];
928
+ const importPattern = /^import\s+((?:static)\s+)?([\w.]+(?:\.\*)?)?\s*;/gm;
929
+ let match;
930
+ while ((match = importPattern.exec(code)) !== null) {
931
+ const isStatic = Boolean(match[1]);
932
+ const fullPath = (match[2] || "").trim();
933
+ if (!fullPath)
934
+ continue;
935
+ const isWildcard = fullPath.endsWith(".*");
936
+ const cleanPath = isWildcard ? fullPath.slice(0, -2) : fullPath;
937
+ const segments = cleanPath.split(".");
938
+ let source;
939
+ let name;
940
+ if (isStatic) {
941
+ name = segments.pop() || cleanPath;
942
+ source = segments.join(".") || cleanPath;
943
+ } else {
944
+ name = segments[segments.length - 1] || cleanPath;
945
+ source = cleanPath;
946
+ }
947
+ imports.push({
948
+ source,
949
+ names: [name],
950
+ isLocal: false
951
+ });
952
+ }
953
+ return imports;
954
+ }
955
+ function extractExports(code) {
956
+ const exports3 = [];
957
+ const typePattern = /^public\s+(?:(?:abstract|final|static)\s+)*(?:class|interface|enum|record|@interface)\s+([A-Za-z_]\w*)/gm;
958
+ let match;
959
+ while ((match = typePattern.exec(code)) !== null) {
960
+ exports3.push(match[1]);
961
+ }
962
+ const methodPattern = /^[ \t]*public\s+(?:(?:static|final|abstract|synchronized|native|default)\s+)*(?:<[^>]*>\s+)?(?:[\w.<>\[\]]+\s+)+([A-Za-z_]\w*)\s*\(/gm;
963
+ while ((match = methodPattern.exec(code)) !== null) {
964
+ const name = match[1];
965
+ if (!["if", "for", "while", "switch", "class", "interface", "enum"].includes(name)) {
966
+ exports3.push(name);
967
+ }
968
+ }
969
+ return [...new Set(exports3)];
970
+ }
971
+ var JavaParser = {
972
+ lang: "java",
973
+ extensions: [".java"],
974
+ extractEntities,
975
+ extractImports,
976
+ extractExports,
977
+ entityPatterns: exports2.javaEntityPatterns
978
+ };
979
+ (0, registry_1.registerParser)(JavaParser);
980
+ }
981
+ });
982
+
983
+ // dist/languages/kotlin.js
984
+ var require_kotlin = __commonJS({
985
+ "dist/languages/kotlin.js"(exports2) {
986
+ "use strict";
987
+ Object.defineProperty(exports2, "__esModule", { value: true });
988
+ exports2.kotlinEntityPatterns = void 0;
989
+ var registry_1 = require_registry();
990
+ var constants_1 = require_constants();
991
+ function escapeRegex(s) {
992
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
993
+ }
994
+ function estimateComplexity(code, name) {
995
+ const lines = code.split("\n");
996
+ const defRegex = new RegExp(`(?:^|\\s)fun\\s+(?:<[^>]*>\\s+)?(?:\\w[\\w.]*\\.)?${escapeRegex(name)}\\s*(?:\\(|<)`, "m");
997
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
998
+ if (defLineIdx === -1)
999
+ return "low";
1000
+ let startLine = defLineIdx;
1001
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
1002
+ startLine++;
1003
+ }
1004
+ if (startLine >= lines.length)
1005
+ return "low";
1006
+ let braceCount = 0;
1007
+ let started = false;
1008
+ const bodyLines = [];
1009
+ for (let i = startLine; i < lines.length; i++) {
1010
+ const line = lines[i];
1011
+ for (const ch of line) {
1012
+ if (ch === "{") {
1013
+ braceCount++;
1014
+ started = true;
1015
+ } else if (ch === "}") {
1016
+ braceCount--;
1017
+ }
1018
+ }
1019
+ bodyLines.push(line);
1020
+ if (started && braceCount <= 0)
1021
+ break;
1022
+ }
1023
+ const body = bodyLines.join("\n");
1024
+ const branches = (body.match(/\b(if|else\s+if|else|for|while|when|catch|&&|\|\|)\b/g) || []).length;
1025
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
1026
+ return "low";
1027
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1028
+ return "medium";
1029
+ return "high";
1030
+ }
1031
+ exports2.kotlinEntityPatterns = [
1032
+ // class declarations (including data class, sealed class, abstract class, inner class)
1033
+ // The trailing brace is optional: abstract classes may have no body on the same line.
1034
+ // We anchor by requiring the class name to be followed by whitespace, <, (, :, { or EOL.
1035
+ {
1036
+ regex: /^[ \t]*(?:(?:public|private|protected|internal|abstract|sealed|data|open|inner|inline|value|annotation)\s+)*class\s+([A-Za-z_]\w*)(?=[\s<(:,{\n]|$)/gm,
1037
+ type: "class"
1038
+ },
1039
+ // object declarations (singleton objects and companion objects)
1040
+ {
1041
+ regex: /^[ \t]*(?:(?:public|private|protected|internal)\s+)*(?:companion\s+)?object\s+([A-Za-z_]\w*)\s*(?::\s*[^{]+)?\s*\{/gm,
1042
+ type: "class"
1043
+ },
1044
+ // interface declarations
1045
+ {
1046
+ regex: /^[ \t]*(?:(?:public|private|protected|internal|sealed|fun)\s+)*interface\s+([A-Za-z_]\w*)(?:\s*<[^{]*)?(?:\s*:\s*[^{]+)?\s*\{/gm,
1047
+ type: "interface"
1048
+ },
1049
+ // enum class
1050
+ {
1051
+ regex: /^[ \t]*(?:(?:public|private|protected|internal)\s+)*enum\s+class\s+([A-Za-z_]\w*)\s*(?:\([^)]*\))?\s*\{/gm,
1052
+ type: "class"
1053
+ },
1054
+ // function declarations (including suspend, inline, operator, extension functions)
1055
+ {
1056
+ regex: /^[ \t]*(?:(?:public|private|protected|internal|override|open|final|abstract|suspend|inline|operator|infix|tailrec|external|actual|expect)\s+)*fun\s+(?:<[^>]*>\s+)?(?:[\w.]+\.)?([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
1057
+ type: "function"
1058
+ }
1059
+ ];
1060
+ function extractEntities(code, _filePath) {
1061
+ const entities = [];
1062
+ for (const { regex, type } of exports2.kotlinEntityPatterns) {
1063
+ regex.lastIndex = 0;
1064
+ let match;
1065
+ while ((match = regex.exec(code)) !== null) {
1066
+ const name = match[1];
1067
+ if (!name)
1068
+ continue;
1069
+ const upToMatch = code.slice(0, match.index);
1070
+ const line = upToMatch.split("\n").length;
1071
+ if (entities.some((e) => e.name === name && e.line === line))
1072
+ continue;
1073
+ entities.push({
1074
+ name,
1075
+ type,
1076
+ line,
1077
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
1078
+ });
1079
+ }
1080
+ }
1081
+ return entities;
1082
+ }
1083
+ function extractImports(code) {
1084
+ const imports = [];
1085
+ const importPattern = /^import\s+([\w.]+?)(\.\*)?\s*(?:as\s+(\w+))?\s*$/gm;
1086
+ let match;
1087
+ while ((match = importPattern.exec(code)) !== null) {
1088
+ const fullPath = match[1];
1089
+ const isWild = Boolean(match[2]);
1090
+ const alias = match[3];
1091
+ if (isWild)
1092
+ continue;
1093
+ const lastName = fullPath.split(".").pop() || fullPath;
1094
+ const localName = alias || lastName;
1095
+ imports.push({
1096
+ source: fullPath,
1097
+ names: [localName],
1098
+ isLocal: false
1099
+ });
1100
+ }
1101
+ return imports;
1102
+ }
1103
+ function extractExports(code) {
1104
+ const exports3 = [];
1105
+ const patterns = [
1106
+ /^(?:(?:public|open|abstract|sealed|data|inline|value)\s+)*class\s+([A-Za-z_]\w*)/gm,
1107
+ /^(?:(?:public)\s+)?object\s+([A-Za-z_]\w*)/gm,
1108
+ /^(?:(?:public|sealed|fun)\s+)*interface\s+([A-Za-z_]\w*)/gm,
1109
+ /^(?:(?:public|open|inline|suspend|operator|infix|tailrec)\s+)*fun\s+(?:<[^>]*>\s+)?([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm
1110
+ ];
1111
+ for (const pattern of patterns) {
1112
+ let match;
1113
+ while ((match = pattern.exec(code)) !== null) {
1114
+ if (match[1])
1115
+ exports3.push(match[1]);
1116
+ }
1117
+ }
1118
+ return [...new Set(exports3)];
1119
+ }
1120
+ var KotlinParser = {
1121
+ lang: "kotlin",
1122
+ extensions: [".kt", ".kts"],
1123
+ extractEntities,
1124
+ extractImports,
1125
+ extractExports,
1126
+ entityPatterns: exports2.kotlinEntityPatterns
1127
+ };
1128
+ (0, registry_1.registerParser)(KotlinParser);
1129
+ }
1130
+ });
1131
+
1132
+ // dist/languages/php.js
1133
+ var require_php = __commonJS({
1134
+ "dist/languages/php.js"(exports2) {
1135
+ "use strict";
1136
+ Object.defineProperty(exports2, "__esModule", { value: true });
1137
+ exports2.phpEntityPatterns = void 0;
1138
+ var registry_1 = require_registry();
1139
+ var constants_1 = require_constants();
1140
+ function escapeRegex(s) {
1141
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1142
+ }
1143
+ function estimateComplexity(code, name) {
1144
+ const lines = code.split("\n");
1145
+ const defRegex = new RegExp(`(?:^|\\s)function\\s+${escapeRegex(name)}\\s*\\(`, "m");
1146
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
1147
+ if (defLineIdx === -1)
1148
+ return "low";
1149
+ let startLine = defLineIdx;
1150
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
1151
+ startLine++;
1152
+ }
1153
+ if (startLine >= lines.length)
1154
+ return "low";
1155
+ let braceCount = 0;
1156
+ let started = false;
1157
+ const bodyLines = [];
1158
+ for (let i = startLine; i < lines.length; i++) {
1159
+ const line = lines[i];
1160
+ for (const ch of line) {
1161
+ if (ch === "{") {
1162
+ braceCount++;
1163
+ started = true;
1164
+ } else if (ch === "}") {
1165
+ braceCount--;
1166
+ }
1167
+ }
1168
+ bodyLines.push(line);
1169
+ if (started && braceCount <= 0)
1170
+ break;
1171
+ }
1172
+ const body = bodyLines.join("\n");
1173
+ const branches = (body.match(/\b(if|elseif|else|for|foreach|while|do|switch|case|catch|&&|\|\|)\b/g) || []).length;
1174
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
1175
+ return "low";
1176
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1177
+ return "medium";
1178
+ return "high";
1179
+ }
1180
+ exports2.phpEntityPatterns = [
1181
+ // class (abstract class, final class, readonly class, etc.)
1182
+ {
1183
+ regex: /^[ \t]*(?:(?:abstract|final|readonly)\s+)*class\s+([A-Za-z_]\w*)(?:\s+extends\s+\S+)?(?:\s+implements\s+[^{]+)?\s*\{/gm,
1184
+ type: "class"
1185
+ },
1186
+ // interface
1187
+ {
1188
+ regex: /^[ \t]*interface\s+([A-Za-z_]\w*)(?:\s+extends\s+[^{]+)?\s*\{/gm,
1189
+ type: "interface"
1190
+ },
1191
+ // trait
1192
+ {
1193
+ regex: /^[ \t]*trait\s+([A-Za-z_]\w*)\s*\{/gm,
1194
+ type: "class"
1195
+ },
1196
+ // enum (PHP 8.1+)
1197
+ {
1198
+ regex: /^[ \t]*enum\s+([A-Za-z_]\w*)(?:\s*:\s*\w+)?(?:\s+implements\s+[^{]+)?\s*\{/gm,
1199
+ type: "class"
1200
+ },
1201
+ // function and method declarations
1202
+ {
1203
+ regex: /^[ \t]*(?:(?:public|protected|private|static|abstract|final|readonly)\s+)*function\s+([A-Za-z_]\w*)\s*\(/gm,
1204
+ type: "function"
1205
+ }
1206
+ ];
1207
+ function extractEntities(code, _filePath) {
1208
+ const entities = [];
1209
+ for (const { regex, type } of exports2.phpEntityPatterns) {
1210
+ regex.lastIndex = 0;
1211
+ let match;
1212
+ while ((match = regex.exec(code)) !== null) {
1213
+ const name = match[1];
1214
+ if (!name)
1215
+ continue;
1216
+ const upToMatch = code.slice(0, match.index);
1217
+ const line = upToMatch.split("\n").length;
1218
+ if (entities.some((e) => e.name === name && e.line === line))
1219
+ continue;
1220
+ entities.push({
1221
+ name,
1222
+ type,
1223
+ line,
1224
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
1225
+ });
1226
+ }
1227
+ }
1228
+ return entities;
1229
+ }
1230
+ function extractImports(code) {
1231
+ const imports = [];
1232
+ const usePattern = /^use\s+([\w\\]+(?:\s*\{[^}]*\})?)\s*(?:as\s+(\w+)\s*)?;/gm;
1233
+ let match;
1234
+ while ((match = usePattern.exec(code)) !== null) {
1235
+ const raw = match[1].trim();
1236
+ const alias = match[2]?.trim();
1237
+ if (raw.includes("{")) {
1238
+ const prefixMatch = raw.match(/^([\w\\]+)\\?\s*\{([^}]*)\}/);
1239
+ if (prefixMatch) {
1240
+ const prefix = prefixMatch[1];
1241
+ const items = prefixMatch[2].split(",");
1242
+ for (const item of items) {
1243
+ const parts = item.trim().split(/\s+as\s+/i);
1244
+ const fullName = (prefix + "\\" + parts[0].trim()).replace(/\\+/g, "\\");
1245
+ const lastName = parts[1] || parts[0].trim().split("\\").pop() || fullName;
1246
+ imports.push({ source: fullName, names: [lastName.trim()], isLocal: false });
1247
+ }
1248
+ }
1249
+ } else {
1250
+ const fullPath = raw;
1251
+ const lastName = alias || fullPath.split("\\").pop() || fullPath;
1252
+ imports.push({ source: fullPath, names: [lastName.trim()], isLocal: false });
1253
+ }
1254
+ }
1255
+ const includePattern = /(?:require|include)(?:_once)?\s*[^;'"]*?['"]([^'"]+)['"]/gm;
1256
+ while ((match = includePattern.exec(code)) !== null) {
1257
+ const source = match[1];
1258
+ const name = source.split("/").pop()?.replace(/\.php$/i, "") || source;
1259
+ imports.push({ source, names: [name], isLocal: true });
1260
+ }
1261
+ return imports;
1262
+ }
1263
+ function extractExports(code) {
1264
+ const exports3 = [];
1265
+ const patterns = [
1266
+ /^(?:(?:abstract|final|readonly)\s+)*class\s+([A-Za-z_]\w*)/gm,
1267
+ /^interface\s+([A-Za-z_]\w*)/gm,
1268
+ /^trait\s+([A-Za-z_]\w*)/gm,
1269
+ /^enum\s+([A-Za-z_]\w*)/gm,
1270
+ /^function\s+([A-Za-z_]\w*)\s*\(/gm
1271
+ ];
1272
+ for (const pattern of patterns) {
1273
+ let match;
1274
+ while ((match = pattern.exec(code)) !== null) {
1275
+ if (match[1])
1276
+ exports3.push(match[1]);
1277
+ }
1278
+ }
1279
+ return [...new Set(exports3)];
1280
+ }
1281
+ var PhpParser = {
1282
+ lang: "php",
1283
+ extensions: [".php", ".phtml", ".php3", ".php4", ".php5", ".php7"],
1284
+ extractEntities,
1285
+ extractImports,
1286
+ extractExports,
1287
+ entityPatterns: exports2.phpEntityPatterns
1288
+ };
1289
+ (0, registry_1.registerParser)(PhpParser);
1290
+ }
1291
+ });
1292
+
1293
+ // dist/languages/ruby.js
1294
+ var require_ruby = __commonJS({
1295
+ "dist/languages/ruby.js"(exports2) {
1296
+ "use strict";
1297
+ Object.defineProperty(exports2, "__esModule", { value: true });
1298
+ exports2.rubyEntityPatterns = void 0;
1299
+ var registry_1 = require_registry();
1300
+ var constants_1 = require_constants();
1301
+ function escapeRegex(s) {
1302
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1303
+ }
1304
+ function sanitizeMethodName(name) {
1305
+ if (name.endsWith("!"))
1306
+ return `${name.slice(0, -1)}_bang`;
1307
+ if (name.endsWith("?"))
1308
+ return `${name.slice(0, -1)}_pred`;
1309
+ if (name.endsWith("="))
1310
+ return `${name.slice(0, -1)}_eq`;
1311
+ return name;
1312
+ }
1313
+ function estimateComplexity(code, name) {
1314
+ const lines = code.split("\n");
1315
+ const defRegex = new RegExp(`^[ \\t]*def\\s+(?:self\\.)?${escapeRegex(name)}(?:[!?=])?\\s*(\\(|$)`, "m");
1316
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
1317
+ if (defLineIdx === -1)
1318
+ return "low";
1319
+ const bodyLines = [];
1320
+ let depth = 0;
1321
+ for (let i = defLineIdx; i < lines.length; i++) {
1322
+ const line = lines[i];
1323
+ const trimmed = line.trim();
1324
+ if (/\b(def|class|module|do\b|begin|if(?!.*\bend\b)|unless(?!.*\bend\b)|while(?!.*\bend\b)|until(?!.*\bend\b)|for\s|case\b)\b/.test(trimmed)) {
1325
+ depth++;
1326
+ }
1327
+ if (/\bend\b/.test(trimmed)) {
1328
+ depth--;
1329
+ if (depth <= 0) {
1330
+ bodyLines.push(line);
1331
+ break;
1332
+ }
1333
+ }
1334
+ bodyLines.push(line);
1335
+ }
1336
+ const body = bodyLines.join("\n");
1337
+ const branches = (body.match(/\b(if|elsif|else|unless|while|until|for|rescue|when|and|or|&&|\|\|)\b/g) || []).length;
1338
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
1339
+ return "low";
1340
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1341
+ return "medium";
1342
+ return "high";
1343
+ }
1344
+ exports2.rubyEntityPatterns = [
1345
+ // class declarations (class Foo, class Foo < Bar)
1346
+ {
1347
+ regex: /^[ \t]*class\s+([A-Z]\w*(?:::[A-Z]\w*)*)\s*(?:<\s*\S+)?\s*$/gm,
1348
+ type: "class"
1349
+ },
1350
+ // module declarations
1351
+ {
1352
+ regex: /^[ \t]*module\s+([A-Z]\w*(?:::[A-Z]\w*)*)\s*$/gm,
1353
+ type: "class"
1354
+ },
1355
+ // singleton methods: def self.method_name[!?=]
1356
+ {
1357
+ regex: /^[ \t]*def\s+self\.([A-Za-z_]\w*[!?=]?)\s*(?:\(|$)/gm,
1358
+ type: "function"
1359
+ },
1360
+ // instance methods: def method_name[!?=]
1361
+ {
1362
+ regex: /^[ \t]*def\s+([A-Za-z_]\w*[!?=]?)\s*(?:\(|$)/gm,
1363
+ type: "function"
1364
+ }
1365
+ ];
1366
+ function extractEntities(code, _filePath) {
1367
+ const entities = [];
1368
+ for (const { regex, type } of exports2.rubyEntityPatterns) {
1369
+ regex.lastIndex = 0;
1370
+ let match;
1371
+ while ((match = regex.exec(code)) !== null) {
1372
+ const rawName = match[1];
1373
+ if (!rawName)
1374
+ continue;
1375
+ const name = type === "function" ? sanitizeMethodName(rawName) : rawName;
1376
+ const upToMatch = code.slice(0, match.index);
1377
+ const line = upToMatch.split("\n").length;
1378
+ if (entities.some((e) => e.name === name && e.line === line))
1379
+ continue;
1380
+ entities.push({
1381
+ name,
1382
+ type,
1383
+ line,
1384
+ complexity: type === "function" ? estimateComplexity(code, rawName) : "low"
1385
+ });
1386
+ }
1387
+ }
1388
+ return entities;
1389
+ }
1390
+ function extractImports(code) {
1391
+ const imports = [];
1392
+ const requirePattern = /^[ \t]*require\s+['"]([^'"]+)['"]/gm;
1393
+ let match;
1394
+ while ((match = requirePattern.exec(code)) !== null) {
1395
+ const source = match[1];
1396
+ const name = source.split("/").pop() || source;
1397
+ imports.push({ source, names: [name], isLocal: false });
1398
+ }
1399
+ const relPattern = /^[ \t]*require_relative\s+['"]([^'"]+)['"]/gm;
1400
+ while ((match = relPattern.exec(code)) !== null) {
1401
+ const source = match[1];
1402
+ const name = source.split("/").pop() || source;
1403
+ imports.push({ source, names: [name], isLocal: true });
1404
+ }
1405
+ const loadPattern = /^[ \t]*load\s+['"]([^'"]+)['"]/gm;
1406
+ while ((match = loadPattern.exec(code)) !== null) {
1407
+ const source = match[1];
1408
+ const name = source.split("/").pop()?.replace(/\.rb$/, "") || source;
1409
+ imports.push({ source, names: [name], isLocal: true });
1410
+ }
1411
+ const mixinPattern = /^[ \t]*(?:include|extend|prepend)\s+([A-Z]\w*(?:::[A-Z]\w*)*)/gm;
1412
+ while ((match = mixinPattern.exec(code)) !== null) {
1413
+ const source = match[1];
1414
+ const name = source.split("::").pop() || source;
1415
+ imports.push({ source, names: [name], isLocal: false });
1416
+ }
1417
+ return imports;
1418
+ }
1419
+ function extractExports(code) {
1420
+ const exports3 = [];
1421
+ const typePattern = /^(?:class|module)\s+([A-Z]\w*(?:::[A-Z]\w*)*)/gm;
1422
+ let match;
1423
+ while ((match = typePattern.exec(code)) !== null) {
1424
+ exports3.push(match[1]);
1425
+ }
1426
+ const attrPattern = /^[ \t]*attr_(?:reader|writer|accessor)\s+(.+)$/gm;
1427
+ while ((match = attrPattern.exec(code)) !== null) {
1428
+ const syms = match[1].split(",").map((s) => s.trim().replace(/^:/, ""));
1429
+ exports3.push(...syms.filter(Boolean));
1430
+ }
1431
+ const pubFuncPattern = /^[ \t]*(?:module_function|public)\s+def\s+([A-Za-z_]\w*[!?=]?)/gm;
1432
+ while ((match = pubFuncPattern.exec(code)) !== null) {
1433
+ exports3.push(sanitizeMethodName(match[1]));
1434
+ }
1435
+ return [...new Set(exports3)];
1436
+ }
1437
+ var RubyParser = {
1438
+ lang: "ruby",
1439
+ extensions: [".rb", ".rake", ".gemspec"],
1440
+ extractEntities,
1441
+ extractImports,
1442
+ extractExports,
1443
+ entityPatterns: exports2.rubyEntityPatterns
1444
+ };
1445
+ (0, registry_1.registerParser)(RubyParser);
1446
+ }
1447
+ });
1448
+
1449
+ // dist/languages/swift.js
1450
+ var require_swift = __commonJS({
1451
+ "dist/languages/swift.js"(exports2) {
1452
+ "use strict";
1453
+ Object.defineProperty(exports2, "__esModule", { value: true });
1454
+ exports2.swiftEntityPatterns = void 0;
1455
+ var registry_1 = require_registry();
1456
+ var constants_1 = require_constants();
1457
+ function escapeRegex(s) {
1458
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1459
+ }
1460
+ function estimateComplexity(code, name) {
1461
+ const lines = code.split("\n");
1462
+ const defRegex = new RegExp(`(?:^|\\s)(?:func\\s+${escapeRegex(name)}|init|deinit|subscript)\\s*(?:<[^>]*>)?\\s*\\(`, "m");
1463
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
1464
+ if (defLineIdx === -1)
1465
+ return "low";
1466
+ let startLine = defLineIdx;
1467
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
1468
+ startLine++;
1469
+ }
1470
+ if (startLine >= lines.length)
1471
+ return "low";
1472
+ let braceCount = 0;
1473
+ let started = false;
1474
+ const bodyLines = [];
1475
+ for (let i = startLine; i < lines.length; i++) {
1476
+ const line = lines[i];
1477
+ for (const ch of line) {
1478
+ if (ch === "{") {
1479
+ braceCount++;
1480
+ started = true;
1481
+ } else if (ch === "}") {
1482
+ braceCount--;
1483
+ }
1484
+ }
1485
+ bodyLines.push(line);
1486
+ if (started && braceCount <= 0)
1487
+ break;
1488
+ }
1489
+ const body = bodyLines.join("\n");
1490
+ const branches = (body.match(/\b(if|else\s+if|else|for\s|while|repeat|switch|case|catch|guard|&&|\|\|)\b/g) || []).length;
1491
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
1492
+ return "low";
1493
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1494
+ return "medium";
1495
+ return "high";
1496
+ }
1497
+ exports2.swiftEntityPatterns = [
1498
+ // class (including final class, open class, public class)
1499
+ {
1500
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|open|final|@MainActor)\s+)*class\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?::\s*[^{]+)?\s*\{/gm,
1501
+ type: "class"
1502
+ },
1503
+ // struct
1504
+ {
1505
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate)\s+)*struct\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?::\s*[^{]+)?\s*\{/gm,
1506
+ type: "class"
1507
+ },
1508
+ // enum
1509
+ {
1510
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|indirect)\s+)*enum\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?::\s*[^{]+)?\s*\{/gm,
1511
+ type: "class"
1512
+ },
1513
+ // protocol
1514
+ {
1515
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate)\s+)*protocol\s+([A-Za-z_]\w*)(?:\s*<[^{]*?)?\s*(?::\s*[^{]+)?\s*\{/gm,
1516
+ type: "interface"
1517
+ },
1518
+ // actor (Swift 5.5+)
1519
+ {
1520
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|distributed)\s+)*actor\s+([A-Za-z_]\w*)(?:\s*:\s*[^{]+)?\s*\{/gm,
1521
+ type: "class"
1522
+ },
1523
+ // extension (cross-file method container, same type as class in Python extractor)
1524
+ // Supports: extension Foo, extension Array where Element: Comparable
1525
+ {
1526
+ regex: /^[ \t]*extension\s+([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)(?:\s*<[^>{]*>)?(?:\s*:\s*[^{]+)?(?:\s+where\s+[^{]+)?\s*\{/gm,
1527
+ type: "class"
1528
+ },
1529
+ // function declarations (including mutating, static, class func, override, async, throws)
1530
+ {
1531
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|open|override|static|class|mutating|nonmutating|dynamic|final|required|convenience|async|throws|rethrows|nonisolated|@discardableResult|@objc|@MainActor)\s+)*func\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm,
1532
+ type: "function"
1533
+ },
1534
+ // init declarations
1535
+ {
1536
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|override|required|convenience)\s+)*init\??\s*(?:<[^>]*>)?\s*\(/gm,
1537
+ type: "function"
1538
+ },
1539
+ // deinit
1540
+ {
1541
+ regex: /^[ \t]*deinit\s*\{/gm,
1542
+ type: "function"
1543
+ },
1544
+ // subscript
1545
+ {
1546
+ regex: /^[ \t]*(?:(?:public|internal|private|fileprivate|static|override)\s+)*subscript\s*(?:<[^>]*>)?\s*\(/gm,
1547
+ type: "function"
1548
+ }
1549
+ ];
1550
+ function extractEntities(code, _filePath) {
1551
+ const entities = [];
1552
+ for (const { regex, type } of exports2.swiftEntityPatterns) {
1553
+ regex.lastIndex = 0;
1554
+ let match;
1555
+ while ((match = regex.exec(code)) !== null) {
1556
+ const name = match[1] ?? (/\binit\b/.test(match[0]) ? "init" : /\bdeinit\b/.test(match[0]) ? "deinit" : "subscript");
1557
+ const upToMatch = code.slice(0, match.index);
1558
+ const line = upToMatch.split("\n").length;
1559
+ if (entities.some((e) => e.name === name && e.line === line))
1560
+ continue;
1561
+ entities.push({
1562
+ name,
1563
+ type,
1564
+ line,
1565
+ complexity: type === "function" ? estimateComplexity(code, name) : "low"
1566
+ });
1567
+ }
1568
+ }
1569
+ return entities;
1570
+ }
1571
+ function extractImports(code) {
1572
+ const imports = [];
1573
+ const importPattern = /^[ \t]*import\s+(?:(?:class|struct|enum|func|var|let|typealias)\s+)?([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)/gm;
1574
+ let match;
1575
+ while ((match = importPattern.exec(code)) !== null) {
1576
+ const fullPath = match[1];
1577
+ const moduleName = fullPath.split(".")[0];
1578
+ if (["class", "struct", "enum", "func", "var", "let", "typealias"].includes(moduleName))
1579
+ continue;
1580
+ imports.push({
1581
+ source: moduleName,
1582
+ names: [moduleName],
1583
+ isLocal: false
1584
+ });
1585
+ }
1586
+ return imports;
1587
+ }
1588
+ function extractExports(code) {
1589
+ const exports3 = [];
1590
+ const publicPatterns = [
1591
+ // public/open class, struct, enum, protocol, actor, extension
1592
+ /^(?:(?:public|open|final)\s+)*(?:class|struct|enum|protocol|actor)\s+([A-Za-z_]\w*)/gm,
1593
+ // public extension is not really an export, but surfaces it for graph linking
1594
+ /^(?:public\s+)?extension\s+([A-Za-z_]\w*)/gm,
1595
+ // public func
1596
+ /^[ \t]*(?:public|open)\s+(?:(?:static|class|override|mutating|async|throws|nonisolated)\s+)*func\s+([A-Za-z_]\w*)/gm,
1597
+ // public var / let
1598
+ /^[ \t]*(?:public|open)\s+(?:(?:static|class|lazy|private\(set\)|internal\(set\))\s+)*(?:var|let)\s+([A-Za-z_]\w*)/gm,
1599
+ // public init
1600
+ /^[ \t]*(?:public|open)\s+(?:required\s+|convenience\s+)?init/gm
1601
+ ];
1602
+ for (const pattern of publicPatterns) {
1603
+ let match;
1604
+ while ((match = pattern.exec(code)) !== null) {
1605
+ if (match[1])
1606
+ exports3.push(match[1]);
1607
+ }
1608
+ }
1609
+ return [...new Set(exports3)];
1610
+ }
1611
+ var SwiftParser = {
1612
+ lang: "swift",
1613
+ extensions: [".swift"],
1614
+ extractEntities,
1615
+ extractImports,
1616
+ extractExports,
1617
+ entityPatterns: exports2.swiftEntityPatterns
1618
+ };
1619
+ (0, registry_1.registerParser)(SwiftParser);
1620
+ }
1621
+ });
1622
+
412
1623
  // dist/stages/collector.js
413
1624
  var require_collector = __commonJS({
414
1625
  "dist/stages/collector.js"(exports2) {
@@ -483,13 +1694,17 @@ var require_parser = __commonJS({
483
1694
  const parser = (0, registry_1.getLanguageParser)(ext);
484
1695
  if (!parser)
485
1696
  return null;
1697
+ const isHashCommentLang = [".py", ".rb", ".sh", ".bash", ".ps1"].includes(ext);
1698
+ const commentChar = isHashCommentLang ? "#" : "//";
486
1699
  const cleanCode = code.split("\n").map((line) => {
487
- const commentIndex = line.indexOf("//");
1700
+ const commentIndex = line.indexOf(commentChar);
488
1701
  if (commentIndex === -1)
489
1702
  return line;
490
1703
  const before = line.slice(0, commentIndex);
491
- const inString = (before.match(/"/g) || []).length % 2 !== 0 || (before.match(/'/g) || []).length % 2 !== 0;
492
- return inString ? line : line.slice(0, commentIndex);
1704
+ const inDouble = (before.match(/"/g) || []).length % 2 !== 0;
1705
+ const inSingle = (before.match(/'/g) || []).length % 2 !== 0;
1706
+ const inBacktick = (before.match(/`/g) || []).length % 2 !== 0;
1707
+ return inDouble || inSingle || inBacktick ? line : line.slice(0, commentIndex);
493
1708
  }).join("\n");
494
1709
  const lines = code.split("\n").length;
495
1710
  const entities = parser.extractEntities(cleanCode, filePath);
@@ -1049,6 +2264,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
1049
2264
  require_javascript();
1050
2265
  require_python();
1051
2266
  require_go();
2267
+ require_csharp();
2268
+ require_java();
2269
+ require_kotlin();
2270
+ require_php();
2271
+ require_ruby();
2272
+ require_swift();
1052
2273
  var fs_1 = __importDefault(require("fs"));
1053
2274
  var collector_1 = require_collector();
1054
2275
  var parser_1 = require_parser();
@@ -1077,7 +2298,7 @@ function getFlag(flag) {
1077
2298
  }
1078
2299
  function printHelp() {
1079
2300
  console.log(`
1080
- ${bold("DepGraph")} ${dim("v1.0.2")}
2301
+ ${bold("DepGraph")} ${dim("v1.5.1")}
1081
2302
  ${dim("Dependency mapping \xB7 Impact simulation \xB7 Developer intelligence")}
1082
2303
 
1083
2304
  ${bold("USAGE")}