mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-15 05:29:27 +08:00
The React resolver's `languages` gates its route extraction, not its resolve(): framework resolvers see every language's references. Its component rule was already JSX-only, but its hook (`use...`) and context (`...Context` / `...Provider`) rules were not: in halo - a Spring app whose UI package makes React detected - 209 Java import edges (`SecurityContext`, `ApplicationContext`, `ObjectProvider`, `DirtiesContext`...) were resolved by it onto import nodes. It now answers only JavaScript / TypeScript / TSX / JSX references. halo -209 +3 (a Java test's `responseContext()` helper now resolves to itself); trpc, excalidraw, react-redux-realworld, bulletproof-react, react-native-reusables unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
/**
|
|
* The React resolver's hook (`use…`) and context (`…Context` / `…Provider`)
|
|
* rules are a script's, never another language's: in halo — a Spring app
|
|
* with a React-detected UI package — Java imports of `SecurityContext` or
|
|
* `ObjectProvider` were taken by the context rule, and a Java test's own
|
|
* `responseContext()` helper went unresolved.
|
|
*/
|
|
import { describe, it, expect, afterAll, beforeAll } from 'vitest';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import { CodeGraph } from '../src';
|
|
|
|
let root = '';
|
|
let cg: CodeGraph;
|
|
|
|
beforeAll(async () => {
|
|
root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-react-lang-'));
|
|
const files: Record<string, string> = {
|
|
'package.json': JSON.stringify({ name: 'app', dependencies: { react: '^18' } }),
|
|
'ui/src/ThemeContext.tsx': `import { createContext } from 'react';
|
|
|
|
export const responseContext = createContext(null);
|
|
`,
|
|
'src/main/java/app/Filter.java': `package app;
|
|
|
|
import org.springframework.security.core.context.SecurityContext;
|
|
|
|
public class Filter {
|
|
Object responseContext() {
|
|
return null;
|
|
}
|
|
|
|
void filter() {
|
|
responseContext();
|
|
}
|
|
}
|
|
`,
|
|
};
|
|
for (const [rel, content] of Object.entries(files)) {
|
|
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
|
fs.writeFileSync(path.join(root, rel), content);
|
|
}
|
|
cg = await CodeGraph.init(root, { index: true });
|
|
});
|
|
|
|
afterAll(() => {
|
|
cg?.close();
|
|
if (root) fs.rmSync(root, { recursive: true, force: true });
|
|
});
|
|
|
|
describe('the React resolver', () => {
|
|
it('does not take a Java import of a …Context class', () => {
|
|
const ids = cg.getNodesInFile('src/main/java/app/Filter.java').map((n) => n.id);
|
|
const byReact = cg.getOutgoingEdgesFrom(ids).filter((e) => (e.metadata as { framework?: string } | undefined)?.framework === 'react');
|
|
expect(byReact).toEqual([]);
|
|
});
|
|
|
|
it('leaves a Java call named like a context to Java', () => {
|
|
const filter = cg.getNodesInFile('src/main/java/app/Filter.java').find((n) => n.name === 'filter')!;
|
|
const targets = cg.getOutgoingEdges(filter.id).filter((e) => e.kind === 'calls').map((e) => cg.getNode(e.target)!);
|
|
expect(targets.map((t) => t.filePath)).not.toContain('ui/src/ThemeContext.tsx');
|
|
expect(targets.map((t) => t.qualifiedName)).toContain('app::Filter::responseContext');
|
|
});
|
|
});
|