@geoql/doctor-core 1.1.0 → 1.1.1
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/dist/index.d.ts +30 -2
- package/dist/index.js +60 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -485,6 +485,29 @@ interface ListRulesFilter {
|
|
|
485
485
|
}
|
|
486
486
|
declare function listRules(filter?: ListRulesFilter): RegisteredRule[];
|
|
487
487
|
//#endregion
|
|
488
|
+
//#region src/audit-filter.d.ts
|
|
489
|
+
/**
|
|
490
|
+
* Filter `report.diagnostics` to a known set of allowed rule ids, then
|
|
491
|
+
* recompute `score`, `errorCount`, `warnCount`, `infoCount`, `scoreResult`,
|
|
492
|
+
* `ruleCounts`, and `exitCode` from the filtered array.
|
|
493
|
+
*
|
|
494
|
+
* Why: the CLI layer calls `audit()` and then applies its own
|
|
495
|
+
* `allowedRuleIds` filter to drop suppressed (`off`) and preset-excluded
|
|
496
|
+
* (`info` rules not in `recommended`) diagnostics. The audit's own
|
|
497
|
+
* `score`/`counts` are computed BEFORE the CLI filter, so they still
|
|
498
|
+
* include the suppressed findings. That desync surfaces to consumers
|
|
499
|
+
* (the SaaS `--push` payload, the dashboard's counts-but-no-findings bug)
|
|
500
|
+
* and to the `score` itself (suppressed findings still penalize).
|
|
501
|
+
*
|
|
502
|
+
* Invariant enforced here:
|
|
503
|
+
* report.errorCount + report.warnCount + report.infoCount === report.diagnostics.length
|
|
504
|
+
* report.scoreResult.totalFindings === report.diagnostics.length
|
|
505
|
+
*
|
|
506
|
+
* `exitCode=2` (oxlint crash) is preserved verbatim; `exitCode=1` is
|
|
507
|
+
* recomputed from the surviving counts + the `failOn` gate.
|
|
508
|
+
*/
|
|
509
|
+
declare function filterReportByRules(report: AuditReport, allowedRuleIds: ReadonlySet<string>, failOn?: 'error' | 'warn' | 'none', oxlintStderr?: string): AuditReport;
|
|
510
|
+
//#endregion
|
|
488
511
|
//#region src/push.d.ts
|
|
489
512
|
/**
|
|
490
513
|
* The 6 fields the SaaS receives for each finding.
|
|
@@ -519,6 +542,8 @@ interface PushOptions {
|
|
|
519
542
|
warnCount: number;
|
|
520
543
|
infoCount: number;
|
|
521
544
|
diagnostics: Diagnostic[];
|
|
545
|
+
/** Project root used to relativize absolute finding file paths. */
|
|
546
|
+
rootDir?: string;
|
|
522
547
|
url: string;
|
|
523
548
|
apiKey: string;
|
|
524
549
|
fetchImpl?: typeof fetch;
|
|
@@ -538,8 +563,11 @@ type PushResult = {
|
|
|
538
563
|
* Strip a list of Diagnostics down to the 6 allowed push fields.
|
|
539
564
|
* Privacy boundary: this function is the single point of enforcement.
|
|
540
565
|
* If you add a new privacy-sensitive field to Diagnostic, add it to the deny list here.
|
|
566
|
+
*
|
|
567
|
+
* Absolute file paths are relativized against rootDir so dashboards show
|
|
568
|
+
* `src/Foo.vue` rather than the CI runner's `/home/runner/work/<repo>/…`.
|
|
541
569
|
*/
|
|
542
|
-
declare function stripFindings(diagnostics: Diagnostic[]): PushedFinding[];
|
|
570
|
+
declare function stripFindings(diagnostics: Diagnostic[], rootDir?: string): PushedFinding[];
|
|
543
571
|
/**
|
|
544
572
|
* Build the top-level POST body. CI fields (commitSha, branch, prNumber) are
|
|
545
573
|
* included ONLY when the matching GITHUB_* env var is set.
|
|
@@ -552,5 +580,5 @@ declare function buildPushPayload(input: PushPayloadInput): PushPayload;
|
|
|
552
580
|
*/
|
|
553
581
|
declare function pushFindings(opts: PushOptions): Promise<PushResult>;
|
|
554
582
|
//#endregion
|
|
555
|
-
export { type ApplyInlineDisablesOptions, type AuditConfig, type AuditReport, type AuditTimings, BUILT_IN_RECOMMENDED, type Capability, type CliOverrides, ConfigCycleError, ConfigFileNotFoundError, type ConfigSource, DOCTOR_REPORT_SCHEMA_VERSION, DeadCodeImportFailed, DeadCodeTimeoutError, type Diagnostic, type DiagnosticSource, type DirectiveLine, type DirectiveRange, type DirectiveSet, type DoctorReport, type DoctorUserConfig, type Framework, type GitScopeMode, type InitConfigFormat, type InitFileWrite, type InitOptions, type InitPlan, type InitPreset, InvalidConfigError, type ListRulesFilter, type LoadRuleDocOptions, type MonorepoKind, type MonorepoResult, OxlintOutputTooLarge, OxlintSpawnFailed, type ProjectInfo, type ProjectInfoLite, type PushOptions, type PushPayload, type PushPayloadInput, type PushResult, type PushedFinding, RULE_REGISTRY, type RawInitAnswers, type RegisteredRule, type ReporterFormat, type ReporterInput, type ReporterOptions, type ResolvedDoctorConfig, type ResolvedInitAnswers, type RuleCategory, type RuleDoc, type RuleSource, type ScoreBreakdownEntry, type ScoreConfig, type ScoreResult, type Severity, type VerboseTraceOptions, type WorkspacePackage, agentReport, applyInlineDisables, audit, buildDoctorReport, buildPushPayload, checkBuildQuality, checkDeadCode, checkDeps, checkNuxtProject, dedupeDeadCodeAgainstLint, defineConfig, detectProject, detectSummary, docsUrl, encodeAnnotation, encodeAnnotations, findMonorepoRoot, format, isNuxtLayoutFile, isNuxtPageFile, isNuxtServerFile, jsonCompactReport, jsonReport, listChangedFiles, listRules, listWorkspacePackages, loadAllRuleDocs, loadDoctorConfig, loadRuleDoc, mergeCliOverrides, normalizeInitAnswers, parseDirectives, parseExcludeList, planInit, prCommentReport, prettyReport, pushFindings, renderDetectSummary, renderVerboseTrace, runCrossFilePass, sarifReport, scoreDiagnostics, stripFindings, validateConfig };
|
|
583
|
+
export { type ApplyInlineDisablesOptions, type AuditConfig, type AuditReport, type AuditTimings, BUILT_IN_RECOMMENDED, type Capability, type CliOverrides, ConfigCycleError, ConfigFileNotFoundError, type ConfigSource, DOCTOR_REPORT_SCHEMA_VERSION, DeadCodeImportFailed, DeadCodeTimeoutError, type Diagnostic, type DiagnosticSource, type DirectiveLine, type DirectiveRange, type DirectiveSet, type DoctorReport, type DoctorUserConfig, type Framework, type GitScopeMode, type InitConfigFormat, type InitFileWrite, type InitOptions, type InitPlan, type InitPreset, InvalidConfigError, type ListRulesFilter, type LoadRuleDocOptions, type MonorepoKind, type MonorepoResult, OxlintOutputTooLarge, OxlintSpawnFailed, type ProjectInfo, type ProjectInfoLite, type PushOptions, type PushPayload, type PushPayloadInput, type PushResult, type PushedFinding, RULE_REGISTRY, type RawInitAnswers, type RegisteredRule, type ReporterFormat, type ReporterInput, type ReporterOptions, type ResolvedDoctorConfig, type ResolvedInitAnswers, type RuleCategory, type RuleDoc, type RuleSource, type ScoreBreakdownEntry, type ScoreConfig, type ScoreResult, type Severity, type VerboseTraceOptions, type WorkspacePackage, agentReport, applyInlineDisables, audit, buildDoctorReport, buildPushPayload, checkBuildQuality, checkDeadCode, checkDeps, checkNuxtProject, dedupeDeadCodeAgainstLint, defineConfig, detectProject, detectSummary, docsUrl, encodeAnnotation, encodeAnnotations, filterReportByRules, findMonorepoRoot, format, isNuxtLayoutFile, isNuxtPageFile, isNuxtServerFile, jsonCompactReport, jsonReport, listChangedFiles, listRules, listWorkspacePackages, loadAllRuleDocs, loadDoctorConfig, loadRuleDoc, mergeCliOverrides, normalizeInitAnswers, parseDirectives, parseExcludeList, planInit, prCommentReport, prettyReport, pushFindings, renderDetectSummary, renderVerboseTrace, runCrossFilePass, sarifReport, scoreDiagnostics, stripFindings, validateConfig };
|
|
556
584
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as listRules, c as InvalidConfigError, i as RULE_REGISTRY, l as BUILT_IN_RECOMMENDED, o as ConfigCycleError, r as validateConfig, s as ConfigFileNotFoundError, t as loadDoctorConfig } from "./load-yXDi-5ti.js";
|
|
2
|
-
import { dirname, join, relative, resolve } from "node:path";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import { performance } from "node:perf_hooks";
|
|
4
4
|
import { access, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
@@ -3011,7 +3011,7 @@ async function listWorkspacePackages(rootDir) {
|
|
|
3011
3011
|
//#endregion
|
|
3012
3012
|
//#region src/reporters/docs-url.ts
|
|
3013
3013
|
function docsUrl(ruleId) {
|
|
3014
|
-
return `https://docs.doctor.
|
|
3014
|
+
return `https://docs.the-doctor.report/rules/${ruleId}`;
|
|
3015
3015
|
}
|
|
3016
3016
|
//#endregion
|
|
3017
3017
|
//#region src/reporters/render.ts
|
|
@@ -3374,7 +3374,7 @@ function jsonCompactReport(input) {
|
|
|
3374
3374
|
}
|
|
3375
3375
|
//#endregion
|
|
3376
3376
|
//#region src/reporters/pr-comment.ts
|
|
3377
|
-
const DOCS_BASE = "https://docs.doctor.
|
|
3377
|
+
const DOCS_BASE = "https://docs.the-doctor.report/rules/";
|
|
3378
3378
|
const MAX_PER_SECTION = 5;
|
|
3379
3379
|
function binName(toolName) {
|
|
3380
3380
|
return toolName.replace("@geoql/", "");
|
|
@@ -3474,23 +3474,76 @@ function format(input, kind = "agent", options) {
|
|
|
3474
3474
|
return agentReport(input, options);
|
|
3475
3475
|
}
|
|
3476
3476
|
//#endregion
|
|
3477
|
+
//#region src/audit-filter.ts
|
|
3478
|
+
/**
|
|
3479
|
+
* Filter `report.diagnostics` to a known set of allowed rule ids, then
|
|
3480
|
+
* recompute `score`, `errorCount`, `warnCount`, `infoCount`, `scoreResult`,
|
|
3481
|
+
* `ruleCounts`, and `exitCode` from the filtered array.
|
|
3482
|
+
*
|
|
3483
|
+
* Why: the CLI layer calls `audit()` and then applies its own
|
|
3484
|
+
* `allowedRuleIds` filter to drop suppressed (`off`) and preset-excluded
|
|
3485
|
+
* (`info` rules not in `recommended`) diagnostics. The audit's own
|
|
3486
|
+
* `score`/`counts` are computed BEFORE the CLI filter, so they still
|
|
3487
|
+
* include the suppressed findings. That desync surfaces to consumers
|
|
3488
|
+
* (the SaaS `--push` payload, the dashboard's counts-but-no-findings bug)
|
|
3489
|
+
* and to the `score` itself (suppressed findings still penalize).
|
|
3490
|
+
*
|
|
3491
|
+
* Invariant enforced here:
|
|
3492
|
+
* report.errorCount + report.warnCount + report.infoCount === report.diagnostics.length
|
|
3493
|
+
* report.scoreResult.totalFindings === report.diagnostics.length
|
|
3494
|
+
*
|
|
3495
|
+
* `exitCode=2` (oxlint crash) is preserved verbatim; `exitCode=1` is
|
|
3496
|
+
* recomputed from the surviving counts + the `failOn` gate.
|
|
3497
|
+
*/
|
|
3498
|
+
function filterReportByRules(report, allowedRuleIds, failOn = "error", oxlintStderr) {
|
|
3499
|
+
const filtered = [];
|
|
3500
|
+
for (const d of report.diagnostics) if (allowedRuleIds.has(d.ruleId)) filtered.push(d);
|
|
3501
|
+
const threshold = report.scoreResult.threshold;
|
|
3502
|
+
const scoreResult = scoreDiagnostics(filtered, { threshold });
|
|
3503
|
+
const ruleCounts = {};
|
|
3504
|
+
for (const d of filtered) ruleCounts[d.ruleId] = (ruleCounts[d.ruleId] ?? 0) + 1;
|
|
3505
|
+
let exitCode = report.exitCode;
|
|
3506
|
+
if (exitCode !== 2) if (failOn === "none") exitCode = 0;
|
|
3507
|
+
else exitCode = (failOn === "warn" ? scoreResult.errorCount + scoreResult.warnCount : scoreResult.errorCount) > 0 ? 1 : 0;
|
|
3508
|
+
return {
|
|
3509
|
+
...report,
|
|
3510
|
+
diagnostics: filtered,
|
|
3511
|
+
score: scoreResult.score,
|
|
3512
|
+
errorCount: scoreResult.errorCount,
|
|
3513
|
+
warnCount: scoreResult.warnCount,
|
|
3514
|
+
infoCount: scoreResult.infoCount,
|
|
3515
|
+
scoreResult,
|
|
3516
|
+
ruleCounts,
|
|
3517
|
+
exitCode
|
|
3518
|
+
};
|
|
3519
|
+
}
|
|
3520
|
+
//#endregion
|
|
3477
3521
|
//#region src/push.ts
|
|
3478
3522
|
const PUSH_TIMEOUT_MS = 5e3;
|
|
3479
3523
|
const categoryByRuleId = new Map(RULE_REGISTRY.map((r) => [r.id, r.category]));
|
|
3480
3524
|
function lookupCategory(ruleId) {
|
|
3481
3525
|
return categoryByRuleId.get(ruleId) ?? "unknown";
|
|
3482
3526
|
}
|
|
3527
|
+
function toRepoRelative(file, rootDir) {
|
|
3528
|
+
if (!rootDir || !isAbsolute(file)) return file;
|
|
3529
|
+
const rel = relative(rootDir, file);
|
|
3530
|
+
if (rel.startsWith("..")) return file;
|
|
3531
|
+
return rel;
|
|
3532
|
+
}
|
|
3483
3533
|
/**
|
|
3484
3534
|
* Strip a list of Diagnostics down to the 6 allowed push fields.
|
|
3485
3535
|
* Privacy boundary: this function is the single point of enforcement.
|
|
3486
3536
|
* If you add a new privacy-sensitive field to Diagnostic, add it to the deny list here.
|
|
3537
|
+
*
|
|
3538
|
+
* Absolute file paths are relativized against rootDir so dashboards show
|
|
3539
|
+
* `src/Foo.vue` rather than the CI runner's `/home/runner/work/<repo>/…`.
|
|
3487
3540
|
*/
|
|
3488
|
-
function stripFindings(diagnostics) {
|
|
3541
|
+
function stripFindings(diagnostics, rootDir) {
|
|
3489
3542
|
const out = new Array(diagnostics.length);
|
|
3490
3543
|
for (let i = 0; i < diagnostics.length; i++) {
|
|
3491
3544
|
const d = diagnostics[i];
|
|
3492
3545
|
out[i] = {
|
|
3493
|
-
file: d.file,
|
|
3546
|
+
file: toRepoRelative(d.file, rootDir),
|
|
3494
3547
|
line: d.line,
|
|
3495
3548
|
col: d.column,
|
|
3496
3549
|
ruleId: d.ruleId,
|
|
@@ -3537,7 +3590,7 @@ function buildPushPayload(input) {
|
|
|
3537
3590
|
* exit code is not affected by SaaS downtime.
|
|
3538
3591
|
*/
|
|
3539
3592
|
async function pushFindings(opts) {
|
|
3540
|
-
const findings = stripFindings(opts.diagnostics);
|
|
3593
|
+
const findings = stripFindings(opts.diagnostics, opts.rootDir);
|
|
3541
3594
|
const payload = buildPushPayload({
|
|
3542
3595
|
project: opts.project,
|
|
3543
3596
|
score: opts.score,
|
|
@@ -3580,6 +3633,6 @@ async function pushFindings(opts) {
|
|
|
3580
3633
|
}
|
|
3581
3634
|
}
|
|
3582
3635
|
//#endregion
|
|
3583
|
-
export { BUILT_IN_RECOMMENDED, ConfigCycleError, ConfigFileNotFoundError, DOCTOR_REPORT_SCHEMA_VERSION, DeadCodeImportFailed, DeadCodeTimeoutError, InvalidConfigError, OxlintOutputTooLarge, OxlintSpawnFailed, RULE_REGISTRY, agentReport, applyInlineDisables, audit, buildDoctorReport, buildPushPayload, checkBuildQuality, checkDeadCode, checkDeps, checkNuxtProject, dedupeDeadCodeAgainstLint, defineConfig, detectProject, detectSummary, docsUrl, encodeAnnotation, encodeAnnotations, findMonorepoRoot, format, isNuxtLayoutFile, isNuxtPageFile, isNuxtServerFile, jsonCompactReport, jsonReport, listChangedFiles, listRules, listWorkspacePackages, loadAllRuleDocs, loadDoctorConfig, loadRuleDoc, mergeCliOverrides, normalizeInitAnswers, parseDirectives, parseExcludeList, planInit, prCommentReport, prettyReport, pushFindings, renderDetectSummary, renderVerboseTrace, runCrossFilePass, sarifReport, scoreDiagnostics, stripFindings, validateConfig };
|
|
3636
|
+
export { BUILT_IN_RECOMMENDED, ConfigCycleError, ConfigFileNotFoundError, DOCTOR_REPORT_SCHEMA_VERSION, DeadCodeImportFailed, DeadCodeTimeoutError, InvalidConfigError, OxlintOutputTooLarge, OxlintSpawnFailed, RULE_REGISTRY, agentReport, applyInlineDisables, audit, buildDoctorReport, buildPushPayload, checkBuildQuality, checkDeadCode, checkDeps, checkNuxtProject, dedupeDeadCodeAgainstLint, defineConfig, detectProject, detectSummary, docsUrl, encodeAnnotation, encodeAnnotations, filterReportByRules, findMonorepoRoot, format, isNuxtLayoutFile, isNuxtPageFile, isNuxtServerFile, jsonCompactReport, jsonReport, listChangedFiles, listRules, listWorkspacePackages, loadAllRuleDocs, loadDoctorConfig, loadRuleDoc, mergeCliOverrides, normalizeInitAnswers, parseDirectives, parseExcludeList, planInit, prCommentReport, prettyReport, pushFindings, renderDetectSummary, renderVerboseTrace, runCrossFilePass, sarifReport, scoreDiagnostics, stripFindings, validateConfig };
|
|
3584
3637
|
|
|
3585
3638
|
//# sourceMappingURL=index.js.map
|