@opensip-cli/graph-java 0.1.0

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 (76) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/cache-key.test.d.ts +5 -0
  5. package/dist/__tests__/cache-key.test.d.ts.map +1 -0
  6. package/dist/__tests__/cache-key.test.js +45 -0
  7. package/dist/__tests__/cache-key.test.js.map +1 -0
  8. package/dist/__tests__/coverage-edges.test.d.ts +19 -0
  9. package/dist/__tests__/coverage-edges.test.d.ts.map +1 -0
  10. package/dist/__tests__/coverage-edges.test.js +254 -0
  11. package/dist/__tests__/coverage-edges.test.js.map +1 -0
  12. package/dist/__tests__/depends-on-emission.test.d.ts +15 -0
  13. package/dist/__tests__/depends-on-emission.test.d.ts.map +1 -0
  14. package/dist/__tests__/depends-on-emission.test.js +229 -0
  15. package/dist/__tests__/depends-on-emission.test.js.map +1 -0
  16. package/dist/__tests__/discover.test.d.ts +5 -0
  17. package/dist/__tests__/discover.test.d.ts.map +1 -0
  18. package/dist/__tests__/discover.test.js +68 -0
  19. package/dist/__tests__/discover.test.js.map +1 -0
  20. package/dist/__tests__/parse.test.d.ts +5 -0
  21. package/dist/__tests__/parse.test.d.ts.map +1 -0
  22. package/dist/__tests__/parse.test.js +59 -0
  23. package/dist/__tests__/parse.test.js.map +1 -0
  24. package/dist/__tests__/resolve.test.d.ts +17 -0
  25. package/dist/__tests__/resolve.test.d.ts.map +1 -0
  26. package/dist/__tests__/resolve.test.js +201 -0
  27. package/dist/__tests__/resolve.test.js.map +1 -0
  28. package/dist/__tests__/walk.test.d.ts +11 -0
  29. package/dist/__tests__/walk.test.d.ts.map +1 -0
  30. package/dist/__tests__/walk.test.js +227 -0
  31. package/dist/__tests__/walk.test.js.map +1 -0
  32. package/dist/body-digest.d.ts +19 -0
  33. package/dist/body-digest.d.ts.map +1 -0
  34. package/dist/body-digest.js +140 -0
  35. package/dist/body-digest.js.map +1 -0
  36. package/dist/cache-key.d.ts +19 -0
  37. package/dist/cache-key.d.ts.map +1 -0
  38. package/dist/cache-key.js +20 -0
  39. package/dist/cache-key.js.map +1 -0
  40. package/dist/discover.d.ts +28 -0
  41. package/dist/discover.d.ts.map +1 -0
  42. package/dist/discover.js +50 -0
  43. package/dist/discover.js.map +1 -0
  44. package/dist/index.d.ts +43 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +46 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/parse.d.ts +17 -0
  49. package/dist/parse.d.ts.map +1 -0
  50. package/dist/parse.js +14 -0
  51. package/dist/parse.js.map +1 -0
  52. package/dist/resolve-dependencies.d.ts +38 -0
  53. package/dist/resolve-dependencies.d.ts.map +1 -0
  54. package/dist/resolve-dependencies.js +203 -0
  55. package/dist/resolve-dependencies.js.map +1 -0
  56. package/dist/resolve.d.ts +32 -0
  57. package/dist/resolve.d.ts.map +1 -0
  58. package/dist/resolve.js +145 -0
  59. package/dist/resolve.js.map +1 -0
  60. package/dist/rule-hints.d.ts +13 -0
  61. package/dist/rule-hints.d.ts.map +1 -0
  62. package/dist/rule-hints.js +50 -0
  63. package/dist/rule-hints.js.map +1 -0
  64. package/dist/walk-dependencies.d.ts +25 -0
  65. package/dist/walk-dependencies.d.ts.map +1 -0
  66. package/dist/walk-dependencies.js +68 -0
  67. package/dist/walk-dependencies.js.map +1 -0
  68. package/dist/walk-metadata.d.ts +26 -0
  69. package/dist/walk-metadata.d.ts.map +1 -0
  70. package/dist/walk-metadata.js +134 -0
  71. package/dist/walk-metadata.js.map +1 -0
  72. package/dist/walk.d.ts +59 -0
  73. package/dist/walk.d.ts.map +1 -0
  74. package/dist/walk.js +244 -0
  75. package/dist/walk.js.map +1 -0
  76. package/package.json +54 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Tests for the Java adapter's module-level depends_on edge emission.
3
+ * Phase 4 Task 4.6 of opensip's substrate consolidation (opensip DEC-498).
4
+ *
5
+ * Exercises the full adapter contract surface (discoverFiles →
6
+ * parseProject → walkProject → resolveCallSites) against small fixtures
7
+ * covering the Java `import`-declaration matrix: type imports, wildcard
8
+ * imports, static type imports, static wildcard imports, inner-class
9
+ * fallback, stdlib + Jakarta paths, external third-party paths, and
10
+ * Maven (`src/main/java/`) vs plain (project-root) source layouts.
11
+ *
12
+ * Mirrors the Rust adapter's Task 4.5 test layout.
13
+ */
14
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
15
+ import { tmpdir } from 'node:os';
16
+ import { join } from 'node:path';
17
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
18
+ import { javaGraphAdapter } from '../index.js';
19
+ let fixtureRoot;
20
+ beforeEach(() => {
21
+ fixtureRoot = mkdtempSync(join(tmpdir(), 'graph-java-depends-on-'));
22
+ });
23
+ afterEach(() => {
24
+ rmSync(fixtureRoot, { recursive: true, force: true });
25
+ });
26
+ function writeFile(rel, content) {
27
+ const abs = join(fixtureRoot, rel);
28
+ mkdirSync(join(abs, '..'), { recursive: true });
29
+ writeFileSync(abs, content, 'utf8');
30
+ }
31
+ function findModuleInit(catalog, filePath) {
32
+ for (const occs of Object.values(catalog.functions)) {
33
+ for (const o of occs) {
34
+ if (o.kind === 'module-init' && o.filePath === filePath)
35
+ return o;
36
+ }
37
+ }
38
+ return undefined;
39
+ }
40
+ function runAdapter() {
41
+ const discovery = javaGraphAdapter.discoverFiles({ cwd: fixtureRoot });
42
+ const parsed = javaGraphAdapter.parseProject({
43
+ projectDirAbs: discovery.projectDirAbs,
44
+ files: discovery.files,
45
+ compilerOptions: discovery.compilerOptions,
46
+ resolutionMode: 'exact',
47
+ });
48
+ const walked = javaGraphAdapter.walkProject({
49
+ project: parsed.project,
50
+ projectDirAbs: discovery.projectDirAbs,
51
+ files: discovery.files,
52
+ });
53
+ const initialCatalog = {
54
+ version: '3.0',
55
+ tool: 'graph',
56
+ language: 'java',
57
+ builtAt: new Date().toISOString(),
58
+ cacheKey: 'test',
59
+ functions: walked.occurrences,
60
+ };
61
+ const resolved = javaGraphAdapter.resolveCallSites({
62
+ project: parsed.project,
63
+ catalog: initialCatalog,
64
+ callSites: walked.callSites,
65
+ dependencySites: walked.dependencySites,
66
+ projectDirAbs: discovery.projectDirAbs,
67
+ resolutionMode: 'exact',
68
+ });
69
+ return { catalog: initialCatalog, dependenciesByOwner: resolved.dependenciesByOwner };
70
+ }
71
+ describe('Java adapter — depends_on emission (Phase 4)', () => {
72
+ it('resolves a plain type import to the target module-init (plain layout)', () => {
73
+ writeFile('com/example/Main.java', `package com.example;\n\nimport com.example.foo.Bar;\n\nclass Main { void run(Bar b) {} }\n`);
74
+ writeFile('com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar {}\n`);
75
+ const { catalog, dependenciesByOwner } = runAdapter();
76
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
77
+ const barInit = findModuleInit(catalog, 'com/example/foo/Bar.java');
78
+ expect(mainInit, 'main module-init').toBeDefined();
79
+ expect(barInit, 'bar module-init').toBeDefined();
80
+ expect(dependenciesByOwner, 'dependenciesByOwner').toBeDefined();
81
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
82
+ expect(deps, 'main has dependency edges').toHaveLength(1);
83
+ expect(deps[0].specifier).toBe('com.example.foo.Bar');
84
+ expect(deps[0].to).toEqual([barInit.bodyHash]);
85
+ });
86
+ it('resolves a wildcard import to every module-init in the package (polymorphic)', () => {
87
+ writeFile('com/example/Main.java', `package com.example;\n\nimport com.example.foo.*;\n\nclass Main {}\n`);
88
+ writeFile('com/example/foo/A.java', `package com.example.foo;\n\npublic class A {}\n`);
89
+ writeFile('com/example/foo/B.java', `package com.example.foo;\n\npublic class B {}\n`);
90
+ const { catalog, dependenciesByOwner } = runAdapter();
91
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
92
+ const aInit = findModuleInit(catalog, 'com/example/foo/A.java');
93
+ const bInit = findModuleInit(catalog, 'com/example/foo/B.java');
94
+ expect(mainInit).toBeDefined();
95
+ expect(aInit).toBeDefined();
96
+ expect(bInit).toBeDefined();
97
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
98
+ expect(deps).toHaveLength(1);
99
+ expect(deps[0].specifier).toBe('com.example.foo.*');
100
+ expect([...deps[0].to].sort()).toEqual([aInit.bodyHash, bInit.bodyHash].sort());
101
+ });
102
+ it('resolves an inner-class import via fall-back to the outer class', () => {
103
+ // `Outer.Inner` is not in the catalog as a file; we fall back to
104
+ // `Outer` (which IS a file).
105
+ writeFile('com/example/Main.java', `package com.example;\n\nimport com.example.foo.Outer.Inner;\n\nclass Main {}\n`);
106
+ writeFile('com/example/foo/Outer.java', `package com.example.foo;\n\npublic class Outer { public static class Inner {} }\n`);
107
+ const { catalog, dependenciesByOwner } = runAdapter();
108
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
109
+ const outerInit = findModuleInit(catalog, 'com/example/foo/Outer.java');
110
+ expect(mainInit).toBeDefined();
111
+ expect(outerInit).toBeDefined();
112
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
113
+ expect(deps).toHaveLength(1);
114
+ expect(deps[0].specifier).toBe('com.example.foo.Outer.Inner');
115
+ expect(deps[0].to).toEqual([outerInit.bodyHash]);
116
+ });
117
+ it('resolves a static type import to the owning class module-init', () => {
118
+ writeFile('com/example/Main.java', `package com.example;\n\nimport static com.example.foo.Bar.someMethod;\n\nclass Main {}\n`);
119
+ writeFile('com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar { public static void someMethod() {} }\n`);
120
+ const { catalog, dependenciesByOwner } = runAdapter();
121
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
122
+ const barInit = findModuleInit(catalog, 'com/example/foo/Bar.java');
123
+ expect(mainInit).toBeDefined();
124
+ expect(barInit).toBeDefined();
125
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
126
+ expect(deps).toHaveLength(1);
127
+ expect(deps[0].specifier).toBe('static com.example.foo.Bar.someMethod');
128
+ expect(deps[0].to).toEqual([barInit.bodyHash]);
129
+ });
130
+ it('resolves a static wildcard import to the owning class module-init', () => {
131
+ writeFile('com/example/Main.java', `package com.example;\n\nimport static com.example.foo.Bar.*;\n\nclass Main {}\n`);
132
+ writeFile('com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar { public static void a() {} public static int b = 1; }\n`);
133
+ const { catalog, dependenciesByOwner } = runAdapter();
134
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
135
+ const barInit = findModuleInit(catalog, 'com/example/foo/Bar.java');
136
+ expect(mainInit).toBeDefined();
137
+ expect(barInit).toBeDefined();
138
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
139
+ expect(deps).toHaveLength(1);
140
+ expect(deps[0].specifier).toBe('static com.example.foo.Bar.*');
141
+ expect(deps[0].to).toEqual([barInit.bodyHash]);
142
+ });
143
+ it('emits unresolved edges for stdlib (`java.*`) imports', () => {
144
+ writeFile('com/example/Main.java', `package com.example;\n\nimport java.util.List;\n\nclass Main {}\n`);
145
+ const { catalog, dependenciesByOwner } = runAdapter();
146
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
147
+ expect(mainInit).toBeDefined();
148
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
149
+ expect(deps).toHaveLength(1);
150
+ expect(deps[0].specifier).toBe('java.util.List');
151
+ expect(deps[0].to).toEqual([]);
152
+ });
153
+ it('emits unresolved edges for `javax.*` / `jakarta.*` imports', () => {
154
+ writeFile('com/example/Main.java', `package com.example;\n\nimport javax.servlet.HttpServletRequest;\nimport jakarta.inject.Inject;\n\nclass Main {}\n`);
155
+ const { catalog, dependenciesByOwner } = runAdapter();
156
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
157
+ expect(mainInit).toBeDefined();
158
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
159
+ expect(deps).toHaveLength(2);
160
+ const specifiers = deps.map((d) => d.specifier).sort();
161
+ expect(specifiers).toEqual(['jakarta.inject.Inject', 'javax.servlet.HttpServletRequest']);
162
+ for (const d of deps) {
163
+ expect(d.to).toEqual([]);
164
+ }
165
+ });
166
+ it('emits unresolved edges for external third-party imports', () => {
167
+ writeFile('com/example/Main.java', `package com.example;\n\nimport com.google.gson.Gson;\n\nclass Main {}\n`);
168
+ const { catalog, dependenciesByOwner } = runAdapter();
169
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
170
+ expect(mainInit).toBeDefined();
171
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
172
+ expect(deps).toHaveLength(1);
173
+ expect(deps[0].specifier).toBe('com.google.gson.Gson');
174
+ expect(deps[0].to).toEqual([]);
175
+ });
176
+ it('emits one dep site per import statement when a file has many imports', () => {
177
+ writeFile('com/example/Main.java', `package com.example;\n\nimport com.example.foo.Bar;\nimport java.util.List;\nimport com.example.foo.Baz;\n\nclass Main {}\n`);
178
+ writeFile('com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar {}\n`);
179
+ writeFile('com/example/foo/Baz.java', `package com.example.foo;\n\npublic class Baz {}\n`);
180
+ const { catalog, dependenciesByOwner } = runAdapter();
181
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
182
+ const barInit = findModuleInit(catalog, 'com/example/foo/Bar.java');
183
+ const bazInit = findModuleInit(catalog, 'com/example/foo/Baz.java');
184
+ expect(mainInit).toBeDefined();
185
+ expect(barInit).toBeDefined();
186
+ expect(bazInit).toBeDefined();
187
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
188
+ expect(deps).toHaveLength(3);
189
+ const bySpec = new Map(deps.map((d) => [d.specifier, d]));
190
+ expect(bySpec.get('com.example.foo.Bar').to).toEqual([barInit.bodyHash]);
191
+ expect(bySpec.get('java.util.List').to).toEqual([]);
192
+ expect(bySpec.get('com.example.foo.Baz').to).toEqual([bazInit.bodyHash]);
193
+ });
194
+ it('produces no dependency edges for a file with no explicit imports', () => {
195
+ writeFile('com/example/Main.java', `package com.example;\n\nclass Main { int answer() { return 42; } }\n`);
196
+ const { catalog, dependenciesByOwner } = runAdapter();
197
+ const mainInit = findModuleInit(catalog, 'com/example/Main.java');
198
+ expect(mainInit).toBeDefined();
199
+ const deps = dependenciesByOwner?.get(mainInit.bodyHash);
200
+ expect(deps).toBeUndefined();
201
+ });
202
+ it('resolves imports under the Maven `src/main/java/` source root', () => {
203
+ writeFile('src/main/java/com/example/Main.java', `package com.example;\n\nimport com.example.foo.Bar;\n\nclass Main { void run(Bar b) {} }\n`);
204
+ writeFile('src/main/java/com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar {}\n`);
205
+ const { catalog, dependenciesByOwner } = runAdapter();
206
+ const mainInit = findModuleInit(catalog, 'src/main/java/com/example/Main.java');
207
+ const barInit = findModuleInit(catalog, 'src/main/java/com/example/foo/Bar.java');
208
+ expect(mainInit, 'main module-init').toBeDefined();
209
+ expect(barInit, 'bar module-init').toBeDefined();
210
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
211
+ expect(deps).toHaveLength(1);
212
+ expect(deps[0].specifier).toBe('com.example.foo.Bar');
213
+ expect(deps[0].to).toEqual([barInit.bodyHash]);
214
+ });
215
+ it('resolves imports under the plain `src/` source root', () => {
216
+ writeFile('src/com/example/Main.java', `package com.example;\n\nimport com.example.foo.Bar;\n\nclass Main {}\n`);
217
+ writeFile('src/com/example/foo/Bar.java', `package com.example.foo;\n\npublic class Bar {}\n`);
218
+ const { catalog, dependenciesByOwner } = runAdapter();
219
+ const mainInit = findModuleInit(catalog, 'src/com/example/Main.java');
220
+ const barInit = findModuleInit(catalog, 'src/com/example/foo/Bar.java');
221
+ expect(mainInit).toBeDefined();
222
+ expect(barInit).toBeDefined();
223
+ const deps = dependenciesByOwner.get(mainInit.bodyHash);
224
+ expect(deps).toHaveLength(1);
225
+ expect(deps[0].specifier).toBe('com.example.foo.Bar');
226
+ expect(deps[0].to).toEqual([barInit.bodyHash]);
227
+ });
228
+ });
229
+ //# sourceMappingURL=depends-on-emission.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"depends-on-emission.test.js","sourceRoot":"","sources":["../../src/__tests__/depends-on-emission.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/discover.ts.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=discover.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/discover.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/discover.ts.
3
+ */
4
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
8
+ import { discoverFiles } from '../discover.js';
9
+ describe('graph-java discover.ts — branches', () => {
10
+ let dir;
11
+ beforeEach(() => {
12
+ dir = mkdtempSync(join(tmpdir(), 'graph-java-discover-'));
13
+ });
14
+ afterEach(() => {
15
+ rmSync(dir, { recursive: true, force: true });
16
+ });
17
+ it('returns undefined configPathAbs when no build file exists', () => {
18
+ const out = discoverFiles({ cwd: dir });
19
+ expect(out.configPathAbs).toBeUndefined();
20
+ expect(out.files).toEqual([]);
21
+ });
22
+ it('uses gradle.lockfile when present (highest precedence)', () => {
23
+ writeFileSync(join(dir, 'gradle.lockfile'), '# locked\n', 'utf8');
24
+ writeFileSync(join(dir, 'pom.xml'), '<project/>\n', 'utf8');
25
+ const out = discoverFiles({ cwd: dir });
26
+ expect(out.configPathAbs).toContain('gradle.lockfile');
27
+ });
28
+ it('falls back to pom.xml when no gradle lockfile', () => {
29
+ writeFileSync(join(dir, 'pom.xml'), '<project/>\n', 'utf8');
30
+ const out = discoverFiles({ cwd: dir });
31
+ expect(out.configPathAbs).toContain('pom.xml');
32
+ });
33
+ it('falls back to build.gradle.kts when no Maven file', () => {
34
+ writeFileSync(join(dir, 'build.gradle.kts'), '// gradle\n', 'utf8');
35
+ const out = discoverFiles({ cwd: dir });
36
+ expect(out.configPathAbs).toContain('build.gradle.kts');
37
+ });
38
+ it('falls back to build.gradle (Groovy DSL) last', () => {
39
+ writeFileSync(join(dir, 'build.gradle'), '// groovy\n', 'utf8');
40
+ const out = discoverFiles({ cwd: dir });
41
+ expect(out.configPathAbs).toContain('build.gradle');
42
+ });
43
+ it('honors a configPathOverride that exists', () => {
44
+ const override = join(dir, 'custom.xml');
45
+ writeFileSync(override, '<project/>\n', 'utf8');
46
+ const out = discoverFiles({ cwd: dir, configPathOverride: 'custom.xml' });
47
+ expect(out.configPathAbs).toContain('custom.xml');
48
+ });
49
+ it('returns the override path verbatim when the override does not exist', () => {
50
+ const out = discoverFiles({ cwd: dir, configPathOverride: 'nonexistent.xml' });
51
+ expect(out.configPathAbs).toContain('nonexistent.xml');
52
+ });
53
+ it('collects .java files (sorted, dedup) and excludes target/ and build/', () => {
54
+ mkdirSync(join(dir, 'src/main/java'), { recursive: true });
55
+ writeFileSync(join(dir, 'src/main/java/A.java'), 'class A {}\n', 'utf8');
56
+ writeFileSync(join(dir, 'src/main/java/B.java'), 'class B {}\n', 'utf8');
57
+ mkdirSync(join(dir, 'target/classes'), { recursive: true });
58
+ writeFileSync(join(dir, 'target/classes/Stale.java'), 'class Stale {}\n', 'utf8');
59
+ mkdirSync(join(dir, 'build/generated'), { recursive: true });
60
+ writeFileSync(join(dir, 'build/generated/Gen.java'), 'class Gen {}\n', 'utf8');
61
+ const out = discoverFiles({ cwd: dir });
62
+ expect(out.files.length).toBe(2);
63
+ expect(out.files.every((f) => !f.includes('/target/'))).toBe(true);
64
+ expect(out.files.every((f) => !f.includes('/build/'))).toBe(true);
65
+ expect([...out.files]).toEqual([...out.files].sort());
66
+ });
67
+ });
68
+ //# sourceMappingURL=discover.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.test.js","sourceRoot":"","sources":["../../src/__tests__/discover.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/parse.ts.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=parse.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/parse.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/parse.ts.
3
+ */
4
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
8
+ import { parseProject } from '../parse.js';
9
+ describe('graph-java parse.ts — branches', () => {
10
+ let dir;
11
+ beforeEach(() => {
12
+ dir = mkdtempSync(join(tmpdir(), 'graph-java-parse-'));
13
+ });
14
+ afterEach(() => {
15
+ rmSync(dir, { recursive: true, force: true });
16
+ });
17
+ it('returns no parseErrors for a syntactically valid file', () => {
18
+ const file = join(dir, 'A.java');
19
+ writeFileSync(file, 'class A { void m() { int x = 1; } }\n', 'utf8');
20
+ const out = parseProject({ projectDirAbs: dir, files: [file], resolutionMode: 'exact' });
21
+ expect(out.parseErrors).toEqual([]);
22
+ expect(out.project.files.size).toBe(1);
23
+ });
24
+ it('records a parseError when tree-sitter reports rootNode.hasError', () => {
25
+ const file = join(dir, 'Broken.java');
26
+ // Unterminated method body — tree-sitter still produces a partial tree.
27
+ writeFileSync(file, 'class Broken { void m() { int x = \n', 'utf8');
28
+ const out = parseProject({ projectDirAbs: dir, files: [file], resolutionMode: 'exact' });
29
+ expect(out.parseErrors.length).toBeGreaterThan(0);
30
+ expect(out.parseErrors[0]?.message).toContain('tree-sitter');
31
+ expect(out.project.files.size).toBe(1);
32
+ });
33
+ it('processes multiple files independently', () => {
34
+ const a = join(dir, 'A.java');
35
+ const b = join(dir, 'B.java');
36
+ writeFileSync(a, 'class A { void ok() {} }\n', 'utf8');
37
+ writeFileSync(b, 'class B { void broken() { int x = \n', 'utf8');
38
+ const out = parseProject({ projectDirAbs: dir, files: [a, b], resolutionMode: 'exact' });
39
+ expect(out.project.files.size).toBe(2);
40
+ expect(out.parseErrors.length).toBeGreaterThan(0);
41
+ });
42
+ it('parses Java source with line/block/Javadoc comments and string literals', () => {
43
+ const file = join(dir, 'Comments.java');
44
+ writeFileSync(file, `// line comment\n` +
45
+ `/* block comment */\n` +
46
+ `/** Javadoc */\n` +
47
+ `class Comments {\n` +
48
+ ` /** method Javadoc */\n` +
49
+ ' String m() {\n' +
50
+ ' String s = "a /* fake comment */ inside";\n' +
51
+ ' String t = """\n multi-line text block\n """;\n' +
52
+ ' return s + t;\n' +
53
+ ` }\n` +
54
+ `}\n`, 'utf8');
55
+ const out = parseProject({ projectDirAbs: dir, files: [file], resolutionMode: 'exact' });
56
+ expect(out.parseErrors).toEqual([]);
57
+ });
58
+ });
59
+ //# sourceMappingURL=parse.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.js","sourceRoot":"","sources":["../../src/__tests__/parse.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/resolve.ts.
3
+ *
4
+ * Drives the full Java adapter (discover + parse + walk + resolve)
5
+ * over fixtures exercising:
6
+ * - `method_invocation` (`foo()`, `obj.foo()`, `this.foo()`,
7
+ * `super.foo()`, `Class.foo()`)
8
+ * - `object_creation_expression` (`new Foo()`) and constructor lookup
9
+ * - `explicit_constructor_invocation` (`super(...)`, `this(...)`) ─
10
+ * resolved as unresolved (`to: []`)
11
+ * - Confidence ladder: 0 matches → unknown/low; 1 → static/medium;
12
+ * N matches → method-dispatch/low
13
+ * - `creation` edges from lambdas flowing through the resolver
14
+ * - I-4: catalog is not mutated
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=resolve.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/resolve.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Branch-coverage tests for graph-java/resolve.ts.
3
+ *
4
+ * Drives the full Java adapter (discover + parse + walk + resolve)
5
+ * over fixtures exercising:
6
+ * - `method_invocation` (`foo()`, `obj.foo()`, `this.foo()`,
7
+ * `super.foo()`, `Class.foo()`)
8
+ * - `object_creation_expression` (`new Foo()`) and constructor lookup
9
+ * - `explicit_constructor_invocation` (`super(...)`, `this(...)`) ─
10
+ * resolved as unresolved (`to: []`)
11
+ * - Confidence ladder: 0 matches → unknown/low; 1 → static/medium;
12
+ * N matches → method-dispatch/low
13
+ * - `creation` edges from lambdas flowing through the resolver
14
+ * - I-4: catalog is not mutated
15
+ */
16
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { tmpdir } from 'node:os';
18
+ import { join } from 'node:path';
19
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
20
+ import { javaGraphAdapter } from '../index.js';
21
+ function pipeline(dir) {
22
+ const discovery = javaGraphAdapter.discoverFiles({ cwd: dir });
23
+ const parsed = javaGraphAdapter.parseProject({
24
+ projectDirAbs: discovery.projectDirAbs,
25
+ files: discovery.files,
26
+ compilerOptions: discovery.compilerOptions,
27
+ resolutionMode: 'exact',
28
+ });
29
+ const walk = javaGraphAdapter.walkProject({
30
+ project: parsed.project,
31
+ projectDirAbs: discovery.projectDirAbs,
32
+ files: discovery.files,
33
+ });
34
+ const catalog = {
35
+ version: '3.0',
36
+ tool: 'graph',
37
+ language: javaGraphAdapter.id,
38
+ builtAt: '2026-05-27T00:00:00.000Z',
39
+ cacheKey: javaGraphAdapter.cacheKey({
40
+ projectDirAbs: discovery.projectDirAbs,
41
+ configPathAbs: discovery.configPathAbs,
42
+ compilerOptions: discovery.compilerOptions,
43
+ resolutionMode: 'exact',
44
+ }),
45
+ functions: walk.occurrences,
46
+ };
47
+ const resolved = javaGraphAdapter.resolveCallSites({
48
+ project: parsed.project,
49
+ catalog,
50
+ callSites: walk.callSites,
51
+ projectDirAbs: discovery.projectDirAbs,
52
+ resolutionMode: 'exact',
53
+ });
54
+ return { project: parsed.project, walk, catalog, resolved };
55
+ }
56
+ function allEdges(resolved) {
57
+ const out = [];
58
+ for (const edges of resolved.edgesByOwner.values())
59
+ out.push(...edges);
60
+ return out;
61
+ }
62
+ describe('graph-java resolve.ts', () => {
63
+ let dir;
64
+ beforeEach(() => {
65
+ dir = mkdtempSync(join(tmpdir(), 'graph-java-resolve-'));
66
+ });
67
+ afterEach(() => {
68
+ rmSync(dir, { recursive: true, force: true });
69
+ });
70
+ it('resolves single-match method_invocation as static/medium', () => {
71
+ writeFileSync(join(dir, 'A.java'), `package x;\nclass A {\n void caller() { callee(); }\n void callee() {}\n}\n`, 'utf8');
72
+ const { resolved } = pipeline(dir);
73
+ const edges = allEdges(resolved);
74
+ const callEdge = edges.find((e) => e.text.startsWith('callee('));
75
+ expect(callEdge).toBeDefined();
76
+ expect(callEdge?.resolution).toBe('static');
77
+ expect(callEdge?.confidence).toBe('medium');
78
+ expect(callEdge?.to.length).toBe(1);
79
+ expect(resolved.stats.resolvedMedium).toBeGreaterThan(0);
80
+ });
81
+ it('resolves multi-match method_invocation as method-dispatch/low', () => {
82
+ writeFileSync(join(dir, 'M.java'), `package x;\nclass A { void run() {} }\nclass B { void run() {} }\nclass C { void caller(A a, B b) { a.run(); b.run(); } }\n`, 'utf8');
83
+ const { resolved } = pipeline(dir);
84
+ const edges = allEdges(resolved).filter((e) => e.text.includes('.run('));
85
+ expect(edges.length).toBeGreaterThan(0);
86
+ for (const e of edges) {
87
+ expect(e.resolution).toBe('method-dispatch');
88
+ expect(e.confidence).toBe('low');
89
+ expect(e.to.length).toBe(2);
90
+ }
91
+ expect(resolved.stats.resolvedLow).toBeGreaterThan(0);
92
+ });
93
+ it('reports unknown/low when no catalog entry matches the called name', () => {
94
+ writeFileSync(join(dir, 'U.java'), `package x;\nclass U { void caller() { unknownFunc(); } }\n`, 'utf8');
95
+ const { resolved } = pipeline(dir);
96
+ const edges = allEdges(resolved).filter((e) => e.text.startsWith('unknownFunc('));
97
+ expect(edges.length).toBe(1);
98
+ expect(edges[0]?.resolution).toBe('unknown');
99
+ expect(edges[0]?.confidence).toBe('low');
100
+ expect(edges[0]?.to).toEqual([]);
101
+ expect(resolved.stats.unresolved).toBeGreaterThan(0);
102
+ });
103
+ it('resolves object_creation_expression (new Foo()) against the constructor', () => {
104
+ writeFileSync(join(dir, 'N.java'), `package x;\nclass Foo { Foo() {} }\nclass User { void make() { Foo f = new Foo(); } }\n`, 'utf8');
105
+ const { resolved } = pipeline(dir);
106
+ const edges = allEdges(resolved).filter((e) => e.text.startsWith('new Foo'));
107
+ expect(edges.length).toBe(1);
108
+ // Constructor is catalogued under simpleName="Foo" so this should
109
+ // resolve to exactly one match (the ctor) → static/medium.
110
+ expect(edges[0]?.resolution).toBe('static');
111
+ expect(edges[0]?.to.length).toBe(1);
112
+ });
113
+ it('handles generic types in object_creation_expression (new Box<T>())', () => {
114
+ writeFileSync(join(dir, 'G.java'), `package x;\nclass Box<T> { Box() {} }\nclass User { void make() { Box<String> b = new Box<>(); } }\n`, 'utf8');
115
+ const { resolved } = pipeline(dir);
116
+ const edges = allEdges(resolved).filter((e) => e.text.startsWith('new Box'));
117
+ expect(edges.length).toBe(1);
118
+ expect(edges[0]?.resolution).toBe('static');
119
+ });
120
+ it('decodes scoped_type_identifier (new pkg.Foo())', () => {
121
+ writeFileSync(join(dir, 'S.java'), `package x;\nclass User { void make() { java.lang.Object o = new java.lang.Object(); } }\n`, 'utf8');
122
+ const { resolved } = pipeline(dir);
123
+ const edges = allEdges(resolved).filter((e) => e.text.startsWith('new java.lang.Object'));
124
+ expect(edges.length).toBe(1);
125
+ // No catalog entry named "Object" exists in this fixture → unknown.
126
+ expect(edges[0]?.resolution).toBe('unknown');
127
+ expect(edges[0]?.to).toEqual([]);
128
+ });
129
+ it('records explicit_constructor_invocation as unresolved (target null)', () => {
130
+ writeFileSync(join(dir, 'Sub.java'), `package x;\nclass Base { Base(int n) {} }\nclass Sub extends Base {\n Sub() { super(1); }\n Sub(int n) { this(); }\n}\n`, 'utf8');
131
+ const { resolved } = pipeline(dir);
132
+ const edges = allEdges(resolved);
133
+ const explicits = edges.filter((e) => e.text.startsWith('super(') || e.text.startsWith('this('));
134
+ expect(explicits.length).toBeGreaterThanOrEqual(2);
135
+ for (const e of explicits) {
136
+ expect(e.resolution).toBe('unknown');
137
+ expect(e.to).toEqual([]);
138
+ }
139
+ });
140
+ it('emits a creation edge (static/high) for lambdas', () => {
141
+ writeFileSync(join(dir, 'L.java'), `package x;\nimport java.util.function.IntUnaryOperator;\nclass L { static IntUnaryOperator make() { IntUnaryOperator inc = n -> n + 1; return inc; } }\n`, 'utf8');
142
+ const { resolved } = pipeline(dir);
143
+ const edges = allEdges(resolved);
144
+ const creationEdges = edges.filter((e) => e.resolution === 'static' && e.confidence === 'high');
145
+ expect(creationEdges.length).toBeGreaterThan(0);
146
+ expect(resolved.stats.resolvedHigh).toBeGreaterThan(0);
147
+ });
148
+ it('marks call edges as discarded when in expression_statement context', () => {
149
+ writeFileSync(join(dir, 'D.java'), `package x;\nclass D {\n void caller() { sideEffect(); }\n void sideEffect() {}\n int useResult() { int x = compute(); return x; }\n int compute() { return 1; }\n}\n`, 'utf8');
150
+ const { resolved } = pipeline(dir);
151
+ const edges = allEdges(resolved);
152
+ const sideEffect = edges.find((e) => e.text.startsWith('sideEffect('));
153
+ const compute = edges.find((e) => e.text.startsWith('compute('));
154
+ expect(sideEffect?.discarded).toBe(true);
155
+ // `int x = compute()` is part of a local variable declaration, NOT
156
+ // an expression statement → not discarded.
157
+ expect(compute?.discarded).toBe(false);
158
+ });
159
+ it('treats parenthesized_expression transparently when checking discard', () => {
160
+ writeFileSync(join(dir, 'P.java'), `package x;\nclass P {\n void caller() { (compute()); }\n int compute() { return 1; }\n}\n`, 'utf8');
161
+ const { resolved } = pipeline(dir);
162
+ const edges = allEdges(resolved);
163
+ const compute = edges.find((e) => e.text.startsWith('compute('));
164
+ expect(compute).toBeDefined();
165
+ // Wrapped in parens but still at expression_statement root → discarded.
166
+ expect(compute?.discarded).toBe(true);
167
+ });
168
+ it('I-4 — resolveCallSites does not mutate the input catalog', () => {
169
+ writeFileSync(join(dir, 'A.java'), `package x;\nclass A { void m() { n(); } void n() {} }\n`, 'utf8');
170
+ const { catalog, walk, project } = pipeline(dir);
171
+ const before = JSON.stringify(catalog);
172
+ javaGraphAdapter.resolveCallSites({
173
+ project,
174
+ catalog,
175
+ callSites: walk.callSites,
176
+ projectDirAbs: dir,
177
+ resolutionMode: 'exact',
178
+ });
179
+ expect(JSON.stringify(catalog)).toBe(before);
180
+ });
181
+ it('skips synthetic <module-init> entries from the byName index', () => {
182
+ // Two files each contribute a `<module-init>` entry but its name
183
+ // starts with `<` and must be excluded from the name index.
184
+ writeFileSync(join(dir, 'A.java'), `package x;\nclass A { void m() {} }\n`, 'utf8');
185
+ writeFileSync(join(dir, 'B.java'), `package x;\nclass B { void m() {} }\n`, 'utf8');
186
+ const { resolved } = pipeline(dir);
187
+ // No call sites reference `<module-init>` (it's synthetic), so
188
+ // simply verify the resolver ran without producing any unexpected
189
+ // 'method-dispatch' edges for unrelated calls.
190
+ const edges = allEdges(resolved);
191
+ expect(edges.every((e) => !e.text.includes('<module-init>'))).toBe(true);
192
+ });
193
+ it('emits empty edge map when there are no call sites', () => {
194
+ writeFileSync(join(dir, 'Empty.java'), `package x;\nclass Empty {}\n`, 'utf8');
195
+ const { resolved } = pipeline(dir);
196
+ // module-init occurrence exists but no call-sites are emitted.
197
+ expect(resolved.stats.totalCallSites).toBe(0);
198
+ expect(resolved.edgesByOwner.size).toBe(0);
199
+ });
200
+ });
201
+ //# sourceMappingURL=resolve.test.js.map