mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-14 09:01:33 +00:00
fix(route): isolate Win alias tests and guard unnamed class mappings
Stub the vendor-prefix env in alias tests and fail closed when a class mapping has no name. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
1f29c8ea97
commit
f4f67f08ec
4 changed files with 27 additions and 15 deletions
|
|
@ -450,11 +450,6 @@ function inferKotlinOkHttpMethod(urlCall: Parser.SyntaxNode): string | null {
|
|||
return name === null ? 'GET' : name.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the plugin only if the Kotlin grammar is available. Compiling
|
||||
* the queries against a null grammar would throw at module load time
|
||||
* and abort the whole http-route-extractor module.
|
||||
*/
|
||||
function enclosingAnnotationText(node: Parser.SyntaxNode): string {
|
||||
for (let current: Parser.SyntaxNode | null = node; current; current = current.parent) {
|
||||
if (current.type === 'annotation') return current.text;
|
||||
|
|
@ -462,6 +457,11 @@ function enclosingAnnotationText(node: Parser.SyntaxNode): string {
|
|||
return node.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the plugin only if the Kotlin grammar is available. Compiling
|
||||
* the queries against a null grammar would throw at module load time
|
||||
* and abort the whole http-route-extractor module.
|
||||
*/
|
||||
function buildKotlinPlugin(language: unknown): HttpLanguagePlugin {
|
||||
// ─── Provider: Spring class-level @RequestMapping prefix ──────────────
|
||||
// Two patterns mirror the Java plugin's positional vs named split:
|
||||
|
|
|
|||
|
|
@ -442,11 +442,13 @@ function annotationHasRouteMember(ann: Parser.SyntaxNode): boolean {
|
|||
/** Static class/interface-level RequestMapping method constraint, or wildcard by default. */
|
||||
function typeRequestMethods(typeNode: Parser.SyntaxNode): readonly string[] {
|
||||
const mappings = declarationAnnotations(typeNode).filter((ann) =>
|
||||
isClassLevelMappingAnnotation(annotationName(ann)),
|
||||
isClassLevelMappingAnnotation(annotationName(ann) ?? ''),
|
||||
);
|
||||
if (mappings.length === 0) return ['*'];
|
||||
if (mappings.length !== 1) return [];
|
||||
return springAnnotationHttpMethods(annotationName(mappings[0]), mappings[0].text);
|
||||
const mappingName = annotationName(mappings[0]);
|
||||
if (!mappingName) return [];
|
||||
return springAnnotationHttpMethods(mappingName, mappings[0].text);
|
||||
}
|
||||
|
||||
function annotationRoutePathsOrDefault(ann: Parser.SyntaxNode): string[] {
|
||||
|
|
@ -459,7 +461,7 @@ function annotationRoutePathsOrDefault(ann: Parser.SyntaxNode): string[] {
|
|||
function typeClassPrefixes(typeNode: Parser.SyntaxNode): string[] {
|
||||
const prefixes: string[] = [];
|
||||
for (const ann of declarationAnnotations(typeNode)) {
|
||||
if (isClassLevelMappingAnnotation(annotationName(ann)))
|
||||
if (isClassLevelMappingAnnotation(annotationName(ann) ?? ''))
|
||||
prefixes.push(...annotationRoutePaths(ann));
|
||||
}
|
||||
return prefixes;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* The Kotlin grammar is optional. Importing the extractor itself must not load
|
||||
* that grammar; only this guarded test setup does.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import Parser from 'tree-sitter';
|
||||
import { requireVendoredGrammar } from '../../src/core/tree-sitter/vendored-grammars.js';
|
||||
import { extractKotlinSpringRoutes } from '../../src/core/ingestion/route-extractors/kotlin-spring.js';
|
||||
|
|
@ -29,6 +29,14 @@ if (Kotlin) parser.setLanguage(Kotlin as Parser.Language);
|
|||
const parse = (source: string): Parser.Tree => parser.parse(source);
|
||||
const describeKotlin = Kotlin ? describe : describe.skip;
|
||||
|
||||
describeKotlin('extractKotlinSpringRoutes', () => {
|
||||
beforeEach(() => {
|
||||
vi.stubEnv('GITNEXUS_SPRING_VENDOR_PREFIXES', 'Win');
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
function constantsOf(files: Record<string, string>): RepoConstants {
|
||||
return new Map(
|
||||
Object.entries(files).map(([filePath, source]) => [
|
||||
|
|
@ -38,7 +46,6 @@ function constantsOf(files: Record<string, string>): RepoConstants {
|
|||
);
|
||||
}
|
||||
|
||||
describeKotlin('extractKotlinSpringRoutes', () => {
|
||||
it('extracts direct RestController functions with independent class prefixes and handlers', () => {
|
||||
const routes = extractKotlinSpringRoutes(
|
||||
parse(`
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
* 3. End-to-end `extractSpringRoutes` with a fixture using vendor annotations
|
||||
* 4. Parity: both ingestion and group extractors surface the same routes
|
||||
*/
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest';
|
||||
import Parser from 'tree-sitter';
|
||||
import Java from 'tree-sitter-java';
|
||||
import {
|
||||
|
|
@ -30,6 +30,13 @@ function parse(code: string): Parser.Tree {
|
|||
return parser.parse(code);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubEnv('GITNEXUS_SPRING_VENDOR_PREFIXES', 'Win');
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe('resolveSpringAnnotationAlias', () => {
|
||||
it('returns undefined for exact built-in shortcut annotations', () => {
|
||||
expect(resolveSpringAnnotationAlias('PostMapping')).toBeUndefined();
|
||||
|
|
@ -79,10 +86,6 @@ describe('resolveSpringAnnotationAlias', () => {
|
|||
});
|
||||
|
||||
describe('Spring vendor prefix freshness', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it('canonicalizes equivalent lists regardless of order and duplicates', () => {
|
||||
vi.stubEnv('GITNEXUS_SPRING_VENDOR_PREFIXES', ' Win,Acme,Win ');
|
||||
const first = springVendorPrefixesKey();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue