дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
feat(search): find a Spring endpoint by its request path (#820)
Search Everywhere lists Spring Web endpoints matched by request path (context path tolerated) or handler method name, and Enter opens the handler. The host scans Java/Kotlin sources that name a mapping; http-client parses and indexes them and hands the entries to search through an endpoint contribution, so search does not import http-client. The index is invalidated when a Java/Kotlin file changes. Route source path assertions compare by path component so they hold on Windows. Co-authored-by: misswell <[email protected]> Co-Authored-By: Claude Opus 5.5 <[email protected]>
Цей коміт міститься в:
17 files changed
+587
-6
No files matched your search
@@ -1317,6 +1317,41 @@ export function runAnythingProviderList(): RunAnythingProvider[] {
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Project endpoints supplied by framework features for request-path search.
|
||||
|
||||
export interface EndpointEntry {
|
||||
/** `GET`, `POST`, … */
|
||||
method: string;
|
||||
/** Class-level and method-level mapping joined; `{var}` kept. */
|
||||
url: string;
|
||||
controller: string;
|
||||
methodName: string;
|
||||
path: string;
|
||||
rel: string;
|
||||
line: number;
|
||||
col: number;
|
||||
}
|
||||
|
||||
export interface EndpointProvider {
|
||||
id: string;
|
||||
endpoints(root: string): Promise<EndpointEntry[]>;
|
||||
}
|
||||
|
||||
const endpointProviders = new Map<string, EndpointProvider>();
|
||||
|
||||
export function registerEndpointProvider(p: EndpointProvider): () => void {
|
||||
endpointProviders.set(p.id, p);
|
||||
return () => {
|
||||
if (endpointProviders.get(p.id) === p) endpointProviders.delete(p.id);
|
||||
};
|
||||
}
|
||||
|
||||
export async function searchEndpoints(root: string | null): Promise<EndpointEntry[]> {
|
||||
if (!root) return [];
|
||||
return (await Promise.all([...endpointProviders.values()].map((p) => p.endpoints(root)))).flat();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Status bar info text (IDEA's status bar message, e.g. "3 of 12" after Next
|
||||
// Occurrence). Cleared by the next message or after a while.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { expect, it, vi } from "vitest";
|
||||
import { registerEndpointProvider, searchEndpoints, type EndpointEntry } from "./contributions";
|
||||
|
||||
const endpoint: EndpointEntry = {
|
||||
method: "GET",
|
||||
url: "/menu/list",
|
||||
controller: "MenuController",
|
||||
methodName: "listMenus",
|
||||
path: "/p/MenuController.java",
|
||||
rel: "MenuController.java",
|
||||
line: 4,
|
||||
col: 11,
|
||||
};
|
||||
|
||||
it("collects endpoints from all providers for the requested root", async () => {
|
||||
const first = vi.fn(async () => [endpoint]);
|
||||
const second = vi.fn(async () => [{ ...endpoint, url: "/other" }]);
|
||||
const disposers = [
|
||||
registerEndpointProvider({ id: "test.first", endpoints: first }),
|
||||
registerEndpointProvider({ id: "test.second", endpoints: second }),
|
||||
];
|
||||
try {
|
||||
expect(await searchEndpoints(null)).toEqual([]);
|
||||
expect(first).not.toHaveBeenCalled();
|
||||
expect(second).not.toHaveBeenCalled();
|
||||
expect(await searchEndpoints("/p")).toEqual([endpoint, { ...endpoint, url: "/other" }]);
|
||||
expect(first).toHaveBeenCalledWith("/p");
|
||||
expect(second).toHaveBeenCalledWith("/p");
|
||||
} finally {
|
||||
disposers.forEach((dispose) => dispose());
|
||||
}
|
||||
expect(await searchEndpoints("/p")).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps a replacement provider registered when its predecessor is disposed", async () => {
|
||||
const disposeOld = registerEndpointProvider({ id: "test.replaced", endpoints: async () => [] });
|
||||
const disposeNew = registerEndpointProvider({ id: "test.replaced", endpoints: async () => [endpoint] });
|
||||
try {
|
||||
disposeOld();
|
||||
expect(await searchEndpoints("/p")).toEqual([endpoint]);
|
||||
} finally {
|
||||
disposeOld();
|
||||
disposeNew();
|
||||
}
|
||||
expect(await searchEndpoints("/p")).toEqual([]);
|
||||
});
|
||||
Reference in new issue
Заблокувати користувача