react-doctor 0.8.0 → 0.8.1-dev.1839566
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/cli.js +602 -75
- package/dist/index.d.ts +92 -94
- package/dist/index.js +107 -6
- package/dist/lsp.js +108 -7
- package/dist/skills/react-doctor/references/explain.md +1 -0
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -8980,6 +8980,84 @@ declare namespace Annotations {
|
|
|
8980
8980
|
}
|
|
8981
8981
|
//#endregion
|
|
8982
8982
|
//#region ../core/dist/index.d.ts
|
|
8983
|
+
/**
|
|
8984
|
+
* A secondary source location attached to a diagnostic (oxlint's
|
|
8985
|
+
* non-primary labels). Editors render these as
|
|
8986
|
+
* `Diagnostic.relatedInformation` so a user can jump from, say, a
|
|
8987
|
+
* `no-derived-state` finding to the originating prop declaration.
|
|
8988
|
+
* Positions mirror `Diagnostic` semantics: `line` / `column` are
|
|
8989
|
+
* 1-indexed, and `offset` / `length` are UTF-8 byte spans from oxlint
|
|
8990
|
+
* when available (preferred for precise ranges).
|
|
8991
|
+
*/
|
|
8992
|
+
interface DiagnosticRelatedLocation {
|
|
8993
|
+
filePath: string;
|
|
8994
|
+
line: number;
|
|
8995
|
+
column: number;
|
|
8996
|
+
offset?: number;
|
|
8997
|
+
length?: number;
|
|
8998
|
+
endLine?: number;
|
|
8999
|
+
endColumn?: number;
|
|
9000
|
+
message: string;
|
|
9001
|
+
}
|
|
9002
|
+
type DiagnosticFileContext = "test" | "story" | "production";
|
|
9003
|
+
interface Diagnostic {
|
|
9004
|
+
filePath: string;
|
|
9005
|
+
plugin: string;
|
|
9006
|
+
rule: string;
|
|
9007
|
+
severity: "error" | "warning";
|
|
9008
|
+
title?: string;
|
|
9009
|
+
message: string;
|
|
9010
|
+
help: string;
|
|
9011
|
+
url?: string;
|
|
9012
|
+
line: number;
|
|
9013
|
+
column: number;
|
|
9014
|
+
/**
|
|
9015
|
+
* UTF-8 byte offset of the diagnostic's primary span start, straight
|
|
9016
|
+
* from oxlint's label span. Optional because environment / dead-code
|
|
9017
|
+
* diagnostics carry no source span. Editors (LSP) convert this into a
|
|
9018
|
+
* precise range via the in-memory document; non-editor consumers can
|
|
9019
|
+
* ignore it.
|
|
9020
|
+
*/
|
|
9021
|
+
offset?: number;
|
|
9022
|
+
/** UTF-8 byte length of the primary span (pairs with `offset`). */
|
|
9023
|
+
length?: number;
|
|
9024
|
+
/** 1-indexed end line of the primary span, when derivable. */
|
|
9025
|
+
endLine?: number;
|
|
9026
|
+
/** 1-indexed end column of the primary span, when derivable. */
|
|
9027
|
+
endColumn?: number;
|
|
9028
|
+
category: string;
|
|
9029
|
+
/**
|
|
9030
|
+
* Set when the finding's identity is the flagged element itself (a missing
|
|
9031
|
+
* attribute, a wrong element) rather than the flagged line's text — every
|
|
9032
|
+
* Accessibility-category finding, plus rules that opt in via their
|
|
9033
|
+
* `matchByOccurrence` metadata flag. After strict evidence matching,
|
|
9034
|
+
* `computeDiagnosticDelta` may match these by same-file `(plugin/rule,
|
|
9035
|
+
* message)` occurrence count, so reformatting the flagged element doesn't
|
|
9036
|
+
* reclassify a pre-existing finding as new. Resolved at diagnostic creation,
|
|
9037
|
+
* where rule metadata is available. Absent means diagnosed-source-sensitive
|
|
9038
|
+
* matching (the default).
|
|
9039
|
+
*/
|
|
9040
|
+
matchByOccurrence?: boolean;
|
|
9041
|
+
/**
|
|
9042
|
+
* Set when the file never ships to users (`"test"` / `"story"`), so
|
|
9043
|
+
* renderers can label the site instead of implying production impact.
|
|
9044
|
+
* Omitted for production files (the default).
|
|
9045
|
+
*/
|
|
9046
|
+
fileContext?: Exclude<DiagnosticFileContext, "production">;
|
|
9047
|
+
suppressionHint?: string;
|
|
9048
|
+
/** Secondary source locations (oxlint's non-primary labels). */
|
|
9049
|
+
relatedLocations?: DiagnosticRelatedLocation[];
|
|
9050
|
+
/**
|
|
9051
|
+
* Stable id shared by every finding that a single fix resolves together —
|
|
9052
|
+
* e.g. four `useEffect`s that reset state on one prop change all clear with
|
|
9053
|
+
* one `key` prop. Set only when ≥2 findings share a root cause; absent for
|
|
9054
|
+
* standalone findings. A consumer that turns findings into work items should
|
|
9055
|
+
* group by it so one fix reads as one task, not N. Presentation-only and
|
|
9056
|
+
* score-neutral — the score never reads it.
|
|
9057
|
+
*/
|
|
9058
|
+
fixGroupId?: string;
|
|
9059
|
+
}
|
|
9060
|
+
//#endregion
|
|
8983
9061
|
//#region src/types/config.d.ts
|
|
8984
9062
|
/**
|
|
8985
9063
|
* Severity threshold at which a scan blocks CI (exits non-zero). Controlled
|
|
@@ -9057,9 +9135,9 @@ interface ReactDoctorIgnoreConfig {
|
|
|
9057
9135
|
* Defaults: design rules (tag `"design"`) are excluded from `prComment`,
|
|
9058
9136
|
* `score`, and `ciFailure` so style cleanup doesn't dilute meaningful
|
|
9059
9137
|
* React findings. Diagnostics stamped with `fileContext: "test" | "story"`
|
|
9060
|
-
* are excluded from `score` and `ciFailure`. Both remain in `cli
|
|
9061
|
-
*
|
|
9062
|
-
*
|
|
9138
|
+
* are excluded from `score` and `ciFailure`. Both remain in `cli`. Explicit
|
|
9139
|
+
* rule, category, or tag includes promote matching diagnostics, while
|
|
9140
|
+
* `includeFileContexts` restores a context without bypassing other exclusions.
|
|
9063
9141
|
*/
|
|
9064
9142
|
type DiagnosticSurface = "cli" | "prComment" | "score" | "ciFailure";
|
|
9065
9143
|
/**
|
|
@@ -9089,6 +9167,11 @@ interface SeverityBuckets {
|
|
|
9089
9167
|
"compiler-cleanup"?: RuleSeverityOverride;
|
|
9090
9168
|
}
|
|
9091
9169
|
interface SurfaceControls {
|
|
9170
|
+
/**
|
|
9171
|
+
* Non-production file contexts to retain on this surface. This restores
|
|
9172
|
+
* test or story findings without overriding unrelated tag exclusions.
|
|
9173
|
+
*/
|
|
9174
|
+
includeFileContexts?: Array<Exclude<DiagnosticFileContext, "production">>;
|
|
9092
9175
|
/**
|
|
9093
9176
|
* Tag names whose diagnostics should be force-included on the surface,
|
|
9094
9177
|
* even if a default or category-level exclusion would otherwise drop
|
|
@@ -9353,9 +9436,9 @@ interface ReactDoctorConfig {
|
|
|
9353
9436
|
* - `score` and `ciFailure` exclude test/story file contexts unless explicitly included
|
|
9354
9437
|
*
|
|
9355
9438
|
* Pass any controls block, including an empty `{}`, to keep the defaults.
|
|
9356
|
-
* Your include/exclude entries layer on top.
|
|
9357
|
-
*
|
|
9358
|
-
*
|
|
9439
|
+
* Your include/exclude entries layer on top. Rule, category, and tag includes
|
|
9440
|
+
* win over their exclusions. Included file contexts still respect unrelated
|
|
9441
|
+
* exclusions, so restoring story findings does not restore every design rule.
|
|
9359
9442
|
*/
|
|
9360
9443
|
surfaces?: Partial<Record<DiagnosticSurface, SurfaceControls>>;
|
|
9361
9444
|
/**
|
|
@@ -9449,84 +9532,6 @@ interface ReactDoctorConfig {
|
|
|
9449
9532
|
*/
|
|
9450
9533
|
plugins?: string[];
|
|
9451
9534
|
} //#endregion
|
|
9452
|
-
//#region src/types/diagnostic.d.ts
|
|
9453
|
-
/**
|
|
9454
|
-
* A secondary source location attached to a diagnostic (oxlint's
|
|
9455
|
-
* non-primary labels). Editors render these as
|
|
9456
|
-
* `Diagnostic.relatedInformation` so a user can jump from, say, a
|
|
9457
|
-
* `no-derived-state` finding to the originating prop declaration.
|
|
9458
|
-
* Positions mirror `Diagnostic` semantics: `line` / `column` are
|
|
9459
|
-
* 1-indexed, and `offset` / `length` are UTF-8 byte spans from oxlint
|
|
9460
|
-
* when available (preferred for precise ranges).
|
|
9461
|
-
*/
|
|
9462
|
-
interface DiagnosticRelatedLocation {
|
|
9463
|
-
filePath: string;
|
|
9464
|
-
line: number;
|
|
9465
|
-
column: number;
|
|
9466
|
-
offset?: number;
|
|
9467
|
-
length?: number;
|
|
9468
|
-
endLine?: number;
|
|
9469
|
-
endColumn?: number;
|
|
9470
|
-
message: string;
|
|
9471
|
-
}
|
|
9472
|
-
type DiagnosticFileContext = "test" | "story" | "production";
|
|
9473
|
-
interface Diagnostic {
|
|
9474
|
-
filePath: string;
|
|
9475
|
-
plugin: string;
|
|
9476
|
-
rule: string;
|
|
9477
|
-
severity: "error" | "warning";
|
|
9478
|
-
title?: string;
|
|
9479
|
-
message: string;
|
|
9480
|
-
help: string;
|
|
9481
|
-
url?: string;
|
|
9482
|
-
line: number;
|
|
9483
|
-
column: number;
|
|
9484
|
-
/**
|
|
9485
|
-
* UTF-8 byte offset of the diagnostic's primary span start, straight
|
|
9486
|
-
* from oxlint's label span. Optional because environment / dead-code
|
|
9487
|
-
* diagnostics carry no source span. Editors (LSP) convert this into a
|
|
9488
|
-
* precise range via the in-memory document; non-editor consumers can
|
|
9489
|
-
* ignore it.
|
|
9490
|
-
*/
|
|
9491
|
-
offset?: number;
|
|
9492
|
-
/** UTF-8 byte length of the primary span (pairs with `offset`). */
|
|
9493
|
-
length?: number;
|
|
9494
|
-
/** 1-indexed end line of the primary span, when derivable. */
|
|
9495
|
-
endLine?: number;
|
|
9496
|
-
/** 1-indexed end column of the primary span, when derivable. */
|
|
9497
|
-
endColumn?: number;
|
|
9498
|
-
category: string;
|
|
9499
|
-
/**
|
|
9500
|
-
* Set when the finding's identity is the flagged element itself (a missing
|
|
9501
|
-
* attribute, a wrong element) rather than the flagged line's text — every
|
|
9502
|
-
* Accessibility-category finding, plus rules that opt in via their
|
|
9503
|
-
* `matchByOccurrence` metadata flag. `computeDiagnosticDelta` matches these
|
|
9504
|
-
* by `(filePath, plugin/rule)` occurrence count, so reformatting the flagged
|
|
9505
|
-
* line doesn't reclassify a pre-existing finding as new. Resolved at
|
|
9506
|
-
* diagnostic creation, where rule metadata is available. Absent means
|
|
9507
|
-
* line-text-sensitive matching (the default).
|
|
9508
|
-
*/
|
|
9509
|
-
matchByOccurrence?: boolean;
|
|
9510
|
-
/**
|
|
9511
|
-
* Set when the file never ships to users (`"test"` / `"story"`), so
|
|
9512
|
-
* renderers can label the site instead of implying production impact.
|
|
9513
|
-
* Omitted for production files (the default).
|
|
9514
|
-
*/
|
|
9515
|
-
fileContext?: Exclude<DiagnosticFileContext, "production">;
|
|
9516
|
-
suppressionHint?: string;
|
|
9517
|
-
/** Secondary source locations (oxlint's non-primary labels). */
|
|
9518
|
-
relatedLocations?: DiagnosticRelatedLocation[];
|
|
9519
|
-
/**
|
|
9520
|
-
* Stable id shared by every finding that a single fix resolves together —
|
|
9521
|
-
* e.g. four `useEffect`s that reset state on one prop change all clear with
|
|
9522
|
-
* one `key` prop. Set only when ≥2 findings share a root cause; absent for
|
|
9523
|
-
* standalone findings. A consumer that turns findings into work items should
|
|
9524
|
-
* group by it so one fix reads as one task, not N. Presentation-only and
|
|
9525
|
-
* score-neutral — the score never reads it.
|
|
9526
|
-
*/
|
|
9527
|
-
fixGroupId?: string;
|
|
9528
|
-
}
|
|
9529
|
-
//#endregion
|
|
9530
9535
|
//#region src/types/project-info.d.ts
|
|
9531
9536
|
type Framework = FrameworkToken;
|
|
9532
9537
|
interface ProjectInfo {
|
|
@@ -9843,7 +9848,8 @@ interface InspectResult {
|
|
|
9843
9848
|
baselineDelta?: {
|
|
9844
9849
|
/** The commit the base content was read from (resolved merge-base). */baseRef: string; /** Findings present at base but gone at head — resolved by the change. */
|
|
9845
9850
|
fixedCount: number; /** Total findings at base (over the same files), for context. */
|
|
9846
|
-
baseTotalCount: number;
|
|
9851
|
+
baseTotalCount: number; /** Pre-existing findings matched after moving to a different file. */
|
|
9852
|
+
crossFileMatchCount?: number;
|
|
9847
9853
|
};
|
|
9848
9854
|
}
|
|
9849
9855
|
/**
|
|
@@ -10259,15 +10265,7 @@ declare const buildJsonReport: (input: BuildJsonReportInput) => JsonReportV3$1;
|
|
|
10259
10265
|
* `GitBaseBranchMissing`) as clean user errors instead of crashes.
|
|
10260
10266
|
*/
|
|
10261
10267
|
declare const getDiffInfo: (directory: string, explicitBaseBranch?: string, includeUntracked?: boolean) => Promise<DiffInfo | null>;
|
|
10262
|
-
declare const filterSourceFiles: (filePaths: string
|
|
10263
|
-
/**
|
|
10264
|
-
* Programmatic façade over `Git.changedLineRanges` (the `lines` scope). Diffs
|
|
10265
|
-
* `files` with `--unified=0` against `baseRef` (or the index when `cached`),
|
|
10266
|
-
* returning per-file changed line ranges relative to `directory`. Returns
|
|
10267
|
-
* `null` when the ranges can't be computed (git unavailable / unsafe ref /
|
|
10268
|
-
* non-zero exit) so the caller degrades to file-level scope; an empty array
|
|
10269
|
-
* means git succeeded but the files added no lines.
|
|
10270
|
-
*/
|
|
10268
|
+
declare const filterSourceFiles: (filePaths: ReadonlyArray<string>) => string[];
|
|
10271
10269
|
//#endregion
|
|
10272
10270
|
//#region src/summarize-diagnostics.d.ts
|
|
10273
10271
|
declare const summarizeDiagnostics: (diagnostics: Diagnostic[], worstScore?: number | null, worstScoreLabel?: string | null) => JsonReportSummary; //#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f645a3f8-ff1c-5f09-a174-8281db00eaa4")}catch(e){}}();
|
|
3
3
|
import { r as __toESM$1, t as __commonJSMin$1 } from "./chunk-N93fKeF6.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import reactDoctorPlugin, { ALL_REACT_DOCTOR_RULE_KEYS, CROSS_FILE_DEPENDENCY_COLLECTORS, CROSS_FILE_RULE_IDS, FRAMEWORK_SPECIFIC_RULE_KEYS, FRAMEWORK_TOKENS, MOTION_LIBRARY_PACKAGES, REACT_COMPILER_RULES, REACT_DOCTOR_RULES, classifySecurityScanFile, collectCrossFileDependencyProbes, resetManifestCaches, shouldReadSecurityScanContent } from "oxlint-plugin-react-doctor";
|
|
@@ -33040,7 +33040,7 @@ const SOCKET_FREE_USER_AGENT = "react-doctor-supply-chain";
|
|
|
33040
33040
|
const FILE_LINT_CACHE_FILENAME = "file-lint-cache.json";
|
|
33041
33041
|
const FILE_LINT_CACHE_MAX_FILE_COUNT = 5e4;
|
|
33042
33042
|
const SIDECAR_LINT_CACHE_FILENAME = "sidecar-lint-cache.json";
|
|
33043
|
-
const CORE_PACKAGE_VERSION = "0.8.
|
|
33043
|
+
const CORE_PACKAGE_VERSION = "0.8.1";
|
|
33044
33044
|
const DEAD_CODE_CACHE_FILENAME = "dead-code-cache.json";
|
|
33045
33045
|
const DEAD_CODE_SUMMARY_CACHE_FILENAME = "dead-code-summaries.json";
|
|
33046
33046
|
const SUPPLY_CHAIN_PLUGIN = "socket";
|
|
@@ -35155,6 +35155,9 @@ const SCRIPT_EXTENSION_FRAGMENT = "[cm]?[jt]sx?";
|
|
|
35155
35155
|
const STORY_FILE_SUFFIX_PATTERN = new RegExp(`\\.(?:stories|story)\\.(?:${SCRIPT_EXTENSION_FRAGMENT})$`);
|
|
35156
35156
|
const TEST_FILE_SUFFIX_PATTERN = new RegExp(`\\.(?:test|spec|fixture|fixtures)\\.(?:${SCRIPT_EXTENSION_FRAGMENT})$`);
|
|
35157
35157
|
const TEST_FILE_DIRECTORY_PATTERN = /(?:^|\/)(?:__tests__|__test__|tests|test|__mocks__|cypress|e2e|playwright)\//;
|
|
35158
|
+
const AMBIGUOUS_TEST_ROUTE_DIRECTORY_PATTERN = /(?:^|\/)(?:tests|test)\//;
|
|
35159
|
+
const NEXT_APP_ROUTE_FILE_SUFFIX_PATTERN = /\/(?:default|error|forbidden|global-error|layout|loading|not-found|page|route|template|unauthorized)\.[cm]?[jt]sx?$/;
|
|
35160
|
+
const SCRIPT_FILE_SUFFIX_PATTERN = /\.[cm]?[jt]sx?$/;
|
|
35158
35161
|
const FIXTURE_PROJECT_PATTERN = /\/(?:fixtures|__fixtures__)\//;
|
|
35159
35162
|
const SOURCE_ROOT_PATTERN = /\/(?:src|app|lib|components|pages|features|modules|packages|apps|frontend|client)\//g;
|
|
35160
35163
|
const stripAboveSourceRoot = (relativePath) => {
|
|
@@ -35165,6 +35168,14 @@ const stripAboveSourceRoot = (relativePath) => {
|
|
|
35165
35168
|
if (lastIdx >= 0) return relativePath.slice(lastIdx);
|
|
35166
35169
|
return relativePath.slice(fixtureMatch.index + fixtureMatch[0].length - 1);
|
|
35167
35170
|
};
|
|
35171
|
+
const isFrameworkRouteBeforeAmbiguousTestDirectory = (relativePath) => {
|
|
35172
|
+
const testDirectoryMatch = AMBIGUOUS_TEST_ROUTE_DIRECTORY_PATTERN.exec(relativePath);
|
|
35173
|
+
if (testDirectoryMatch === null) return false;
|
|
35174
|
+
let nearestRouteRoot;
|
|
35175
|
+
for (const pathSegment of relativePath.slice(0, testDirectoryMatch.index).split("/")) if (pathSegment === "app" || pathSegment === "pages") nearestRouteRoot = pathSegment;
|
|
35176
|
+
if (nearestRouteRoot === void 0) return false;
|
|
35177
|
+
return nearestRouteRoot === "pages" ? SCRIPT_FILE_SUFFIX_PATTERN.test(relativePath) : NEXT_APP_ROUTE_FILE_SUFFIX_PATTERN.test(relativePath);
|
|
35178
|
+
};
|
|
35168
35179
|
/**
|
|
35169
35180
|
* Classifies where a file sits relative to shipped code. A finding in a
|
|
35170
35181
|
* `.stories.tsx` or `.spec.ts` file never runs in front of users, so
|
|
@@ -35181,6 +35192,7 @@ const classifyFileContext = (relativePath) => {
|
|
|
35181
35192
|
if (STORY_FILE_SUFFIX_PATTERN.test(forwardSlashed)) return "story";
|
|
35182
35193
|
if (TEST_FILE_SUFFIX_PATTERN.test(forwardSlashed)) return "test";
|
|
35183
35194
|
const scoped = stripAboveSourceRoot(forwardSlashed);
|
|
35195
|
+
if (isFrameworkRouteBeforeAmbiguousTestDirectory(scoped)) return "production";
|
|
35184
35196
|
return TEST_FILE_DIRECTORY_PATTERN.test(scoped) ? "test" : "production";
|
|
35185
35197
|
};
|
|
35186
35198
|
/**
|
|
@@ -36044,6 +36056,7 @@ const VALID_RULE_SEVERITIES = [
|
|
|
36044
36056
|
"warn",
|
|
36045
36057
|
"off"
|
|
36046
36058
|
];
|
|
36059
|
+
const VALID_INCLUDED_FILE_CONTEXTS = ["test", "story"];
|
|
36047
36060
|
const KNOWN_CATEGORY_LABEL = DIAGNOSTIC_CATEGORY_BUCKETS.join(", ");
|
|
36048
36061
|
const isDiagnosticCategoryBucket = (value) => DIAGNOSTIC_CATEGORY_BUCKETS.includes(value);
|
|
36049
36062
|
const filterKnownCategories = (fieldName, categories) => categories.filter((category) => {
|
|
@@ -36078,6 +36091,7 @@ const SURFACE_CONTROL_FIELD_NAMES = [
|
|
|
36078
36091
|
"includeRules",
|
|
36079
36092
|
"excludeRules"
|
|
36080
36093
|
];
|
|
36094
|
+
const isIncludedFileContext = (value) => VALID_INCLUDED_FILE_CONTEXTS.some((fileContext) => fileContext === value);
|
|
36081
36095
|
const SEVERITY_FIELD_NAMES = ["rules", "categories"];
|
|
36082
36096
|
const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36083
36097
|
const formatType = (value) => typeof value === "string" ? `"${value}"` : typeof value;
|
|
@@ -36112,6 +36126,15 @@ const validateSurfaceControls = (surface, rawControls) => {
|
|
|
36112
36126
|
return;
|
|
36113
36127
|
}
|
|
36114
36128
|
const validatedSurfaceControls = {};
|
|
36129
|
+
if (rawControls.includeFileContexts !== void 0) {
|
|
36130
|
+
const qualifiedName = `surfaces.${surface}.includeFileContexts`;
|
|
36131
|
+
const result = validateStringArrayField(qualifiedName, rawControls.includeFileContexts);
|
|
36132
|
+
if (result !== void 0) validatedSurfaceControls.includeFileContexts = result.filter((fileContext) => {
|
|
36133
|
+
if (isIncludedFileContext(fileContext)) return true;
|
|
36134
|
+
warnConfigIssue(`config field "${qualifiedName}" lists "${fileContext}", which is not a non-production file context (expected one of: ${VALID_INCLUDED_FILE_CONTEXTS.join(", ")}); ignoring the entry.`);
|
|
36135
|
+
return false;
|
|
36136
|
+
});
|
|
36137
|
+
}
|
|
36115
36138
|
for (const fieldName of SURFACE_CONTROL_FIELD_NAMES) {
|
|
36116
36139
|
if (rawControls[fieldName] === void 0) continue;
|
|
36117
36140
|
const qualifiedName = `surfaces.${surface}.${fieldName}`;
|
|
@@ -38803,6 +38826,7 @@ const buildResolvedControls = (surface, userControls) => {
|
|
|
38803
38826
|
for (const tag of includeTags) excludeTags.delete(tag);
|
|
38804
38827
|
for (const tag of toStringSet(userControls?.excludeTags)) excludeTags.add(tag);
|
|
38805
38828
|
return {
|
|
38829
|
+
includeFileContexts: toStringSet(userControls?.includeFileContexts),
|
|
38806
38830
|
includeTags,
|
|
38807
38831
|
excludeTags,
|
|
38808
38832
|
includeCategories: toStringSet(userControls?.includeCategories),
|
|
@@ -38818,7 +38842,7 @@ const isDiagnosticOnSurface = (diagnostic, surface, config) => {
|
|
|
38818
38842
|
if (resolved.includeRuleKeys.has(ruleKey)) return true;
|
|
38819
38843
|
if (resolved.includeCategories.has(category)) return true;
|
|
38820
38844
|
if (intersects(tags, resolved.includeTags)) return true;
|
|
38821
|
-
if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure")) return false;
|
|
38845
|
+
if (diagnostic.fileContext !== void 0 && (surface === "score" || surface === "ciFailure") && !resolved.includeFileContexts.has(diagnostic.fileContext)) return false;
|
|
38822
38846
|
if (resolved.excludeRuleKeys.has(ruleKey)) return false;
|
|
38823
38847
|
if (resolved.excludeCategories.has(category)) return false;
|
|
38824
38848
|
if (intersects(tags, resolved.excludeTags)) return false;
|
|
@@ -39066,6 +39090,35 @@ const parseGithubViewerPermission = (stdout) => {
|
|
|
39066
39090
|
return /^[A-Z_]+$/.test(value) ? value.toLowerCase() : null;
|
|
39067
39091
|
};
|
|
39068
39092
|
const splitNullSeparated = (value) => value.split("\0").filter((entry) => entry.length > 0);
|
|
39093
|
+
const parseBaselineDiffPlan = (value) => {
|
|
39094
|
+
const entries = splitNullSeparated(value);
|
|
39095
|
+
const baseFiles = /* @__PURE__ */ new Set();
|
|
39096
|
+
const headFiles = /* @__PURE__ */ new Set();
|
|
39097
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 2) {
|
|
39098
|
+
const status = entries[entryIndex];
|
|
39099
|
+
const filePath = entries[entryIndex + 1];
|
|
39100
|
+
if (status === void 0 || filePath === void 0 || status.length !== 1) return null;
|
|
39101
|
+
if (status === "A") {
|
|
39102
|
+
headFiles.add(filePath);
|
|
39103
|
+
continue;
|
|
39104
|
+
}
|
|
39105
|
+
if (status === "D") {
|
|
39106
|
+
baseFiles.add(filePath);
|
|
39107
|
+
continue;
|
|
39108
|
+
}
|
|
39109
|
+
if (status === "M" || status === "T") {
|
|
39110
|
+
baseFiles.add(filePath);
|
|
39111
|
+
headFiles.add(filePath);
|
|
39112
|
+
continue;
|
|
39113
|
+
}
|
|
39114
|
+
return null;
|
|
39115
|
+
}
|
|
39116
|
+
return {
|
|
39117
|
+
baseFiles: [...baseFiles],
|
|
39118
|
+
headFiles: [...headFiles],
|
|
39119
|
+
untrackedFiles: []
|
|
39120
|
+
};
|
|
39121
|
+
};
|
|
39069
39122
|
const UNTRACKED_FILE_LAST_LINE = Number.MAX_SAFE_INTEGER;
|
|
39070
39123
|
/**
|
|
39071
39124
|
* `Git` wraps every `git`-via-subprocess call react-doctor makes
|
|
@@ -39268,6 +39321,45 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39268
39321
|
githubViewerPermission,
|
|
39269
39322
|
branchExists,
|
|
39270
39323
|
mergeBase,
|
|
39324
|
+
baselineDiffPlan: (input) => {
|
|
39325
|
+
if (!isSafeGitRevision(input.ref)) return succeed$2(null);
|
|
39326
|
+
return gen(function* () {
|
|
39327
|
+
const unmerged = yield* runGit(input.directory, [
|
|
39328
|
+
"diff",
|
|
39329
|
+
"--no-ext-diff",
|
|
39330
|
+
"-z",
|
|
39331
|
+
"--name-only",
|
|
39332
|
+
"--diff-filter=U",
|
|
39333
|
+
"--relative"
|
|
39334
|
+
]);
|
|
39335
|
+
if (unmerged.status !== 0 || unmerged.stdout.length > 0) return null;
|
|
39336
|
+
const result = yield* runGit(input.directory, [
|
|
39337
|
+
"diff",
|
|
39338
|
+
"--no-ext-diff",
|
|
39339
|
+
"--no-textconv",
|
|
39340
|
+
"--no-renames",
|
|
39341
|
+
"-z",
|
|
39342
|
+
"--name-status",
|
|
39343
|
+
"--relative",
|
|
39344
|
+
input.ref
|
|
39345
|
+
]);
|
|
39346
|
+
if (result.status !== 0) return null;
|
|
39347
|
+
const plan = parseBaselineDiffPlan(result.stdout);
|
|
39348
|
+
if (plan === null) return null;
|
|
39349
|
+
const untracked = yield* runGit(input.directory, [
|
|
39350
|
+
"ls-files",
|
|
39351
|
+
"--others",
|
|
39352
|
+
"--exclude-standard",
|
|
39353
|
+
"-z"
|
|
39354
|
+
]);
|
|
39355
|
+
if (untracked.status !== 0) return null;
|
|
39356
|
+
return {
|
|
39357
|
+
baseFiles: plan.baseFiles,
|
|
39358
|
+
headFiles: plan.headFiles,
|
|
39359
|
+
untrackedFiles: splitNullSeparated(untracked.stdout)
|
|
39360
|
+
};
|
|
39361
|
+
}).pipe(catch_$1(() => succeed$2(null)), withSpan("Git.baselineDiffPlan"));
|
|
39362
|
+
},
|
|
39271
39363
|
diffSelection: ({ directory, explicitBaseBranch, includeUntracked = false }) => gen(function* () {
|
|
39272
39364
|
if (explicitBaseBranch !== void 0 && explicitBaseBranch.trim().length === 0) return yield* fail$4(new ReactDoctorError({ reason: new GitBaseBranchInvalid({ detail: "Diff base branch cannot be empty." }) }));
|
|
39273
39365
|
if (explicitBaseBranch !== void 0) {
|
|
@@ -39417,6 +39509,7 @@ var Git = class Git extends Service()("react-doctor/Git") {
|
|
|
39417
39509
|
githubViewerPermission: () => succeed$2(snapshot.githubViewerPermission ?? null),
|
|
39418
39510
|
branchExists: (_directory, branch) => succeed$2(snapshot.branchExists?.get(branch) ?? false),
|
|
39419
39511
|
mergeBase: ({ ref }) => succeed$2(snapshot.mergeBase?.get(ref) ?? null),
|
|
39512
|
+
baselineDiffPlan: () => succeed$2(snapshot.baselineDiffPlan ?? null),
|
|
39420
39513
|
diffSelection: () => succeed$2(snapshot.diffSelection ?? null),
|
|
39421
39514
|
stagedFilePaths: () => succeed$2(snapshot.stagedFiles ?? []),
|
|
39422
39515
|
showStagedContent: (_directory, relativePath) => succeed$2(snapshot.stagedContent?.get(relativePath) ?? null),
|
|
@@ -43142,12 +43235,19 @@ const isPathInsideDirectory = (childAbsolutePath, parentAbsolutePath) => {
|
|
|
43142
43235
|
*/
|
|
43143
43236
|
const materializeSourceTree = (input) => gen(function* () {
|
|
43144
43237
|
const materializedFiles = [];
|
|
43238
|
+
const unmaterializedFiles = [];
|
|
43145
43239
|
const resolvedTempDirectory = path.resolve(input.tempDirectory);
|
|
43146
43240
|
for (const relativePath of input.files) {
|
|
43147
43241
|
const content = yield* input.readContent(relativePath).pipe(orElseSucceed(() => null));
|
|
43148
|
-
if (content === null)
|
|
43242
|
+
if (content === null) {
|
|
43243
|
+
unmaterializedFiles.push(relativePath);
|
|
43244
|
+
continue;
|
|
43245
|
+
}
|
|
43149
43246
|
const candidateTargetPath = path.resolve(resolvedTempDirectory, relativePath);
|
|
43150
|
-
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory))
|
|
43247
|
+
if (!isPathInsideDirectory(candidateTargetPath, resolvedTempDirectory)) {
|
|
43248
|
+
unmaterializedFiles.push(relativePath);
|
|
43249
|
+
continue;
|
|
43250
|
+
}
|
|
43151
43251
|
yield* sync(() => {
|
|
43152
43252
|
fs.mkdirSync(path.dirname(candidateTargetPath), { recursive: true });
|
|
43153
43253
|
fs.writeFileSync(candidateTargetPath, content);
|
|
@@ -43164,6 +43264,7 @@ const materializeSourceTree = (input) => gen(function* () {
|
|
|
43164
43264
|
return {
|
|
43165
43265
|
tempDirectory: input.tempDirectory,
|
|
43166
43266
|
materializedFiles,
|
|
43267
|
+
unmaterializedFiles,
|
|
43167
43268
|
cleanup: () => {
|
|
43168
43269
|
try {
|
|
43169
43270
|
fs.rmSync(input.tempDirectory, {
|
|
@@ -43727,4 +43828,4 @@ const toJsonReport = (result, options) => buildJsonReport({
|
|
|
43727
43828
|
export { AmbiguousProjectError, NoReactDependencyError, NotADirectoryError, PackageJsonNotFoundError, ProjectNotFoundError, ReactDoctorError, buildJsonReport, buildJsonReportError, clearCaches, defineConfig, diagnose, filterSourceFiles, getDiffInfo, hasReactRuntime, isProjectDiscoveryError, isReactDoctorError, summarizeDiagnostics, toJsonReport };
|
|
43728
43829
|
|
|
43729
43830
|
//# sourceMappingURL=index.js.map
|
|
43730
|
-
//# debugId=
|
|
43831
|
+
//# debugId=f645a3f8-ff1c-5f09-a174-8281db00eaa4
|