diff --git a/.gitignore b/.gitignore index e8d56e7..715e1e5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dist/ .env *.log .superpowers/ +data/demo-pmd/target/ diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md index fbd9bb5..8085c45 100644 --- a/_AI_USAGE_LOG.md +++ b/_AI_USAGE_LOG.md @@ -228,3 +228,4 @@ | 2026-08-25 21:54 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 从插件内置 PMD 配置移除 5 条实际不可触发的规则(AvoidAssertAsIdentifier/AvoidEnumAsIdentifier 语言版本上限 1.3/1.4、AccessorClassGeneration/AccessorMethodGeneration 上限 Java 10、LoosePackageCoupling 需显式 packages 配置),使内置配置=全部可触发,demo-pmd 覆盖率基线对齐 269+12=281 可达成 100%。改动:jars/pmd/pmd-java-ruleset.xml 三个分类 exclude 各追加(bestpractices 2 + design 1 + errorprone 2)并将 description 计数 274→269;src/rules/static-rules.json linterVersion.pmd 改 269、移除 5 条规则条目(pmd 295→290);scripts/translations/pmd-1.mjs/pmd-2.mjs 同步删除 5 条翻译种子项。验证:PMD 实际跑内置 ruleset 无加载异常 / lint 0 error / compile 通过 / npm test 117 passing | 中间产物:static-rules.json 第一处编辑误保留 AccessorClassGeneration 块(只删了 AccessorMethodGeneration),复查 JSON 计数发现后补删 | jars/pmd/pmd-java-ruleset.xml src/rules/static-rules.json scripts/translations/pmd-1.mjs scripts/translations/pmd-2.mjs | deepseek-v4-flash | | 2026-08-26 19:05 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 仓库目录对齐赛道二 §8 成果物规范:分支 vscode-code-reviewer 合并入 main(冲突文件 docs/superpowers/specs/2026-07-10-code-reviewer-design.md 取开发分支完整版,add/add 冲突已解决);src/test 迁移至根目录 tests/(16 个测试 + fixtures/manual),36 处 import '../' → '../src/';新建 tsconfig.test.json(rootDir ".",include tests + src/types 声明文件);.vscode-test.mjs files 改 'out/tests/**/*.test.js';package.json 新增 compile:test、test 改为 compile:test && vscode-test;.gitignore 移除 src/test/;3 个中文文件名 demo-*插件实测覆盖率报告.md 重命名为 demo-*-coverage-report.md;git rm --cached 解除 vscode-code-reviewer-1.0.0.vsix 跟踪;README 追加演示视频(进行中)章节。验证:lint 0 error / compile 通过 / compile:test 通过 / npm test 116 passing | 中间产物:tsconfig.test.json 初版 include 仅 tests/**/*,编译报 stylelint-config-recommended 声明缺失(主 tsconfig include src/**/* 含 src/types 声明文件而 test 配置未含),补 include src/types/**/* 后通过 | tests/ tests/fixtures/ tests/manual/ tsconfig.test.json(新建) .vscode-test.mjs package.json .gitignore README.md data/demo-eslint/reports/demo-eslint-coverage-report.md data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md data/demo-stylelint/reports/demo-stylelint-coverage-report.md | deepseek-v4-flash | | 2026-08-26 19:16 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 补齐 tests/ 实验报告(§8 成果物 04,coverage/ 按用户确认忽略):新建 tests/test-execution-log.md(测试执行日志:命令/环境/结果 116 passing 0 failing);tests/test-cases.md(从 16 个测试文件提取 suite/test 声明,116 条用例清单+覆盖点+统计);tests/measure/measure-review-time.mjs(提效测量脚本:内联复刻 src/rules/builtin-rules.ts 的 ESLint/Stylelint 内置配置,用 eslint/stylelint 引擎直跑 data/demo-*/src 样例计时,输出 tests/measure/results/measure-results.json);tests/measure/performance-comparison.md(提效对比骨架:测量方法+对比维度+插件侧实测数据已填 demo-eslint 6 文件 294 诊断 192.2ms / demo-stylelint 2 文件 115 诊断 2106.7ms / 合计 409 诊断 2298.9ms,人工基线留待实测)。验证:measure 脚本实测运行产出 JSON / lint 0 error(仅既有 mockDocument 2 warning)/ 主流程 npm test 116 passing 不受影响 | 中间产物:measure 脚本初版 import '../../src/rules/builtin-rules'(ESM 无法直接加载 TS 报 ERR_MODULE_NOT_FOUND)→ 改 import 编译产物 '../../out/rules/builtin-rules.js' 又因模块顶层 import vscode 脱离扩展宿主报 MODULE_NOT_FOUND → 最终改为内联规则配置(与 data/demo-eslint/run-coverage.mjs 既有模式一致);measure() 计时函数初版未 await 异步 fn,result 为 Promise 导致 result.reduce 报错,改为 async/await 后通过 | tests/test-execution-log.md(新建) tests/test-cases.md(新建) tests/measure/measure-review-time.mjs(新建) tests/measure/performance-comparison.md(新建) tests/measure/results/measure-results.json(新建) | deepseek-v4-flash | +| 2026-08-26 21:29 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复 Windows 下 spawn 拉起 .cmd/.bat 必然 EINVAL 问题(方案 A):auxClasspath.ts exec() 对 Windows 批处理命令(mvnw.cmd/gradlew.bat/mvn.cmd/gradle.bat)改走 spawn('cmd.exe', ['/d','/s','/c', 双层引号包装命令]) + windowsVerbatimArguments:true,非批处理分支不变;新增私有 helper quoteCmdArg(安全字符正则含 \ 及 Windows 路径符,含空格/引号参数用 cmd 双引号转义 "→"")。修复 Maven/Gradle 自动 aux classpath 在 Windows 完全失效问题。验证:实测 npm.cmd 与含空格路径+含空格参数 .cmd 冒烟通过(exit 0)/ lint 0 error(仅既有 mockDocument 2 warning)/ compile 通过 / npm test 116 passing | 中间产物:①cmd /s /c 单层引号方案失败——命令首字符为引号时 cmd 剥首尾引号并移除最后一个引号字符,导致路径后残留引号拼接成非法命令(实测 'F:\nodejs\node.exe" -e "console.log' 无法识别),改为外层再包一层引号(双层引号)后通过;②quoteCmdArg safe 正则初版漏 \ 反斜杠,考虑 -Dmdep.outputFile=C:\... 参数补入;③PowerShell 双引号 here-string 内联 node 测试脚本引号被解析破坏报 SyntaxError,改用单引号 here-string 后通过;④是否加 windowsVerbatimArguments 决策点——不加则 Node 二次转义拼好的命令行,实测确认必须加 | src/services/auxClasspath.ts | deepseek-v4-flash | diff --git a/data/demo-eslint/reports/demo-eslint-coverage-report.md b/data/demo-eslint/reports/demo-eslint-coverage-report.md index 21bf0d8..3a3c9c9 100644 --- a/data/demo-eslint/reports/demo-eslint-coverage-report.md +++ b/data/demo-eslint/reports/demo-eslint-coverage-report.md @@ -109,11 +109,6 @@ 2. ✅ 内置配置全覆盖达成(126/126 种规则,零解析错误) 3. ✅ 「内置配置回退」路径完整验证(工程无配置文件的场景) -**后续建议**(如需继续扩展验证): - -- **其他 3 个工程复测**:`demo-sqlfluff`、`demo-pmd`、`demo-stylelint` 按同样方法(先本地模拟基线 → 实测比对),其中 PMD 注意 Java 版本与 ruleset、SQLFluff 注意 dialect 与 AL06 样例、Stylelint 注意配置优先级。 -- **「工程配置优先」路径补验**(可选):若后续想验证插件发现工程配置的行为,可在工程根添加 `eslint.config.mjs` 并以工程根为第一个工作区文件夹打开,预期插件改用工程配置(诊断会有差异,属正常)。 - --- *报告生成于 2026-08-25 · demo-eslint 插件实测 · 比对脚本:`round2-compare.mjs` · 数据:`round2-verify.json`* diff --git a/data/demo-pmd/.mvn/wrapper/maven-wrapper.jar b/data/demo-pmd/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..7967f30 Binary files /dev/null and b/data/demo-pmd/.mvn/wrapper/maven-wrapper.jar differ diff --git a/data/demo-pmd/.mvn/wrapper/maven-wrapper.properties b/data/demo-pmd/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..308007b --- /dev/null +++ b/data/demo-pmd/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar diff --git a/data/demo-pmd/.vscode/settings.json b/data/demo-pmd/.vscode/settings.json new file mode 100644 index 0000000..5347b58 --- /dev/null +++ b/data/demo-pmd/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "java.project.referencedLibraries": [ + "lib/**/*.jar" + ], + "java.project.sourcePaths": [ + "src" + ] +} \ No newline at end of file diff --git a/data/demo-pmd/cp.txt b/data/demo-pmd/cp.txt new file mode 100644 index 0000000..d022b97 --- /dev/null +++ b/data/demo-pmd/cp.txt @@ -0,0 +1 @@ +C:\Users\Fan\.m2\repository\junit\junit\4.13.2\junit-4.13.2.jar;C:\Users\Fan\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\Fan\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.10.2\junit-jupiter-api-5.10.2.jar;C:\Users\Fan\.m2\repository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;C:\Users\Fan\.m2\repository\org\junit\platform\junit-platform-commons\1.10.2\junit-platform-commons-1.10.2.jar;C:\Users\Fan\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\Fan\.m2\repository\org\slf4j\slf4j-api\2.0.16\slf4j-api-2.0.16.jar;C:\Users\Fan\.m2\repository\commons-logging\commons-logging\1.3.4\commons-logging-1.3.4.jar \ No newline at end of file diff --git a/data/demo-pmd/lib/apiguardian-api-1.1.2.jar b/data/demo-pmd/lib/apiguardian-api-1.1.2.jar new file mode 100644 index 0000000..2b678e1 Binary files /dev/null and b/data/demo-pmd/lib/apiguardian-api-1.1.2.jar differ diff --git a/data/demo-pmd/lib/commons-logging-1.3.4.jar b/data/demo-pmd/lib/commons-logging-1.3.4.jar new file mode 100644 index 0000000..b6339bb Binary files /dev/null and b/data/demo-pmd/lib/commons-logging-1.3.4.jar differ diff --git a/data/demo-pmd/lib/hamcrest-core-1.3.jar b/data/demo-pmd/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000..9d5fe16 Binary files /dev/null and b/data/demo-pmd/lib/hamcrest-core-1.3.jar differ diff --git a/data/demo-pmd/lib/junit-4.13.2.jar b/data/demo-pmd/lib/junit-4.13.2.jar new file mode 100644 index 0000000..6da55d8 Binary files /dev/null and b/data/demo-pmd/lib/junit-4.13.2.jar differ diff --git a/data/demo-pmd/lib/junit-jupiter-api-5.10.2.jar b/data/demo-pmd/lib/junit-jupiter-api-5.10.2.jar new file mode 100644 index 0000000..b779e1b Binary files /dev/null and b/data/demo-pmd/lib/junit-jupiter-api-5.10.2.jar differ diff --git a/data/demo-pmd/lib/opentest4j-1.3.0.jar b/data/demo-pmd/lib/opentest4j-1.3.0.jar new file mode 100644 index 0000000..7ec7bc5 Binary files /dev/null and b/data/demo-pmd/lib/opentest4j-1.3.0.jar differ diff --git a/data/demo-pmd/lib/slf4j-api-2.0.16.jar b/data/demo-pmd/lib/slf4j-api-2.0.16.jar new file mode 100644 index 0000000..cbb5448 Binary files /dev/null and b/data/demo-pmd/lib/slf4j-api-2.0.16.jar differ diff --git a/data/demo-pmd/mvnw b/data/demo-pmd/mvnw new file mode 100644 index 0000000..68af9e4 --- /dev/null +++ b/data/demo-pmd/mvnw @@ -0,0 +1,138 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup script, version 3.3.2 +# ---------------------------------------------------------------------------- + +# Required ENV vars: +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars: +# MAVEN_OPTS - parameters passed to the Java VM, e.g. -Xmx512m +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. +cygwin=false; +darwin=false; +mingw=false +case "$(uname)" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + if [ -z "$JAVA_VERSION" ] ; then + JAVA_VERSION="MajorVersion" + fi + ;; +esac + +[ -n "$JAVA_HOME" ] && export PATH="$JAVA_HOME/bin:$PATH" + +if [ -z "$JAVA_HOME" ] ; then + if $darwin ; then + if [ -z "$JAVA_VERSION" ] ; then + JAVA_VERSION="MajorVersion" + fi + JAVA_HOME=$(/usr/libexec/java_home -v "$JAVA_VERSION") + if [ $? -ne 0 ] ; then + echo "Unable to find Java version: $JAVA_VERSION" >&2 + exit 1 + fi + else + JAVA_HOME=$(which java 2>/dev/null) + if [ -z "$JAVA_HOME" ] ; then + echo "Error: JAVA_HOME not found in your environment." >&2 + echo "Please set the JAVA_HOME variable in your environment to match the" >&2 + echo "location of your Java installation." >&2 + exit 1 + fi + JAVA_HOME=$(dirname "$(dirname "$JAVA_HOME")") + fi +fi + +# For Cygwin, ensure paths are in UNIX format +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] && CLASSPATH=$(cygpath --path --unix "$CLASSPATH") +fi + +# For Mingw, ensure paths are in UNIX format +if $mingw ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME="$(cd "$JAVA_HOME" && pwd)" +fi + +# shellcheck disable=SC2034 +MAVEN_PROJECTBASEDIR="${MAVEN_BASEDIR:-$(cd "$(dirname "$0")" && pwd)}" +MAVEN_CMD_LINE_ARGS="$@" + +# shellcheck disable=SC2086 +MAVEN_OPTS="${MAVEN_OPTS:--Xmx512m} $([ -f "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config" ] && cat "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config")" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" + +WRAPPER_JAR="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +if [ -f "$WRAPPER_JAR" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found $WRAPPER_JAR" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find $WRAPPER_JAR, downloading it ..." + fi + WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + if [ -n "$MVNW_REPOURL" ]; then + WRAPPER_URL="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + fi + if command -v curl > /dev/null 2>&1; then + curl -o "$WRAPPER_JAR" "$WRAPPER_URL" + elif command -v wget > /dev/null 2>&1; then + wget -O "$WRAPPER_JAR" "$WRAPPER_URL" + else + echo "Error: Unable to download $WRAPPER_URL" >&2 + exit 1 + fi +fi + +# shellcheck disable=SC2086 +exec "$JAVA_HOME/bin/java" \ + $MAVEN_OPTS \ + -classpath "$WRAPPER_JAR" \ + "-Dmaven.multiModuleProjectDirectory=$MAVEN_PROJECTBASEDIR" \ + $WRAPPER_LAUNCHER $MAVEN_CMD_LINE_ARGS diff --git a/data/demo-pmd/mvnw.cmd b/data/demo-pmd/mvnw.cmd new file mode 100644 index 0000000..ee8b1d3 --- /dev/null +++ b/data/demo-pmd/mvnw.cmd @@ -0,0 +1,193 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_OPTS - parameters passed to the Java VM, e.g. -Xmx512m +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echo by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +if not "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%\.mvn" goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$ErrorActionPreference = 'Stop';"^ + "if (!(Test-Path -Path '%WRAPPER_JAR%')) {"^ + "New-Item -Path '%WRAPPER_JAR%' -Force | Out-Null;"^ + "}"^ + "if (!(Test-Path -Path '%MAVEN_PROJECTBASEDIR%\.mvn\wrapper')) {"^ + "New-Item -Path '%MAVEN_PROJECTBASEDIR%\.mvn\wrapper' -ItemType Directory -Force | Out-Null;"^ + "}"^ + "$webclient = New-Object System.Net.WebClient;"^ + "try {"^ + "$webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}"^ + "catch {"^ + "if (!$?) {"^ + "Write-Output ""Unable to download %WRAPPER_URL%"";"^ + "exit 1;"^ + "}"^ + "}"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/data/demo-pmd/pom.xml b/data/demo-pmd/pom.xml new file mode 100644 index 0000000..8f2a032 --- /dev/null +++ b/data/demo-pmd/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + com.demo + demo-pmd + 1.0.0 + jar + + PMD Demo + PMD 规则演示项目,包含 JUnit 3/4/5 及 SLF4J 依赖 + + + 11 + 11 + UTF-8 + + + + + src + + + + + + junit + junit + 4.13.2 + + + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + + + + + org.slf4j + slf4j-api + 2.0.16 + + + + + commons-logging + commons-logging + 1.3.4 + + + diff --git a/data/demo-pmd/reports/demo-pmd-coverage-report.md b/data/demo-pmd/reports/demo-pmd-coverage-report.md new file mode 100644 index 0000000..87ddaca --- /dev/null +++ b/data/demo-pmd/reports/demo-pmd-coverage-report.md @@ -0,0 +1,174 @@ +# demo-pmd 插件实测覆盖率报告 + +> **工程**:`demo-pmd`(PMD 内置规则集形态:`jars/pmd/pmd-java-ruleset.xml` + `pmd-jsp-ruleset.xml`) +> **测试对象**:插件 PMD 适配器(引擎 PMD 7.26.0,Java 269 条 / JSP 10 条内置规则) +> **实测日期**:2026-08-26(当日完成含辅助 classpath 的全量复测收官) +> **比对基线**:插件同版本引擎 + 同规则集独立复现的基线(比对键 = 规则 + 行号;JSP 另含三层架构逐层复现) + +--- + +## 一、核心结论 + +| 指标 | 结果 | 状态 | +|---|---|---| +| 插件行为一致性(vs 基线) | **1813/1813 条逐条一致,零偏差** | ✅ 100% | +| Java 规则覆盖率 | **269/269 种(100%)** | ✅ 7/7 类满覆盖 | +| JSP 规则覆盖率 | **10/10 种(100%)** | ✅ 全覆盖 | +| 规则总覆盖率 | **279/279 种(100%)** | ✅ 全覆盖 | +| 解析错误 | **0 处** | ✅ | +| 静态诊断总数 | 1819 条(PMD 1813 + ESLint 6) | — | + +**实测完全达成全覆盖基准**:演示工程全部 26 个文件(23 Java + 3 JSP)的插件报告,共 1813 条 PMD 静态诊断与独立基线**规则名、行号逐条完全一致**,零误报、零漏报、零解析错误;Java 269 条与 JSP 10 条内置规则**全部触发**,两类规则集均达 100% 覆盖。**PMD 适配器静态分析链路(规则加载、Java/JSP 双语言路由、scriptlet 包装、诊断映射、辅助 classpath 自动解析)验证通过。** + +--- + +## 二、逐文件比对(实测 vs 基线) + +**Java 23 份**(基线 = PMD 7.26.0 + `pmd-java-ruleset.xml`;★ 为启用辅助 classpath 后复测的文件): + +| 文件 | 实测 | 基线 | 一致性 | 说明 | +|---|---:|---:|---|---| +| `DesignErrorProne.java` | 762 | 762 | ✅ 逐条一致 | 单文件最大(design + errorprone 主样例) | +| `BestPracticesCodeStyle.java` | 517 | 517 | ✅ 逐条一致 | bestpractices + codestyle 主样例 | +| `MultiPerfSecurity.java` | 190 | 190 | ✅ 逐条一致 | multithreading + performance + security 样例 | +| `GodClassDemo.java` | 79 | 79 | ✅ 逐条一致 | design 类规则样例 | +| `JUnit4RulesTest.java` ★ | 67 | 67 | ✅ 逐条一致 | JUnit4 相关规则样例(classpath 后 +16) | +| `AccessorAndIpDemo.java` | 14 | 14 | ✅ 逐条一致 | 访问器 + 硬编码 IP 样例 | +| `JUnit3RulesTest.java` | 15 | 15 | ✅ 逐条一致 | JUnit3 相关规则样例 | +| `AccessorDemo.java` | 12 | 12 | ✅ 逐条一致 | 访问器生成样例 | +| `FileItemDemo.java` | 12 | 12 | ✅ 逐条一致 | commons-fileupload 样例 | +| `AssertStmtTest.java` | 10 | 10 | ✅ 逐条一致 | 断言语句样例 | +| `LoggerDemo.java` ★ | 11 | 11 | ✅ 逐条一致 | 日志调用样例(classpath 后 +1) | +| `AccessorGen2.java` | 11 | 11 | ✅ 逐条一致 | 内部类访问器样例 | +| `StaticEJBFieldDemo.java` | 9 | 9 | ✅ 逐条一致 | EJB 静态字段样例 | +| `JUnit5RulesTest.java` | 9 | 9 | ✅ 逐条一致 | JUnit5 相关规则样例 | +| `JUnit5ArgOrderTest.java` ★ | 9 | 9 | ✅ 逐条一致 | 断言参数顺序样例(classpath 后 +2) | +| `EJBNamingDemo.java` | 8 | 8 | ✅ 逐条一致 | EJB 命名样例 | +| `AfterBeforeTest.java` | 7 | 7 | ✅ 逐条一致 | setUp/tearDown 样例 | +| `CallSuperDemo.java` | 7 | 7 | ✅ 逐条一致 | CallSuper 样例 | +| `InvalidBeanDemo.java` | 7 | 7 | ✅ 逐条一致 | JavaBean 规范样例 | +| `ApiService.java` | 2 | 2 | ✅ 逐条一致 | 接口设计样例 | +| `NoPackageDemo.java` | 4 | 4 | ✅ 逐条一致 | 无包声明样例 | +| `PackageCaseDemo.java` | 4 | 4 | ✅ 逐条一致 | 包命名规范样例 | +| `LoosePackageCouplingDemo.java` | 3 | 3 | ✅ 逐条一致 | 包耦合度样例 | +| **Java 合计** | **1769** | **1769** | **✅ 零偏差** | — | + +> ★ 三份复测说明:`JUnit4RulesTest` / `JUnit5ArgOrderTest` / `LoggerDemo` 首轮以无 classpath 模式测得 51 / 7 / 10 条(与 noaux 基线逐条一致);辅助 classpath 生效后复测为 67 / 9 / 11 条(与 aux 基线逐条一致),新增的 19 条全部来自 4 个类型解析规则(见第三节)。两轮均零偏差。 + +**JSP 3 份**(基线 = 三层架构逐层复现,见第四节): + +| 文件 | PMD 实测 | PMD 基线 | ESLint | 一致性 | +|---|---:|---:|---:|---| +| `JspFix.jsp` | 35 | 35 | 3 | ✅ 逐条一致 | +| `DemoJsp.jsp` | 9 | 9 | 3 | ✅ 逐条一致 | +| `SecurityDemo.jsp` | 0 | 0 | 0 | ✅ 一致(无 scriptlet/script,三层均无输出) | +| **JSP 合计** | **44** | **44** | **6** | **✅ 零偏差** | + +> 比对方法:将插件报告中的每条静态诊断(规则名 + 行号)与基线做多重集合比对;26 个文件全部 `missing = 0`、`extra = 0`。 + +--- + +## 三、覆盖率分布与最后 4 条规则的达成 + +**Java 规则集按类别**(269 条,7 类,全部满覆盖): + +| 类别 | 总数 | 已覆盖 | 覆盖率 | +|---|---:|---:|---:| +| Error Prone | 90 | 90 | 100% | +| Best Practices | 58 | 58 | 100% | +| Code Style | 57 | 57 | 100% | +| Design | 29 | 29 | 100% | +| Performance | 24 | 24 | 100% | +| Multithreading | 9 | 9 | 100% | +| Security | 2 | 2 | 100% | +| **合计** | **269** | **269** | **100%** | + +**JSP 规则集**:bestpractices / codestyle / design / errorprone 四类共 10 条全部触发(`JspFix` 贡献 6 种、`DemoJsp` 贡献 6 种,并集 10/10)。 + +**最后 4 条规则的两阶段达成过程**: + +| 规则 | 类别 | 触发依赖 | 达成方式 | +|---|---|---|---| +| `UnitTestAssertionsShouldIncludeMessage` | Best Practices | JUnit `assertEquals` 类型解析 | classpath 后 `JUnit4RulesTest` +15、`JUnit5ArgOrderTest` +1 | +| `SimplifiableTestAssertion` | Best Practices | JUnit 断言 API 类型解析 | classpath 后 `JUnit4RulesTest` +1 | +| `AssertEqualsArgumentOrder` | Error Prone | JUnit `assertEquals` 签名解析 | classpath 后 `JUnit5ArgOrderTest` +1 | +| `UseCorrectExceptionLogging` | Error Prone | commons-logging `Logger` 类型解析 | classpath 后 `LoggerDemo` +1 | + +该 4 条规则依赖**辅助 classpath 的类型解析**,触发条件是工程根有 `pom.xml`/`build.gradle` 且插件成功解析依赖。演示工程 `pom.xml` 声明了 junit 4.13.2、junit-jupiter-api 5.10.2、commons-logging 1.3.4、slf4j-api 2.0.16(恰为 4 条规则所需),配合 `mvnw` 包装器在复测轮成功解析依赖后全部触发。 + +--- + +## 四、JSP 三层架构验证 + +插件对 `.jsp` 文件采用三层分析(`src/adapters/jsp.ts`),本次全部逐层复现: + +1. **层 1 · PMD JSP 规则集**:整文件跑 `pmd-jsp-ruleset.xml`(10 条规则); +2. **层 2 · scriptlet 包装**:`<% %>`/`<%! %>`/`<%= %>` 分别按 statement/declaration/expression 三种模板包装成合法 Java 类,跑 Java 规则集,行号经 headerLines 偏移精确映射回原文件(`JspFix` 的 28 条 scriptlet 诊断零行号误差); +3. **层 3 · ESLint**:` + +<%-- NoInlineStyleInformation:内联样式 --%> +

Bold inline style Font inline style

+
Inline style
+ +<%-- NoHtmlComments:HTML 注释太少,占位 --%> +

Content

+ +<%-- DontNestJsfInJstlIteration:占位 --%> + + + + +<%-- NoClassAttribute:占位 --%> +

Class attribute

+ +<%-- NoJspForward:占位 --%> +<%-- DuplicateJspImports:重复导入 --%> +<%@ page import="java.util.List" %> +<%@ page import="java.util.List" %> + +<%-- JspEncoding:页面编码 --%> +

End

+ + \ No newline at end of file diff --git a/data/demo-pmd/src/jsp/JspFix.jsp b/data/demo-pmd/src/jsp/JspFix.jsp new file mode 100644 index 0000000..47378bd --- /dev/null +++ b/data/demo-pmd/src/jsp/JspFix.jsp @@ -0,0 +1,64 @@ +<%-- + "pageEncoding" deliberately omitted to trigger JspEncoding +--%> +<%@ page contentType="text/html" %> + +JSP Fix Demo +<%-- NoInlineScript:内联脚本 --%> + + + +<%-- NoHtmlComments:HTML 注释(非 JSP 注释)--%> + +
inline style
+<%-- NoScriptlets:scriptlet --%> +<% + int x = 1; + int y = 2; + int z = x + y; + out.println(z); +%> +<%-- NoJspForward:转发操作 --%> + +<%-- NoLongScripts:长 scriptlet --%> +<% + int a = 1; + int b = 2; + int c = 3; + int d = 4; + int e = 5; + int f = 6; + int g = 7; + int h = 8; + int i2 = 9; + int j2 = 10; + int k = 11; + int l = 12; + int m = 13; + int n = 14; + int o = 15; + int p = 16; + int q = 17; + int r = 18; + int s2 = 19; + int t = 20; + int u = 21; + int v = 22; + int w = 23; + int xx = 24; + int yy = 25; + out.println(xx + yy); +%> + + \ No newline at end of file diff --git a/data/demo-pmd/src/jsp/SecurityDemo.jsp b/data/demo-pmd/src/jsp/SecurityDemo.jsp new file mode 100644 index 0000000..80c1f4e --- /dev/null +++ b/data/demo-pmd/src/jsp/SecurityDemo.jsp @@ -0,0 +1,23 @@ +<%@ page contentType="text/html; charset=UTF-8" %> +<%-- ============================================================ + PMD 演示样例 — JSP security 分类规则 + (对应 pmd-jsp-ruleset.xml 的 category/jsp/security.xml) + ============================================================ --%> + + + JSP Security Demo + + +<%-- IframeMissingSrcAttribute:iframe 缺少 src 属性 --%> + + + +<%-- NoUnsanitizedJSPExpression:未转义的 EL 表达式直接输出,存在 XSS 风险 --%> +

Hello, ${userInput}

+

Search: ${searchTerm}

+ +<%-- 对照组:正确写法(转义 / 带 src 的 iframe),不应触发规则 --%> +

Safe:

+ + + diff --git a/data/demo-pmd/src/nopackage/NoPackageDemo.java b/data/demo-pmd/src/nopackage/NoPackageDemo.java new file mode 100644 index 0000000..00024c8 --- /dev/null +++ b/data/demo-pmd/src/nopackage/NoPackageDemo.java @@ -0,0 +1,10 @@ +// ============================================================ +// PMD 演示样例 — NoPackage:所有类型必须属于命名包 +// 本文件故意没有 package 声明 +// ============================================================ + +class NoPackageClass { + void m() { + System.out.println("no package"); + } +} \ No newline at end of file diff --git a/data/demo-pmd/src/org/example/beans/InvalidBeanDemo.java b/data/demo-pmd/src/org/example/beans/InvalidBeanDemo.java new file mode 100644 index 0000000..c58ede1 --- /dev/null +++ b/data/demo-pmd/src/org/example/beans/InvalidBeanDemo.java @@ -0,0 +1,32 @@ +// ============================================================ +// PMD 演示样例 — Design 剩余规则补齐 +// ============================================================ +package org.example.beans; + +// 133 InvalidJavaBean:Bean 非法(不可序列化、缺 setter) +public class MyBean { + private String label; // 缺 setter + + public String getLabel() { + return label; + } +} + +// 121 AvoidThrowingNewInstanceOfSameException +class WrapException { + void bar() { + try { + doWork(); + } catch (IllegalStateException se) { + throw new IllegalStateException(se); // 包装相同异常类型 + } + } + void doWork() { + } +} + +class BeansMain { + public static void main(String[] args) { + System.out.println("demo beans"); + } +} \ No newline at end of file diff --git a/data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md b/data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md index c747d4c..fa704bd 100644 --- a/data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md +++ b/data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md @@ -137,12 +137,6 @@ const endPos = (v.end_line_pos ?? v.start_line_pos) - 1; 3. ✅ 插件缺陷闭环:JJ01 行号 LNaN → 修复 → 复测验证 L2(发现、定位、修复、验证全流程完成) 4. ✅ 「内置配置回退」路径验证通过(工程无 `.sqlfluff` 配置文件场景) -**后续建议**: - -- ~~插件侧修复 JJ01~~(✅ 已完成并验证) -- **其他工程**:`demo-pmd` 按同样方法实测(先本地基线复现 → 实测逐条比对),注意 Java 版本与 ruleset -- **可选**:若需验证「工程配置优先」路径,可在工程根添加 `.sqlfluff` 配置文件复测(预期插件改用工程配置) - --- *报告生成于 2026-08-25 · demo-sqlfluff 插件实测 · 比对脚本:`sqlfluff-final-compare.mjs` · 数据:`sqlfluff-final-compare.json`* diff --git a/data/demo-stylelint/reports/demo-stylelint-coverage-report.md b/data/demo-stylelint/reports/demo-stylelint-coverage-report.md index 5efa09c..854e68c 100644 --- a/data/demo-stylelint/reports/demo-stylelint-coverage-report.md +++ b/data/demo-stylelint/reports/demo-stylelint-coverage-report.md @@ -113,17 +113,6 @@ 3. ✅ 「内置配置回退」路径完整验证(工程无 `.stylelintrc` 场景) 4. ✅ 零缺陷(对照 SQLFlutt 发现的 JJ01 NaN 问题,Stylelint 适配器的 endLine 回退写法正确) -**实测进度总览**(四个 demo 工程): - -| 工程 | 实测状态 | 结果 | -|---|---|---| -| demo-eslint | ✅ 完成 | 126/126 种 · 292/292 条逐条一致 | -| demo-sqlfluff | ✅ 完成 | 57/57 种 · 113 处(112 条零偏差 + JJ01 行号显示缺陷) | -| demo-stylelint | ✅ 完成 | **68/68 种 · 145/145 条逐条零偏差** | -| demo-pmd | ⏳ 待实测 | 预期 281 条规则(Java 269 + JSP 12),注意 Java 版本与 ruleset | - -**后续建议**:仅剩 `demo-pmd` 待实测——测试机需 JDK 8+(插件用 PmdRunner.class 直跑,无沙箱 JDK 11 限制),打开 Java/JSP 样例文件后与预期基线比对即可,全套四工程验证收官。 - --- *报告生成于 2026-08-25 · demo-stylelint 插件实测 · 比对脚本:`stylelint-compare.mjs` · 数据:`stylelint-final-compare.json`* diff --git a/src/services/auxClasspath.ts b/src/services/auxClasspath.ts index 6a130bf..e497e75 100644 --- a/src/services/auxClasspath.ts +++ b/src/services/auxClasspath.ts @@ -157,6 +157,13 @@ export class AuxClasspathResolver { return systemName; } + private quoteCmdArg(arg: string): string { + if (/^[\w.,:=/@%\\+-]+$/.test(arg)) { + return arg; + } + return `"${arg.replace(/"/g, '""')}"`; + } + private lastNonEmptyLine(output: string): string { const lines = output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0); return lines.length > 0 ? lines[lines.length - 1] : ''; @@ -174,7 +181,16 @@ export class AuxClasspathResolver { reject(new Error(`Command timed out after ${BUILD_TIMEOUT}ms: ${cmd}`)); }, BUILD_TIMEOUT); try { - proc = spawn(cmd, args, { cwd, windowsHide: true }); + if (isWindows() && /\.(cmd|bat)$/i.test(cmd)) { + const inner = `${this.quoteCmdArg(cmd)} ${args.map((arg) => this.quoteCmdArg(arg)).join(' ')}`; + proc = spawn('cmd.exe', ['/d', '/s', '/c', `"${inner}"`], { + cwd, + windowsHide: true, + windowsVerbatimArguments: true, + }); + } else { + proc = spawn(cmd, args, { cwd, windowsHide: true }); + } } catch (err) { clearTimeout(timer); reject(err);