@vyuhlabs/dxkit 2.4.5 → 2.4.7
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/CHANGELOG.md +1022 -0
- package/README.md +160 -45
- package/dist/analysis-result.d.ts +112 -0
- package/dist/analysis-result.d.ts.map +1 -0
- package/dist/analysis-result.js +52 -0
- package/dist/analysis-result.js.map +1 -0
- package/dist/analyzers/bom/detailed.d.ts.map +1 -1
- package/dist/analyzers/bom/detailed.js +19 -0
- package/dist/analyzers/bom/detailed.js.map +1 -1
- package/dist/analyzers/bom/gather.d.ts +27 -26
- package/dist/analyzers/bom/gather.d.ts.map +1 -1
- package/dist/analyzers/bom/gather.js +26 -87
- package/dist/analyzers/bom/gather.js.map +1 -1
- package/dist/analyzers/bom/index.d.ts +0 -7
- package/dist/analyzers/bom/index.d.ts.map +1 -1
- package/dist/analyzers/bom/index.js +98 -48
- package/dist/analyzers/bom/index.js.map +1 -1
- package/dist/analyzers/bom/types.d.ts +11 -13
- package/dist/analyzers/bom/types.d.ts.map +1 -1
- package/dist/analyzers/cache.d.ts +95 -0
- package/dist/analyzers/cache.d.ts.map +1 -0
- package/dist/analyzers/cache.js +309 -0
- package/dist/analyzers/cache.js.map +1 -0
- package/dist/analyzers/coverage-runner.d.ts +56 -0
- package/dist/analyzers/coverage-runner.d.ts.map +1 -0
- package/dist/analyzers/coverage-runner.js +72 -0
- package/dist/analyzers/coverage-runner.js.map +1 -0
- package/dist/analyzers/dashboard/index.d.ts +24 -0
- package/dist/analyzers/dashboard/index.d.ts.map +1 -0
- package/dist/analyzers/dashboard/index.js +666 -0
- package/dist/analyzers/dashboard/index.js.map +1 -0
- package/dist/analyzers/developer/gather.d.ts.map +1 -1
- package/dist/analyzers/developer/gather.js +205 -37
- package/dist/analyzers/developer/gather.js.map +1 -1
- package/dist/analyzers/developer/index.d.ts +1 -1
- package/dist/analyzers/developer/index.d.ts.map +1 -1
- package/dist/analyzers/developer/index.js +19 -8
- package/dist/analyzers/developer/index.js.map +1 -1
- package/dist/analyzers/dispatcher.d.ts +37 -0
- package/dist/analyzers/dispatcher.d.ts.map +1 -1
- package/dist/analyzers/dispatcher.js +56 -9
- package/dist/analyzers/dispatcher.js.map +1 -1
- package/dist/analyzers/docs/shallow.d.ts +17 -5
- package/dist/analyzers/docs/shallow.d.ts.map +1 -1
- package/dist/analyzers/docs/shallow.js +65 -2
- package/dist/analyzers/docs/shallow.js.map +1 -1
- package/dist/analyzers/dx/shallow.d.ts +17 -5
- package/dist/analyzers/dx/shallow.d.ts.map +1 -1
- package/dist/analyzers/dx/shallow.js +66 -2
- package/dist/analyzers/dx/shallow.js.map +1 -1
- package/dist/analyzers/health/actions.d.ts +1 -1
- package/dist/analyzers/health/actions.d.ts.map +1 -1
- package/dist/analyzers/health/actions.js +27 -9
- package/dist/analyzers/health/actions.js.map +1 -1
- package/dist/analyzers/health/detailed.d.ts +2 -1
- package/dist/analyzers/health/detailed.d.ts.map +1 -1
- package/dist/analyzers/health/detailed.js +11 -7
- package/dist/analyzers/health/detailed.js.map +1 -1
- package/dist/analyzers/health.d.ts +27 -0
- package/dist/analyzers/health.d.ts.map +1 -1
- package/dist/analyzers/health.js +271 -33
- package/dist/analyzers/health.js.map +1 -1
- package/dist/analyzers/licenses/gather.d.ts +35 -8
- package/dist/analyzers/licenses/gather.d.ts.map +1 -1
- package/dist/analyzers/licenses/gather.js +70 -13
- package/dist/analyzers/licenses/gather.js.map +1 -1
- package/dist/analyzers/licenses/index.d.ts +1 -1
- package/dist/analyzers/licenses/index.d.ts.map +1 -1
- package/dist/analyzers/licenses/index.js +52 -11
- package/dist/analyzers/licenses/index.js.map +1 -1
- package/dist/analyzers/licenses/types.d.ts +15 -0
- package/dist/analyzers/licenses/types.d.ts.map +1 -1
- package/dist/analyzers/maintainability/shallow.d.ts +17 -5
- package/dist/analyzers/maintainability/shallow.d.ts.map +1 -1
- package/dist/analyzers/maintainability/shallow.js +80 -2
- package/dist/analyzers/maintainability/shallow.js.map +1 -1
- package/dist/analyzers/quality/detailed.d.ts.map +1 -1
- package/dist/analyzers/quality/detailed.js +4 -6
- package/dist/analyzers/quality/detailed.js.map +1 -1
- package/dist/analyzers/quality/gather.d.ts +1 -14
- package/dist/analyzers/quality/gather.d.ts.map +1 -1
- package/dist/analyzers/quality/gather.js +48 -137
- package/dist/analyzers/quality/gather.js.map +1 -1
- package/dist/analyzers/quality/index.d.ts +9 -2
- package/dist/analyzers/quality/index.d.ts.map +1 -1
- package/dist/analyzers/quality/index.js +189 -117
- package/dist/analyzers/quality/index.js.map +1 -1
- package/dist/analyzers/quality/shallow.d.ts +50 -5
- package/dist/analyzers/quality/shallow.d.ts.map +1 -1
- package/dist/analyzers/quality/shallow.js +155 -2
- package/dist/analyzers/quality/shallow.js.map +1 -1
- package/dist/analyzers/quality/types.d.ts +14 -0
- package/dist/analyzers/quality/types.d.ts.map +1 -1
- package/dist/analyzers/security/actions.d.ts +11 -4
- package/dist/analyzers/security/actions.d.ts.map +1 -1
- package/dist/analyzers/security/actions.js +87 -37
- package/dist/analyzers/security/actions.js.map +1 -1
- package/dist/analyzers/security/aggregator.d.ts +236 -0
- package/dist/analyzers/security/aggregator.d.ts.map +1 -0
- package/dist/analyzers/security/aggregator.js +347 -0
- package/dist/analyzers/security/aggregator.js.map +1 -0
- package/dist/analyzers/security/detailed.d.ts +2 -2
- package/dist/analyzers/security/detailed.d.ts.map +1 -1
- package/dist/analyzers/security/detailed.js +10 -9
- package/dist/analyzers/security/detailed.js.map +1 -1
- package/dist/analyzers/security/gather.d.ts +103 -1
- package/dist/analyzers/security/gather.d.ts.map +1 -1
- package/dist/analyzers/security/gather.js +281 -9
- package/dist/analyzers/security/gather.js.map +1 -1
- package/dist/analyzers/security/index.d.ts +15 -0
- package/dist/analyzers/security/index.d.ts.map +1 -1
- package/dist/analyzers/security/index.js +463 -50
- package/dist/analyzers/security/index.js.map +1 -1
- package/dist/analyzers/security/shallow.d.ts +50 -6
- package/dist/analyzers/security/shallow.d.ts.map +1 -1
- package/dist/analyzers/security/shallow.js +154 -2
- package/dist/analyzers/security/shallow.js.map +1 -1
- package/dist/analyzers/security/types.d.ts +51 -0
- package/dist/analyzers/security/types.d.ts.map +1 -1
- package/dist/analyzers/tests/detailed.d.ts.map +1 -1
- package/dist/analyzers/tests/detailed.js +2 -3
- package/dist/analyzers/tests/detailed.js.map +1 -1
- package/dist/analyzers/tests/gather.d.ts +2 -1
- package/dist/analyzers/tests/gather.d.ts.map +1 -1
- package/dist/analyzers/tests/gather.js +98 -69
- package/dist/analyzers/tests/gather.js.map +1 -1
- package/dist/analyzers/tests/index.d.ts +11 -2
- package/dist/analyzers/tests/index.d.ts.map +1 -1
- package/dist/analyzers/tests/index.js +85 -18
- package/dist/analyzers/tests/index.js.map +1 -1
- package/dist/analyzers/tests/shallow.d.ts +19 -5
- package/dist/analyzers/tests/shallow.d.ts.map +1 -1
- package/dist/analyzers/tests/shallow.js +89 -2
- package/dist/analyzers/tests/shallow.js.map +1 -1
- package/dist/analyzers/tests/types.d.ts +41 -1
- package/dist/analyzers/tests/types.d.ts.map +1 -1
- package/dist/analyzers/tools/autogen-header.d.ts +8 -0
- package/dist/analyzers/tools/autogen-header.d.ts.map +1 -0
- package/dist/analyzers/tools/autogen-header.js +107 -0
- package/dist/analyzers/tools/autogen-header.js.map +1 -0
- package/dist/analyzers/tools/cloc.d.ts.map +1 -1
- package/dist/analyzers/tools/cloc.js +36 -5
- package/dist/analyzers/tools/cloc.js.map +1 -1
- package/dist/analyzers/tools/coverage.d.ts +1 -1
- package/dist/analyzers/tools/coverage.d.ts.map +1 -1
- package/dist/analyzers/tools/coverage.js.map +1 -1
- package/dist/analyzers/tools/debug-statements.d.ts +17 -0
- package/dist/analyzers/tools/debug-statements.d.ts.map +1 -0
- package/dist/analyzers/tools/debug-statements.js +58 -0
- package/dist/analyzers/tools/debug-statements.js.map +1 -0
- package/dist/analyzers/tools/default-exclusions.gitignore +28 -0
- package/dist/analyzers/tools/exclusions.d.ts +33 -6
- package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
- package/dist/analyzers/tools/exclusions.js +95 -26
- package/dist/analyzers/tools/exclusions.js.map +1 -1
- package/dist/analyzers/tools/generic.d.ts +17 -2
- package/dist/analyzers/tools/generic.d.ts.map +1 -1
- package/dist/analyzers/tools/generic.js +206 -109
- package/dist/analyzers/tools/generic.js.map +1 -1
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
- package/dist/analyzers/tools/gitleaks.js +48 -1
- package/dist/analyzers/tools/gitleaks.js.map +1 -1
- package/dist/analyzers/tools/graphify.d.ts +30 -2
- package/dist/analyzers/tools/graphify.d.ts.map +1 -1
- package/dist/analyzers/tools/graphify.js +131 -15
- package/dist/analyzers/tools/graphify.js.map +1 -1
- package/dist/analyzers/tools/jscpd.d.ts +12 -2
- package/dist/analyzers/tools/jscpd.d.ts.map +1 -1
- package/dist/analyzers/tools/jscpd.js +129 -6
- package/dist/analyzers/tools/jscpd.js.map +1 -1
- package/dist/analyzers/tools/minified-detection.d.ts +9 -0
- package/dist/analyzers/tools/minified-detection.d.ts.map +1 -0
- package/dist/analyzers/tools/minified-detection.js +147 -0
- package/dist/analyzers/tools/minified-detection.js.map +1 -0
- package/dist/analyzers/tools/nuget-package-reference.d.ts +131 -0
- package/dist/analyzers/tools/nuget-package-reference.d.ts.map +1 -0
- package/dist/analyzers/tools/nuget-package-reference.js +175 -0
- package/dist/analyzers/tools/nuget-package-reference.js.map +1 -0
- package/dist/analyzers/tools/osv-scanner-deps.d.ts +48 -0
- package/dist/analyzers/tools/osv-scanner-deps.d.ts.map +1 -0
- package/dist/analyzers/tools/{osv-scanner-maven.js → osv-scanner-deps.js} +78 -46
- package/dist/analyzers/tools/osv-scanner-deps.js.map +1 -0
- package/dist/analyzers/tools/osv.d.ts +36 -0
- package/dist/analyzers/tools/osv.d.ts.map +1 -1
- package/dist/analyzers/tools/osv.js +26 -0
- package/dist/analyzers/tools/osv.js.map +1 -1
- package/dist/analyzers/tools/parallel.d.ts +1 -1
- package/dist/analyzers/tools/parallel.d.ts.map +1 -1
- package/dist/analyzers/tools/parallel.js +2 -2
- package/dist/analyzers/tools/parallel.js.map +1 -1
- package/dist/analyzers/tools/risk-score.d.ts +7 -0
- package/dist/analyzers/tools/risk-score.d.ts.map +1 -1
- package/dist/analyzers/tools/risk-score.js +9 -2
- package/dist/analyzers/tools/risk-score.js.map +1 -1
- package/dist/analyzers/tools/run-tests-helper.d.ts +43 -0
- package/dist/analyzers/tools/run-tests-helper.d.ts.map +1 -0
- package/dist/analyzers/tools/run-tests-helper.js +156 -0
- package/dist/analyzers/tools/run-tests-helper.js.map +1 -0
- package/dist/analyzers/tools/runner.d.ts.map +1 -1
- package/dist/analyzers/tools/runner.js +75 -12
- package/dist/analyzers/tools/runner.js.map +1 -1
- package/dist/analyzers/tools/semgrep.d.ts +39 -2
- package/dist/analyzers/tools/semgrep.d.ts.map +1 -1
- package/dist/analyzers/tools/semgrep.js +131 -9
- package/dist/analyzers/tools/semgrep.js.map +1 -1
- package/dist/analyzers/tools/timing.d.ts +17 -3
- package/dist/analyzers/tools/timing.d.ts.map +1 -1
- package/dist/analyzers/tools/timing.js +36 -14
- package/dist/analyzers/tools/timing.js.map +1 -1
- package/dist/analyzers/tools/tool-registry.d.ts +10 -0
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +120 -1
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- package/dist/analyzers/tools/tools-unavailable-prose.d.ts +18 -0
- package/dist/analyzers/tools/tools-unavailable-prose.d.ts.map +1 -0
- package/dist/analyzers/tools/tools-unavailable-prose.js +69 -0
- package/dist/analyzers/tools/tools-unavailable-prose.js.map +1 -0
- package/dist/analyzers/tools/upgrade-plan-resolver.d.ts.map +1 -1
- package/dist/analyzers/tools/upgrade-plan-resolver.js +7 -0
- package/dist/analyzers/tools/upgrade-plan-resolver.js.map +1 -1
- package/dist/analyzers/tools/vendored-advisor.d.ts +43 -0
- package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -0
- package/dist/analyzers/tools/vendored-advisor.js +107 -0
- package/dist/analyzers/tools/vendored-advisor.js.map +1 -0
- package/dist/analyzers/tools/walk-paths.d.ts +78 -0
- package/dist/analyzers/tools/walk-paths.d.ts.map +1 -0
- package/dist/analyzers/tools/walk-paths.js +150 -0
- package/dist/analyzers/tools/walk-paths.js.map +1 -0
- package/dist/analyzers/tools/walk-source-files.d.ts +70 -0
- package/dist/analyzers/tools/walk-source-files.d.ts.map +1 -0
- package/dist/analyzers/tools/walk-source-files.js +369 -0
- package/dist/analyzers/tools/walk-source-files.js.map +1 -0
- package/dist/analyzers/types.d.ts +204 -4
- package/dist/analyzers/types.d.ts.map +1 -1
- package/dist/analyzers/xlsx/bom.d.ts.map +1 -1
- package/dist/analyzers/xlsx/bom.js +8 -1
- package/dist/analyzers/xlsx/bom.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +557 -189
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +24 -7
- package/dist/detect.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +103 -53
- package/dist/doctor.js.map +1 -1
- package/dist/languages/capabilities/provider.d.ts +130 -1
- package/dist/languages/capabilities/provider.d.ts.map +1 -1
- package/dist/languages/capabilities/types.d.ts +68 -7
- package/dist/languages/capabilities/types.d.ts.map +1 -1
- package/dist/languages/csharp.d.ts +15 -1
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +624 -146
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +89 -11
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/index.d.ts +131 -2
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +208 -0
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +121 -32
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +140 -32
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +149 -44
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts +115 -0
- package/dist/languages/ruby.d.ts.map +1 -0
- package/dist/languages/ruby.js +665 -0
- package/dist/languages/ruby.js.map +1 -0
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +103 -16
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +228 -5
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +201 -14
- package/dist/languages/typescript.js.map +1 -1
- package/dist/scoring/dimensions/documentation.d.ts +53 -0
- package/dist/scoring/dimensions/documentation.d.ts.map +1 -0
- package/dist/scoring/dimensions/documentation.js +106 -0
- package/dist/scoring/dimensions/documentation.js.map +1 -0
- package/dist/scoring/dimensions/dx.d.ts +53 -0
- package/dist/scoring/dimensions/dx.d.ts.map +1 -0
- package/dist/scoring/dimensions/dx.js +105 -0
- package/dist/scoring/dimensions/dx.js.map +1 -0
- package/dist/scoring/dimensions/maintainability.d.ts +53 -0
- package/dist/scoring/dimensions/maintainability.d.ts.map +1 -0
- package/dist/scoring/dimensions/maintainability.js +101 -0
- package/dist/scoring/dimensions/maintainability.js.map +1 -0
- package/dist/scoring/dimensions/quality.d.ts +108 -0
- package/dist/scoring/dimensions/quality.d.ts.map +1 -0
- package/dist/scoring/dimensions/quality.js +174 -0
- package/dist/scoring/dimensions/quality.js.map +1 -0
- package/dist/scoring/dimensions/security.d.ts +84 -0
- package/dist/scoring/dimensions/security.d.ts.map +1 -0
- package/dist/scoring/dimensions/security.js +135 -0
- package/dist/scoring/dimensions/security.js.map +1 -0
- package/dist/scoring/dimensions/testing.d.ts +56 -0
- package/dist/scoring/dimensions/testing.d.ts.map +1 -0
- package/dist/scoring/dimensions/testing.js +98 -0
- package/dist/scoring/dimensions/testing.js.map +1 -0
- package/dist/scoring/evaluator.d.ts +27 -0
- package/dist/scoring/evaluator.d.ts.map +1 -0
- package/dist/scoring/evaluator.js +124 -0
- package/dist/scoring/evaluator.js.map +1 -0
- package/dist/scoring/format.d.ts +34 -0
- package/dist/scoring/format.d.ts.map +1 -0
- package/dist/scoring/format.js +63 -0
- package/dist/scoring/format.js.map +1 -0
- package/dist/scoring/index.d.ts +37 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +57 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/overall.d.ts +54 -0
- package/dist/scoring/overall.d.ts.map +1 -0
- package/dist/scoring/overall.js +76 -0
- package/dist/scoring/overall.js.map +1 -0
- package/dist/scoring/result.d.ts +111 -0
- package/dist/scoring/result.d.ts.map +1 -0
- package/dist/scoring/result.js +14 -0
- package/dist/scoring/result.js.map +1 -0
- package/dist/scoring/spec.d.ts +76 -0
- package/dist/scoring/spec.d.ts.map +1 -0
- package/dist/scoring/spec.js +22 -0
- package/dist/scoring/spec.js.map +1 -0
- package/dist/scoring/thresholds.d.ts +56 -0
- package/dist/scoring/thresholds.d.ts.map +1 -0
- package/dist/scoring/thresholds.js +75 -0
- package/dist/scoring/thresholds.js.map +1 -0
- package/dist/tools-cli.d.ts.map +1 -1
- package/dist/tools-cli.js +21 -2
- package/dist/tools-cli.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/commands/dashboard.md +17 -9
- package/templates/.claude/rules/ruby.md +11 -0
- package/templates/configs/ruby/README.md +6 -0
- package/dist/analyzers/scoring.d.ts +0 -49
- package/dist/analyzers/scoring.d.ts.map +0 -1
- package/dist/analyzers/scoring.js +0 -422
- package/dist/analyzers/scoring.js.map +0 -1
- package/dist/analyzers/security/scoring.d.ts +0 -29
- package/dist/analyzers/security/scoring.d.ts.map +0 -1
- package/dist/analyzers/security/scoring.js +0 -40
- package/dist/analyzers/security/scoring.js.map +0 -1
- package/dist/analyzers/tools/osv-scanner-maven.d.ts +0 -42
- package/dist/analyzers/tools/osv-scanner-maven.d.ts.map +0 -1
- package/dist/analyzers/tools/osv-scanner-maven.js.map +0 -1
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ruby = void 0;
|
|
37
|
+
exports.extractRubyImportsRaw = extractRubyImportsRaw;
|
|
38
|
+
exports.mapRubocopSeverity = mapRubocopSeverity;
|
|
39
|
+
exports.parseRubocopOutput = parseRubocopOutput;
|
|
40
|
+
exports.parseSimpleCovResultset = parseSimpleCovResultset;
|
|
41
|
+
exports.gatherSimpleCovOutcome = gatherSimpleCovOutcome;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const coverage_1 = require("../analyzers/tools/coverage");
|
|
45
|
+
const walk_paths_1 = require("../analyzers/tools/walk-paths");
|
|
46
|
+
const exclusions_1 = require("../analyzers/tools/exclusions");
|
|
47
|
+
const osv_scanner_deps_1 = require("../analyzers/tools/osv-scanner-deps");
|
|
48
|
+
const runner_1 = require("../analyzers/tools/runner");
|
|
49
|
+
const run_tests_helper_1 = require("../analyzers/tools/run-tests-helper");
|
|
50
|
+
const tool_registry_1 = require("../analyzers/tools/tool-registry");
|
|
51
|
+
// ─── Detection ──────────────────────────────────────────────────────────────
|
|
52
|
+
/**
|
|
53
|
+
* Walk the project tree (bounded depth) looking for a `.rb` source file.
|
|
54
|
+
* G9 discipline (Recipe v3): manifest-only detection (Gemfile alone)
|
|
55
|
+
* over-activates on mixed-stack repos and scaffolded-but-empty projects.
|
|
56
|
+
* The pack only matters when there is actual Ruby source to analyze.
|
|
57
|
+
*/
|
|
58
|
+
function detectRuby(cwd) {
|
|
59
|
+
// Depth-unlimited via the canonical walker. The previous depth-5
|
|
60
|
+
// cap missed nested Ruby projects in monorepos and engines layouts.
|
|
61
|
+
return (0, walk_paths_1.walkPaths)(cwd, { extensions: ['.rb'] }).length > 0;
|
|
62
|
+
}
|
|
63
|
+
// ─── Imports (regex extraction, no resolver) ────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Capture Ruby require / require_relative / autoload specifiers from source
|
|
66
|
+
* text. Three forms recognised:
|
|
67
|
+
*
|
|
68
|
+
* require 'json' → 'json'
|
|
69
|
+
* require_relative '../foo/bar' → '../foo/bar'
|
|
70
|
+
* autoload :Sym, 'foo/bar' → 'foo/bar'
|
|
71
|
+
*
|
|
72
|
+
* Ruby's metaprogramming (`__send__`, `Object.const_missing`, Rails'
|
|
73
|
+
* Zeitwerk autoloader) makes static import analysis fundamentally
|
|
74
|
+
* best-effort — many "imports" in idiomatic Ruby never appear as
|
|
75
|
+
* literal `require` calls. This parser extracts the literal-string
|
|
76
|
+
* cases only; downstream consumers should treat the output as a lower
|
|
77
|
+
* bound. Future v4 candidate: explicit best-effort contract on the
|
|
78
|
+
* imports envelope so consumers can distinguish "exhaustive" (TS, Go)
|
|
79
|
+
* from "best-effort" (Ruby, kotlin/Java reflection paths).
|
|
80
|
+
*
|
|
81
|
+
* Comments are stripped (single-line `#`) before matching so a
|
|
82
|
+
* commented-out `# require 'foo'` does not false-match. Multi-line
|
|
83
|
+
* `=begin ... =end` blocks containing requires are not extracted
|
|
84
|
+
* (acceptable: comment-out-import is intentional non-use).
|
|
85
|
+
*
|
|
86
|
+
* Both single and double quotes are accepted; dynamic `require x` (no
|
|
87
|
+
* literal string) is skipped — there is no specifier to capture.
|
|
88
|
+
*
|
|
89
|
+
* Exported for unit tests; consumed by `gatherRubyImportsResult`.
|
|
90
|
+
*/
|
|
91
|
+
function extractRubyImportsRaw(content) {
|
|
92
|
+
const out = [];
|
|
93
|
+
// Strip line comments first so `# require 'foo'` doesn't false-match.
|
|
94
|
+
// Conservative: only `#` at start-of-line or after whitespace, to avoid
|
|
95
|
+
// mangling `#{interpolation}` inside double-quoted strings.
|
|
96
|
+
const stripped = content.replace(/(^|\s)#[^\n]*/g, '$1');
|
|
97
|
+
const requireRe = /^\s*(?:require|require_relative)\s+['"]([^'"]+)['"]/gm;
|
|
98
|
+
let m;
|
|
99
|
+
while ((m = requireRe.exec(stripped)) !== null) {
|
|
100
|
+
out.push(m[1]);
|
|
101
|
+
}
|
|
102
|
+
// autoload :Sym, 'path' — capture the path arg only (the symbol is the
|
|
103
|
+
// local binding name, not the import target).
|
|
104
|
+
const autoloadRe = /^\s*autoload\s+:[A-Za-z_]\w*\s*,\s*['"]([^'"]+)['"]/gm;
|
|
105
|
+
while ((m = autoloadRe.exec(stripped)) !== null) {
|
|
106
|
+
out.push(m[1]);
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Enumerate `.rb` files under cwd and capture per-file imports. Ruby has
|
|
112
|
+
* no file-level resolver — `require 'foo'` searches `$LOAD_PATH` (a
|
|
113
|
+
* runtime-mutable array), Rails projects defer wholly to Zeitwerk's
|
|
114
|
+
* convention-based autoload, and `require_relative` paths sometimes
|
|
115
|
+
* lack the `.rb` extension. Mirrors rust/kotlin/csharp/java packs:
|
|
116
|
+
* `extracted` is populated for completeness, `edges` is always empty,
|
|
117
|
+
* file-level resolution is left to graphify if downstream consumers
|
|
118
|
+
* need it.
|
|
119
|
+
*/
|
|
120
|
+
function gatherRubyImportsResult(cwd) {
|
|
121
|
+
const excludes = (0, exclusions_1.getFindExcludeFlags)(cwd);
|
|
122
|
+
const raw = (0, runner_1.run)(`find . -type f -name "*.rb" ${excludes} 2>/dev/null`, cwd);
|
|
123
|
+
if (!raw)
|
|
124
|
+
return null;
|
|
125
|
+
const extracted = new Map();
|
|
126
|
+
for (const line of raw.split('\n')) {
|
|
127
|
+
const p = line.trim();
|
|
128
|
+
if (!p)
|
|
129
|
+
continue;
|
|
130
|
+
const rel = p.replace(/^\.\//, '');
|
|
131
|
+
let content;
|
|
132
|
+
try {
|
|
133
|
+
content = fs.readFileSync(path.join(cwd, rel), 'utf-8');
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
extracted.set(rel, extractRubyImportsRaw(content));
|
|
139
|
+
}
|
|
140
|
+
if (extracted.size === 0)
|
|
141
|
+
return null;
|
|
142
|
+
return {
|
|
143
|
+
schemaVersion: 1,
|
|
144
|
+
tool: 'ruby-imports',
|
|
145
|
+
sourceExtensions: ['.rb'],
|
|
146
|
+
extracted,
|
|
147
|
+
edges: new Map(),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const rubyImportsProvider = {
|
|
151
|
+
source: 'ruby',
|
|
152
|
+
async gather(cwd) {
|
|
153
|
+
return gatherRubyImportsResult(cwd);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
// ─── Test framework (Gemfile / Gemfile.lock text scan) ──────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* Detect the Ruby test framework by scanning Gemfile + Gemfile.lock for
|
|
159
|
+
* known gem names. Order of precedence: rspec → minitest → test-unit.
|
|
160
|
+
*
|
|
161
|
+
* - RSpec ('rspec', 'rspec-rails') — by far the most common Ruby
|
|
162
|
+
* test runner, takes precedence when present.
|
|
163
|
+
* - Minitest — Ruby stdlib's runner, often used directly or via
|
|
164
|
+
* Rails' default `test/` directory.
|
|
165
|
+
* - test-unit — Ruby 1.8-era runner; still used by some legacy
|
|
166
|
+
* projects and by Ruby itself's stdlib tests.
|
|
167
|
+
*
|
|
168
|
+
* Falls back to test-file glob counts when no Gemfile is present (a
|
|
169
|
+
* vendored library directory or scratch script repo). The glob counts
|
|
170
|
+
* mirror the test patterns declared on the pack: `*_spec.rb` → rspec,
|
|
171
|
+
* `*_test.rb` / `test_*.rb` → minitest.
|
|
172
|
+
*
|
|
173
|
+
* Returns null when nothing identifies a framework — analyzers should
|
|
174
|
+
* treat null as "test-runner unknown" rather than "no tests."
|
|
175
|
+
*/
|
|
176
|
+
function gatherRubyTestFrameworkResult(cwd) {
|
|
177
|
+
const manifests = ['Gemfile', 'Gemfile.lock'];
|
|
178
|
+
let combined = '';
|
|
179
|
+
for (const rel of manifests) {
|
|
180
|
+
if (!(0, runner_1.fileExists)(cwd, rel))
|
|
181
|
+
continue;
|
|
182
|
+
try {
|
|
183
|
+
combined += fs.readFileSync(path.join(cwd, rel), 'utf-8') + '\n';
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
/* ignore unreadable */
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (combined) {
|
|
190
|
+
if (/\brspec(?:-rails)?\b/.test(combined)) {
|
|
191
|
+
return { schemaVersion: 1, tool: 'ruby', name: 'rspec' };
|
|
192
|
+
}
|
|
193
|
+
if (/\bminitest\b/.test(combined)) {
|
|
194
|
+
return { schemaVersion: 1, tool: 'ruby', name: 'minitest' };
|
|
195
|
+
}
|
|
196
|
+
if (/\btest-unit\b/.test(combined)) {
|
|
197
|
+
return { schemaVersion: 1, tool: 'ruby', name: 'test-unit' };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Glob-count fallback: no Gemfile (or Gemfile mentions no known runner).
|
|
201
|
+
// Run two cheap finds and pick the framework whose convention dominates.
|
|
202
|
+
const excludes = (0, exclusions_1.getFindExcludeFlags)(cwd);
|
|
203
|
+
const specCount = (0, runner_1.run)(`find . -type f -name "*_spec.rb" ${excludes} 2>/dev/null | wc -l`, cwd);
|
|
204
|
+
const testCount = (0, runner_1.run)(`find . -type f \\( -name "*_test.rb" -o -name "test_*.rb" \\) ${excludes} 2>/dev/null | wc -l`, cwd);
|
|
205
|
+
const specs = parseInt(specCount, 10) || 0;
|
|
206
|
+
const tests = parseInt(testCount, 10) || 0;
|
|
207
|
+
if (specs === 0 && tests === 0)
|
|
208
|
+
return null;
|
|
209
|
+
return {
|
|
210
|
+
schemaVersion: 1,
|
|
211
|
+
tool: 'ruby',
|
|
212
|
+
name: specs >= tests ? 'rspec' : 'minitest',
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const rubyTestFrameworkProvider = {
|
|
216
|
+
source: 'ruby',
|
|
217
|
+
async gather(cwd) {
|
|
218
|
+
return gatherRubyTestFrameworkResult(cwd);
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
// ─── Lint (rubocop --format json) ───────────────────────────────────────────
|
|
222
|
+
/**
|
|
223
|
+
* Map RuboCop's severity strings to dxkit's four-tier scheme. RuboCop
|
|
224
|
+
* canonically emits 5 severities (see `RuboCop::Cop::Severity::CODES`
|
|
225
|
+
* in the upstream source — `lib/rubocop/cop/severity.rb`):
|
|
226
|
+
*
|
|
227
|
+
* - `convention` → low (style + naming — the bulk of findings)
|
|
228
|
+
* - `refactor` → low (complexity hints; Metrics/* cops)
|
|
229
|
+
* - `warning` → medium (Lint/* cops — actual code-quality risk)
|
|
230
|
+
* - `error` → high (real defects; rare in default config)
|
|
231
|
+
* - `fatal` → critical (rubocop-internal failure or syntax error)
|
|
232
|
+
*
|
|
233
|
+
* Defensive `'low'` default for unknown severities — matches the
|
|
234
|
+
* mapDetektSeverity / mapRuffSeverity contract: never silently drop a
|
|
235
|
+
* finding, even if rubocop adds a new tier we don't recognize yet.
|
|
236
|
+
*
|
|
237
|
+
* Exported for unit tests.
|
|
238
|
+
*/
|
|
239
|
+
function mapRubocopSeverity(severity) {
|
|
240
|
+
if (typeof severity !== 'string')
|
|
241
|
+
return 'low';
|
|
242
|
+
switch (severity.toLowerCase()) {
|
|
243
|
+
case 'fatal':
|
|
244
|
+
return 'critical';
|
|
245
|
+
case 'error':
|
|
246
|
+
return 'high';
|
|
247
|
+
case 'warning':
|
|
248
|
+
return 'medium';
|
|
249
|
+
case 'convention':
|
|
250
|
+
case 'refactor':
|
|
251
|
+
return 'low';
|
|
252
|
+
default:
|
|
253
|
+
return 'low';
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Pure parser for RuboCop's JSON output (rubocop --format json). The
|
|
258
|
+
* shape is fixed per the upstream `RuboCop::Formatter::JSONFormatter`
|
|
259
|
+
* contract — `metadata` + `files[*].offenses[*]` + `summary`. We only
|
|
260
|
+
* need the offenses; metadata + summary are surface for future
|
|
261
|
+
* enrichment (per-file attribution, top-N rules) but not needed for
|
|
262
|
+
* the dxkit lint envelope which carries SeverityCounts only.
|
|
263
|
+
*
|
|
264
|
+
* Returns zero counts on malformed input rather than throwing —
|
|
265
|
+
* matches mapDetektSeverity / parseEslintFinal conventions. The
|
|
266
|
+
* gather function distinguishes "rubocop ran fine, found nothing"
|
|
267
|
+
* from "rubocop missing / parse error" via LintGatherOutcome's
|
|
268
|
+
* kind field.
|
|
269
|
+
*
|
|
270
|
+
* Exported for unit tests; consumed by `gatherRubyLintResult`.
|
|
271
|
+
*/
|
|
272
|
+
function parseRubocopOutput(raw) {
|
|
273
|
+
const counts = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
274
|
+
let data;
|
|
275
|
+
try {
|
|
276
|
+
data = JSON.parse(raw);
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return counts;
|
|
280
|
+
}
|
|
281
|
+
for (const file of data.files ?? []) {
|
|
282
|
+
for (const offense of file.offenses ?? []) {
|
|
283
|
+
counts[mapRubocopSeverity(offense.severity)]++;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return counts;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Single source of truth for the ruby pack's lint gathering. Consumed
|
|
290
|
+
* by `rubyLintProvider` (capability dispatcher).
|
|
291
|
+
*
|
|
292
|
+
* RuboCop is invoked with `--format json` so we always get a
|
|
293
|
+
* machine-readable payload (the default formatter is human-text).
|
|
294
|
+
* Exit code: rubocop exits 1 when offenses are found, 0 when clean.
|
|
295
|
+
* We tolerate any exit code (rubocop writes valid JSON to stdout
|
|
296
|
+
* regardless) and rely on parseRubocopOutput's empty-on-malformed
|
|
297
|
+
* contract.
|
|
298
|
+
*/
|
|
299
|
+
function gatherRubyLintResult(cwd) {
|
|
300
|
+
const rubocop = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.rubocop, cwd);
|
|
301
|
+
if (!rubocop.available || !rubocop.path) {
|
|
302
|
+
return { kind: 'unavailable', reason: 'not installed' };
|
|
303
|
+
}
|
|
304
|
+
const raw = (0, runner_1.run)(`${rubocop.path} --format json . 2>/dev/null`, cwd, 120000);
|
|
305
|
+
if (!raw) {
|
|
306
|
+
return { kind: 'unavailable', reason: 'no rubocop output' };
|
|
307
|
+
}
|
|
308
|
+
const counts = parseRubocopOutput(raw);
|
|
309
|
+
const envelope = { schemaVersion: 1, tool: 'rubocop', counts };
|
|
310
|
+
return { kind: 'success', envelope };
|
|
311
|
+
}
|
|
312
|
+
const rubyLintProvider = {
|
|
313
|
+
source: 'ruby',
|
|
314
|
+
async gather(cwd) {
|
|
315
|
+
const outcome = gatherRubyLintResult(cwd);
|
|
316
|
+
return outcome.kind === 'success' ? outcome.envelope : null;
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Pure parser for SimpleCov `.resultset.json`. Returns null when the
|
|
321
|
+
* input has no parseable suites (empty file, missing `coverage` key,
|
|
322
|
+
* or malformed JSON) — distinct from "0% coverage" (where suites
|
|
323
|
+
* exist with zero hits).
|
|
324
|
+
*
|
|
325
|
+
* Exported for unit tests; consumed by `gatherSimpleCovCoverageResult`.
|
|
326
|
+
*/
|
|
327
|
+
function parseSimpleCovResultset(raw, sourceFile, cwd) {
|
|
328
|
+
let data;
|
|
329
|
+
try {
|
|
330
|
+
data = JSON.parse(raw);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
// Per-file line arrays unioned across suites (max per index).
|
|
336
|
+
const merged = new Map();
|
|
337
|
+
for (const suite of Object.values(data)) {
|
|
338
|
+
const cov = suite?.coverage;
|
|
339
|
+
if (!cov || typeof cov !== 'object')
|
|
340
|
+
continue;
|
|
341
|
+
for (const [absPath, entry] of Object.entries(cov)) {
|
|
342
|
+
const lines = entry?.lines;
|
|
343
|
+
if (!Array.isArray(lines))
|
|
344
|
+
continue;
|
|
345
|
+
const existing = merged.get(absPath);
|
|
346
|
+
if (!existing) {
|
|
347
|
+
merged.set(absPath, lines.slice());
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
// Union: per index, keep max(existing, new). null stays null only if
|
|
351
|
+
// both are null; any int wins over null; max int wins between two ints.
|
|
352
|
+
const len = Math.max(existing.length, lines.length);
|
|
353
|
+
const out = new Array(len);
|
|
354
|
+
for (let i = 0; i < len; i++) {
|
|
355
|
+
const a = existing[i] ?? null;
|
|
356
|
+
const b = lines[i] ?? null;
|
|
357
|
+
if (a === null && b === null)
|
|
358
|
+
out[i] = null;
|
|
359
|
+
else if (a === null)
|
|
360
|
+
out[i] = b;
|
|
361
|
+
else if (b === null)
|
|
362
|
+
out[i] = a;
|
|
363
|
+
else
|
|
364
|
+
out[i] = Math.max(a, b);
|
|
365
|
+
}
|
|
366
|
+
merged.set(absPath, out);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (merged.size === 0)
|
|
370
|
+
return null;
|
|
371
|
+
const files = new Map();
|
|
372
|
+
let totalCovered = 0;
|
|
373
|
+
let totalExecutable = 0;
|
|
374
|
+
for (const [absPath, lines] of merged) {
|
|
375
|
+
let covered = 0;
|
|
376
|
+
let executable = 0;
|
|
377
|
+
for (const v of lines) {
|
|
378
|
+
if (v === null)
|
|
379
|
+
continue;
|
|
380
|
+
executable += 1;
|
|
381
|
+
if (v > 0)
|
|
382
|
+
covered += 1;
|
|
383
|
+
}
|
|
384
|
+
const rel = (0, coverage_1.toRelative)(absPath, cwd);
|
|
385
|
+
files.set(rel, {
|
|
386
|
+
path: rel,
|
|
387
|
+
covered,
|
|
388
|
+
total: executable,
|
|
389
|
+
pct: (0, coverage_1.round1)(executable > 0 ? (covered / executable) * 100 : 0),
|
|
390
|
+
});
|
|
391
|
+
totalCovered += covered;
|
|
392
|
+
totalExecutable += executable;
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
source: 'simplecov',
|
|
396
|
+
sourceFile,
|
|
397
|
+
linePercent: (0, coverage_1.round1)(totalExecutable > 0 ? (totalCovered / totalExecutable) * 100 : 0),
|
|
398
|
+
files,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Probe SimpleCov's canonical artifact path. The default formatter
|
|
403
|
+
* writes `coverage/.resultset.json`; the simplecov-json gem writes
|
|
404
|
+
* `coverage/coverage.json` (less common). We probe the canonical
|
|
405
|
+
* path first — it ships with vanilla SimpleCov and is the most
|
|
406
|
+
* likely to exist.
|
|
407
|
+
*/
|
|
408
|
+
function findSimpleCovResultset(cwd) {
|
|
409
|
+
const candidates = ['coverage/.resultset.json', 'coverage/coverage.json'];
|
|
410
|
+
for (const rel of candidates) {
|
|
411
|
+
if ((0, runner_1.fileExists)(cwd, rel))
|
|
412
|
+
return rel;
|
|
413
|
+
}
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Probe SimpleCov state and produce the discriminated outcome. Three
|
|
418
|
+
* paths, all distinguishable downstream:
|
|
419
|
+
* 1. `success` — parseable JSON found at `.resultset.json` or
|
|
420
|
+
* `coverage.json`; envelope ready to ship.
|
|
421
|
+
* 2. `html-only` — `coverage/index.html` exists but no JSON;
|
|
422
|
+
* SimpleCov ran, but in a format we can't parse.
|
|
423
|
+
* Includes a hint string for the user.
|
|
424
|
+
* 3. `unavailable` — neither JSON nor HTML; tool didn't run.
|
|
425
|
+
*/
|
|
426
|
+
function gatherSimpleCovOutcome(cwd) {
|
|
427
|
+
const reportRel = findSimpleCovResultset(cwd);
|
|
428
|
+
if (reportRel) {
|
|
429
|
+
try {
|
|
430
|
+
const raw = fs.readFileSync(path.join(cwd, reportRel), 'utf-8');
|
|
431
|
+
const coverage = parseSimpleCovResultset(raw, reportRel, cwd);
|
|
432
|
+
if (coverage) {
|
|
433
|
+
return {
|
|
434
|
+
kind: 'success',
|
|
435
|
+
envelope: { schemaVersion: 1, tool: `coverage:${coverage.source}`, coverage },
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
// Fall through to the html-only / unavailable check — a corrupt
|
|
441
|
+
// JSON shouldn't masquerade as "tool didn't run" when the user
|
|
442
|
+
// clearly did run SimpleCov (HTML is the tell).
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if ((0, runner_1.fileExists)(cwd, 'coverage/index.html')) {
|
|
446
|
+
return {
|
|
447
|
+
kind: 'html-only',
|
|
448
|
+
hint: 'SimpleCov produced HTML output only. ' +
|
|
449
|
+
'Install the simplecov-json gem to emit `coverage/coverage.json`, ' +
|
|
450
|
+
'or keep the default formatter (which produces the binary intermediate ' +
|
|
451
|
+
'`coverage/.resultset.json` that dxkit also reads).',
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
return { kind: 'unavailable' };
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Single source of truth for the ruby pack's coverage gathering.
|
|
458
|
+
* Consumed by `rubyCoverageProvider` (capability dispatcher).
|
|
459
|
+
*
|
|
460
|
+
* Thin adapter over `gatherSimpleCovOutcome`: collapses the three-way
|
|
461
|
+
* outcome to the dispatcher's binary `CoverageResult | null` contract.
|
|
462
|
+
* Callers that need the html-only signal should use
|
|
463
|
+
* `gatherSimpleCovOutcome` directly.
|
|
464
|
+
*/
|
|
465
|
+
function gatherSimpleCovCoverageResult(cwd) {
|
|
466
|
+
const outcome = gatherSimpleCovOutcome(cwd);
|
|
467
|
+
return outcome.kind === 'success' ? outcome.envelope : null;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Check that SimpleCov is required + started in the project's
|
|
471
|
+
* `spec_helper.rb` or `rails_helper.rb`. Without this, `bundle exec
|
|
472
|
+
* rspec` runs cleanly but writes no `.resultset.json` — the user
|
|
473
|
+
* spends 30+ seconds running tests then sees "tests ran but no
|
|
474
|
+
* coverage artifact was produced." Better to short-circuit upfront
|
|
475
|
+
* with the actionable hint.
|
|
476
|
+
*
|
|
477
|
+
* Looks for the canonical setup form: `require 'simplecov'` followed
|
|
478
|
+
* eventually by `SimpleCov.start`. Tolerates double quotes and any
|
|
479
|
+
* whitespace. spec_helper / rails_helper are the conventional
|
|
480
|
+
* locations; we check both because Rails projects use the latter.
|
|
481
|
+
*/
|
|
482
|
+
function simplecovIsRequired(cwd) {
|
|
483
|
+
const candidates = ['spec/spec_helper.rb', 'spec/rails_helper.rb', 'test/test_helper.rb'];
|
|
484
|
+
for (const c of candidates) {
|
|
485
|
+
const abs = path.join(cwd, c);
|
|
486
|
+
let raw;
|
|
487
|
+
try {
|
|
488
|
+
raw = fs.readFileSync(abs, 'utf-8');
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
const hasRequire = /\brequire\s+['"]simplecov['"]/.test(raw);
|
|
494
|
+
const hasStart = /\bSimpleCov\.start\b/.test(raw);
|
|
495
|
+
if (hasRequire && hasStart)
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Run `bundle exec rspec` from cwd (D021).
|
|
502
|
+
*
|
|
503
|
+
* SimpleCov is the canonical Ruby coverage tool. It's required from
|
|
504
|
+
* `spec_helper.rb` (not invoked separately) and writes its resultset
|
|
505
|
+
* during the rspec run itself — `bundle exec rspec` is therefore the
|
|
506
|
+
* coverage command, no extra flags needed.
|
|
507
|
+
*
|
|
508
|
+
* Preflight (in order, cheapest first):
|
|
509
|
+
* 1. `Gemfile` must exist — without one, bundler can't resolve the
|
|
510
|
+
* gem set and rspec won't be invokable.
|
|
511
|
+
* 2. `simplecov` gem must be installed (registry-tracked via
|
|
512
|
+
* `TOOL_DEFS.simplecov`, library-only gem detected via
|
|
513
|
+
* `gemPackage`).
|
|
514
|
+
* 3. `simplecov` must be `require`d AND `SimpleCov.start` called in
|
|
515
|
+
* `spec_helper.rb` / `rails_helper.rb` / `test_helper.rb`. SimpleCov
|
|
516
|
+
* is opt-in per-project; merely installing the gem doesn't
|
|
517
|
+
* instrument the test run. This check matches the G_v4_3
|
|
518
|
+
* gatherSimpleCovOutcome shape (html-only outcome surfaces
|
|
519
|
+
* separately on the read side).
|
|
520
|
+
*
|
|
521
|
+
* If all three pass, rspec is invoked via bundler so it resolves to
|
|
522
|
+
* the project's pinned version + plugins. Artifact is the canonical
|
|
523
|
+
* `coverage/.resultset.json` that `gatherSimpleCovOutcome` reads.
|
|
524
|
+
*/
|
|
525
|
+
function runRubyTestsWithCoverage(cwd) {
|
|
526
|
+
return Promise.resolve((0, run_tests_helper_1.runTestsWithCoverage)({
|
|
527
|
+
pack: 'ruby',
|
|
528
|
+
cmd: 'bundle exec rspec',
|
|
529
|
+
cwd,
|
|
530
|
+
artifact: 'coverage/.resultset.json',
|
|
531
|
+
preflight: (cwd) => {
|
|
532
|
+
if (!(0, runner_1.fileExists)(cwd, 'Gemfile')) {
|
|
533
|
+
return 'no Gemfile in this directory — not a Ruby/bundler project';
|
|
534
|
+
}
|
|
535
|
+
if (!(0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS.simplecov, cwd).available) {
|
|
536
|
+
return 'simplecov gem not installed — run `vyuh-dxkit tools install`';
|
|
537
|
+
}
|
|
538
|
+
if (!simplecovIsRequired(cwd)) {
|
|
539
|
+
return "simplecov not required/started in spec_helper.rb — add `require 'simplecov'` + `SimpleCov.start` at the top";
|
|
540
|
+
}
|
|
541
|
+
return null;
|
|
542
|
+
},
|
|
543
|
+
}));
|
|
544
|
+
}
|
|
545
|
+
const rubyCoverageProvider = {
|
|
546
|
+
source: 'ruby',
|
|
547
|
+
async gather(cwd) {
|
|
548
|
+
return gatherSimpleCovCoverageResult(cwd);
|
|
549
|
+
},
|
|
550
|
+
async runTests(cwd) {
|
|
551
|
+
return runRubyTestsWithCoverage(cwd);
|
|
552
|
+
},
|
|
553
|
+
};
|
|
554
|
+
// ─── DepVulns (osv-scanner against Gemfile.lock) ────────────────────────────
|
|
555
|
+
//
|
|
556
|
+
// Parser + manifest discovery + tool invocation + CVSS resolution all
|
|
557
|
+
// live in `src/analyzers/tools/osv-scanner-deps.ts` — language-agnostic
|
|
558
|
+
// SSOT (CLAUDE.md rule #2). Same module powers kotlin/java's Maven
|
|
559
|
+
// scanning. ParseOsvScannerFindings is exported there for unit tests
|
|
560
|
+
// and is exercised by both Maven and RubyGems fixtures.
|
|
561
|
+
//
|
|
562
|
+
// bundler-audit alternative: deliberately NOT used. Its JSON output
|
|
563
|
+
// is unstable upstream (line-oriented text is the canonical format),
|
|
564
|
+
// and osv-scanner gives us SSOT consistency across Maven/RubyGems/PyPI
|
|
565
|
+
// + stable JSON + CVSS resolution + the same enrichment surface. If a
|
|
566
|
+
// future customer needs bundler-audit specifically (e.g. air-gapped
|
|
567
|
+
// env where osv.dev queries are unavailable), it can be added as a
|
|
568
|
+
// secondary tool without disturbing this primary path.
|
|
569
|
+
const RUBY_DEP_MANIFESTS = ['Gemfile.lock'];
|
|
570
|
+
const rubyDepVulnsProvider = {
|
|
571
|
+
source: 'ruby',
|
|
572
|
+
async gather(cwd) {
|
|
573
|
+
const outcome = await (0, osv_scanner_deps_1.gatherOsvScannerDepVulnsResult)(cwd, 'ruby', 'RubyGems', RUBY_DEP_MANIFESTS);
|
|
574
|
+
return outcome.kind === 'success' ? outcome.envelope : null;
|
|
575
|
+
},
|
|
576
|
+
async gatherOutcome(cwd) {
|
|
577
|
+
return (0, osv_scanner_deps_1.gatherOsvScannerDepVulnsResult)(cwd, 'ruby', 'RubyGems', RUBY_DEP_MANIFESTS);
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
// ─── Pack export ────────────────────────────────────────────────────────────
|
|
581
|
+
exports.ruby = {
|
|
582
|
+
id: 'ruby',
|
|
583
|
+
displayName: 'Ruby',
|
|
584
|
+
sourceExtensions: ['.rb'],
|
|
585
|
+
testFilePatterns: [
|
|
586
|
+
'*_spec.rb',
|
|
587
|
+
'*_test.rb',
|
|
588
|
+
'test_*.rb',
|
|
589
|
+
'spec/**/*_spec.rb',
|
|
590
|
+
'test/**/*_test.rb',
|
|
591
|
+
],
|
|
592
|
+
extraExcludes: ['vendor/bundle', '.bundle', 'coverage', 'tmp', 'log'],
|
|
593
|
+
// D027 (2.4.7): YARD documentation convention uses `##` block
|
|
594
|
+
// comments (distinguished from regular `#` line comments). Plain
|
|
595
|
+
// `#` would over-match every commented-out line; `##` is the
|
|
596
|
+
// documented-block marker.
|
|
597
|
+
docCommentPatterns: ['^[[:space:]]*##'],
|
|
598
|
+
// D034 (2.4.7): OpenSSL TLS-bypass idioms for Ruby's stdlib
|
|
599
|
+
// `net/http` and `httpclient` gems. `VERIFY_NONE` is the constant
|
|
600
|
+
// ruby code sets on `http.verify_mode` to disable cert checks.
|
|
601
|
+
tlsBypassPatterns: [
|
|
602
|
+
'OpenSSL::SSL::VERIFY_NONE',
|
|
603
|
+
'verify_mode[[:space:]]*=[[:space:]]*.*VERIFY_NONE',
|
|
604
|
+
],
|
|
605
|
+
upgradeCommand(name, version) {
|
|
606
|
+
return `# Edit Gemfile: \`gem '${name}', '${version}'\`, then \`bundle install\``;
|
|
607
|
+
},
|
|
608
|
+
// Rails (`app/controllers/`, `app/services/`, `app/models/`,
|
|
609
|
+
// `app/views/`) is the dominant Ruby application shape. Sinatra
|
|
610
|
+
// and Hanami sometimes diverge but typically also adopt the Rails
|
|
611
|
+
// app/<role> convention. Paths are anchored at `/app/<role>/` to
|
|
612
|
+
// avoid matching a top-level `models/` directory in a non-Rails
|
|
613
|
+
// gem.
|
|
614
|
+
architecturalShape: {
|
|
615
|
+
primaryComponentPaths: [
|
|
616
|
+
'/app/controllers/',
|
|
617
|
+
'/app/services/',
|
|
618
|
+
'/app/jobs/',
|
|
619
|
+
'/app/helpers/',
|
|
620
|
+
'/app/views/',
|
|
621
|
+
'/app/channels/',
|
|
622
|
+
'/app/workers/',
|
|
623
|
+
],
|
|
624
|
+
routePaths: ['/app/controllers/', '/app/channels/'],
|
|
625
|
+
modelPaths: ['/app/models/', '/app/serializers/'],
|
|
626
|
+
vocabulary: {
|
|
627
|
+
components: 'controllers/services',
|
|
628
|
+
models: 'models',
|
|
629
|
+
routes: 'routes',
|
|
630
|
+
},
|
|
631
|
+
testGapPriority: {
|
|
632
|
+
high: ['/app/controllers/', '/app/services/', '/app/jobs/', '/app/workers/'],
|
|
633
|
+
medium: ['/app/helpers/', '/app/views/', '/app/channels/', '/app/serializers/'],
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
clocLanguageNames: ['Ruby'],
|
|
637
|
+
detect: detectRuby,
|
|
638
|
+
tools: ['osv-scanner', 'rubocop', 'simplecov'],
|
|
639
|
+
semgrepRulesets: ['p/ruby'],
|
|
640
|
+
capabilities: {
|
|
641
|
+
imports: rubyImportsProvider,
|
|
642
|
+
testFramework: rubyTestFrameworkProvider,
|
|
643
|
+
coverage: rubyCoverageProvider,
|
|
644
|
+
lint: rubyLintProvider,
|
|
645
|
+
depVulns: rubyDepVulnsProvider,
|
|
646
|
+
},
|
|
647
|
+
mapLintSeverity: mapRubocopSeverity,
|
|
648
|
+
permissions: [
|
|
649
|
+
'Bash(bundle:*)',
|
|
650
|
+
'Bash(rake:*)',
|
|
651
|
+
'Bash(rspec:*)',
|
|
652
|
+
'Bash(rubocop:*)',
|
|
653
|
+
'Bash(ruby:*)',
|
|
654
|
+
],
|
|
655
|
+
ruleFile: 'ruby.md',
|
|
656
|
+
templateFiles: [],
|
|
657
|
+
cliBinaries: ['ruby', 'bundle'],
|
|
658
|
+
defaultVersion: '3.3.0',
|
|
659
|
+
projectYamlBlock: ({ config, enabled }) => [
|
|
660
|
+
` ruby:`,
|
|
661
|
+
` enabled: ${enabled}`,
|
|
662
|
+
` version: "${config.versions['ruby'] ?? '3.3.0'}"`,
|
|
663
|
+
].join('\n'),
|
|
664
|
+
};
|
|
665
|
+
//# sourceMappingURL=ruby.js.map
|