@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.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/cache-key.test.d.ts +5 -0
- package/dist/__tests__/cache-key.test.d.ts.map +1 -0
- package/dist/__tests__/cache-key.test.js +45 -0
- package/dist/__tests__/cache-key.test.js.map +1 -0
- package/dist/__tests__/coverage-edges.test.d.ts +19 -0
- package/dist/__tests__/coverage-edges.test.d.ts.map +1 -0
- package/dist/__tests__/coverage-edges.test.js +254 -0
- package/dist/__tests__/coverage-edges.test.js.map +1 -0
- package/dist/__tests__/depends-on-emission.test.d.ts +15 -0
- package/dist/__tests__/depends-on-emission.test.d.ts.map +1 -0
- package/dist/__tests__/depends-on-emission.test.js +229 -0
- package/dist/__tests__/depends-on-emission.test.js.map +1 -0
- package/dist/__tests__/discover.test.d.ts +5 -0
- package/dist/__tests__/discover.test.d.ts.map +1 -0
- package/dist/__tests__/discover.test.js +68 -0
- package/dist/__tests__/discover.test.js.map +1 -0
- package/dist/__tests__/parse.test.d.ts +5 -0
- package/dist/__tests__/parse.test.d.ts.map +1 -0
- package/dist/__tests__/parse.test.js +59 -0
- package/dist/__tests__/parse.test.js.map +1 -0
- package/dist/__tests__/resolve.test.d.ts +17 -0
- package/dist/__tests__/resolve.test.d.ts.map +1 -0
- package/dist/__tests__/resolve.test.js +201 -0
- package/dist/__tests__/resolve.test.js.map +1 -0
- package/dist/__tests__/walk.test.d.ts +11 -0
- package/dist/__tests__/walk.test.d.ts.map +1 -0
- package/dist/__tests__/walk.test.js +227 -0
- package/dist/__tests__/walk.test.js.map +1 -0
- package/dist/body-digest.d.ts +19 -0
- package/dist/body-digest.d.ts.map +1 -0
- package/dist/body-digest.js +140 -0
- package/dist/body-digest.js.map +1 -0
- package/dist/cache-key.d.ts +19 -0
- package/dist/cache-key.d.ts.map +1 -0
- package/dist/cache-key.js +20 -0
- package/dist/cache-key.js.map +1 -0
- package/dist/discover.d.ts +28 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +50 -0
- package/dist/discover.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +17 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +14 -0
- package/dist/parse.js.map +1 -0
- package/dist/resolve-dependencies.d.ts +38 -0
- package/dist/resolve-dependencies.d.ts.map +1 -0
- package/dist/resolve-dependencies.js +203 -0
- package/dist/resolve-dependencies.js.map +1 -0
- package/dist/resolve.d.ts +32 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +145 -0
- package/dist/resolve.js.map +1 -0
- package/dist/rule-hints.d.ts +13 -0
- package/dist/rule-hints.d.ts.map +1 -0
- package/dist/rule-hints.js +50 -0
- package/dist/rule-hints.js.map +1 -0
- package/dist/walk-dependencies.d.ts +25 -0
- package/dist/walk-dependencies.d.ts.map +1 -0
- package/dist/walk-dependencies.js +68 -0
- package/dist/walk-dependencies.js.map +1 -0
- package/dist/walk-metadata.d.ts +26 -0
- package/dist/walk-metadata.d.ts.map +1 -0
- package/dist/walk-metadata.js +134 -0
- package/dist/walk-metadata.js.map +1 -0
- package/dist/walk.d.ts +59 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +244 -0
- package/dist/walk.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAK3D,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUsB,CAAC;AAEpD,iFAAiF;AACjF,OAAO,EAAE,gBAAgB,IAAI,OAAO,EAAE,CAAC;AACvC,eAAO,MAAM,QAAQ;;;;CAIX,CAAC;AAEX,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @opensip-cli/graph — Java language adapter.
|
|
3
|
+
*
|
|
4
|
+
* Sibling of graph-rust, graph-python, and graph-go. Backed by
|
|
5
|
+
* tree-sitter-java.
|
|
6
|
+
*
|
|
7
|
+
* Per-rule fidelity: same name-based resolution profile as the other
|
|
8
|
+
* tree-sitter adapters. Mostly `'medium'` for single-match identifiers;
|
|
9
|
+
* `'low'` for ambiguous matches. Receiver-type narrowing is NOT done
|
|
10
|
+
* because Java's `obj.method()` (instance call) and `Class.method()`
|
|
11
|
+
* (static call) are AST-indistinguishable without a type checker.
|
|
12
|
+
*
|
|
13
|
+
* File layout mirrors graph-go/:
|
|
14
|
+
* discoverFiles → ./discover.ts (Maven/Gradle build files + glob)
|
|
15
|
+
* parseProject → ./parse.ts
|
|
16
|
+
* walkProject → ./walk.ts
|
|
17
|
+
* resolveCallSites → ./resolve.ts
|
|
18
|
+
* cacheKey → ./cache-key.ts (`java-…`)
|
|
19
|
+
* ruleHints → ./rule-hints.ts
|
|
20
|
+
*/
|
|
21
|
+
import { cacheKey as javaCacheKey } from './cache-key.js';
|
|
22
|
+
import { discoverFiles as javaDiscoverFiles } from './discover.js';
|
|
23
|
+
import { parseProject as javaParseProject } from './parse.js';
|
|
24
|
+
import { resolveCallSites as javaResolveCallSites } from './resolve.js';
|
|
25
|
+
import { javaRuleHints } from './rule-hints.js';
|
|
26
|
+
import { walkProject as javaWalkProject } from './walk.js';
|
|
27
|
+
export const javaGraphAdapter = {
|
|
28
|
+
id: 'java',
|
|
29
|
+
fileExtensions: ['.java'],
|
|
30
|
+
displayName: 'Java',
|
|
31
|
+
discoverFiles: javaDiscoverFiles,
|
|
32
|
+
parseProject: javaParseProject,
|
|
33
|
+
walkProject: javaWalkProject,
|
|
34
|
+
resolveCallSites: javaResolveCallSites,
|
|
35
|
+
cacheKey: javaCacheKey,
|
|
36
|
+
ruleHints: javaRuleHints,
|
|
37
|
+
};
|
|
38
|
+
/** Plugin discovery contract: exported as `adapter` for runtime registration. */
|
|
39
|
+
export { javaGraphAdapter as adapter };
|
|
40
|
+
export const metadata = {
|
|
41
|
+
id: javaGraphAdapter.id,
|
|
42
|
+
displayName: javaGraphAdapter.displayName,
|
|
43
|
+
fileExtensions: javaGraphAdapter.fileExtensions,
|
|
44
|
+
};
|
|
45
|
+
export { javaRuleHints } from './rule-hints.js';
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAK3D,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,EAAE,EAAE,MAAM;IACV,cAAc,EAAE,CAAC,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM;IACnB,aAAa,EAAE,iBAAiB;IAChC,YAAY,EAAE,gBAAgB;IAC9B,WAAW,EAAE,eAAe;IAC5B,gBAAgB,EAAE,oBAAoB;IACtC,QAAQ,EAAE,YAAY;IACtB,SAAS,EAAE,aAAa;CACyB,CAAC;AAEpD,iFAAiF;AACjF,OAAO,EAAE,gBAAgB,IAAI,OAAO,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,gBAAgB,CAAC,EAAE;IACvB,WAAW,EAAE,gBAAgB,CAAC,WAAW;IACzC,cAAc,EAAE,gBAAgB,CAAC,cAAc;CACvC,CAAC;AAGX,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java parseProject — consumes `@opensip-cli/lang-java` (ADR-0010).
|
|
3
|
+
*
|
|
4
|
+
* `lang-java` is the canonical Java parse substrate: it owns the vendored
|
|
5
|
+
* tree-sitter-java grammar and produces the `{ tree, source }` parsed-file
|
|
6
|
+
* shape. The graph adapter no longer loads a grammar of its own; it binds the
|
|
7
|
+
* shared `createParseProjectFromAdapter` driver to `javaAdapter`. The
|
|
8
|
+
* parsed-project shape and the downstream walk/resolve are unchanged.
|
|
9
|
+
*/
|
|
10
|
+
import { type TreeSitterParsedFile, type TreeSitterParsedProject } from '@opensip-cli/graph-adapter-common';
|
|
11
|
+
/** Parsed Java source file: tree-sitter parse tree plus original source text. */
|
|
12
|
+
export type JavaParsedFile = TreeSitterParsedFile;
|
|
13
|
+
/** Parsed Java project: map of file path → {@link JavaParsedFile}. */
|
|
14
|
+
export type JavaParsedProject = TreeSitterParsedProject<JavaParsedFile>;
|
|
15
|
+
/** Parses every Java source file in the input set into a {@link JavaParsedProject}. */
|
|
16
|
+
export declare const parseProject: (input: import("@opensip-cli/graph").ParseInput) => import("@opensip-cli/graph").ParseOutput<TreeSitterParsedProject>;
|
|
17
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,mCAAmC,CAAC;AAG3C,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAElD,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,cAAc,CAAC,CAAC;AAExE,uFAAuF;AACvF,eAAO,MAAM,YAAY,uHAA6C,CAAC"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java parseProject — consumes `@opensip-cli/lang-java` (ADR-0010).
|
|
3
|
+
*
|
|
4
|
+
* `lang-java` is the canonical Java parse substrate: it owns the vendored
|
|
5
|
+
* tree-sitter-java grammar and produces the `{ tree, source }` parsed-file
|
|
6
|
+
* shape. The graph adapter no longer loads a grammar of its own; it binds the
|
|
7
|
+
* shared `createParseProjectFromAdapter` driver to `javaAdapter`. The
|
|
8
|
+
* parsed-project shape and the downstream walk/resolve are unchanged.
|
|
9
|
+
*/
|
|
10
|
+
import { createParseProjectFromAdapter, } from '@opensip-cli/graph-adapter-common';
|
|
11
|
+
import { javaAdapter } from '@opensip-cli/lang-java';
|
|
12
|
+
/** Parses every Java source file in the input set into a {@link JavaParsedProject}. */
|
|
13
|
+
export const parseProject = createParseProjectFromAdapter(javaAdapter);
|
|
14
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,6BAA6B,GAG9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQrD,uFAAuF;AACvF,MAAM,CAAC,MAAM,YAAY,GAAG,6BAA6B,CAAC,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Java import-specifier → dependency-edge resolution.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `resolve.ts` so the call-site resolver and dependency
|
|
5
|
+
* resolver each live in a focused module. This file owns the Java-
|
|
6
|
+
* specific FQN lookup logic (source-root prefix stripping, package vs.
|
|
7
|
+
* type indexing, stdlib short-circuit, static-import + wildcard handling).
|
|
8
|
+
*
|
|
9
|
+
* Phase 4 of opensip's substrate consolidation (DEC-498).
|
|
10
|
+
*/
|
|
11
|
+
import type { Catalog, DependencyEdge, DependencySiteRecord } from '@opensip-cli/graph';
|
|
12
|
+
/**
|
|
13
|
+
* Resolve each Java dependency site to one or more catalog bodyHashes.
|
|
14
|
+
*
|
|
15
|
+
* Strategy:
|
|
16
|
+
* 1. Build two FQN indexes from the catalog's module-init occurrences:
|
|
17
|
+
* - `type → bodyHash` (e.g. `com.example.Foo` → '<hash>')
|
|
18
|
+
* - `package → [bodyHash]` (e.g. `com.example` → ['<Foo-hash>', '<Bar-hash>'])
|
|
19
|
+
* Source roots are stripped from filePath in a fixed priority
|
|
20
|
+
* order, using the first prefix that strictly contains the file path.
|
|
21
|
+
* 2. For each site, classify the specifier and look up the target(s):
|
|
22
|
+
* - `<pkg>.*` → all types in package.
|
|
23
|
+
* - `static X.*` → that type's module-init.
|
|
24
|
+
* - `static X.m` → X's module-init (m is a member).
|
|
25
|
+
* - `X` or `X.Y` → direct type lookup with one-level outer-class fallback.
|
|
26
|
+
*
|
|
27
|
+
* Out of scope: non-default Gradle `sourceSets`, multi-module Maven
|
|
28
|
+
* layouts, and generated-source dirs (`target/generated-sources/...`).
|
|
29
|
+
* Files outside the four canonical roots fall back to project-root and
|
|
30
|
+
* may produce inflated FQNs that miss the lookup (those imports
|
|
31
|
+
* surface as `to: []`, which is the correct unresolved behavior).
|
|
32
|
+
*
|
|
33
|
+
* Stdlib classes (`java.*`, `javax.*`, `jakarta.*`) are treated as
|
|
34
|
+
* external — they're never in the project catalog so we short-circuit
|
|
35
|
+
* to `to: []` without attempting lookup.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveDependencies(sites: readonly DependencySiteRecord[], catalog: Catalog): ReadonlyMap<string, readonly DependencyEdge[]>;
|
|
38
|
+
//# sourceMappingURL=resolve-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-dependencies.d.ts","sourceRoot":"","sources":["../src/resolve-dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,oBAAoB,EAErB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,OAAO,EAAE,OAAO,GACf,WAAW,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC,CAoBhD"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Java import-specifier → dependency-edge resolution.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `resolve.ts` so the call-site resolver and dependency
|
|
5
|
+
* resolver each live in a focused module. This file owns the Java-
|
|
6
|
+
* specific FQN lookup logic (source-root prefix stripping, package vs.
|
|
7
|
+
* type indexing, stdlib short-circuit, static-import + wildcard handling).
|
|
8
|
+
*
|
|
9
|
+
* Phase 4 of opensip's substrate consolidation (DEC-498).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Resolve each Java dependency site to one or more catalog bodyHashes.
|
|
13
|
+
*
|
|
14
|
+
* Strategy:
|
|
15
|
+
* 1. Build two FQN indexes from the catalog's module-init occurrences:
|
|
16
|
+
* - `type → bodyHash` (e.g. `com.example.Foo` → '<hash>')
|
|
17
|
+
* - `package → [bodyHash]` (e.g. `com.example` → ['<Foo-hash>', '<Bar-hash>'])
|
|
18
|
+
* Source roots are stripped from filePath in a fixed priority
|
|
19
|
+
* order, using the first prefix that strictly contains the file path.
|
|
20
|
+
* 2. For each site, classify the specifier and look up the target(s):
|
|
21
|
+
* - `<pkg>.*` → all types in package.
|
|
22
|
+
* - `static X.*` → that type's module-init.
|
|
23
|
+
* - `static X.m` → X's module-init (m is a member).
|
|
24
|
+
* - `X` or `X.Y` → direct type lookup with one-level outer-class fallback.
|
|
25
|
+
*
|
|
26
|
+
* Out of scope: non-default Gradle `sourceSets`, multi-module Maven
|
|
27
|
+
* layouts, and generated-source dirs (`target/generated-sources/...`).
|
|
28
|
+
* Files outside the four canonical roots fall back to project-root and
|
|
29
|
+
* may produce inflated FQNs that miss the lookup (those imports
|
|
30
|
+
* surface as `to: []`, which is the correct unresolved behavior).
|
|
31
|
+
*
|
|
32
|
+
* Stdlib classes (`java.*`, `javax.*`, `jakarta.*`) are treated as
|
|
33
|
+
* external — they're never in the project catalog so we short-circuit
|
|
34
|
+
* to `to: []` without attempting lookup.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveDependencies(sites, catalog) {
|
|
37
|
+
const { typeFQN, packageFQN } = buildJavaFQNIndex(catalog);
|
|
38
|
+
const out = new Map();
|
|
39
|
+
for (const site of sites) {
|
|
40
|
+
const to = resolveJavaImportSpecifier(site.specifier, typeFQN, packageFQN);
|
|
41
|
+
const edge = {
|
|
42
|
+
to,
|
|
43
|
+
line: site.line,
|
|
44
|
+
column: site.column,
|
|
45
|
+
specifier: site.specifier,
|
|
46
|
+
};
|
|
47
|
+
const existing = out.get(site.ownerHash);
|
|
48
|
+
if (existing === undefined) {
|
|
49
|
+
out.set(site.ownerHash, [edge]);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
existing.push(edge);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/** The canonical source-root prefixes we recognize, in priority order.
|
|
58
|
+
* First strict-prefix match on a catalog file's filePath wins. */
|
|
59
|
+
const JAVA_SOURCE_ROOT_PREFIXES = ['src/main/java/', 'src/test/java/', 'src/'];
|
|
60
|
+
/**
|
|
61
|
+
* Build both FQN lookup maps from the catalog's module-init occurrences.
|
|
62
|
+
*
|
|
63
|
+
* For each module-init occurrence:
|
|
64
|
+
* 1. Strip a recognized source-root prefix (or `''` for project-root).
|
|
65
|
+
* 2. Strip the `.java` extension.
|
|
66
|
+
* 3. Slash-to-dot → that's the type FQN. The package is everything
|
|
67
|
+
* before the last dot.
|
|
68
|
+
*/
|
|
69
|
+
function buildJavaFQNIndex(catalog) {
|
|
70
|
+
const typeFQN = new Map();
|
|
71
|
+
const packageFQN = new Map();
|
|
72
|
+
for (const occs of Object.values(catalog.functions)) {
|
|
73
|
+
if (!occs)
|
|
74
|
+
continue;
|
|
75
|
+
for (const o of occs) {
|
|
76
|
+
indexModuleInitOccurrence(o, typeFQN, packageFQN);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { typeFQN, packageFQN };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Index a single catalog occurrence into the FQN maps. No-op for any
|
|
83
|
+
* occurrence that isn't a `module-init` or whose filePath doesn't
|
|
84
|
+
* resolve to a Java type FQN.
|
|
85
|
+
*/
|
|
86
|
+
function indexModuleInitOccurrence(o, typeFQN, packageFQN) {
|
|
87
|
+
if (o.kind !== 'module-init')
|
|
88
|
+
return;
|
|
89
|
+
const fqn = filePathToJavaTypeFQN(o.filePath);
|
|
90
|
+
if (fqn === null)
|
|
91
|
+
return;
|
|
92
|
+
typeFQN.set(fqn, o.bodyHash);
|
|
93
|
+
const lastDot = fqn.lastIndexOf('.');
|
|
94
|
+
const pkg = lastDot === -1 ? '' : fqn.slice(0, lastDot);
|
|
95
|
+
const bucket = packageFQN.get(pkg);
|
|
96
|
+
if (bucket === undefined)
|
|
97
|
+
packageFQN.set(pkg, [o.bodyHash]);
|
|
98
|
+
else
|
|
99
|
+
bucket.push(o.bodyHash);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Map a project-relative POSIX filePath to its Java type FQN. Returns
|
|
103
|
+
* `null` when the file doesn't end in `.java` (defensive — the discover
|
|
104
|
+
* pass should already filter by extension, but module-init occurrences
|
|
105
|
+
* could in principle carry any path).
|
|
106
|
+
*
|
|
107
|
+
* Examples:
|
|
108
|
+
* - `src/main/java/com/example/foo/Bar.java` → `com.example.foo.Bar`
|
|
109
|
+
* - `src/test/java/com/example/FooTest.java` → `com.example.FooTest`
|
|
110
|
+
* - `src/com/example/foo/Bar.java` → `com.example.foo.Bar`
|
|
111
|
+
* - `com/example/foo/Bar.java` → `com.example.foo.Bar`
|
|
112
|
+
* - `Bar.java` → `Bar` (default package)
|
|
113
|
+
*/
|
|
114
|
+
function filePathToJavaTypeFQN(filePath) {
|
|
115
|
+
if (!filePath.endsWith('.java')) /* v8 ignore next */
|
|
116
|
+
return null;
|
|
117
|
+
let stripped = filePath;
|
|
118
|
+
for (const prefix of JAVA_SOURCE_ROOT_PREFIXES) {
|
|
119
|
+
if (filePath.startsWith(prefix)) {
|
|
120
|
+
stripped = filePath.slice(prefix.length);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const noExt = stripped.slice(0, -'.java'.length);
|
|
125
|
+
return noExt.replaceAll('/', '.');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve one Java import-specifier string to its target module-init
|
|
129
|
+
* bodyHash(es).
|
|
130
|
+
*
|
|
131
|
+
* Stdlib short-circuit: `java.*`, `javax.*`, `jakarta.*` are never in
|
|
132
|
+
* the catalog. The `kotlin.*` and `scala.*` runtimes are similarly
|
|
133
|
+
* external for Java projects, but we don't special-case them — they
|
|
134
|
+
* fall through to the type-FQN lookup and miss naturally.
|
|
135
|
+
*
|
|
136
|
+
* Static imports always target a static MEMBER (method or field) of
|
|
137
|
+
* a class. The class's module-init occurrence is the dependency target,
|
|
138
|
+
* so we strip the trailing identifier before lookup. Static wildcards
|
|
139
|
+
* (`static com.foo.Bar.*`) target all static members of one class — same
|
|
140
|
+
* type lookup as plain static imports.
|
|
141
|
+
*/
|
|
142
|
+
function resolveJavaImportSpecifier(specifier, typeFQN, packageFQN) {
|
|
143
|
+
const { raw, isStatic } = parseStaticPrefix(specifier);
|
|
144
|
+
// Stdlib short-circuit. These never reside in a project catalog.
|
|
145
|
+
if (isJavaStdlibSpecifier(raw))
|
|
146
|
+
return [];
|
|
147
|
+
if (raw.endsWith('.*')) {
|
|
148
|
+
return resolveWildcardImport(raw.slice(0, -'.*'.length), isStatic, typeFQN, packageFQN);
|
|
149
|
+
}
|
|
150
|
+
return resolveSingleTargetImport(raw, isStatic, typeFQN);
|
|
151
|
+
}
|
|
152
|
+
/** Strip a leading `static ` keyword, returning the remainder and the flag. */
|
|
153
|
+
function parseStaticPrefix(specifier) {
|
|
154
|
+
if (specifier.startsWith('static ')) {
|
|
155
|
+
return { raw: specifier.slice('static '.length), isStatic: true };
|
|
156
|
+
}
|
|
157
|
+
return { raw: specifier, isStatic: false };
|
|
158
|
+
}
|
|
159
|
+
function isJavaStdlibSpecifier(raw) {
|
|
160
|
+
return raw.startsWith('java.') || raw.startsWith('javax.') || raw.startsWith('jakarta.');
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Wildcard imports come in two flavors:
|
|
164
|
+
* - `<pkg>.*` (non-static) → all types in the package.
|
|
165
|
+
* - `<type>.*` (static) → all static members of the type, which
|
|
166
|
+
* resolves to that type's module-init.
|
|
167
|
+
*/
|
|
168
|
+
function resolveWildcardImport(head, isStatic, typeFQN, packageFQN) {
|
|
169
|
+
if (isStatic) {
|
|
170
|
+
const hash = typeFQN.get(head);
|
|
171
|
+
return hash === undefined ? [] : [hash];
|
|
172
|
+
}
|
|
173
|
+
const bucket = packageFQN.get(head);
|
|
174
|
+
return bucket === undefined ? [] : [...bucket];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Non-wildcard imports target exactly one type's module-init.
|
|
178
|
+
*
|
|
179
|
+
* - Static (`static com.foo.Bar.method`) — strip the trailing member
|
|
180
|
+
* identifier; the remainder is the owning type's FQN.
|
|
181
|
+
* - Plain (`com.foo.Bar`) — direct FQN lookup, with a one-level
|
|
182
|
+
* inner-class fallback for `Outer.Inner`-shaped imports (a
|
|
183
|
+
* heuristic, since `Outer.Inner` and `package.Type` are
|
|
184
|
+
* structurally indistinguishable without declaring-file resolution).
|
|
185
|
+
*/
|
|
186
|
+
function resolveSingleTargetImport(raw, isStatic, typeFQN) {
|
|
187
|
+
if (isStatic) {
|
|
188
|
+
const lastDot = raw.lastIndexOf('.');
|
|
189
|
+
if (lastDot === -1)
|
|
190
|
+
return [];
|
|
191
|
+
const hash = typeFQN.get(raw.slice(0, lastDot));
|
|
192
|
+
return hash === undefined ? [] : [hash];
|
|
193
|
+
}
|
|
194
|
+
const direct = typeFQN.get(raw);
|
|
195
|
+
if (direct !== undefined)
|
|
196
|
+
return [direct];
|
|
197
|
+
const lastDot = raw.lastIndexOf('.');
|
|
198
|
+
if (lastDot === -1)
|
|
199
|
+
return [];
|
|
200
|
+
const outer = typeFQN.get(raw.slice(0, lastDot));
|
|
201
|
+
return outer === undefined ? [] : [outer];
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=resolve-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-dependencies.js","sourceRoot":"","sources":["../src/resolve-dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java resolveCallSites — name-based catalog lookup.
|
|
3
|
+
*
|
|
4
|
+
* Tree-sitter has no symbol table, so we resolve by simple name. For
|
|
5
|
+
* each call site:
|
|
6
|
+
*
|
|
7
|
+
* 1. Decode the called expression. Three node kinds surface as calls:
|
|
8
|
+
* - `method_invocation` — name from the `name` field.
|
|
9
|
+
* Covers `foo(...)`, `obj.foo(...)`, `Class.foo(...)`,
|
|
10
|
+
* `this.foo(...)`, `super.foo(...)` — all have the same shape.
|
|
11
|
+
* - `object_creation_expression` — `new Foo(...)`. The target
|
|
12
|
+
* is the type name (`Foo`), which matches the constructor's
|
|
13
|
+
* `simpleName` since constructors carry their class name.
|
|
14
|
+
* - `explicit_constructor_invocation` — `super(...)` or
|
|
15
|
+
* `this(...)` inside a constructor body. We map `super` →
|
|
16
|
+
* unresolved (parent type unknown without full lookup) and
|
|
17
|
+
* `this` → unresolved (we can't tell which sibling ctor without
|
|
18
|
+
* argument-arity matching, which is out of scope).
|
|
19
|
+
*
|
|
20
|
+
* 2. Look up matching catalog entries by simple name. Confidence
|
|
21
|
+
* ladder mirrors graph-python/graph-go:
|
|
22
|
+
* - 0 matches → `to: []`, resolution `'unknown'`, confidence `'low'`
|
|
23
|
+
* - 1 match → `to: [hash]`, resolution `'static'`, confidence `'medium'`
|
|
24
|
+
* - N matches → `to: [allHashes]`, resolution `'method-dispatch'`,
|
|
25
|
+
* confidence `'low'`
|
|
26
|
+
*
|
|
27
|
+
* Per I-4: this function does NOT mutate the input catalog.
|
|
28
|
+
*/
|
|
29
|
+
import type { JavaParsedProject } from './parse.js';
|
|
30
|
+
import type { ResolveInput, ResolveOutput } from '@opensip-cli/graph';
|
|
31
|
+
export declare function resolveCallSites(input: ResolveInput<JavaParsedProject>): ResolveOutput;
|
|
32
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAaH,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAIV,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAkB5B,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,CAAC,iBAAiB,CAAC,GAAG,aAAa,CAsCtF"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java resolveCallSites — name-based catalog lookup.
|
|
3
|
+
*
|
|
4
|
+
* Tree-sitter has no symbol table, so we resolve by simple name. For
|
|
5
|
+
* each call site:
|
|
6
|
+
*
|
|
7
|
+
* 1. Decode the called expression. Three node kinds surface as calls:
|
|
8
|
+
* - `method_invocation` — name from the `name` field.
|
|
9
|
+
* Covers `foo(...)`, `obj.foo(...)`, `Class.foo(...)`,
|
|
10
|
+
* `this.foo(...)`, `super.foo(...)` — all have the same shape.
|
|
11
|
+
* - `object_creation_expression` — `new Foo(...)`. The target
|
|
12
|
+
* is the type name (`Foo`), which matches the constructor's
|
|
13
|
+
* `simpleName` since constructors carry their class name.
|
|
14
|
+
* - `explicit_constructor_invocation` — `super(...)` or
|
|
15
|
+
* `this(...)` inside a constructor body. We map `super` →
|
|
16
|
+
* unresolved (parent type unknown without full lookup) and
|
|
17
|
+
* `this` → unresolved (we can't tell which sibling ctor without
|
|
18
|
+
* argument-arity matching, which is out of scope).
|
|
19
|
+
*
|
|
20
|
+
* 2. Look up matching catalog entries by simple name. Confidence
|
|
21
|
+
* ladder mirrors graph-python/graph-go:
|
|
22
|
+
* - 0 matches → `to: []`, resolution `'unknown'`, confidence `'low'`
|
|
23
|
+
* - 1 match → `to: [hash]`, resolution `'static'`, confidence `'medium'`
|
|
24
|
+
* - N matches → `to: [allHashes]`, resolution `'method-dispatch'`,
|
|
25
|
+
* confidence `'low'`
|
|
26
|
+
*
|
|
27
|
+
* Per I-4: this function does NOT mutate the input catalog.
|
|
28
|
+
*/
|
|
29
|
+
import { logger } from '@opensip-cli/core';
|
|
30
|
+
import { appendEdge, createMutableStats, pushCreationEdge, truncateForCallEdge, } from '@opensip-cli/graph';
|
|
31
|
+
import { buildNameIndex, isReturnValueDiscarded } from '@opensip-cli/graph-adapter-common';
|
|
32
|
+
import { resolveDependencies } from './resolve-dependencies.js';
|
|
33
|
+
function javaPosition(node, file) {
|
|
34
|
+
return {
|
|
35
|
+
line: node.startPosition.row + 1,
|
|
36
|
+
column: node.startPosition.column,
|
|
37
|
+
text: file.source.slice(node.startIndex, node.endIndex),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function resolveCallSites(input) {
|
|
41
|
+
logger.info({ evt: 'graph.edges.start', module: 'graph:edges:java' });
|
|
42
|
+
const byName = buildNameIndex(input.catalog.functions);
|
|
43
|
+
const edgesByOwner = new Map();
|
|
44
|
+
const stats = createMutableStats();
|
|
45
|
+
const sink = { edgesByOwner, stats };
|
|
46
|
+
for (const r of input.callSites) {
|
|
47
|
+
const node = r.nodeRef;
|
|
48
|
+
const file = r.sourceFileRef;
|
|
49
|
+
if (r.kind === 'creation') {
|
|
50
|
+
if (r.childHash === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
pushCreationEdge(javaPosition(node, file), r.ownerHash, r.childHash, sink);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
pushCallEdge(node, file, r.ownerHash, byName, sink);
|
|
56
|
+
}
|
|
57
|
+
const finalStats = {
|
|
58
|
+
totalCallSites: stats.totalCallSites,
|
|
59
|
+
resolvedHigh: stats.resolvedHigh,
|
|
60
|
+
resolvedMedium: stats.resolvedMedium,
|
|
61
|
+
resolvedLow: stats.resolvedLow,
|
|
62
|
+
unresolved: stats.unresolved,
|
|
63
|
+
};
|
|
64
|
+
logger.info({ evt: 'graph.edges.complete', module: 'graph:edges:java', ...finalStats });
|
|
65
|
+
// Phase 4 (DEC-498): resolve dependency sites if any. Mirrors the
|
|
66
|
+
// other tree-sitter adapters' resolveDependencies pattern, adapted to
|
|
67
|
+
// Java's package = directory-mirror convention.
|
|
68
|
+
const dependenciesByOwner = input.dependencySites && input.dependencySites.length > 0
|
|
69
|
+
? resolveDependencies(input.dependencySites, input.catalog)
|
|
70
|
+
: undefined;
|
|
71
|
+
return dependenciesByOwner === undefined
|
|
72
|
+
? { edgesByOwner, stats: finalStats }
|
|
73
|
+
: { edgesByOwner, dependenciesByOwner, stats: finalStats };
|
|
74
|
+
}
|
|
75
|
+
function pushCallEdge(node, file, ownerHash, byName, sink) {
|
|
76
|
+
const { edgesByOwner, stats } = sink;
|
|
77
|
+
stats.totalCallSites++;
|
|
78
|
+
const target = extractCallTargetName(node);
|
|
79
|
+
const pos = javaPosition(node, file);
|
|
80
|
+
const truncated = truncateForCallEdge(pos.text);
|
|
81
|
+
const discarded = isReturnValueDiscarded(node);
|
|
82
|
+
const edge = buildJavaCallEdge(target, byName, {
|
|
83
|
+
line: pos.line,
|
|
84
|
+
column: pos.column,
|
|
85
|
+
text: truncated,
|
|
86
|
+
discarded,
|
|
87
|
+
});
|
|
88
|
+
appendEdge(edgesByOwner, ownerHash, edge);
|
|
89
|
+
stats.apply(edge);
|
|
90
|
+
}
|
|
91
|
+
function buildJavaCallEdge(target, byName, loc) {
|
|
92
|
+
if (target === null) {
|
|
93
|
+
return { to: [], ...loc, resolution: 'unknown', confidence: 'low' };
|
|
94
|
+
}
|
|
95
|
+
const matches = byName.get(target);
|
|
96
|
+
if (!matches || matches.length === 0) {
|
|
97
|
+
return { to: [], ...loc, resolution: 'unknown', confidence: 'low' };
|
|
98
|
+
}
|
|
99
|
+
if (matches.length === 1) {
|
|
100
|
+
return { to: [...matches], ...loc, resolution: 'static', confidence: 'medium' };
|
|
101
|
+
}
|
|
102
|
+
return { to: [...matches], ...loc, resolution: 'method-dispatch', confidence: 'low' };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Decode a Java call-site node's target into a simple name. Returns
|
|
106
|
+
* null when the shape isn't one we recognize.
|
|
107
|
+
*/
|
|
108
|
+
function extractCallTargetName(node) {
|
|
109
|
+
if (node.type === 'method_invocation') {
|
|
110
|
+
const name = node.childForFieldName('name');
|
|
111
|
+
return name ? name.text : null;
|
|
112
|
+
}
|
|
113
|
+
if (node.type === 'object_creation_expression') {
|
|
114
|
+
// `new Foo(...)` — target is the type name. The `type` field holds
|
|
115
|
+
// a type_identifier (`Foo`), generic_type (`Foo<T>`), or
|
|
116
|
+
// scoped_type_identifier (`pkg.Foo`).
|
|
117
|
+
const ty = node.childForFieldName('type');
|
|
118
|
+
return ty ? decodeTypeName(ty) : null;
|
|
119
|
+
}
|
|
120
|
+
if (node.type === 'explicit_constructor_invocation') {
|
|
121
|
+
// `super(...)` or `this(...)`. We can't disambiguate constructor
|
|
122
|
+
// overloads without argument-arity matching against the catalog,
|
|
123
|
+
// and `super` targets a parent class we may not have. Leave
|
|
124
|
+
// unresolved (callers will see the edge with text but to=[]).
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
/* v8 ignore next */
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function decodeTypeName(node) {
|
|
131
|
+
if (node.type === 'type_identifier')
|
|
132
|
+
return node.text;
|
|
133
|
+
if (node.type === 'generic_type') {
|
|
134
|
+
const inner = node.childForFieldName('type') ?? node.namedChild(0);
|
|
135
|
+
return inner ? decodeTypeName(inner) : null;
|
|
136
|
+
}
|
|
137
|
+
if (node.type === 'scoped_type_identifier') {
|
|
138
|
+
// `pkg.Foo` — trailing identifier is the type.
|
|
139
|
+
const last = node.namedChild(node.namedChildCount - 1);
|
|
140
|
+
return last ? last.text : null;
|
|
141
|
+
}
|
|
142
|
+
/* v8 ignore next */
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java rule hints — language-specific signals for rules.
|
|
3
|
+
*
|
|
4
|
+
* `isTestFile` honors both path-based (Maven/Gradle `src/test/java/`,
|
|
5
|
+
* generic `/test/`) and filename-based (`*Test.java`, `*Tests.java`,
|
|
6
|
+
* `*IT.java`) conventions. Either signal is sufficient.
|
|
7
|
+
*
|
|
8
|
+
* Throw-syntax: Java's structural error-propagation is `throw new X()`.
|
|
9
|
+
* The regex matches the leading `throw` keyword.
|
|
10
|
+
*/
|
|
11
|
+
import type { RuleHints } from '@opensip-cli/graph';
|
|
12
|
+
export declare const javaRuleHints: RuleHints;
|
|
13
|
+
//# sourceMappingURL=rule-hints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-hints.d.ts","sourceRoot":"","sources":["../src/rule-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAqCpD,eAAO,MAAM,aAAa,EAAE,SAK3B,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Java rule hints — language-specific signals for rules.
|
|
3
|
+
*
|
|
4
|
+
* `isTestFile` honors both path-based (Maven/Gradle `src/test/java/`,
|
|
5
|
+
* generic `/test/`) and filename-based (`*Test.java`, `*Tests.java`,
|
|
6
|
+
* `*IT.java`) conventions. Either signal is sufficient.
|
|
7
|
+
*
|
|
8
|
+
* Throw-syntax: Java's structural error-propagation is `throw new X()`.
|
|
9
|
+
* The regex matches the leading `throw` keyword.
|
|
10
|
+
*/
|
|
11
|
+
import { isTestFile } from './walk.js';
|
|
12
|
+
const JAVA_SIDE_EFFECT_PRIMITIVES = [
|
|
13
|
+
'System.out.print',
|
|
14
|
+
'System.out.println',
|
|
15
|
+
'System.out.printf',
|
|
16
|
+
'System.err.print',
|
|
17
|
+
'System.err.println',
|
|
18
|
+
'System.err.printf',
|
|
19
|
+
'System.exit',
|
|
20
|
+
'System.setProperty',
|
|
21
|
+
'System.clearProperty',
|
|
22
|
+
'Runtime.exit',
|
|
23
|
+
'Runtime.halt',
|
|
24
|
+
'Thread.sleep',
|
|
25
|
+
'Math.random',
|
|
26
|
+
'Files.write',
|
|
27
|
+
'Files.delete',
|
|
28
|
+
'Files.deleteIfExists',
|
|
29
|
+
'Files.createFile',
|
|
30
|
+
'Files.createDirectory',
|
|
31
|
+
'Files.createDirectories',
|
|
32
|
+
];
|
|
33
|
+
// Java's structural throw analogue: `throw …` (no `panic!` macro).
|
|
34
|
+
// `throw new ExceptionType(...)` is by far the dominant form.
|
|
35
|
+
const JAVA_THROW_REGEX = /\bthrow\b/;
|
|
36
|
+
const JAVA_GENERATED_FILE_PATTERNS = [
|
|
37
|
+
'**/target/**',
|
|
38
|
+
'**/build/**',
|
|
39
|
+
'**/out/**',
|
|
40
|
+
'**/generated/**',
|
|
41
|
+
'**/generated-sources/**',
|
|
42
|
+
'**/*$Pb.java',
|
|
43
|
+
];
|
|
44
|
+
export const javaRuleHints = {
|
|
45
|
+
isTestFile,
|
|
46
|
+
generatedFilePatterns: JAVA_GENERATED_FILE_PATTERNS,
|
|
47
|
+
sideEffectPrimitives: JAVA_SIDE_EFFECT_PRIMITIVES,
|
|
48
|
+
throwSyntaxRegex: JAVA_THROW_REGEX,
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=rule-hints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-hints.js","sourceRoot":"","sources":["../src/rule-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,MAAM,2BAA2B,GAAsB;IACrD,kBAAkB;IAClB,oBAAoB;IACpB,mBAAmB;IACnB,kBAAkB;IAClB,oBAAoB;IACpB,mBAAmB;IACnB,aAAa;IACb,oBAAoB;IACpB,sBAAsB;IACtB,cAAc;IACd,cAAc;IACd,cAAc;IACd,aAAa;IACb,aAAa;IACb,cAAc;IACd,sBAAsB;IACtB,kBAAkB;IAClB,uBAAuB;IACvB,yBAAyB;CAC1B,CAAC;AAEF,mEAAmE;AACnE,8DAA8D;AAC9D,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAErC,MAAM,4BAA4B,GAAsB;IACtD,cAAc;IACd,aAAa;IACb,WAAW;IACX,iBAAiB;IACjB,yBAAyB;IACzB,cAAc;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,UAAU;IACV,qBAAqB,EAAE,4BAA4B;IACnD,oBAAoB,EAAE,2BAA2B;IACjD,gBAAgB,EAAE,gBAAgB;CACnC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Java import-declaration → dependency-site emission.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `walk.ts` so the main walker stays focused on
|
|
5
|
+
* function-occurrence construction.
|
|
6
|
+
*
|
|
7
|
+
* We detect `static` by scanning the anonymous (non-named) children for
|
|
8
|
+
* a token whose type is `'static'`, and detect the wildcard by checking
|
|
9
|
+
* for a named `asterisk` child. The dotted path is the single named
|
|
10
|
+
* `scoped_identifier` (or bare `identifier` in the degenerate
|
|
11
|
+
* `import Foo;` default-package case) child.
|
|
12
|
+
*
|
|
13
|
+
* Out of scope at v1:
|
|
14
|
+
* - `module-info.java` `requires` directives (Java 9+ Java Platform
|
|
15
|
+
* Module System) — declarative module deps live there, not here.
|
|
16
|
+
* - Implicit `java.lang.*` imports — every Java file imports these,
|
|
17
|
+
* but we don't synthesize edges for non-explicit imports.
|
|
18
|
+
* - Implicit same-package visibility — Java doesn't require imports
|
|
19
|
+
* for sibling types in the same package; we likewise don't
|
|
20
|
+
* synthesize them.
|
|
21
|
+
*/
|
|
22
|
+
import type { JavaParsedFile } from './parse.js';
|
|
23
|
+
import type { DependencySiteRecord } from '@opensip-cli/graph';
|
|
24
|
+
export declare function collectDependencySites(file: JavaParsedFile, moduleInitHash: string, out: DependencySiteRecord[]): void;
|
|
25
|
+
//# sourceMappingURL=walk-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-dependencies.d.ts","sourceRoot":"","sources":["../src/walk-dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EACpB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,oBAAoB,EAAE,GAC1B,IAAI,CAcN"}
|