From 73bd5d933103f4ce0b75dfa2cc1e3ae7cf53db13 Mon Sep 17 00:00:00 2001 From: Derek Pearson Date: Sun, 22 Mar 2026 08:16:20 -0400 Subject: [PATCH] fix(skills): address QA round 13 QA13-1: Strip inline trailing comments when scanning dependency/build files so comment-only mentions of fastapi or spring-boot no longer emit synthetic framework markers. QA13-2: Detect Spring Boot in Gradle version-catalog alias setups by including libs.versions.toml in the scan and matching spring.boot / spring-boot alias patterns as well as org.springframework.boot. Add regression tests for: - FastAPI inline comments - Android inline spring-boot comments - Spring Boot version-catalog alias detection --- src/resources/extensions/gsd/detection.ts | 13 +++--- .../extensions/gsd/tests/detection.test.ts | 41 +++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/resources/extensions/gsd/detection.ts b/src/resources/extensions/gsd/detection.ts index 5905ac1b6..491f82e8d 100644 --- a/src/resources/extensions/gsd/detection.ts +++ b/src/resources/extensions/gsd/detection.ts @@ -435,7 +435,10 @@ export function detectProjectSignals(basePath: string): ProjectSignals { } const springBootFiles = scannedFiles.filter((file) => - file.endsWith("pom.xml") || file.endsWith("build.gradle") || file.endsWith("build.gradle.kts"), + file.endsWith("pom.xml") || + file.endsWith("build.gradle") || + file.endsWith("build.gradle.kts") || + file.endsWith("libs.versions.toml"), ); if (containsDependencyMarker(basePath, springBootFiles, "spring-boot")) { pushUnique(detectedFiles, "dep:spring-boot"); @@ -773,7 +776,7 @@ function containsDependencyMarker(basePath: string, relativePaths: string[], mar if (marker === "fastapi" && /\bfastapi(?:[-_][a-z0-9]+)?\b/.test(content)) { return true; } - if (marker === "spring-boot" && /(org\.springframework\.boot|spring-boot(?:-starter)?)/.test(content)) { + if (marker === "spring-boot" && /(org\.springframework\.boot|spring[-.]boot(?:[-.]starter)?)/.test(content)) { return true; } } catch { @@ -786,10 +789,10 @@ function containsDependencyMarker(basePath: string, relativePaths: string[], mar function stripDependencyComments(relativePath: string, content: string): string { if (relativePath.endsWith("requirements.txt")) { - return content.replace(/^\s*#.*$/gm, ""); + return content.replace(/(^|\s)#.*$/gm, ""); } if (relativePath.endsWith("pyproject.toml")) { - return content.replace(/^\s*#.*$/gm, ""); + return content.replace(/(^|\s)#.*$/gm, ""); } if (relativePath.endsWith("pom.xml")) { return content.replace(//g, ""); @@ -797,7 +800,7 @@ function stripDependencyComments(relativePath: string, content: string): string if (relativePath.endsWith("build.gradle") || relativePath.endsWith("build.gradle.kts")) { return content .replace(/\/\*[\s\S]*?\*\//g, "") - .replace(/^\s*\/\/.*$/gm, ""); + .replace(/\/\/.*$/gm, ""); } return content; } diff --git a/src/resources/extensions/gsd/tests/detection.test.ts b/src/resources/extensions/gsd/tests/detection.test.ts index 70488aa94..42cab6bb7 100644 --- a/src/resources/extensions/gsd/tests/detection.test.ts +++ b/src/resources/extensions/gsd/tests/detection.test.ts @@ -793,6 +793,17 @@ test("detectProjectSignals: FastAPI comments do not trigger dep:fastapi", () => } }); +test("detectProjectSignals: FastAPI inline comments do not trigger dep:fastapi", () => { + const dir = makeTempDir("signals-fastapi-inline-comment"); + try { + writeFileSync(join(dir, "requirements.txt"), "flask==3.0 # maybe fastapi later\n", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(!signals.detectedFiles.includes("dep:fastapi"), "inline comments should not trigger FastAPI detection"); + } finally { + cleanup(dir); + } +}); + test("detectProjectSignals: Django project does NOT get dep:fastapi marker", () => { const dir = makeTempDir("signals-django-no-fastapi"); try { @@ -870,3 +881,33 @@ test("detectProjectSignals: Android Gradle project does not emit dep:spring-boot cleanup(dir); } }); + +test("detectProjectSignals: Android inline comments do not emit dep:spring-boot", () => { + const dir = makeTempDir("signals-android-inline-comment"); + try { + writeFileSync(join(dir, "build.gradle"), "plugins { id 'com.android.application' } // spring-boot maybe later", "utf-8"); + mkdirSync(join(dir, "app"), { recursive: true }); + writeFileSync(join(dir, "app", "build.gradle"), "plugins { id 'com.android.application' }", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(!signals.detectedFiles.includes("dep:spring-boot"), "inline comments should not trigger Spring Boot detection"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Spring Boot version-catalog alias emits dep:spring-boot", () => { + const dir = makeTempDir("signals-spring-version-catalog"); + try { + mkdirSync(join(dir, "gradle"), { recursive: true }); + writeFileSync(join(dir, "build.gradle.kts"), "plugins { alias(libs.plugins.spring.boot) }", "utf-8"); + writeFileSync( + join(dir, "gradle", "libs.versions.toml"), + "[plugins]\nspring-boot = { id = 'org.springframework.boot', version = '3.2.0' }\n", + "utf-8", + ); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("dep:spring-boot"), "should detect Spring Boot via version-catalog alias"); + } finally { + cleanup(dir); + } +});