react-doctor 0.9.7-dev.13138a4 → 0.9.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.
@@ -1,581 +0,0 @@
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]="3482bd59-e632-5753-a94a-167622d04810")}catch(e){}}();
3
- import { At as clearConfigCache, Et as buildRuleDocsUrl, G as COMPILER_CLEANUP_BUCKET, K as COMPILER_CLEANUP_RULE_KEYS, Nn as validateConfigTypes, Yt as getEquivalentRuleKeys, en as highlighter, ln as isSameRuleKey, mn as loadConfigWithSource, on as isPlainObject, t as recordCount, y as METRIC } from "./record-metric-CtlQma6P.js";
4
- import { L as cliLogger, n as findNearestPackageDirectory } from "./install-doctor-script-DxrteuEw.js";
5
- import { t as readObjectFile } from "./read-object-file-ITGVjFKp.js";
6
- import * as path$1 from "node:path";
7
- import * as fs$1 from "node:fs";
8
- import { REACT_DOCTOR_RULES } from "oxlint-plugin-react-doctor/core";
9
- import { generateCode, loadFile, writeFile } from "magicast";
10
- import { getConfigFromVariableDeclaration, getDefaultExportOptions } from "magicast/helpers";
11
- //#region src/cli/utils/rule-catalog.ts
12
- const buildRuleCatalog = () => REACT_DOCTOR_RULES.map((entry) => ({
13
- key: entry.key,
14
- id: entry.id,
15
- category: entry.rule.category ?? "Other",
16
- defaultSeverity: entry.rule.severity,
17
- framework: entry.rule.framework ?? "global",
18
- tags: entry.rule.tags ?? [],
19
- recommendation: entry.rule.recommendation,
20
- defaultEnabled: entry.rule.defaultEnabled !== false
21
- }));
22
- /**
23
- * Resolves a user-supplied rule reference to a catalog entry. Accepts the
24
- * fully-qualified key (`react-doctor/no-danger`), the bare id (`no-danger`),
25
- * and legacy plugin keys (`react/no-danger`) via the shared alias map.
26
- */
27
- const findRuleInCatalog = (catalog, ruleQuery) => {
28
- const normalizedQuery = ruleQuery.trim();
29
- if (normalizedQuery.length === 0) return void 0;
30
- const directMatch = catalog.find((entry) => entry.key === normalizedQuery || entry.id === normalizedQuery);
31
- if (directMatch) return directMatch;
32
- return catalog.find((entry) => isSameRuleKey(entry.key, normalizedQuery));
33
- };
34
- const listRuleCategories = (catalog) => [...new Set(catalog.map((entry) => entry.category))].sort();
35
- const listRuleTags = (catalog) => [...new Set(catalog.flatMap((entry) => [...entry.tags]))].sort();
36
- //#endregion
37
- //#region src/cli/utils/render-rule-catalog.ts
38
- const SEVERITY_COLUMN_WIDTH_CHARS = 6;
39
- const colorizeSeverity = (severity, text) => {
40
- if (severity === "error") return highlighter.error(text);
41
- if (severity === "warn") return highlighter.warn(text);
42
- return highlighter.gray(text);
43
- };
44
- const formatSourceNote = (effective) => effective.source === "default" ? highlighter.dim("(default)") : highlighter.dim(`(${effective.source})`);
45
- const renderRuleCatalog = (rows) => {
46
- if (rows.length === 0) return highlighter.dim("No rules match the given filters.");
47
- const rowsByCategory = /* @__PURE__ */ new Map();
48
- for (const row of rows) {
49
- const bucket = rowsByCategory.get(row.entry.category) ?? [];
50
- bucket.push(row);
51
- rowsByCategory.set(row.entry.category, bucket);
52
- }
53
- const lines = [];
54
- for (const category of [...rowsByCategory.keys()].sort()) {
55
- const categoryRows = (rowsByCategory.get(category) ?? []).sort((leftRow, rightRow) => leftRow.entry.key.localeCompare(rightRow.entry.key));
56
- lines.push(highlighter.bold(`${category} ${highlighter.dim(`(${categoryRows.length})`)}`));
57
- for (const row of categoryRows) {
58
- const severityBadge = colorizeSeverity(row.effective.value, row.effective.value.padEnd(SEVERITY_COLUMN_WIDTH_CHARS));
59
- const tagSuffix = row.entry.tags.length > 0 ? highlighter.dim(` [${row.entry.tags.join(", ")}]`) : "";
60
- lines.push(` ${severityBadge} ${row.entry.key} ${formatSourceNote(row.effective)}${tagSuffix}`);
61
- }
62
- lines.push("");
63
- }
64
- lines.push(highlighter.dim(`${rows.length} rule${rows.length === 1 ? "" : "s"} shown.`));
65
- return lines.join("\n");
66
- };
67
- const DETAIL_LABEL_COLUMN_WIDTH_CHARS = 18;
68
- const formatDetailRow = (label, value) => ` ${highlighter.dim(label.padEnd(DETAIL_LABEL_COLUMN_WIDTH_CHARS))}${value}`;
69
- const renderRuleExplanation = (row) => {
70
- const { entry, effective } = row;
71
- const lines = [highlighter.bold(entry.key), ""];
72
- lines.push(formatDetailRow("Category", entry.category));
73
- lines.push(formatDetailRow("Default severity", entry.defaultSeverity));
74
- lines.push(formatDetailRow("Current severity", `${colorizeSeverity(effective.value, effective.value)} ${formatSourceNote(effective)}`));
75
- lines.push(formatDetailRow("Framework", entry.framework));
76
- lines.push(formatDetailRow("Tags", entry.tags.length > 0 ? entry.tags.join(", ") : "none"));
77
- lines.push(formatDetailRow("Default enabled", entry.defaultEnabled ? "yes" : "no (opt-in)"));
78
- lines.push("");
79
- lines.push(highlighter.bold("Why it matters"));
80
- lines.push(` ${entry.recommendation ?? "No additional guidance recorded for this rule yet."}`);
81
- lines.push("");
82
- lines.push(highlighter.bold("Configure"));
83
- lines.push(highlighter.dim(` react-doctor rules disable ${entry.key}`));
84
- lines.push(highlighter.dim(` react-doctor rules enable ${entry.key} --severity error`));
85
- lines.push(highlighter.dim(` react-doctor rules set ${entry.key} warn`));
86
- lines.push("");
87
- lines.push(highlighter.bold("Learn more"));
88
- lines.push(highlighter.dim(` ${buildRuleDocsUrl("react-doctor", entry.id)}`));
89
- return lines.join("\n");
90
- };
91
- //#endregion
92
- //#region src/cli/utils/rule-config-file.ts
93
- const NEW_CONFIG_FILENAME = "doctor.config.json";
94
- const PACKAGE_JSON_CONFIG_KEY = "reactDoctor";
95
- const JSON_INDENT_SPACES = 2;
96
- const MANAGED_KEYS = [
97
- "rules",
98
- "categories",
99
- "ignore"
100
- ];
101
- /**
102
- * Decides where a rule-config mutation should be written. Discovery
103
- * reuses `loadConfigWithSource` (the loader the scan uses) so edits land
104
- * in the file the scan reads — `doctor.config.{ts,js,…}` is preferred,
105
- * then `package.json#reactDoctor`. When nothing exists, a fresh
106
- * `doctor.config.json` is targeted at `projectRoot`. Data configs are
107
- * re-read raw so unrelated fields round-trip untouched.
108
- */
109
- const resolveRuleConfigTarget = async (projectRoot) => {
110
- clearConfigCache();
111
- const loaded = await loadConfigWithSource(projectRoot);
112
- if (loaded) {
113
- if (loaded.format === "package-json") {
114
- const embedded = (readObjectFile(loaded.configFilePath) ?? {})[PACKAGE_JSON_CONFIG_KEY];
115
- return {
116
- format: "package-json",
117
- filePath: loaded.configFilePath,
118
- directory: loaded.sourceDirectory,
119
- exists: true,
120
- config: isPlainObject(embedded) ? embedded : {}
121
- };
122
- }
123
- if (loaded.format === "json") {
124
- if (path$1.basename(loaded.configFilePath) === "react-doctor.config.json") {
125
- const legacyConfig = readObjectFile(loaded.configFilePath) ?? {};
126
- delete legacyConfig.$schema;
127
- return {
128
- format: "json",
129
- filePath: path$1.join(loaded.sourceDirectory, NEW_CONFIG_FILENAME),
130
- directory: loaded.sourceDirectory,
131
- exists: false,
132
- config: legacyConfig,
133
- migratedFromFilePath: loaded.configFilePath
134
- };
135
- }
136
- return {
137
- format: "json",
138
- filePath: loaded.configFilePath,
139
- directory: loaded.sourceDirectory,
140
- exists: true,
141
- config: readObjectFile(loaded.configFilePath) ?? {}
142
- };
143
- }
144
- return {
145
- format: "module",
146
- filePath: loaded.configFilePath,
147
- directory: loaded.sourceDirectory,
148
- exists: true,
149
- config: loaded.config
150
- };
151
- }
152
- return {
153
- format: "json",
154
- filePath: path$1.join(projectRoot, NEW_CONFIG_FILENAME),
155
- directory: projectRoot,
156
- exists: false,
157
- config: {}
158
- };
159
- };
160
- const writeJsonConfig = (filePath, nextConfig) => {
161
- const { $schema, ...rest } = nextConfig;
162
- const serialized = JSON.stringify({
163
- $schema: $schema ?? "https://react.doctor/schema/config.json",
164
- ...rest
165
- }, null, JSON_INDENT_SPACES);
166
- fs$1.writeFileSync(filePath, `${serialized}\n`);
167
- };
168
- const writePackageJsonConfig = (filePath, nextConfig) => {
169
- const packageJson = readObjectFile(filePath) ?? {};
170
- const serialized = JSON.stringify({
171
- ...packageJson,
172
- [PACKAGE_JSON_CONFIG_KEY]: nextConfig
173
- }, null, JSON_INDENT_SPACES);
174
- fs$1.writeFileSync(filePath, `${serialized}\n`);
175
- };
176
- const syncManagedKeys = (target, nextConfig) => {
177
- for (const key of MANAGED_KEYS) {
178
- const value = nextConfig[key];
179
- if (value === void 0) {
180
- if (target[key] !== void 0) delete target[key];
181
- } else target[key] = value;
182
- }
183
- };
184
- const assignNodeSource = (owner, key, code) => {
185
- owner[key] = code;
186
- };
187
- const editVariableDeclarationConfig = (declaration, config, nextConfig) => {
188
- syncManagedKeys(config, nextConfig);
189
- const initializer = declaration.init;
190
- if (!initializer) return false;
191
- const generatedSource = generateCode(config).code;
192
- if (initializer.type === "ObjectExpression") {
193
- assignNodeSource(declaration, "init", generatedSource);
194
- return true;
195
- }
196
- if (initializer.type === "TSSatisfiesExpression" && initializer.expression.type === "ObjectExpression") {
197
- assignNodeSource(initializer, "expression", generatedSource);
198
- return true;
199
- }
200
- return false;
201
- };
202
- const writeModuleConfig = async (filePath, nextConfig) => {
203
- try {
204
- const module = await loadFile(filePath);
205
- if (module.exports.default?.$type === "identifier") {
206
- const { declaration, config } = getConfigFromVariableDeclaration(module);
207
- if (!config || !editVariableDeclarationConfig(declaration, config, nextConfig)) return false;
208
- } else syncManagedKeys(getDefaultExportOptions(module), nextConfig);
209
- await writeFile(module, filePath);
210
- return true;
211
- } catch {
212
- return false;
213
- }
214
- };
215
- const writeRuleConfig = async (target, nextConfig) => {
216
- if (target.format === "module") {
217
- const written = await writeModuleConfig(target.filePath, nextConfig);
218
- if (written) clearConfigCache();
219
- return { written };
220
- }
221
- if (target.format === "package-json") writePackageJsonConfig(target.filePath, nextConfig);
222
- else {
223
- writeJsonConfig(target.filePath, nextConfig);
224
- if (target.migratedFromFilePath) fs$1.rmSync(target.migratedFromFilePath, { force: true });
225
- }
226
- clearConfigCache();
227
- return { written: true };
228
- };
229
- //#endregion
230
- //#region src/cli/utils/resolve-effective-rule-severity.ts
231
- /**
232
- * Resolves what a rule will actually do under the current config without
233
- * running a scan. `ignore.tags` is a pre-lint gate: a rule carrying an
234
- * ignored tag is dropped (via `shouldEnableRule`) before any severity is
235
- * read, so it wins over every override. Among rules that survive the gate,
236
- * the scanner's order is `rules` > `categories` > `buckets` > the registry
237
- * default.
238
- */
239
- const resolveEffectiveRuleSeverity = (config, entry) => {
240
- const ignoredTags = config?.ignore?.tags ?? [];
241
- if (entry.tags.some((tag) => ignoredTags.includes(tag))) return {
242
- value: "off",
243
- source: "tag"
244
- };
245
- const ruleOverrides = config?.rules ?? {};
246
- for (const equivalentKey of getEquivalentRuleKeys(entry.key)) {
247
- const override = ruleOverrides[equivalentKey];
248
- if (override !== void 0) return {
249
- value: override,
250
- source: "rule"
251
- };
252
- }
253
- if (!entry.defaultEnabled) return {
254
- value: "off",
255
- source: "default"
256
- };
257
- const categoryOverride = config?.categories?.[entry.category];
258
- if (categoryOverride !== void 0) return {
259
- value: categoryOverride,
260
- source: "category"
261
- };
262
- if (COMPILER_CLEANUP_RULE_KEYS.has(entry.key)) {
263
- const bucketOverride = config?.buckets?.[COMPILER_CLEANUP_BUCKET];
264
- if (bucketOverride !== void 0) return {
265
- value: bucketOverride,
266
- source: "bucket"
267
- };
268
- }
269
- return {
270
- value: entry.defaultEnabled ? entry.defaultSeverity : "off",
271
- source: "default"
272
- };
273
- };
274
- //#endregion
275
- //#region src/cli/utils/update-rule-config.ts
276
- /**
277
- * Sets a per-rule severity, replacing any existing entry for the same
278
- * rule (including legacy-aliased keys, so a config still targeting
279
- * `react/no-danger` is rewritten to the canonical key instead of
280
- * leaving a dead duplicate).
281
- */
282
- const setRuleSeverity = (config, ruleKey, severity) => {
283
- const equivalentKeys = new Set(getEquivalentRuleKeys(ruleKey));
284
- const nextRules = {};
285
- for (const [existingKey, existingSeverity] of Object.entries(config.rules ?? {})) if (!equivalentKeys.has(existingKey)) nextRules[existingKey] = existingSeverity;
286
- nextRules[ruleKey] = severity;
287
- return {
288
- ...config,
289
- rules: nextRules
290
- };
291
- };
292
- const setCategorySeverity = (config, category, severity) => ({
293
- ...config,
294
- categories: {
295
- ...config.categories,
296
- [category]: severity
297
- }
298
- });
299
- const addIgnoredTag = (config, tag) => {
300
- const currentTags = config.ignore?.tags ?? [];
301
- if (currentTags.includes(tag)) return config;
302
- return {
303
- ...config,
304
- ignore: {
305
- ...config.ignore,
306
- tags: [...new Set([...currentTags, tag])].sort()
307
- }
308
- };
309
- };
310
- const removeIgnoredTag = (config, tag) => {
311
- const currentTags = config.ignore?.tags ?? [];
312
- if (!currentTags.includes(tag)) return config;
313
- const remainingTags = currentTags.filter((existingTag) => existingTag !== tag);
314
- const { tags: _removed, ...remainingIgnore } = config.ignore ?? {};
315
- if (remainingTags.length === 0) {
316
- if (Object.keys(remainingIgnore).length === 0) {
317
- const { ignore: _ignore, ...configWithoutIgnore } = config;
318
- return configWithoutIgnore;
319
- }
320
- return {
321
- ...config,
322
- ignore: remainingIgnore
323
- };
324
- }
325
- return {
326
- ...config,
327
- ignore: {
328
- ...remainingIgnore,
329
- tags: remainingTags
330
- }
331
- };
332
- };
333
- //#endregion
334
- //#region src/cli/commands/rules.ts
335
- const SEVERITY_VALUES = [
336
- "off",
337
- "warn",
338
- "error"
339
- ];
340
- const recordRulesInvocation = () => recordCount(METRIC.cliInvoked, 1, { command: "rules" });
341
- const resolveProjectRoot = (options) => {
342
- const requestedDirectory = path$1.resolve(options.cwd ?? process.cwd());
343
- return findNearestPackageDirectory(requestedDirectory) ?? requestedDirectory;
344
- };
345
- const parseSeverity = (value) => SEVERITY_VALUES.includes(value) ? value : null;
346
- const reportInvalidSeverity = (value) => {
347
- cliLogger.error(`Invalid severity "${value}". Expected one of: ${SEVERITY_VALUES.join(", ")}.`);
348
- process.exitCode = 1;
349
- };
350
- const reportRuleNotFound = (ruleQuery) => {
351
- cliLogger.error(`Unknown rule "${ruleQuery}".`);
352
- cliLogger.dim(" Run `react-doctor rules list` to see every available rule.");
353
- process.exitCode = 1;
354
- };
355
- const describeTargetPath = (target) => {
356
- const relativePath = path$1.relative(process.cwd(), target.filePath);
357
- const displayPath = relativePath.length > 0 && !relativePath.startsWith("..") ? relativePath : target.filePath;
358
- return target.exists ? displayPath : `${displayPath} ${highlighter.dim("(created)")}`;
359
- };
360
- const applyConfigChange = async (options, change) => {
361
- const target = await resolveRuleConfigTarget(resolveProjectRoot(options));
362
- const nextConfig = change(target.config);
363
- const { written } = await writeRuleConfig(target, nextConfig);
364
- return {
365
- target,
366
- nextConfig,
367
- written
368
- };
369
- };
370
- const reportManualEdit = (target, nextConfig) => {
371
- const managed = {};
372
- for (const key of [
373
- "rules",
374
- "categories",
375
- "ignore"
376
- ]) if (nextConfig[key] !== void 0) managed[key] = nextConfig[key];
377
- cliLogger.error(`Couldn't automatically edit ${describeTargetPath(target)} (dynamic config).`);
378
- cliLogger.dim(" Apply this to your config's default export, then re-run:");
379
- for (const line of JSON.stringify(managed, null, 2).split("\n")) cliLogger.dim(` ${line}`);
380
- process.exitCode = 1;
381
- };
382
- const rulesListAction = async (options) => {
383
- recordRulesInvocation();
384
- recordCount(METRIC.rulesQueried, 1, {
385
- subcommand: "list",
386
- hadFilter: Boolean(options.category || options.tag || options.framework || options.configured)
387
- });
388
- const catalog = buildRuleCatalog();
389
- const config = validateConfigTypes((await resolveRuleConfigTarget(resolveProjectRoot(options))).config);
390
- const categoryFilter = typeof options.category === "string" ? options.category.toLowerCase() : void 0;
391
- const frameworkFilter = options.framework?.toLowerCase();
392
- const rows = catalog.filter((entry) => {
393
- if (categoryFilter && entry.category.toLowerCase() !== categoryFilter) return false;
394
- if (frameworkFilter && entry.framework.toLowerCase() !== frameworkFilter) return false;
395
- if (options.tag && !entry.tags.includes(options.tag)) return false;
396
- return true;
397
- }).map((entry) => ({
398
- entry,
399
- effective: resolveEffectiveRuleSeverity(config, entry)
400
- })).filter((row) => options.configured ? row.effective.source !== "default" : true);
401
- if (options.json) {
402
- const payload = rows.map((row) => ({
403
- key: row.entry.key,
404
- id: row.entry.id,
405
- category: row.entry.category,
406
- framework: row.entry.framework,
407
- tags: row.entry.tags,
408
- defaultSeverity: row.entry.defaultSeverity,
409
- defaultEnabled: row.entry.defaultEnabled,
410
- severity: row.effective.value,
411
- source: row.effective.source
412
- }));
413
- cliLogger.log(JSON.stringify(payload, null, 2));
414
- return;
415
- }
416
- cliLogger.log(renderRuleCatalog(rows));
417
- };
418
- const rulesExplainAction = async (ruleQuery, options) => {
419
- recordRulesInvocation();
420
- recordCount(METRIC.rulesQueried, 1, { subcommand: "explain" });
421
- const entry = findRuleInCatalog(buildRuleCatalog(), ruleQuery);
422
- if (!entry) {
423
- reportRuleNotFound(ruleQuery);
424
- return;
425
- }
426
- const effective = resolveEffectiveRuleSeverity(validateConfigTypes((await resolveRuleConfigTarget(resolveProjectRoot(options))).config), entry);
427
- if (options.json) {
428
- cliLogger.log(JSON.stringify({
429
- key: entry.key,
430
- id: entry.id,
431
- category: entry.category,
432
- framework: entry.framework,
433
- tags: entry.tags,
434
- defaultSeverity: entry.defaultSeverity,
435
- defaultEnabled: entry.defaultEnabled,
436
- severity: effective.value,
437
- source: effective.source,
438
- recommendation: entry.recommendation ?? null,
439
- learnMoreUrl: buildRuleDocsUrl("react-doctor", entry.id)
440
- }, null, 2));
441
- return;
442
- }
443
- cliLogger.log(renderRuleExplanation({
444
- entry,
445
- effective
446
- }));
447
- };
448
- const setRuleSeverityAndReport = async (entry, severity, options, action) => {
449
- const { target, nextConfig, written } = await applyConfigChange(options, (config) => setRuleSeverity(config, entry.key, severity));
450
- if (!written) {
451
- reportManualEdit(target, nextConfig);
452
- return;
453
- }
454
- cliLogger.success(`Set ${entry.key} → ${severity}`);
455
- cliLogger.dim(` Updated ${describeTargetPath(target)}`);
456
- recordCount(METRIC.rulesChanged, 1, {
457
- action,
458
- severity,
459
- target: entry.key
460
- });
461
- };
462
- const rulesSetAction = async (ruleQuery, severityValue, options) => {
463
- recordRulesInvocation();
464
- const severity = parseSeverity(severityValue);
465
- if (!severity) {
466
- reportInvalidSeverity(severityValue);
467
- return;
468
- }
469
- const entry = findRuleInCatalog(buildRuleCatalog(), ruleQuery);
470
- if (!entry) {
471
- reportRuleNotFound(ruleQuery);
472
- return;
473
- }
474
- await setRuleSeverityAndReport(entry, severity, options, "set");
475
- };
476
- const rulesEnableAction = async (ruleQuery, options) => {
477
- recordRulesInvocation();
478
- const entry = findRuleInCatalog(buildRuleCatalog(), ruleQuery);
479
- if (!entry) {
480
- reportRuleNotFound(ruleQuery);
481
- return;
482
- }
483
- if (options.severity === void 0) {
484
- await setRuleSeverityAndReport(entry, entry.defaultSeverity, options, "enable");
485
- return;
486
- }
487
- const severity = parseSeverity(options.severity);
488
- if (!severity) {
489
- reportInvalidSeverity(options.severity);
490
- return;
491
- }
492
- if (severity === "off") {
493
- cliLogger.error("`enable` cannot set a rule to off. Use `react-doctor rules disable` instead.");
494
- process.exitCode = 1;
495
- return;
496
- }
497
- await setRuleSeverityAndReport(entry, severity, options, "enable");
498
- };
499
- const rulesDisableAction = async (ruleQuery, options) => {
500
- recordRulesInvocation();
501
- const entry = findRuleInCatalog(buildRuleCatalog(), ruleQuery);
502
- if (!entry) {
503
- reportRuleNotFound(ruleQuery);
504
- return;
505
- }
506
- await setRuleSeverityAndReport(entry, "off", options, "disable");
507
- };
508
- const rulesCategoryAction = async (categoryQuery, severityValue, options) => {
509
- recordRulesInvocation();
510
- const severity = parseSeverity(severityValue);
511
- if (!severity) {
512
- reportInvalidSeverity(severityValue);
513
- return;
514
- }
515
- const knownCategories = listRuleCategories(buildRuleCatalog());
516
- const matchedCategory = knownCategories.find((category) => category.toLowerCase() === categoryQuery.toLowerCase());
517
- if (!matchedCategory) {
518
- cliLogger.error(`Unknown category "${categoryQuery}".`);
519
- cliLogger.dim(` Known categories: ${knownCategories.join(", ")}`);
520
- process.exitCode = 1;
521
- return;
522
- }
523
- const { target, nextConfig, written } = await applyConfigChange(options, (config) => setCategorySeverity(config, matchedCategory, severity));
524
- if (!written) {
525
- reportManualEdit(target, nextConfig);
526
- return;
527
- }
528
- cliLogger.success(`Set category "${matchedCategory}" → ${severity}`);
529
- cliLogger.dim(` Updated ${describeTargetPath(target)}`);
530
- recordCount(METRIC.rulesChanged, 1, {
531
- action: "category",
532
- severity,
533
- target: matchedCategory
534
- });
535
- };
536
- const rulesIgnoreTagAction = async (tag, options) => {
537
- recordRulesInvocation();
538
- const knownTags = listRuleTags(buildRuleCatalog());
539
- if (!knownTags.includes(tag)) {
540
- cliLogger.error(`Unknown tag "${tag}".`);
541
- cliLogger.dim(` Known tags: ${knownTags.join(", ")}`);
542
- process.exitCode = 1;
543
- return;
544
- }
545
- const { target, nextConfig, written } = await applyConfigChange(options, (config) => addIgnoredTag(config, tag));
546
- if (!written) {
547
- reportManualEdit(target, nextConfig);
548
- return;
549
- }
550
- cliLogger.success(`Ignoring tag "${tag}" (rules with this tag are skipped before linting)`);
551
- cliLogger.dim(` Updated ${describeTargetPath(target)}`);
552
- recordCount(METRIC.rulesChanged, 1, {
553
- action: "ignoreTag",
554
- target: tag
555
- });
556
- };
557
- const rulesUnignoreTagAction = async (tag, options) => {
558
- recordRulesInvocation();
559
- const target = await resolveRuleConfigTarget(resolveProjectRoot(options));
560
- if (!(target.config.ignore?.tags ?? []).includes(tag)) {
561
- cliLogger.dim(`Tag "${tag}" was not being ignored; nothing to change.`);
562
- return;
563
- }
564
- const nextConfig = removeIgnoredTag(target.config, tag);
565
- const { written } = await writeRuleConfig(target, nextConfig);
566
- if (!written) {
567
- reportManualEdit(target, nextConfig);
568
- return;
569
- }
570
- cliLogger.success(`Tag "${tag}" is no longer ignored`);
571
- cliLogger.dim(` Updated ${describeTargetPath(target)}`);
572
- recordCount(METRIC.rulesChanged, 1, {
573
- action: "unignoreTag",
574
- target: tag
575
- });
576
- };
577
- //#endregion
578
- export { rulesCategoryAction, rulesDisableAction, rulesEnableAction, rulesExplainAction, rulesIgnoreTagAction, rulesListAction, rulesSetAction, rulesUnignoreTagAction };
579
-
580
- //# sourceMappingURL=rules-6-d19pN1.js.map
581
- //# debugId=3482bd59-e632-5753-a94a-167622d04810
@@ -1,53 +0,0 @@
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]="79ff9a14-c5d9-5dbf-9e16-2fab909c6901")}catch(e){}}();
3
- import { P as isNonInteractiveEnvironment, Tn as resolveScanTarget, t as recordCount, y as METRIC } from "./record-metric-CtlQma6P.js";
4
- import { i as warnDeprecatedDiff } from "./resolve-scope-gy72JH3h.js";
5
- import { _ as resolveCliInspectOptions, i as validateModeFlags } from "./should-fail-scan-gate-DImKUuu-.js";
6
- import { n as warnDeprecatedFailOn, r as runProjectMigrations, t as inspectAction } from "./inspect-DBJtHure.js";
7
- import path from "node:path";
8
- //#region src/cli/utils/should-use-tui.ts
9
- const shouldUseTui = (input) => {
10
- if (input.isNonInteractiveEnvironment || !input.stdinIsTty || !input.stdoutIsTty || !input.supportsRawMode || input.nodeMajorVersion < 22 || input.terminalName === "dumb") return false;
11
- const flags = input.flags;
12
- return !(flags.score === true || flags.json === true || flags.jsonCompact === true || flags.jsonOut !== void 0 || flags.staged === true || flags.changedFilesFrom !== void 0);
13
- };
14
- //#endregion
15
- //#region src/cli/commands/scan.ts
16
- const runScanCommand = async (input) => {
17
- if (input.flags.cache === false) process.env.REACT_DOCTOR_NO_CACHE = "1";
18
- const nodeMajorVersion = Number(process.versions.node.split(".")[0]);
19
- if (!shouldUseTui({
20
- flags: input.flags,
21
- isNonInteractiveEnvironment: isNonInteractiveEnvironment(),
22
- nodeMajorVersion,
23
- stdinIsTty: process.stdin.isTTY === true,
24
- stdoutIsTty: process.stdout.isTTY === true,
25
- supportsRawMode: typeof process.stdin.setRawMode === "function",
26
- terminalName: process.env.TERM
27
- })) {
28
- await inspectAction(input.directory, input.flags, input.invocationCommand);
29
- return;
30
- }
31
- await runProjectMigrations(path.resolve(input.directory));
32
- const scanTarget = await resolveScanTarget(input.directory, { allowAmbiguous: true });
33
- validateModeFlags(input.flags);
34
- warnDeprecatedFailOn(input.flags, scanTarget.userConfig);
35
- warnDeprecatedDiff(input.flags, scanTarget.userConfig);
36
- recordCount(METRIC.cliInvoked, 1, { command: input.invocationCommand });
37
- const { runScanApp } = await import("./run-scan-app-Drlqxtzl.js");
38
- const { shouldFail } = await runScanApp({
39
- directory: input.directory,
40
- scanTarget,
41
- options: resolveCliInspectOptions(input.flags, null),
42
- projectFlag: input.flags.project,
43
- skipPrompts: input.flags.yes ?? false,
44
- blocking: input.flags.blocking ?? input.flags.failOn,
45
- flags: input.flags
46
- });
47
- if (shouldFail) process.exitCode = 1;
48
- };
49
- //#endregion
50
- export { runScanCommand };
51
-
52
- //# sourceMappingURL=scan-C3Io41Dq.js.map
53
- //# debugId=79ff9a14-c5d9-5dbf-9e16-2fab909c6901