mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-21 16:57:09 +08:00
fix(play): a Play project in a subdirectory is still Play (#2156)
Detection only looked at the root (`build.sbt`, `conf/routes`, `conf/application.conf`); playframework/play-samples keeps each project's `conf/routes` in its own directory and had no routes. Any indexed Play routes file now counts. play-samples 0 → 139 routes (+108 edges); root-level Play repos are unaffected. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
### Fixes
|
||||
|
||||
- Play projects kept in subdirectories are recognized, so each one's `conf/routes` is read. A repository with no Play build at its root, like playframework's samples, went from no routes to over 130.
|
||||
- Rails routes are now read with their nesting: `namespace` and `scope` add their path and controller module, nested `resources` sit under their parent's `:id`, and `member` / `collection` blocks add their actions. A namespaced route now links to its own module's controller. Routes in a Rails engine's `config/routes.rb` are found too: solidus went from no routes to over 600, and mastodon's route-to-action links nearly tripled.
|
||||
- Flask routes registered with `add_url_rule(…)` are now found and linked to their view function or class-based view. So are routes registered through a project's own helper that passes a list of paths and a `view_func=`. flaskbb, which registers every view that way, went from no routes to over 100.
|
||||
- In Lua and Luau, a call through a standard or host library table (`string`, `table`, `io`, `vim`, `ngx`, busted's `assert`…) or a string method like `line:find(…)` no longer lands on the one project method with the same name. Functions the project itself defines on those tables still link. On kong, the specs' `assert.truthy(…)` and `assert.falsy(…)` used to land on a condition helper over 1,700 times; on telescope, `line:find(…)` on the picker's `find`.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* A repository of Play projects — playframework/play-samples keeps each one's
|
||||
* `conf/routes` in its own directory, with no build at the root — still reads
|
||||
* as Play: it had no routes at all.
|
||||
*/
|
||||
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-play-nested-'));
|
||||
const files: Record<string, string> = {
|
||||
'play-java-hello/conf/routes': `GET / controllers.HomeController.index()
|
||||
GET /count controllers.CountController.count()
|
||||
`,
|
||||
'play-java-hello/app/controllers/HomeController.java': `package controllers;
|
||||
public class HomeController {
|
||||
public Result index() { return null; }
|
||||
}
|
||||
`,
|
||||
'play-java-hello/app/controllers/CountController.java': `package controllers;
|
||||
public class CountController {
|
||||
public Result count() { return null; }
|
||||
}
|
||||
`,
|
||||
};
|
||||
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('Play projects in subdirectories', () => {
|
||||
it('have their routes, linked to the actions', () => {
|
||||
const routes = cg.getNodesByKind('route');
|
||||
expect(routes.map((r) => r.name).sort()).toEqual(['GET /', 'GET /count']);
|
||||
const count = routes.find((r) => r.name === 'GET /count')!;
|
||||
const target = cg.getOutgoingEdges(count.id).map((e) => cg.getNode(e.target)!.qualifiedName);
|
||||
expect(target.some((t) => t.endsWith('CountController::count'))).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -34,7 +34,9 @@ export const playResolver: FrameworkResolver = {
|
||||
if (buildSbt && /playframework|"play"|sbt-plugin|PlayScala|PlayJava/i.test(buildSbt)) return true;
|
||||
if (context.fileExists('conf/routes')) return true;
|
||||
if (context.fileExists('conf/application.conf')) return true;
|
||||
return false;
|
||||
// A repository of Play projects (playframework/play-samples) keeps each
|
||||
// one's `conf/routes` in its own directory.
|
||||
return context.getAllFiles().some((f) => isPlayRoutesFile(f));
|
||||
},
|
||||
|
||||
// The handler is `Controller.method` (a class-qualified action), which names no
|
||||
|
||||
Reference in New Issue
Block a user