pi-usereq 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.g.conf +20 -0
- package/.github/workflows/release-npm.yml +131 -0
- package/.gitignore +270 -0
- package/CHANGELOG.md +221 -0
- package/LICENSE +674 -0
- package/README.md +260 -0
- package/TODO.md +20 -0
- package/docs/pi.dev/agent-document-manifest.json +6399 -0
- package/docs/pi.dev/coding-agent-docs/compaction.md +394 -0
- package/docs/pi.dev/coding-agent-docs/custom-provider.md +596 -0
- package/docs/pi.dev/coding-agent-docs/development.md +71 -0
- package/docs/pi.dev/coding-agent-docs/extensions.md +2262 -0
- package/docs/pi.dev/coding-agent-docs/images/doom-extension.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/exy.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/interactive-mode.png +0 -0
- package/docs/pi.dev/coding-agent-docs/images/tree-view.png +0 -0
- package/docs/pi.dev/coding-agent-docs/json.md +82 -0
- package/docs/pi.dev/coding-agent-docs/keybindings.md +175 -0
- package/docs/pi.dev/coding-agent-docs/models.md +392 -0
- package/docs/pi.dev/coding-agent-docs/packages.md +218 -0
- package/docs/pi.dev/coding-agent-docs/prompt-templates.md +67 -0
- package/docs/pi.dev/coding-agent-docs/providers.md +195 -0
- package/docs/pi.dev/coding-agent-docs/rpc.md +1377 -0
- package/docs/pi.dev/coding-agent-docs/sdk.md +1124 -0
- package/docs/pi.dev/coding-agent-docs/session.md +412 -0
- package/docs/pi.dev/coding-agent-docs/settings.md +247 -0
- package/docs/pi.dev/coding-agent-docs/shell-aliases.md +13 -0
- package/docs/pi.dev/coding-agent-docs/skills.md +232 -0
- package/docs/pi.dev/coding-agent-docs/terminal-setup.md +106 -0
- package/docs/pi.dev/coding-agent-docs/termux.md +127 -0
- package/docs/pi.dev/coding-agent-docs/themes.md +295 -0
- package/docs/pi.dev/coding-agent-docs/tmux.md +61 -0
- package/docs/pi.dev/coding-agent-docs/tree.md +231 -0
- package/docs/pi.dev/coding-agent-docs/tui.md +887 -0
- package/docs/pi.dev/coding-agent-docs/windows.md +17 -0
- package/docs/pi.dev/mom-docs/artifacts-server.md +475 -0
- package/docs/pi.dev/mom-docs/events.md +307 -0
- package/docs/pi.dev/mom-docs/new.md +970 -0
- package/docs/pi.dev/mom-docs/sandbox.md +153 -0
- package/docs/pi.dev/mom-docs/slack-bot-minimal-guide.md +399 -0
- package/docs/pi.dev/mom-docs/v86.md +319 -0
- package/docs/pi.dev/pods-docs/gml-4.5.md +189 -0
- package/docs/pi.dev/pods-docs/gpt-oss.md +233 -0
- package/docs/pi.dev/pods-docs/implementation-plan.md +183 -0
- package/docs/pi.dev/pods-docs/kimi-k2.md +197 -0
- package/docs/pi.dev/pods-docs/models.md +116 -0
- package/docs/pi.dev/pods-docs/plan.md +166 -0
- package/docs/pi.dev/pods-docs/qwen3-coder.md +132 -0
- package/images/flowchart-bw.png +0 -0
- package/images/flowchart-bw.svg +102 -0
- package/images/flowchart.md +100 -0
- package/images/flowchart.png +0 -0
- package/images/flowchart.svg +3 -0
- package/package.json +46 -0
- package/req/docs/REFERENCES.md +4554 -0
- package/req/docs/REQUIREMENTS.md +475 -0
- package/req/docs/WORKFLOW.md +1059 -0
- package/scripts/debug-extension.ts +497 -0
- package/scripts/lib/extension-debug-harness.ts +450 -0
- package/scripts/lib/recording-extension-api.ts +786 -0
- package/scripts/lib/sdk-smoke.ts +503 -0
- package/scripts/pi-usereq-debug.sh +330 -0
- package/scripts/tool-args-to-params.ts +208 -0
- package/src/cli.ts +349 -0
- package/src/core/agent-tool-json.ts +621 -0
- package/src/core/compress-files.ts +72 -0
- package/src/core/compress-payload.ts +648 -0
- package/src/core/compress.ts +464 -0
- package/src/core/config.ts +272 -0
- package/src/core/doxygen-parser.ts +318 -0
- package/src/core/errors.ts +31 -0
- package/src/core/extension-status.ts +660 -0
- package/src/core/find-constructs.ts +319 -0
- package/src/core/find-payload.ts +915 -0
- package/src/core/generate-markdown.ts +120 -0
- package/src/core/path-context.ts +196 -0
- package/src/core/pi-notify.ts +430 -0
- package/src/core/pi-usereq-tools.ts +140 -0
- package/src/core/prompts.ts +184 -0
- package/src/core/reference-payload.ts +818 -0
- package/src/core/resources.ts +63 -0
- package/src/core/runtime-project-paths.ts +99 -0
- package/src/core/settings-menu.ts +233 -0
- package/src/core/source-analyzer.ts +1721 -0
- package/src/core/static-check.ts +674 -0
- package/src/core/token-counter.ts +729 -0
- package/src/core/tool-runner.ts +717 -0
- package/src/core/utils.ts +185 -0
- package/src/index.ts +2209 -0
- package/src/resources/guidelines/Google_C++_Style_Guide.md +3711 -0
- package/src/resources/guidelines/Google_Python_Style_Guide.md +3709 -0
- package/src/resources/prompts/analyze.md +130 -0
- package/src/resources/prompts/change.md +227 -0
- package/src/resources/prompts/check.md +139 -0
- package/src/resources/prompts/cover.md +219 -0
- package/src/resources/prompts/create.md +104 -0
- package/src/resources/prompts/fix.md +221 -0
- package/src/resources/prompts/flowchart.md +220 -0
- package/src/resources/prompts/implement.md +163 -0
- package/src/resources/prompts/new.md +226 -0
- package/src/resources/prompts/readme.md +182 -0
- package/src/resources/prompts/recreate.md +213 -0
- package/src/resources/prompts/refactor.md +213 -0
- package/src/resources/prompts/references.md +100 -0
- package/src/resources/prompts/renumber.md +119 -0
- package/src/resources/prompts/workflow.md +202 -0
- package/src/resources/prompts/write.md +99 -0
- package/src/resources/sounds/Machine-alert-beep-sound-effect.mp3 +0 -0
- package/src/resources/sounds/Soft-high-tech-notification-sound-effect.mp3 +0 -0
- package/src/resources/templates/Document_Source_Code_in_Doxygen_Style.md +130 -0
- package/src/resources/templates/HDT_Test_Authoring_Guide.md +318 -0
- package/src/resources/templates/Requirements_Template.md +78 -0
- package/tests/attended-results-scenarios.ts +758 -0
- package/tests/attended-results.test.ts +39 -0
- package/tests/cli-command-option-parity.test.ts +815 -0
- package/tests/debug-extension-harness.test.ts +463 -0
- package/tests/extension-registration.test.ts +2006 -0
- package/tests/fixtures/fixture_c.c +361 -0
- package/tests/fixtures/fixture_cpp.cpp +407 -0
- package/tests/fixtures/fixture_csharp.cs +411 -0
- package/tests/fixtures/fixture_elixir.ex +409 -0
- package/tests/fixtures/fixture_go.go +341 -0
- package/tests/fixtures/fixture_haskell.hs +250 -0
- package/tests/fixtures/fixture_java.java +430 -0
- package/tests/fixtures/fixture_javascript.js +383 -0
- package/tests/fixtures/fixture_kotlin.kt +451 -0
- package/tests/fixtures/fixture_lua.lua +276 -0
- package/tests/fixtures/fixture_perl.pl +310 -0
- package/tests/fixtures/fixture_php.php +433 -0
- package/tests/fixtures/fixture_python.py +502 -0
- package/tests/fixtures/fixture_ruby.rb +345 -0
- package/tests/fixtures/fixture_rust.rs +380 -0
- package/tests/fixtures/fixture_scala.scala +398 -0
- package/tests/fixtures/fixture_shell.sh +276 -0
- package/tests/fixtures/fixture_swift.swift +397 -0
- package/tests/fixtures/fixture_typescript.ts +434 -0
- package/tests/fixtures/fixture_zig.zig +295 -0
- package/tests/fixtures_attended_results/project/compress-line-numbers.json +5 -0
- package/tests/fixtures_attended_results/project/compress.json +5 -0
- package/tests/fixtures_attended_results/project/enable-static-check-invalid-command.json +5 -0
- package/tests/fixtures_attended_results/project/enable-static-check-valid.json +5 -0
- package/tests/fixtures_attended_results/project/files-static-check.json +5 -0
- package/tests/fixtures_attended_results/project/find-line-numbers.json +5 -0
- package/tests/fixtures_attended_results/project/find.json +5 -0
- package/tests/fixtures_attended_results/project/get-base-path.json +5 -0
- package/tests/fixtures_attended_results/project/git-check-clean.json +5 -0
- package/tests/fixtures_attended_results/project/git-check-dirty.json +5 -0
- package/tests/fixtures_attended_results/project/git-path.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-create-invalid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-create-valid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-delete-nonexistent.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-delete-valid.json +5 -0
- package/tests/fixtures_attended_results/project/git-wt-name.json +5 -0
- package/tests/fixtures_attended_results/project/references.json +5 -0
- package/tests/fixtures_attended_results/project/static-check.json +5 -0
- package/tests/fixtures_attended_results/project/tokens.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-compress-line-numbers/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-find-line-numbers/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-references/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/files-tokens/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-command/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-dummy/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_zig.zig.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_c.c.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_cpp.cpp.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_csharp.cs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_elixir.ex.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_go.go.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_haskell.hs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_java.java.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_javascript.js.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_kotlin.kt.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_lua.lua.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_perl.pl.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_php.php.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_python.py.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_ruby.rb.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_rust.rs.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_scala.scala.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_shell.sh.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_swift.swift.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_typescript.ts.json +5 -0
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_zig.zig.json +5 -0
- package/tests/helpers.ts +204 -0
- package/tests/oracle-project.test.ts +63 -0
- package/tests/oracle-standalone.test.ts +48 -0
- package/tests/prompt-rendering.test.ts +66 -0
- package/tests/release-workflow.test.ts +133 -0
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* @brief Defines static-check language mappings and checker dispatch implementations.
|
|
4
|
+
* @details Parses static-check configuration syntax, resolves file targets, and runs built-in or command-based analyzers such as Pylance and Ruff. Runtime is linear in file count plus external tool cost. Side effects include filesystem reads, PATH probing, process spawning, and console output.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import process from "node:process";
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import fg from "fast-glob";
|
|
12
|
+
import type { StaticCheckEntry } from "./config.js";
|
|
13
|
+
import { ReqError } from "./errors.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @brief Maps user-facing language aliases to canonical static-check language names.
|
|
17
|
+
* @details Accepts multiple spellings for the same language so config parsing can stay case-insensitive and permissive. Lookup complexity is O(1).
|
|
18
|
+
*/
|
|
19
|
+
export const STATIC_CHECK_LANG_CANONICAL: Record<string, string> = {
|
|
20
|
+
python: "Python",
|
|
21
|
+
c: "C",
|
|
22
|
+
"c++": "C++",
|
|
23
|
+
cpp: "C++",
|
|
24
|
+
"c#": "C#",
|
|
25
|
+
csharp: "C#",
|
|
26
|
+
rust: "Rust",
|
|
27
|
+
javascript: "JavaScript",
|
|
28
|
+
js: "JavaScript",
|
|
29
|
+
typescript: "TypeScript",
|
|
30
|
+
ts: "TypeScript",
|
|
31
|
+
java: "Java",
|
|
32
|
+
go: "Go",
|
|
33
|
+
ruby: "Ruby",
|
|
34
|
+
php: "PHP",
|
|
35
|
+
swift: "Swift",
|
|
36
|
+
kotlin: "Kotlin",
|
|
37
|
+
scala: "Scala",
|
|
38
|
+
lua: "Lua",
|
|
39
|
+
shell: "Shell",
|
|
40
|
+
sh: "Shell",
|
|
41
|
+
perl: "Perl",
|
|
42
|
+
haskell: "Haskell",
|
|
43
|
+
zig: "Zig",
|
|
44
|
+
elixir: "Elixir",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @brief Maps file extensions to canonical static-check language names.
|
|
49
|
+
* @details Used by tool runners to decide which configured analyzers apply to a file. Lookup complexity is O(1).
|
|
50
|
+
*/
|
|
51
|
+
export const STATIC_CHECK_EXT_TO_LANG: Record<string, string> = {
|
|
52
|
+
".py": "Python",
|
|
53
|
+
".c": "C",
|
|
54
|
+
".cpp": "C++",
|
|
55
|
+
".cs": "C#",
|
|
56
|
+
".rs": "Rust",
|
|
57
|
+
".js": "JavaScript",
|
|
58
|
+
".mjs": "JavaScript",
|
|
59
|
+
".ts": "TypeScript",
|
|
60
|
+
".java": "Java",
|
|
61
|
+
".go": "Go",
|
|
62
|
+
".rb": "Ruby",
|
|
63
|
+
".php": "PHP",
|
|
64
|
+
".swift": "Swift",
|
|
65
|
+
".kt": "Kotlin",
|
|
66
|
+
".scala": "Scala",
|
|
67
|
+
".lua": "Lua",
|
|
68
|
+
".sh": "Shell",
|
|
69
|
+
".pl": "Perl",
|
|
70
|
+
".hs": "Haskell",
|
|
71
|
+
".zig": "Zig",
|
|
72
|
+
".ex": "Elixir",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @brief Lists the built-in static-check module identifiers.
|
|
77
|
+
* @details The tuple constrains configuration parsing and menu rendering to supported checker implementations. Access complexity is O(1).
|
|
78
|
+
*/
|
|
79
|
+
export const STATIC_CHECK_MODULES = ["Dummy", "Pylance", "Ruff", "Command"] as const;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @brief Describes supported extensions for one canonical static-check language.
|
|
83
|
+
* @details The interface is used for UI rendering and capability reporting only. It is compile-time only and adds no runtime cost.
|
|
84
|
+
*/
|
|
85
|
+
export interface StaticCheckLanguageSupport {
|
|
86
|
+
language: string;
|
|
87
|
+
extensions: string[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @brief Maps case-insensitive module names to canonical module identifiers.
|
|
92
|
+
* @details Enables permissive user input while keeping downstream dispatch logic deterministic. Lookup complexity is O(1).
|
|
93
|
+
*/
|
|
94
|
+
const CANONICAL_MODULES: Record<string, (typeof STATIC_CHECK_MODULES)[number]> = {
|
|
95
|
+
dummy: "Dummy",
|
|
96
|
+
pylance: "Pylance",
|
|
97
|
+
ruff: "Ruff",
|
|
98
|
+
command: "Command",
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @brief Returns the sorted list of canonical languages with extension support.
|
|
103
|
+
* @details Deduplicates the extension map values and sorts them alphabetically for stable UI and error messages. Runtime is O(n log n). No side effects occur.
|
|
104
|
+
* @return {string[]} Sorted canonical language names.
|
|
105
|
+
*/
|
|
106
|
+
export function getSupportedStaticCheckLanguages(): string[] {
|
|
107
|
+
return [...new Set(Object.values(STATIC_CHECK_EXT_TO_LANG))].sort((left, right) => left.localeCompare(right));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @brief Returns supported languages paired with their known file extensions.
|
|
112
|
+
* @details Groups extensions by canonical language and emits alphabetically sorted extension lists. Runtime is O(n log n). No external state is mutated.
|
|
113
|
+
* @return {StaticCheckLanguageSupport[]} Sorted language-support descriptors.
|
|
114
|
+
*/
|
|
115
|
+
export function getSupportedStaticCheckLanguageSupport(): StaticCheckLanguageSupport[] {
|
|
116
|
+
const extensionsByLanguage = new Map<string, string[]>();
|
|
117
|
+
for (const [extension, language] of Object.entries(STATIC_CHECK_EXT_TO_LANG)) {
|
|
118
|
+
const extensions = extensionsByLanguage.get(language) ?? [];
|
|
119
|
+
extensions.push(extension);
|
|
120
|
+
extensionsByLanguage.set(language, extensions);
|
|
121
|
+
}
|
|
122
|
+
return getSupportedStaticCheckLanguages().map((language) => ({
|
|
123
|
+
language,
|
|
124
|
+
extensions: [...(extensionsByLanguage.get(language) ?? [])].sort((left, right) => left.localeCompare(right)),
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @brief Formats the supported module list for diagnostics.
|
|
130
|
+
* @details Joins `STATIC_CHECK_MODULES` with commas for direct insertion into error strings. Time complexity is O(n). No side effects occur.
|
|
131
|
+
* @return {string} Comma-delimited module names.
|
|
132
|
+
*/
|
|
133
|
+
function formatStaticCheckModules(): string {
|
|
134
|
+
return STATIC_CHECK_MODULES.join(", ");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @brief Splits a comma-delimited static-check specification while honoring quotes.
|
|
139
|
+
* @details Performs a single pass over the right-hand side of `LANG=...`, preserving commas inside quoted segments. Runtime is O(n). No side effects occur.
|
|
140
|
+
* @param[in] specRhs {string} Right-hand side of the enable-static-check specification.
|
|
141
|
+
* @return {string[]} Parsed tokens with surrounding whitespace trimmed.
|
|
142
|
+
*/
|
|
143
|
+
function splitCsvLikeTokens(specRhs: string): string[] {
|
|
144
|
+
const tokens: string[] = [];
|
|
145
|
+
let current = "";
|
|
146
|
+
let activeQuote: string | undefined;
|
|
147
|
+
for (const ch of specRhs) {
|
|
148
|
+
if (!activeQuote) {
|
|
149
|
+
if (ch === '"' || ch === "'") {
|
|
150
|
+
activeQuote = ch;
|
|
151
|
+
} else if (ch === ",") {
|
|
152
|
+
tokens.push(current.trim());
|
|
153
|
+
current = "";
|
|
154
|
+
} else {
|
|
155
|
+
current += ch;
|
|
156
|
+
}
|
|
157
|
+
} else if (ch === activeQuote) {
|
|
158
|
+
activeQuote = undefined;
|
|
159
|
+
} else {
|
|
160
|
+
current += ch;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
tokens.push(current.trim());
|
|
164
|
+
return tokens;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @brief Parses one `LANG=MODULE[,CMD[,PARAM...]]` static-check specification.
|
|
169
|
+
* @details Validates the language alias, canonicalizes the module name, enforces module-specific argument requirements, and returns a config entry ready for persistence. Runtime is O(n) in specification length. No external state is mutated.
|
|
170
|
+
* @param[in] spec {string} Raw static-check specification string.
|
|
171
|
+
* @return {[string, StaticCheckEntry]} Tuple of canonical language name and normalized checker configuration.
|
|
172
|
+
* @throws {ReqError} Throws for missing separators, unknown languages, unknown modules, or missing required command arguments.
|
|
173
|
+
*/
|
|
174
|
+
export function parseEnableStaticCheck(spec: string): [string, StaticCheckEntry] {
|
|
175
|
+
if (!spec.includes("=")) {
|
|
176
|
+
throw new ReqError(
|
|
177
|
+
"Error: --enable-static-check requires format LANG=MODULE[,CMD[,PARAM...]]; missing '=' separator.",
|
|
178
|
+
1,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const [langRaw, rest] = spec.split(/=(.*)/s, 2) as [string, string];
|
|
182
|
+
const langKey = langRaw.trim().toLowerCase();
|
|
183
|
+
if (!(langKey in STATIC_CHECK_LANG_CANONICAL)) {
|
|
184
|
+
const valid = [...new Set(Object.values(STATIC_CHECK_LANG_CANONICAL))].sort((a, b) => a.localeCompare(b));
|
|
185
|
+
throw new ReqError(
|
|
186
|
+
`Error: unknown language '${langRaw.trim()}' in --enable-static-check. Valid language names (case-insensitive): ${valid.join(", ")}`,
|
|
187
|
+
1,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const canonicalLang = STATIC_CHECK_LANG_CANONICAL[langKey]!;
|
|
191
|
+
const parts = splitCsvLikeTokens(rest);
|
|
192
|
+
if (parts.length === 0 || !parts[0]?.trim()) {
|
|
193
|
+
throw new ReqError(
|
|
194
|
+
`Error: --enable-static-check requires MODULE after '='. Valid modules (case-insensitive): ${formatStaticCheckModules()}`,
|
|
195
|
+
1,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const moduleRaw = parts[0]!.trim();
|
|
199
|
+
const moduleKey = moduleRaw.toLowerCase();
|
|
200
|
+
if (!(moduleKey in CANONICAL_MODULES)) {
|
|
201
|
+
throw new ReqError(
|
|
202
|
+
`Error: unknown module '${moduleRaw}' in --enable-static-check. Valid modules (case-insensitive): ${formatStaticCheckModules()}`,
|
|
203
|
+
1,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
const moduleName = CANONICAL_MODULES[moduleKey]!;
|
|
207
|
+
const remaining = parts.slice(1).map((value) => value.trim()).filter(Boolean);
|
|
208
|
+
const config: StaticCheckEntry = { module: moduleName };
|
|
209
|
+
if (moduleName === "Command") {
|
|
210
|
+
if (remaining.length === 0) {
|
|
211
|
+
throw new ReqError(
|
|
212
|
+
"Error: Command module requires a cmd argument in --enable-static-check. Format: LANG=Command,CMD[,PARAM...]",
|
|
213
|
+
1,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
config.cmd = remaining[0]!;
|
|
217
|
+
if (remaining.length > 1) config.params = remaining.slice(1);
|
|
218
|
+
} else if (remaining.length > 0) {
|
|
219
|
+
config.params = remaining;
|
|
220
|
+
}
|
|
221
|
+
return [canonicalLang, config];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @brief Builds the duplicate-identity token for one static-check entry.
|
|
226
|
+
* @details Canonicalizes the language key, module name, command name, and parameter list into a stable JSON tuple used for merge deduplication. Runtime is O(p) in parameter count. No side effects occur.
|
|
227
|
+
* @param[in] language {string} Canonical or alias language name associated with the entry.
|
|
228
|
+
* @param[in] entry {StaticCheckEntry} Static-check configuration entry to normalize.
|
|
229
|
+
* @return {string} Stable identity token suitable for equality comparison.
|
|
230
|
+
* @satisfies REQ-036
|
|
231
|
+
*/
|
|
232
|
+
export function buildStaticCheckEntryIdentity(language: string, entry: StaticCheckEntry): string {
|
|
233
|
+
const moduleName = String(entry.module ?? "").trim().toLowerCase();
|
|
234
|
+
const cmd = typeof entry.cmd === "string" ? entry.cmd.trim() : "";
|
|
235
|
+
const params = Array.isArray(entry.params) ? entry.params.map((value) => String(value).trim()) : [];
|
|
236
|
+
return JSON.stringify([language.trim().toLowerCase(), moduleName, cmd, params]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @brief Validates pre-persistence invariants for one static-check entry.
|
|
241
|
+
* @details Rejects `Command` entries whose executable cannot be resolved before config writes while leaving non-command modules untouched. Runtime is O(p) in PATH entry count. Side effects are limited to filesystem reads.
|
|
242
|
+
* @param[in] entry {StaticCheckEntry} Static-check configuration entry to validate.
|
|
243
|
+
* @return {void} No return value.
|
|
244
|
+
* @throws {ReqError} Throws when a `Command` entry omits `cmd` or resolves to a non-executable program.
|
|
245
|
+
* @satisfies REQ-037
|
|
246
|
+
*/
|
|
247
|
+
export function validateStaticCheckEntry(entry: StaticCheckEntry): void {
|
|
248
|
+
if (String(entry.module ?? "").trim().toLowerCase() !== "command") {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const cmd = typeof entry.cmd === "string" ? entry.cmd.trim() : "";
|
|
252
|
+
if (!cmd) {
|
|
253
|
+
throw new ReqError("Error: Command module requires a cmd argument in --enable-static-check. Format: LANG=Command,CMD[,PARAM...]", 1);
|
|
254
|
+
}
|
|
255
|
+
if (!findExecutable(cmd)) {
|
|
256
|
+
throw new ReqError(`Error: --enable-static-check Command cmd '${cmd}' is not an executable program on this system.`, 1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @brief Resolves explicit files, directories, and glob patterns into absolute file paths.
|
|
262
|
+
* @details Expands glob inputs with `fast-glob`, enumerates direct children for directory inputs, accepts regular files, and warns for invalid entries. Runtime is O(n + m) where m is the total matched path count. Side effects are filesystem reads and warning output to stderr.
|
|
263
|
+
* @param[in] inputs {string[]} Raw file, directory, or glob inputs.
|
|
264
|
+
* @return {string[]} Unique absolute file paths.
|
|
265
|
+
*/
|
|
266
|
+
function resolveFiles(inputs: string[]): string[] {
|
|
267
|
+
const resolved = new Map<string, true>();
|
|
268
|
+
for (const entry of inputs) {
|
|
269
|
+
if (/[*?[]/.test(entry)) {
|
|
270
|
+
for (const match of fg.sync(entry, { onlyFiles: true, dot: false, unique: true })) {
|
|
271
|
+
resolved.set(path.resolve(match), true);
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (fs.existsSync(entry) && fs.statSync(entry).isDirectory()) {
|
|
276
|
+
for (const child of fs.readdirSync(entry, { withFileTypes: true })) {
|
|
277
|
+
if (child.isFile()) {
|
|
278
|
+
resolved.set(path.resolve(entry, child.name), true);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (fs.existsSync(entry) && fs.statSync(entry).isFile()) {
|
|
284
|
+
resolved.set(path.resolve(entry), true);
|
|
285
|
+
} else {
|
|
286
|
+
console.error(` Warning: skipping (not found or not a file): ${entry}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return [...resolved.keys()];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @brief Provides the base implementation for file-oriented static checks.
|
|
294
|
+
* @details Resolves input files once, emits standardized headers, and defines overridable `checkFile` and `emitLine` hooks used by concrete analyzers. Runtime is O(f) plus subclass checker cost. Side effects include console output.
|
|
295
|
+
*/
|
|
296
|
+
export class StaticCheckBase {
|
|
297
|
+
static LABEL = "Dummy";
|
|
298
|
+
protected files: string[];
|
|
299
|
+
protected extraArgs: string[];
|
|
300
|
+
protected failOnly: boolean;
|
|
301
|
+
protected label: string;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @brief Initializes a base static-check runner.
|
|
305
|
+
* @details Resolves the input file set once, stores extra arguments, and derives the default label from the concrete class. Runtime is O(f) in resolved input count. Mutates instance fields only.
|
|
306
|
+
* @param[in] inputs {string[]} Raw file, directory, or glob inputs.
|
|
307
|
+
* @param[in] extraArgs {string[] | undefined} Additional checker arguments.
|
|
308
|
+
* @param[in] failOnly {boolean} When `true`, suppress successful-file output.
|
|
309
|
+
*/
|
|
310
|
+
constructor(inputs: string[], extraArgs?: string[], failOnly = false) {
|
|
311
|
+
this.extraArgs = extraArgs ?? [];
|
|
312
|
+
this.failOnly = failOnly;
|
|
313
|
+
this.files = resolveFiles(inputs);
|
|
314
|
+
this.label = (this.constructor as typeof StaticCheckBase).LABEL;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @brief Runs the checker against all resolved files.
|
|
319
|
+
* @details Iterates through `this.files`, aggregates a non-zero overall status when any file fails, and emits separator lines according to `failOnly`. Runtime is O(f) plus per-file checker cost. Side effects include console output.
|
|
320
|
+
* @return {number} Aggregate exit status where `0` means all files passed.
|
|
321
|
+
*/
|
|
322
|
+
run(): number {
|
|
323
|
+
if (this.files.length === 0) {
|
|
324
|
+
console.error(" Warning: no files resolved for static check.");
|
|
325
|
+
return 0;
|
|
326
|
+
}
|
|
327
|
+
let overall = 0;
|
|
328
|
+
for (const filePath of this.files) {
|
|
329
|
+
const rc = this.checkFile(filePath);
|
|
330
|
+
if (rc !== 0) overall = 1;
|
|
331
|
+
if (!this.failOnly || rc !== 0) this.emitLine("");
|
|
332
|
+
}
|
|
333
|
+
return overall;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @brief Formats the standard result header for one file.
|
|
338
|
+
* @details Includes the checker label and any extra arguments so diagnostic output remains self-describing. Runtime is O(a) in argument count. No side effects occur.
|
|
339
|
+
* @param[in] filePath {string} File being checked.
|
|
340
|
+
* @return {string} Standardized header line.
|
|
341
|
+
*/
|
|
342
|
+
protected headerLine(filePath: string): string {
|
|
343
|
+
const options = this.extraArgs.length > 0 ? ` [${this.extraArgs.join(" ")}]` : "";
|
|
344
|
+
return `# Static-Check(${this.label}): ${filePath}${options}`;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @brief Performs the default no-op successful check.
|
|
349
|
+
* @details Emits an OK record unless `failOnly` suppresses success output. Concrete subclasses override this method to run real analyzers. Runtime is O(1). Side effects include console output.
|
|
350
|
+
* @param[in] filePath {string} File being checked.
|
|
351
|
+
* @return {number} Always returns `0`.
|
|
352
|
+
*/
|
|
353
|
+
protected checkFile(filePath: string): number {
|
|
354
|
+
if (!this.failOnly) {
|
|
355
|
+
this.emitLine(this.headerLine(filePath));
|
|
356
|
+
this.emitLine("Result: OK");
|
|
357
|
+
}
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* @brief Emits one output line for checker reporting.
|
|
363
|
+
* @details Uses `console.log` so subclasses can override output transport if needed. Runtime is O(n) in line length. Side effect: writes to stdout.
|
|
364
|
+
* @param[in] line {string} Output line to emit.
|
|
365
|
+
* @return {void} No return value.
|
|
366
|
+
*/
|
|
367
|
+
protected emitLine(line: string): void {
|
|
368
|
+
console.log(line);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* @brief Resolves the preferred Python executable for Python-based checkers.
|
|
374
|
+
* @details Checks the project virtual environment first, then `PI_USEREQ_PYTHON`, then `python3`, then `python`, and finally falls back to the literal `python3` string. Runtime is O(c) in candidate count. Side effects are filesystem reads and PATH probing.
|
|
375
|
+
* @param[in] projectBase {string | undefined} Optional project root used to probe `.venv/bin/python`.
|
|
376
|
+
* @return {string} Executable path or command name.
|
|
377
|
+
*/
|
|
378
|
+
function detectPythonExecutable(projectBase?: string): string {
|
|
379
|
+
const candidates = [
|
|
380
|
+
projectBase ? path.join(projectBase, ".venv", "bin", "python") : undefined,
|
|
381
|
+
process.env.PI_USEREQ_PYTHON,
|
|
382
|
+
"python3",
|
|
383
|
+
"python",
|
|
384
|
+
].filter((value): value is string => !!value);
|
|
385
|
+
|
|
386
|
+
for (const candidate of candidates) {
|
|
387
|
+
if (candidate.includes(path.sep)) {
|
|
388
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
389
|
+
return candidate;
|
|
390
|
+
}
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (findExecutable(candidate)) {
|
|
394
|
+
return candidate;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return "python3";
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* @brief Runs Pyright/Pylance checks through the selected Python interpreter.
|
|
402
|
+
* @details Invokes `python -m pyright` for each resolved file and emits standardized OK/FAIL records. Runtime is dominated by external checker execution. Side effects include process spawning and console output.
|
|
403
|
+
*/
|
|
404
|
+
export class StaticCheckPylance extends StaticCheckBase {
|
|
405
|
+
static override LABEL = "Pylance";
|
|
406
|
+
private projectBase?: string;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* @brief Initializes a Pylance checker instance.
|
|
410
|
+
* @details Delegates file resolution to the base class, stores the optional project base, and overrides the human-readable label. Runtime is O(f) in resolved input count. Mutates instance fields only.
|
|
411
|
+
* @param[in] inputs {string[]} Raw file inputs.
|
|
412
|
+
* @param[in] extraArgs {string[] | undefined} Extra Pyright arguments.
|
|
413
|
+
* @param[in] failOnly {boolean} When `true`, suppress successful-file output.
|
|
414
|
+
* @param[in] projectBase {string | undefined} Optional project root used for interpreter resolution and process cwd.
|
|
415
|
+
*/
|
|
416
|
+
constructor(inputs: string[], extraArgs?: string[], failOnly = false, projectBase?: string) {
|
|
417
|
+
super(inputs, extraArgs, failOnly);
|
|
418
|
+
this.projectBase = projectBase;
|
|
419
|
+
this.label = "Pylance";
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* @brief Runs Pyright for one file.
|
|
424
|
+
* @details Resolves the Python interpreter, executes `python -m pyright`, and emits standardized OK/FAIL output with captured evidence on failure. Runtime is dominated by external tool execution. Side effects include process spawning and console output.
|
|
425
|
+
* @param[in] filePath {string} File to analyze.
|
|
426
|
+
* @return {number} `0` on success; `1` on execution or analysis failure.
|
|
427
|
+
*/
|
|
428
|
+
protected override checkFile(filePath: string): number {
|
|
429
|
+
const pythonExec = detectPythonExecutable(this.projectBase);
|
|
430
|
+
const command = [pythonExec, "-m", "pyright", "--pythonpath", pythonExec, filePath, ...this.extraArgs];
|
|
431
|
+
const result = spawnSync(command[0]!, command.slice(1), {
|
|
432
|
+
cwd: this.projectBase,
|
|
433
|
+
encoding: "utf8",
|
|
434
|
+
});
|
|
435
|
+
if (result.error) {
|
|
436
|
+
this.emitLine(this.headerLine(filePath));
|
|
437
|
+
this.emitLine("Result: FAIL");
|
|
438
|
+
this.emitLine("Evidence:");
|
|
439
|
+
this.emitLine(" pyright module not available via sys.executable");
|
|
440
|
+
return 1;
|
|
441
|
+
}
|
|
442
|
+
if (result.status === 0) {
|
|
443
|
+
if (!this.failOnly) {
|
|
444
|
+
this.emitLine(this.headerLine(filePath));
|
|
445
|
+
this.emitLine("Result: OK");
|
|
446
|
+
}
|
|
447
|
+
return 0;
|
|
448
|
+
}
|
|
449
|
+
this.emitLine(this.headerLine(filePath));
|
|
450
|
+
this.emitLine("Result: FAIL");
|
|
451
|
+
this.emitLine("Evidence:");
|
|
452
|
+
this.emitLine(`${result.stdout ?? ""}${result.stderr ?? ""}`.trimEnd());
|
|
453
|
+
return 1;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @brief Runs Ruff checks through the selected Python interpreter.
|
|
459
|
+
* @details Invokes `python -m ruff check` for each resolved file and emits standardized OK/FAIL records. Runtime is dominated by external checker execution. Side effects include process spawning and console output.
|
|
460
|
+
*/
|
|
461
|
+
export class StaticCheckRuff extends StaticCheckBase {
|
|
462
|
+
static override LABEL = "Ruff";
|
|
463
|
+
private projectBase?: string;
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* @brief Initializes a Ruff checker instance.
|
|
467
|
+
* @details Delegates file resolution to the base class, stores the optional project base, and overrides the human-readable label. Runtime is O(f) in resolved input count. Mutates instance fields only.
|
|
468
|
+
* @param[in] inputs {string[]} Raw file inputs.
|
|
469
|
+
* @param[in] extraArgs {string[] | undefined} Extra Ruff arguments.
|
|
470
|
+
* @param[in] failOnly {boolean} When `true`, suppress successful-file output.
|
|
471
|
+
* @param[in] projectBase {string | undefined} Optional project root used for interpreter resolution and process cwd.
|
|
472
|
+
*/
|
|
473
|
+
constructor(inputs: string[], extraArgs?: string[], failOnly = false, projectBase?: string) {
|
|
474
|
+
super(inputs, extraArgs, failOnly);
|
|
475
|
+
this.label = "Ruff";
|
|
476
|
+
this.projectBase = projectBase;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* @brief Runs Ruff for one file.
|
|
481
|
+
* @details Resolves the Python interpreter, executes `python -m ruff check`, and emits standardized OK/FAIL output with captured evidence on failure. Runtime is dominated by external tool execution. Side effects include process spawning and console output.
|
|
482
|
+
* @param[in] filePath {string} File to analyze.
|
|
483
|
+
* @return {number} `0` on success; `1` on execution or analysis failure.
|
|
484
|
+
*/
|
|
485
|
+
protected override checkFile(filePath: string): number {
|
|
486
|
+
const pythonExec = detectPythonExecutable(this.projectBase);
|
|
487
|
+
const command = [pythonExec, "-m", "ruff", "check", filePath, ...this.extraArgs];
|
|
488
|
+
const result = spawnSync(command[0]!, command.slice(1), { encoding: "utf8", cwd: this.projectBase });
|
|
489
|
+
if (result.error) {
|
|
490
|
+
this.emitLine(this.headerLine(filePath));
|
|
491
|
+
this.emitLine("Result: FAIL");
|
|
492
|
+
this.emitLine("Evidence:");
|
|
493
|
+
this.emitLine(" ruff module not available via sys.executable");
|
|
494
|
+
return 1;
|
|
495
|
+
}
|
|
496
|
+
if (result.status === 0) {
|
|
497
|
+
if (!this.failOnly) {
|
|
498
|
+
this.emitLine(this.headerLine(filePath));
|
|
499
|
+
this.emitLine("Result: OK");
|
|
500
|
+
}
|
|
501
|
+
return 0;
|
|
502
|
+
}
|
|
503
|
+
this.emitLine(this.headerLine(filePath));
|
|
504
|
+
this.emitLine("Result: FAIL");
|
|
505
|
+
this.emitLine("Evidence:");
|
|
506
|
+
this.emitLine(`${result.stdout ?? ""}${result.stderr ?? ""}`.trimEnd());
|
|
507
|
+
return 1;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* @brief Runs an arbitrary external command as a static checker.
|
|
513
|
+
* @details Validates command availability on PATH during construction, then invokes the command with configured extra arguments plus one target file at a time. Runtime is dominated by external command execution. Side effects include PATH probing, process spawning, and console output.
|
|
514
|
+
*/
|
|
515
|
+
export class StaticCheckCommand extends StaticCheckBase {
|
|
516
|
+
private cmd: string;
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @brief Initializes a command-backed checker instance.
|
|
520
|
+
* @details Validates that the executable exists on PATH before delegating file resolution to the base class and recording the command label. Runtime is O(p + f) where p is PATH entry count and f is resolved input count. Side effects are filesystem reads.
|
|
521
|
+
* @param[in] cmd {string} Executable name.
|
|
522
|
+
* @param[in] inputs {string[]} Raw file inputs.
|
|
523
|
+
* @param[in] extraArgs {string[] | undefined} Extra command arguments.
|
|
524
|
+
* @param[in] failOnly {boolean} When `true`, suppress successful-file output.
|
|
525
|
+
* @throws {ReqError} Throws when the executable cannot be found on PATH.
|
|
526
|
+
*/
|
|
527
|
+
constructor(cmd: string, inputs: string[], extraArgs?: string[], failOnly = false) {
|
|
528
|
+
if (!findExecutable(cmd)) {
|
|
529
|
+
throw new ReqError(`Error: external command '${cmd}' not found on PATH.`, 1);
|
|
530
|
+
}
|
|
531
|
+
super(inputs, extraArgs, failOnly);
|
|
532
|
+
this.cmd = cmd;
|
|
533
|
+
this.label = `Command[${cmd}]`;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* @brief Runs the configured external command for one file.
|
|
538
|
+
* @details Executes the command with extra arguments followed by the target file and emits standardized OK/FAIL output with captured evidence. Runtime is dominated by external command execution. Side effects include process spawning and console output.
|
|
539
|
+
* @param[in] filePath {string} File to analyze.
|
|
540
|
+
* @return {number} `0` on success; `1` on execution or analysis failure.
|
|
541
|
+
*/
|
|
542
|
+
protected override checkFile(filePath: string): number {
|
|
543
|
+
const result = spawnSync(this.cmd, [...this.extraArgs, filePath], { encoding: "utf8" });
|
|
544
|
+
if (result.error) {
|
|
545
|
+
this.emitLine(this.headerLine(filePath));
|
|
546
|
+
this.emitLine("Result: FAIL");
|
|
547
|
+
this.emitLine("Evidence:");
|
|
548
|
+
this.emitLine(` command '${this.cmd}' not found on PATH`);
|
|
549
|
+
return 1;
|
|
550
|
+
}
|
|
551
|
+
if (result.status === 0) {
|
|
552
|
+
if (!this.failOnly) {
|
|
553
|
+
this.emitLine(this.headerLine(filePath));
|
|
554
|
+
this.emitLine("Result: OK");
|
|
555
|
+
}
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
this.emitLine(this.headerLine(filePath));
|
|
559
|
+
this.emitLine("Result: FAIL");
|
|
560
|
+
this.emitLine("Evidence:");
|
|
561
|
+
this.emitLine(`${result.stdout ?? ""}${result.stderr ?? ""}`.trimEnd());
|
|
562
|
+
return 1;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* @brief Tests whether one filesystem path is executable.
|
|
568
|
+
* @details Requires the candidate to exist, be a regular file, and pass `X_OK` access checks. Runtime is O(1). Side effects are limited to filesystem reads.
|
|
569
|
+
* @param[in] candidate {string} Absolute or relative path to inspect.
|
|
570
|
+
* @return {boolean} `true` when the candidate is executable by the current process.
|
|
571
|
+
*/
|
|
572
|
+
function isExecutableFile(candidate: string): boolean {
|
|
573
|
+
if (!fs.existsSync(candidate) || !fs.statSync(candidate).isFile()) {
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
try {
|
|
577
|
+
fs.accessSync(candidate, fs.constants.X_OK);
|
|
578
|
+
return true;
|
|
579
|
+
} catch {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* @brief Locates an executable by scanning the current PATH.
|
|
586
|
+
* @details Checks each PATH directory for an executable file named exactly as the requested command. Runtime is O(p) in PATH entry count. Side effects are filesystem reads.
|
|
587
|
+
* @param[in] cmd {string} Executable name to locate.
|
|
588
|
+
* @return {string | undefined} Absolute executable path, or `undefined` when not found.
|
|
589
|
+
*/
|
|
590
|
+
function findExecutable(cmd: string): string | undefined {
|
|
591
|
+
if (cmd.includes(path.sep)) {
|
|
592
|
+
return isExecutableFile(cmd) ? path.resolve(cmd) : undefined;
|
|
593
|
+
}
|
|
594
|
+
const pathValue = process.env.PATH ?? "";
|
|
595
|
+
for (const dir of pathValue.split(path.delimiter)) {
|
|
596
|
+
if (!dir) continue;
|
|
597
|
+
const candidate = path.join(dir, cmd);
|
|
598
|
+
if (isExecutableFile(candidate)) return candidate;
|
|
599
|
+
}
|
|
600
|
+
return undefined;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @brief Dispatches one configured static checker for a single file.
|
|
605
|
+
* @details Selects the checker implementation by module name, normalizes parameter arrays, and runs exactly one checker instance against the target file. Runtime is dominated by the selected checker. Side effects include console output and possible process spawning.
|
|
606
|
+
* @param[in] filePath {string} Absolute or relative file path to check.
|
|
607
|
+
* @param[in] langConfig {StaticCheckEntry} Normalized static-check configuration entry.
|
|
608
|
+
* @param[in] options {{ failOnly?: boolean; projectBase?: string }} Optional execution controls.
|
|
609
|
+
* @return {number} Checker exit status where `0` means success and non-zero means failure.
|
|
610
|
+
* @throws {ReqError} Throws when configuration is incomplete or names an unknown module.
|
|
611
|
+
*/
|
|
612
|
+
export function dispatchStaticCheckForFile(
|
|
613
|
+
filePath: string,
|
|
614
|
+
langConfig: StaticCheckEntry,
|
|
615
|
+
options: { failOnly?: boolean; projectBase?: string } = {},
|
|
616
|
+
): number {
|
|
617
|
+
const moduleName = String(langConfig.module ?? "");
|
|
618
|
+
const params = Array.isArray(langConfig.params) ? langConfig.params.map(String) : [];
|
|
619
|
+
const cmd = typeof langConfig.cmd === "string" ? langConfig.cmd : undefined;
|
|
620
|
+
const failOnly = options.failOnly ?? false;
|
|
621
|
+
const projectBase = options.projectBase;
|
|
622
|
+
switch (moduleName.toLowerCase()) {
|
|
623
|
+
case "dummy":
|
|
624
|
+
return new StaticCheckBase([filePath], params, failOnly).run();
|
|
625
|
+
case "pylance":
|
|
626
|
+
return new StaticCheckPylance([filePath], params, failOnly, projectBase).run();
|
|
627
|
+
case "ruff":
|
|
628
|
+
return new StaticCheckRuff([filePath], params, failOnly, projectBase).run();
|
|
629
|
+
case "command":
|
|
630
|
+
if (!cmd) {
|
|
631
|
+
throw new ReqError(`Error: Command module requires 'cmd' in static-check config for '${filePath}'.`, 1);
|
|
632
|
+
}
|
|
633
|
+
return new StaticCheckCommand(cmd, [filePath], params, failOnly).run();
|
|
634
|
+
default:
|
|
635
|
+
throw new ReqError(
|
|
636
|
+
`Error: unknown static-check module '${moduleName}'. Valid modules: ${formatStaticCheckModules()}`,
|
|
637
|
+
1,
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @brief Runs the standalone static-check test driver.
|
|
644
|
+
* @details Dispatches subcommands to the built-in checker implementations without consulting project configuration. Runtime is O(n) in argument count plus checker cost. Side effects include console output and external process spawning.
|
|
645
|
+
* @param[in] argv {string[]} Raw static-check subcommand arguments.
|
|
646
|
+
* @return {number} Checker exit status where `0` means success.
|
|
647
|
+
* @throws {ReqError} Throws when no subcommand is provided, the subcommand is unknown, or required arguments are missing.
|
|
648
|
+
*/
|
|
649
|
+
export function runStaticCheck(argv: string[]): number {
|
|
650
|
+
if (argv.length === 0) {
|
|
651
|
+
throw new ReqError("Error: --test-static-check requires a subcommand: dummy, pylance, ruff, command.", 1);
|
|
652
|
+
}
|
|
653
|
+
const [subcommand, ...rest] = argv;
|
|
654
|
+
switch (subcommand) {
|
|
655
|
+
case "dummy":
|
|
656
|
+
return new StaticCheckBase(rest).run();
|
|
657
|
+
case "pylance":
|
|
658
|
+
return new StaticCheckPylance(rest).run();
|
|
659
|
+
case "ruff":
|
|
660
|
+
return new StaticCheckRuff(rest, undefined, false, process.cwd()).run();
|
|
661
|
+
case "command": {
|
|
662
|
+
if (rest.length === 0) {
|
|
663
|
+
throw new ReqError("Error: --test-static-check command requires a <cmd> argument.", 1);
|
|
664
|
+
}
|
|
665
|
+
const [cmd, ...files] = rest;
|
|
666
|
+
return new StaticCheckCommand(cmd!, files).run();
|
|
667
|
+
}
|
|
668
|
+
default:
|
|
669
|
+
throw new ReqError(
|
|
670
|
+
`Error: unknown --test-static-check subcommand '${subcommand}'. Valid subcommands: dummy, pylance, ruff, command.`,
|
|
671
|
+
1,
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|