Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- CodeGraph's refusal to use a sensitive folder such as `~/.ssh`, `~/.config`, `/etc` or `C:\Windows` as a project can no longer be sidestepped: a link or junction that leads to one, a differently capitalized name on Windows and macOS, a `\\?\` spelling on Windows, and a path to a missing folder inside one are now refused like the folder itself. Before, any of these let an AI agent's query read the files inside. Thanks @mixxer for finding it.
- The MCP server no longer uses a sensitive folder such as `~/.ssh`, `~/.config` or `/etc` as a session's default project, whether the folder came from your AI agent's workspace, the folder the server was started in, or `--path`. Before, only a folder an agent asked for by path was refused, so a session started in one that held an index answered from the files inside and kept it synced; now that session has no default project, and the agent can still query any other project by path.

### New Features

- Symfony support: routes from `#[Route]` attributes, `config/routes.yaml` and the compiled router cache now appear as entry points linked to the controller action that serves them, including Shopware 6 shops and plugins. Thanks @jorgerobles. (#611)

### Fixes

- In PHP, an attribute such as `#[AsCommand]`, `#[ORM\Entity]` or `#[Route]` on a class, method or function now links to the attribute's class, so attribute classes show who uses them.
- In TypeScript, an awaited call with type arguments like `await fetchApi<User>("/me")` or `await api.get<T>(url)` now links to the function it calls. Before, the call was dropped, so typed fetch wrappers looked like they had no callers. (#2586)
- In JavaScript and TypeScript, a call or `new` in a parameter's default value, like `function renderWithNote(note = buildNote())`, a destructured `{ size = defaultSize() }` or `constructor(private svc = new Service())`, now counts as the function's own call. Before, it was dropped, so `buildNote` was missing that caller and impact on it came back incomplete. Re-index JavaScript and TypeScript projects after upgrading. Thanks @inth3shadows for the report and the pull request. (#2588)
- In React, a component rendered at module scope, in a top-level constant or inside a test's `it(…)` callback, like `createRoot(el).render(<App />)` or `render(<Card />)`, now counts as rendered there, so an app's entry reaches its root component and a component's tests show among its callers. (#2587)
Expand Down
23 changes: 22 additions & 1 deletion __tests__/kernel-php-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* anonymous-class garbage ref + file-level-function methods), static value
* reads, php type refs, HOF string/array callables, value-ref targets
* (namespaced top-level consts DROPPED), heredoc/nowdoc/interpolation,
* attributes shifting node lines without emitting.
* attributes as `decorates` refs.
* - TortureModule.module — drupal extension routing + un-namespaced
* top-level const value-ref target + hook-docblocked function.
* - TortureHtml.php — leading/interleaved HTML (absolute row positions),
Expand Down Expand Up @@ -136,6 +136,27 @@ describe.skipIf(!kernelBuilt)('kernel PHP extraction parity', () => {
expect(impl?.filePath).toBe('src/W.php');
});

it('attributes on classes, methods and functions are decorates refs on both paths', () => {
const src = [
'<?php',
'#[ORM\\Entity, Package(\'core\')]',
'class A {',
" #[Route('/x')] #[\\Symfony\\Component\\Routing\\Attribute\\Route('/y')]",
' public function m() {}',
'}',
'#[AsCommand(name: \'app:x\')]',
'function f() {}',
'',
].join('\n');
assertParity('src/A.php', src);
const viaKernel = tryKernelExtract('src/A.php', src, 'php');
const decorates = viaKernel!.unresolvedReferences
.filter((r) => r.referenceKind === 'decorates')
.map((r) => `${r.line}:${r.referenceName}`)
.sort();
expect(decorates).toEqual(['2:Entity', '2:Package', '4:Route', '4:Route', '7:AsCommand']);
});

it('files with parse errors defer to the wasm extractor (recovery is encoding-dependent)', () => {
const broken = '<?php\nfunction f( {\n return }} 12 (\n';
process.env.CODEGRAPH_KERNEL_LANGS = 'all';
Expand Down
Loading