@shrkcrft/graph 0.1.0-alpha.10

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.
Files changed (91) hide show
  1. package/dist/index.d.ts +30 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +32 -0
  4. package/dist/indexer/detect-workspace.d.ts +18 -0
  5. package/dist/indexer/detect-workspace.d.ts.map +1 -0
  6. package/dist/indexer/detect-workspace.js +80 -0
  7. package/dist/indexer/extract-csharp-file.d.ts +27 -0
  8. package/dist/indexer/extract-csharp-file.d.ts.map +1 -0
  9. package/dist/indexer/extract-csharp-file.js +163 -0
  10. package/dist/indexer/extract-dart-file.d.ts +28 -0
  11. package/dist/indexer/extract-dart-file.d.ts.map +1 -0
  12. package/dist/indexer/extract-dart-file.js +167 -0
  13. package/dist/indexer/extract-elixir-file.d.ts +27 -0
  14. package/dist/indexer/extract-elixir-file.d.ts.map +1 -0
  15. package/dist/indexer/extract-elixir-file.js +164 -0
  16. package/dist/indexer/extract-go-file.d.ts +28 -0
  17. package/dist/indexer/extract-go-file.d.ts.map +1 -0
  18. package/dist/indexer/extract-go-file.js +156 -0
  19. package/dist/indexer/extract-java-file.d.ts +25 -0
  20. package/dist/indexer/extract-java-file.d.ts.map +1 -0
  21. package/dist/indexer/extract-java-file.js +140 -0
  22. package/dist/indexer/extract-kotlin-file.d.ts +20 -0
  23. package/dist/indexer/extract-kotlin-file.d.ts.map +1 -0
  24. package/dist/indexer/extract-kotlin-file.js +158 -0
  25. package/dist/indexer/extract-php-file.d.ts +26 -0
  26. package/dist/indexer/extract-php-file.d.ts.map +1 -0
  27. package/dist/indexer/extract-php-file.js +161 -0
  28. package/dist/indexer/extract-python-file.d.ts +30 -0
  29. package/dist/indexer/extract-python-file.d.ts.map +1 -0
  30. package/dist/indexer/extract-python-file.js +196 -0
  31. package/dist/indexer/extract-ruby-file.d.ts +29 -0
  32. package/dist/indexer/extract-ruby-file.d.ts.map +1 -0
  33. package/dist/indexer/extract-ruby-file.js +151 -0
  34. package/dist/indexer/extract-rust-file.d.ts +27 -0
  35. package/dist/indexer/extract-rust-file.d.ts.map +1 -0
  36. package/dist/indexer/extract-rust-file.js +186 -0
  37. package/dist/indexer/extract-swift-file.d.ts +27 -0
  38. package/dist/indexer/extract-swift-file.d.ts.map +1 -0
  39. package/dist/indexer/extract-swift-file.js +168 -0
  40. package/dist/indexer/extract-ts-file.d.ts +79 -0
  41. package/dist/indexer/extract-ts-file.d.ts.map +1 -0
  42. package/dist/indexer/extract-ts-file.js +403 -0
  43. package/dist/indexer/incremental-updater.d.ts +41 -0
  44. package/dist/indexer/incremental-updater.d.ts.map +1 -0
  45. package/dist/indexer/incremental-updater.js +395 -0
  46. package/dist/indexer/index-builder.d.ts +23 -0
  47. package/dist/indexer/index-builder.d.ts.map +1 -0
  48. package/dist/indexer/index-builder.js +289 -0
  49. package/dist/indexer/resolve-imports.d.ts +36 -0
  50. package/dist/indexer/resolve-imports.d.ts.map +1 -0
  51. package/dist/indexer/resolve-imports.js +144 -0
  52. package/dist/indexer/unresolved-imports.d.ts +20 -0
  53. package/dist/indexer/unresolved-imports.d.ts.map +1 -0
  54. package/dist/indexer/unresolved-imports.js +32 -0
  55. package/dist/query/cycle-detection.d.ts +40 -0
  56. package/dist/query/cycle-detection.d.ts.map +1 -0
  57. package/dist/query/cycle-detection.js +135 -0
  58. package/dist/query/query-api.d.ts +87 -0
  59. package/dist/query/query-api.d.ts.map +1 -0
  60. package/dist/query/query-api.js +232 -0
  61. package/dist/schema/edge-kind.d.ts +31 -0
  62. package/dist/schema/edge-kind.d.ts.map +1 -0
  63. package/dist/schema/edge-kind.js +35 -0
  64. package/dist/schema/edge.d.ts +22 -0
  65. package/dist/schema/edge.d.ts.map +1 -0
  66. package/dist/schema/edge.js +1 -0
  67. package/dist/schema/file-fingerprint.d.ts +22 -0
  68. package/dist/schema/file-fingerprint.d.ts.map +1 -0
  69. package/dist/schema/file-fingerprint.js +1 -0
  70. package/dist/schema/graph-snapshot.d.ts +18 -0
  71. package/dist/schema/graph-snapshot.d.ts.map +1 -0
  72. package/dist/schema/graph-snapshot.js +1 -0
  73. package/dist/schema/manifest.d.ts +47 -0
  74. package/dist/schema/manifest.d.ts.map +1 -0
  75. package/dist/schema/manifest.js +1 -0
  76. package/dist/schema/node-kind.d.ts +21 -0
  77. package/dist/schema/node-kind.d.ts.map +1 -0
  78. package/dist/schema/node-kind.js +27 -0
  79. package/dist/schema/node.d.ts +26 -0
  80. package/dist/schema/node.d.ts.map +1 -0
  81. package/dist/schema/node.js +1 -0
  82. package/dist/schema/schema-version.d.ts +10 -0
  83. package/dist/schema/schema-version.d.ts.map +1 -0
  84. package/dist/schema/schema-version.js +8 -0
  85. package/dist/store/file-fingerprint.d.ts +8 -0
  86. package/dist/store/file-fingerprint.d.ts.map +1 -0
  87. package/dist/store/file-fingerprint.js +64 -0
  88. package/dist/store/graph-store.d.ts +48 -0
  89. package/dist/store/graph-store.d.ts.map +1 -0
  90. package/dist/store/graph-store.js +194 -0
  91. package/package.json +54 -0
@@ -0,0 +1,30 @@
1
+ export * from './schema/schema-version.js';
2
+ export * from './schema/node-kind.js';
3
+ export * from './schema/edge-kind.js';
4
+ export * from './schema/node.js';
5
+ export * from './schema/edge.js';
6
+ export * from './schema/manifest.js';
7
+ export * from './schema/file-fingerprint.js';
8
+ export * from './schema/graph-snapshot.js';
9
+ export * from './store/file-fingerprint.js';
10
+ export * from './store/graph-store.js';
11
+ export * from './indexer/extract-ts-file.js';
12
+ export * from './indexer/extract-python-file.js';
13
+ export * from './indexer/extract-go-file.js';
14
+ export * from './indexer/extract-java-file.js';
15
+ export * from './indexer/extract-rust-file.js';
16
+ export * from './indexer/extract-kotlin-file.js';
17
+ export * from './indexer/extract-ruby-file.js';
18
+ export * from './indexer/extract-csharp-file.js';
19
+ export * from './indexer/extract-elixir-file.js';
20
+ export * from './indexer/extract-php-file.js';
21
+ export * from './indexer/extract-dart-file.js';
22
+ export * from './indexer/extract-swift-file.js';
23
+ export * from './indexer/detect-workspace.js';
24
+ export * from './indexer/resolve-imports.js';
25
+ export * from './indexer/index-builder.js';
26
+ export * from './indexer/incremental-updater.js';
27
+ export * from './indexer/unresolved-imports.js';
28
+ export * from './query/query-api.js';
29
+ export * from './query/cycle-detection.js';
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAE3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ // Public surface of @shrkcrft/graph.
2
+ //
3
+ // Schema first; store, extractor, indexer, query API follow.
4
+ export * from "./schema/schema-version.js";
5
+ export * from "./schema/node-kind.js";
6
+ export * from "./schema/edge-kind.js";
7
+ export * from "./schema/node.js";
8
+ export * from "./schema/edge.js";
9
+ export * from "./schema/manifest.js";
10
+ export * from "./schema/file-fingerprint.js";
11
+ export * from "./schema/graph-snapshot.js";
12
+ export * from "./store/file-fingerprint.js";
13
+ export * from "./store/graph-store.js";
14
+ export * from "./indexer/extract-ts-file.js";
15
+ export * from "./indexer/extract-python-file.js";
16
+ export * from "./indexer/extract-go-file.js";
17
+ export * from "./indexer/extract-java-file.js";
18
+ export * from "./indexer/extract-rust-file.js";
19
+ export * from "./indexer/extract-kotlin-file.js";
20
+ export * from "./indexer/extract-ruby-file.js";
21
+ export * from "./indexer/extract-csharp-file.js";
22
+ export * from "./indexer/extract-elixir-file.js";
23
+ export * from "./indexer/extract-php-file.js";
24
+ export * from "./indexer/extract-dart-file.js";
25
+ export * from "./indexer/extract-swift-file.js";
26
+ export * from "./indexer/detect-workspace.js";
27
+ export * from "./indexer/resolve-imports.js";
28
+ export * from "./indexer/index-builder.js";
29
+ export * from "./indexer/incremental-updater.js";
30
+ export * from "./indexer/unresolved-imports.js";
31
+ export * from "./query/query-api.js";
32
+ export * from "./query/cycle-detection.js";
@@ -0,0 +1,18 @@
1
+ export interface IWorkspacePackage {
2
+ /** package.json name field. */
3
+ name: string;
4
+ /** Project-relative directory (POSIX separators). */
5
+ dir: string;
6
+ /** Entry point (project-relative) — best-effort. */
7
+ entry?: string;
8
+ }
9
+ /**
10
+ * Discover workspace packages from `package.json`'s `workspaces` field.
11
+ * Supports both the array and the `{ packages: [...] }` form.
12
+ *
13
+ * Nx integration is deliberately out of scope here — Nx's project graph
14
+ * is a separate optional input considered later (see code-intelligence.md
15
+ * §8.3).
16
+ */
17
+ export declare function detectWorkspacePackages(projectRoot: string): readonly IWorkspacePackage[];
18
+ //# sourceMappingURL=detect-workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-workspace.d.ts","sourceRoot":"","sources":["../../src/indexer/detect-workspace.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,iBAAiB,EAAE,CAoDzF"}
@@ -0,0 +1,80 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ /**
4
+ * Discover workspace packages from `package.json`'s `workspaces` field.
5
+ * Supports both the array and the `{ packages: [...] }` form.
6
+ *
7
+ * Nx integration is deliberately out of scope here — Nx's project graph
8
+ * is a separate optional input considered later (see code-intelligence.md
9
+ * §8.3).
10
+ */
11
+ export function detectWorkspacePackages(projectRoot) {
12
+ const pkgPath = nodePath.join(projectRoot, 'package.json');
13
+ if (!existsSync(pkgPath))
14
+ return [];
15
+ let raw;
16
+ try {
17
+ raw = JSON.parse(readFileSync(pkgPath, 'utf8'));
18
+ }
19
+ catch {
20
+ return [];
21
+ }
22
+ const wsRaw = raw.workspaces;
23
+ const patterns = normalizeWorkspaces(wsRaw);
24
+ const out = [];
25
+ for (const pattern of patterns) {
26
+ const dir = pattern.replace(/\/\*?$/, '');
27
+ const full = nodePath.join(projectRoot, dir);
28
+ if (!existsSync(full))
29
+ continue;
30
+ let entries;
31
+ try {
32
+ entries = readdirSync(full);
33
+ }
34
+ catch {
35
+ continue;
36
+ }
37
+ for (const child of entries) {
38
+ const inner = nodePath.join(full, child);
39
+ try {
40
+ if (!statSync(inner).isDirectory())
41
+ continue;
42
+ }
43
+ catch {
44
+ continue;
45
+ }
46
+ const childPkg = nodePath.join(inner, 'package.json');
47
+ if (!existsSync(childPkg))
48
+ continue;
49
+ try {
50
+ const pj = JSON.parse(readFileSync(childPkg, 'utf8'));
51
+ if (!pj.name)
52
+ continue;
53
+ const relDir = nodePath.relative(projectRoot, inner).split(nodePath.sep).join('/');
54
+ const entry = pj.main ?? pj.module ?? pj.types;
55
+ out.push({
56
+ name: pj.name,
57
+ dir: relDir,
58
+ ...(entry ? { entry: `${relDir}/${entry.replace(/^\.\//, '')}` } : {}),
59
+ });
60
+ }
61
+ catch {
62
+ /* ignore */
63
+ }
64
+ }
65
+ }
66
+ return out.sort((a, b) => a.name.localeCompare(b.name));
67
+ }
68
+ function normalizeWorkspaces(value) {
69
+ if (!value)
70
+ return [];
71
+ if (Array.isArray(value))
72
+ return value.filter((v) => typeof v === 'string');
73
+ if (typeof value === 'object') {
74
+ const packages = value.packages;
75
+ if (Array.isArray(packages)) {
76
+ return packages.filter((v) => typeof v === 'string');
77
+ }
78
+ }
79
+ return [];
80
+ }
@@ -0,0 +1,27 @@
1
+ import type { IFileFingerprint } from '../schema/file-fingerprint.js';
2
+ import type { IExtractedFile } from './extract-ts-file.js';
3
+ export declare const EXTRACT_CSHARP_FILE_SOURCE = "extract-csharp-file@v1";
4
+ /**
5
+ * Regex-based C# extractor.
6
+ *
7
+ * Captured (top-level only — nested types are skipped to stay tight):
8
+ * - `[public] class Name`, `[public] sealed class`, `[public] static
9
+ * class`, `[public] abstract class`, `[public] partial class`
10
+ * - `[public] interface Name`
11
+ * - `[public] struct Name`, `[public] readonly struct`
12
+ * - `[public] record Name(...)`, `[public] record class`, `[public]
13
+ * record struct`
14
+ * - `[public] enum Name`
15
+ * - `namespace Name { … }` and `namespace Name;` (file-scoped)
16
+ *
17
+ * Visibility: `public` → exported. `internal`/`private`/`protected`
18
+ * → local. C# defaults to `internal` at the namespace level, so the
19
+ * `isExported` flag honours the explicit modifier; unmodified types
20
+ * are treated as `internal` (local).
21
+ *
22
+ * Imports: classic `using X.Y;`, `using static X.Y.Z;`,
23
+ * `using alias = X.Y;`. We capture the right-hand path; aliases are
24
+ * dropped.
25
+ */
26
+ export declare function extractCsharpFile(fingerprint: IFileFingerprint, absPath: string, content?: string): IExtractedFile;
27
+ //# sourceMappingURL=extract-csharp-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-csharp-file.d.ts","sourceRoot":"","sources":["../../src/indexer/extract-csharp-file.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,CA6ChB"}
@@ -0,0 +1,163 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { EdgeKind } from "../schema/edge-kind.js";
4
+ import { NodeKind } from "../schema/node-kind.js";
5
+ export const EXTRACT_CSHARP_FILE_SOURCE = 'extract-csharp-file@v1';
6
+ /**
7
+ * Regex-based C# extractor.
8
+ *
9
+ * Captured (top-level only — nested types are skipped to stay tight):
10
+ * - `[public] class Name`, `[public] sealed class`, `[public] static
11
+ * class`, `[public] abstract class`, `[public] partial class`
12
+ * - `[public] interface Name`
13
+ * - `[public] struct Name`, `[public] readonly struct`
14
+ * - `[public] record Name(...)`, `[public] record class`, `[public]
15
+ * record struct`
16
+ * - `[public] enum Name`
17
+ * - `namespace Name { … }` and `namespace Name;` (file-scoped)
18
+ *
19
+ * Visibility: `public` → exported. `internal`/`private`/`protected`
20
+ * → local. C# defaults to `internal` at the namespace level, so the
21
+ * `isExported` flag honours the explicit modifier; unmodified types
22
+ * are treated as `internal` (local).
23
+ *
24
+ * Imports: classic `using X.Y;`, `using static X.Y.Z;`,
25
+ * `using alias = X.Y;`. We capture the right-hand path; aliases are
26
+ * dropped.
27
+ */
28
+ export function extractCsharpFile(fingerprint, absPath, content) {
29
+ const text = content ?? readFileSync(absPath, 'utf8');
30
+ const fileNode = makeFileNode(fingerprint, text);
31
+ const symbolNodes = [];
32
+ const edges = [];
33
+ const lines = text.split('\n');
34
+ for (let i = 0; i < lines.length; i += 1) {
35
+ const raw = lines[i];
36
+ if (raw.length === 0)
37
+ continue;
38
+ if (raw.startsWith(' ') || raw.startsWith('\t'))
39
+ continue;
40
+ const trimmed = raw.trimStart();
41
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*'))
42
+ continue;
43
+ // Strip leading attributes like `[Serializable]` or `[Obsolete("…")]`.
44
+ const stripped = trimmed.replace(/^(?:\[[^\]]*\]\s*)+/, '');
45
+ // Pull access modifiers + variant modifiers.
46
+ const visMatch = /^(public|internal|private|protected|protected\s+internal|internal\s+protected|private\s+protected)\s+/.exec(stripped);
47
+ const isExported = !!visMatch && /\bpublic\b/.test(visMatch[1]);
48
+ const rest = visMatch ? stripped.slice(visMatch[0].length) : stripped;
49
+ const noModifiers = rest.replace(/^(?:static\s+|sealed\s+|abstract\s+|partial\s+|readonly\s+|ref\s+|unsafe\s+|new\s+|virtual\s+|override\s+|async\s+)+/, '');
50
+ let m = /^class\s+([A-Za-z_]\w*)/.exec(noModifiers);
51
+ if (m) {
52
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1, isExported);
53
+ continue;
54
+ }
55
+ m = /^interface\s+([A-Za-z_]\w*)/.exec(noModifiers);
56
+ if (m) {
57
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'interface', i + 1, isExported);
58
+ continue;
59
+ }
60
+ m = /^struct\s+([A-Za-z_]\w*)/.exec(noModifiers);
61
+ if (m) {
62
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1, isExported);
63
+ continue;
64
+ }
65
+ m = /^record(?:\s+(?:class|struct))?\s+([A-Za-z_]\w*)/.exec(noModifiers);
66
+ if (m) {
67
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1, isExported);
68
+ continue;
69
+ }
70
+ m = /^enum\s+([A-Za-z_]\w*)/.exec(noModifiers);
71
+ if (m) {
72
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'enum', i + 1, isExported);
73
+ continue;
74
+ }
75
+ m = /^namespace\s+([\w.]+)\s*[;{]/.exec(noModifiers);
76
+ if (m) {
77
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'namespace', i + 1, true);
78
+ }
79
+ }
80
+ return {
81
+ fileNode,
82
+ symbolNodes,
83
+ edges,
84
+ rawImportSpecifiers: scanUsings(text),
85
+ importBindings: [],
86
+ identifierReferences: [],
87
+ };
88
+ }
89
+ function pushSymbol(fp, nodes, edges, fileId, name, declKind, line, isExported) {
90
+ const sym = {
91
+ id: `symbol:${fp.path}#${name}`,
92
+ kind: NodeKind.Symbol,
93
+ label: name,
94
+ path: fp.path,
95
+ line,
96
+ data: { declKind, visibility: isExported ? 'export' : 'local', isExported, language: 'csharp' },
97
+ };
98
+ nodes.push(sym);
99
+ edges.push({
100
+ id: createHash('sha1').update(`${fileId}|${sym.id}|${EdgeKind.DeclaresSymbol}`).digest('hex'),
101
+ from: fileId,
102
+ to: sym.id,
103
+ kind: EdgeKind.DeclaresSymbol,
104
+ source: EXTRACT_CSHARP_FILE_SOURCE,
105
+ data: { visibility: isExported ? 'export' : 'local', declKind, line },
106
+ });
107
+ }
108
+ function makeFileNode(fp, text) {
109
+ const label = fp.path.split('/').pop() ?? fp.path;
110
+ const tags = ['csharp'];
111
+ if (isCsharpTestPath(fp.path))
112
+ tags.push('test');
113
+ const nsMatch = /^namespace\s+([\w.]+)/m.exec(text);
114
+ return {
115
+ id: fp.nodeId,
116
+ kind: NodeKind.File,
117
+ label,
118
+ path: fp.path,
119
+ tags,
120
+ data: {
121
+ language: 'csharp',
122
+ sizeBytes: fp.sizeBytes,
123
+ sha1: fp.sha1,
124
+ hasDefaultExport: false,
125
+ exportCount: 0,
126
+ localCount: 0,
127
+ reExportCount: 0,
128
+ ...(nsMatch ? { csharpNamespace: nsMatch[1] } : {}),
129
+ },
130
+ };
131
+ }
132
+ function isCsharpTestPath(rel) {
133
+ return /(?:^|\/)[\w.-]+Tests?\.cs$/.test(rel) || /(?:^|\/)test\//.test(rel);
134
+ }
135
+ function scanUsings(text) {
136
+ const out = [];
137
+ // `using X.Y;`, `using static X.Y.Z;`, `using alias = X.Y.Z;`,
138
+ // `using alias = X.Y.Generic<int, string>;`
139
+ const re = /^using\s+(?:static\s+)?(?:[\w]+\s*=\s*)?([\w.]+)(?:\s*<[^;]*>)?\s*;/gm;
140
+ let m;
141
+ while ((m = re.exec(text)) !== null) {
142
+ const line = lineFromOffset(text, m.index);
143
+ out.push({ specifier: m[1], line, kind: 'csharp-using' });
144
+ }
145
+ const seen = new Set();
146
+ const deduped = [];
147
+ for (const it of out) {
148
+ const k = `${it.specifier}|${it.line}`;
149
+ if (seen.has(k))
150
+ continue;
151
+ seen.add(k);
152
+ deduped.push(it);
153
+ }
154
+ return deduped;
155
+ }
156
+ function lineFromOffset(text, offset) {
157
+ let line = 1;
158
+ for (let i = 0; i < offset && i < text.length; i++) {
159
+ if (text.charCodeAt(i) === 10)
160
+ line += 1;
161
+ }
162
+ return line;
163
+ }
@@ -0,0 +1,28 @@
1
+ import type { IFileFingerprint } from '../schema/file-fingerprint.js';
2
+ import type { IExtractedFile } from './extract-ts-file.js';
3
+ export declare const EXTRACT_DART_FILE_SOURCE = "extract-dart-file@v1";
4
+ /**
5
+ * Regex-based Dart extractor.
6
+ *
7
+ * Top-level declarations only (column-0). Detected:
8
+ * - `[abstract] class Name [extends X] [with M] [implements I]`
9
+ * - `mixin Name`, `mixin Name on X`
10
+ * - `enum Name { … }`
11
+ * - `typedef Name = …`
12
+ * - `extension Name on X { … }`
13
+ * - `[Type] name(…) { … }`, `void name(…) { … }` — file-scope functions
14
+ *
15
+ * Imports: `import 'package:foo/bar.dart' [as X] [show A, B] [hide C]`;
16
+ * `export 'package:foo/bar.dart'`. Relative imports captured as-is.
17
+ *
18
+ * Visibility: Dart marks private members with a leading underscore.
19
+ * Public symbols (no leading `_`) get `isExported: true`; otherwise
20
+ * `local`.
21
+ *
22
+ * Out of scope:
23
+ * - `part of` / `part` directive handling.
24
+ * - Inline `@Annotation()` capture.
25
+ * - Class body walking (methods).
26
+ */
27
+ export declare function extractDartFile(fingerprint: IFileFingerprint, absPath: string, content?: string): IExtractedFile;
28
+ //# sourceMappingURL=extract-dart-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-dart-file.d.ts","sourceRoot":"","sources":["../../src/indexer/extract-dart-file.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,CA8DhB"}
@@ -0,0 +1,167 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { EdgeKind } from "../schema/edge-kind.js";
4
+ import { NodeKind } from "../schema/node-kind.js";
5
+ export const EXTRACT_DART_FILE_SOURCE = 'extract-dart-file@v1';
6
+ /**
7
+ * Regex-based Dart extractor.
8
+ *
9
+ * Top-level declarations only (column-0). Detected:
10
+ * - `[abstract] class Name [extends X] [with M] [implements I]`
11
+ * - `mixin Name`, `mixin Name on X`
12
+ * - `enum Name { … }`
13
+ * - `typedef Name = …`
14
+ * - `extension Name on X { … }`
15
+ * - `[Type] name(…) { … }`, `void name(…) { … }` — file-scope functions
16
+ *
17
+ * Imports: `import 'package:foo/bar.dart' [as X] [show A, B] [hide C]`;
18
+ * `export 'package:foo/bar.dart'`. Relative imports captured as-is.
19
+ *
20
+ * Visibility: Dart marks private members with a leading underscore.
21
+ * Public symbols (no leading `_`) get `isExported: true`; otherwise
22
+ * `local`.
23
+ *
24
+ * Out of scope:
25
+ * - `part of` / `part` directive handling.
26
+ * - Inline `@Annotation()` capture.
27
+ * - Class body walking (methods).
28
+ */
29
+ export function extractDartFile(fingerprint, absPath, content) {
30
+ const text = content ?? readFileSync(absPath, 'utf8');
31
+ const fileNode = makeFileNode(fingerprint);
32
+ const symbolNodes = [];
33
+ const edges = [];
34
+ const lines = text.split('\n');
35
+ for (let i = 0; i < lines.length; i += 1) {
36
+ const raw = lines[i];
37
+ if (raw.length === 0)
38
+ continue;
39
+ if (raw.startsWith(' ') || raw.startsWith('\t'))
40
+ continue;
41
+ const trimmed = raw.trimStart();
42
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*'))
43
+ continue;
44
+ // class / abstract class / sealed class / interface class / final class / base class / mixin class
45
+ let m = /^(?:abstract\s+|sealed\s+|base\s+|interface\s+|final\s+|mixin\s+)*class\s+([A-Za-z_]\w*)/.exec(trimmed);
46
+ if (m) {
47
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1);
48
+ continue;
49
+ }
50
+ m = /^mixin\s+([A-Za-z_]\w*)/.exec(trimmed);
51
+ if (m) {
52
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1);
53
+ continue;
54
+ }
55
+ m = /^enum\s+([A-Za-z_]\w*)/.exec(trimmed);
56
+ if (m) {
57
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'enum', i + 1);
58
+ continue;
59
+ }
60
+ m = /^typedef\s+([A-Za-z_]\w*)/.exec(trimmed);
61
+ if (m) {
62
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'type-alias', i + 1);
63
+ continue;
64
+ }
65
+ m = /^extension\s+([A-Za-z_]\w*)/.exec(trimmed);
66
+ if (m) {
67
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, m[1], 'class', i + 1);
68
+ continue;
69
+ }
70
+ // File-scope functions: `<Type> name(…)` or `void name(…)`.
71
+ // Require either a `{` to open a body (anywhere on the line) or
72
+ // an arrow `=>` so we don't sweep up variable declarations or
73
+ // function-type fields.
74
+ m = /^([A-Za-z_]\w*(?:<[^>]*>)?\??)\s+([A-Za-z_]\w*)\s*\(/.exec(trimmed);
75
+ if (m && (/\{/.test(trimmed) || /=>/.test(trimmed))) {
76
+ const name = m[2];
77
+ // Skip constructor-style names that begin with `Type.` (those are
78
+ // class members, not file-scope functions).
79
+ if (!name.includes('.')) {
80
+ pushSymbol(fingerprint, symbolNodes, edges, fileNode.id, name, 'function', i + 1);
81
+ }
82
+ }
83
+ }
84
+ return {
85
+ fileNode,
86
+ symbolNodes,
87
+ edges,
88
+ rawImportSpecifiers: scanDartImports(text),
89
+ importBindings: [],
90
+ identifierReferences: [],
91
+ };
92
+ }
93
+ function pushSymbol(fp, nodes, edges, fileId, name, declKind, line) {
94
+ const isExported = !name.startsWith('_');
95
+ const sym = {
96
+ id: `symbol:${fp.path}#${name}`,
97
+ kind: NodeKind.Symbol,
98
+ label: name,
99
+ path: fp.path,
100
+ line,
101
+ data: { declKind, visibility: isExported ? 'export' : 'local', isExported, language: 'dart' },
102
+ };
103
+ nodes.push(sym);
104
+ edges.push({
105
+ id: createHash('sha1').update(`${fileId}|${sym.id}|${EdgeKind.DeclaresSymbol}`).digest('hex'),
106
+ from: fileId,
107
+ to: sym.id,
108
+ kind: EdgeKind.DeclaresSymbol,
109
+ source: EXTRACT_DART_FILE_SOURCE,
110
+ data: { visibility: isExported ? 'export' : 'local', declKind, line },
111
+ });
112
+ }
113
+ function makeFileNode(fp) {
114
+ const label = fp.path.split('/').pop() ?? fp.path;
115
+ const tags = ['dart'];
116
+ if (isDartTestPath(fp.path))
117
+ tags.push('test');
118
+ return {
119
+ id: fp.nodeId,
120
+ kind: NodeKind.File,
121
+ label,
122
+ path: fp.path,
123
+ tags,
124
+ data: {
125
+ language: 'dart',
126
+ sizeBytes: fp.sizeBytes,
127
+ sha1: fp.sha1,
128
+ hasDefaultExport: false,
129
+ exportCount: 0,
130
+ localCount: 0,
131
+ reExportCount: 0,
132
+ },
133
+ };
134
+ }
135
+ function isDartTestPath(rel) {
136
+ return (/(?:^|\/)test\//.test(rel) ||
137
+ /(?:^|\/)[\w-]+_test\.dart$/.test(rel));
138
+ }
139
+ function scanDartImports(text) {
140
+ const out = [];
141
+ // `import 'package:foo/bar.dart' [as X] [show A] [hide B];`
142
+ // `export 'package:foo/bar.dart';`
143
+ const re = /^\s*(import|export)\s+['"]([^'"]+)['"](?:\s+(?:as\s+\w+|show\s+[^;]+|hide\s+[^;]+|deferred\s+as\s+\w+))*\s*;/gm;
144
+ let m;
145
+ while ((m = re.exec(text)) !== null) {
146
+ const line = lineFromOffset(text, m.index);
147
+ out.push({ specifier: m[2], line, kind: `dart-${m[1]}` });
148
+ }
149
+ const seen = new Set();
150
+ const deduped = [];
151
+ for (const it of out) {
152
+ const k = `${it.kind}|${it.specifier}|${it.line}`;
153
+ if (seen.has(k))
154
+ continue;
155
+ seen.add(k);
156
+ deduped.push(it);
157
+ }
158
+ return deduped;
159
+ }
160
+ function lineFromOffset(text, offset) {
161
+ let line = 1;
162
+ for (let i = 0; i < offset && i < text.length; i++) {
163
+ if (text.charCodeAt(i) === 10)
164
+ line += 1;
165
+ }
166
+ return line;
167
+ }
@@ -0,0 +1,27 @@
1
+ import type { IFileFingerprint } from '../schema/file-fingerprint.js';
2
+ import type { IExtractedFile } from './extract-ts-file.js';
3
+ export declare const EXTRACT_ELIXIR_FILE_SOURCE = "extract-elixir-file@v1";
4
+ /**
5
+ * Regex-based Elixir extractor.
6
+ *
7
+ * Top-level constructs only (column-0):
8
+ * - `defmodule Path.To.Mod do` → module
9
+ * - `def name(...)` → function (exported)
10
+ * - `defp name(...)` → function (local)
11
+ * - `defstruct …` and `defprotocol` / `defimpl` headers → struct / protocol
12
+ *
13
+ * Nested `def`s under a `defmodule` show up at column 0 in this
14
+ * extractor's view; that's intentional because they're the publicly
15
+ * callable functions on that module.
16
+ *
17
+ * Imports: `alias Foo.Bar`, `alias Foo.{A, B}`, `import Enum`,
18
+ * `require Logger`, `use MyAppWeb, :controller`. Aliases inside
19
+ * `{...}` are expanded.
20
+ *
21
+ * Out of scope:
22
+ * - Pipe operator chains.
23
+ * - Macro definitions (`defmacro`/`defmacrop`).
24
+ * - Inline guard clauses (`when ...`).
25
+ */
26
+ export declare function extractElixirFile(fingerprint: IFileFingerprint, absPath: string, content?: string): IExtractedFile;
27
+ //# sourceMappingURL=extract-elixir-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-elixir-file.d.ts","sourceRoot":"","sources":["../../src/indexer/extract-elixir-file.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,CAiDhB"}