@colrealpro/react-luau-doctor 0.18.1 → 0.18.2
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 +314 -36
- package/dist/cli.js.map +6 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
|
-
import
|
|
5
|
+
import fs11 from "fs";
|
|
6
6
|
import os2 from "os";
|
|
7
|
-
import
|
|
7
|
+
import path13 from "path";
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@colrealpro/react-luau-doctor",
|
|
11
11
|
publishConfig: {
|
|
12
12
|
access: "public"
|
|
13
13
|
},
|
|
14
|
-
version: "0.18.
|
|
14
|
+
version: "0.18.2",
|
|
15
15
|
description: "Static analysis for React-Luau hooks, effects, rendering, and performance.",
|
|
16
16
|
license: "MIT",
|
|
17
17
|
type: "module",
|
|
@@ -10698,6 +10698,210 @@ async function runCiCommand(argv) {
|
|
|
10698
10698
|
throw new Error("ci requires install, config, or upgrade");
|
|
10699
10699
|
}
|
|
10700
10700
|
|
|
10701
|
+
// src/update-check.ts
|
|
10702
|
+
import { spawn } from "child_process";
|
|
10703
|
+
import fs10 from "fs";
|
|
10704
|
+
import path12 from "path";
|
|
10705
|
+
var UPDATE_CHECK_INTERVAL_MS = 2 * 60 * 60 * 1000;
|
|
10706
|
+
var UPDATE_REQUEST_TIMEOUT_MS = 5000;
|
|
10707
|
+
var UPDATE_CACHE_FILENAME = "update-check.json";
|
|
10708
|
+
function updateCacheFilename() {
|
|
10709
|
+
return path12.join(cacheBaseDirectory(), UPDATE_CACHE_FILENAME);
|
|
10710
|
+
}
|
|
10711
|
+
function readUpdateCache() {
|
|
10712
|
+
try {
|
|
10713
|
+
const parsed = JSON.parse(fs10.readFileSync(updateCacheFilename(), "utf8"));
|
|
10714
|
+
if (typeof parsed.checkedAt !== "number" || !Number.isFinite(parsed.checkedAt))
|
|
10715
|
+
return null;
|
|
10716
|
+
if (parsed.latest !== undefined && typeof parsed.latest !== "string")
|
|
10717
|
+
return null;
|
|
10718
|
+
return {
|
|
10719
|
+
checkedAt: parsed.checkedAt,
|
|
10720
|
+
latest: parsed.latest
|
|
10721
|
+
};
|
|
10722
|
+
} catch {
|
|
10723
|
+
return null;
|
|
10724
|
+
}
|
|
10725
|
+
}
|
|
10726
|
+
function writeUpdateCache(cache) {
|
|
10727
|
+
try {
|
|
10728
|
+
const filename = updateCacheFilename();
|
|
10729
|
+
fs10.mkdirSync(path12.dirname(filename), { recursive: true });
|
|
10730
|
+
fs10.writeFileSync(filename, `${JSON.stringify(cache)}
|
|
10731
|
+
`);
|
|
10732
|
+
} catch {}
|
|
10733
|
+
}
|
|
10734
|
+
function parseVersion(value) {
|
|
10735
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value.trim());
|
|
10736
|
+
if (!match)
|
|
10737
|
+
return null;
|
|
10738
|
+
return {
|
|
10739
|
+
major: Number(match[1]),
|
|
10740
|
+
minor: Number(match[2]),
|
|
10741
|
+
patch: Number(match[3]),
|
|
10742
|
+
prerelease: match[4]?.split(".") ?? []
|
|
10743
|
+
};
|
|
10744
|
+
}
|
|
10745
|
+
function comparePrerelease(left, right) {
|
|
10746
|
+
if (left.length === 0 || right.length === 0) {
|
|
10747
|
+
if (left.length === right.length)
|
|
10748
|
+
return 0;
|
|
10749
|
+
return left.length === 0 ? 1 : -1;
|
|
10750
|
+
}
|
|
10751
|
+
const count = Math.max(left.length, right.length);
|
|
10752
|
+
for (let index = 0;index < count; index += 1) {
|
|
10753
|
+
const leftPart = left[index];
|
|
10754
|
+
const rightPart = right[index];
|
|
10755
|
+
if (leftPart === undefined)
|
|
10756
|
+
return -1;
|
|
10757
|
+
if (rightPart === undefined)
|
|
10758
|
+
return 1;
|
|
10759
|
+
if (leftPart === rightPart)
|
|
10760
|
+
continue;
|
|
10761
|
+
const leftNumber = /^\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
10762
|
+
const rightNumber = /^\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
10763
|
+
if (leftNumber !== null && rightNumber !== null)
|
|
10764
|
+
return leftNumber < rightNumber ? -1 : 1;
|
|
10765
|
+
if (leftNumber !== null)
|
|
10766
|
+
return -1;
|
|
10767
|
+
if (rightNumber !== null)
|
|
10768
|
+
return 1;
|
|
10769
|
+
return leftPart < rightPart ? -1 : 1;
|
|
10770
|
+
}
|
|
10771
|
+
return 0;
|
|
10772
|
+
}
|
|
10773
|
+
function compareVersions(left, right) {
|
|
10774
|
+
const a = parseVersion(left);
|
|
10775
|
+
const b = parseVersion(right);
|
|
10776
|
+
if (!a || !b)
|
|
10777
|
+
return null;
|
|
10778
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
10779
|
+
if (a[key] !== b[key])
|
|
10780
|
+
return a[key] < b[key] ? -1 : 1;
|
|
10781
|
+
}
|
|
10782
|
+
return comparePrerelease(a.prerelease, b.prerelease);
|
|
10783
|
+
}
|
|
10784
|
+
function updateRegistryUrl() {
|
|
10785
|
+
const registry = process.env.REACT_LUAU_DOCTOR_UPDATE_REGISTRY ?? process.env.npm_config_registry ?? process.env.NPM_CONFIG_REGISTRY ?? "https://registry.npmjs.org/";
|
|
10786
|
+
const base = registry.endsWith("/") ? registry : `${registry}/`;
|
|
10787
|
+
return new URL(`${encodeURIComponent(package_default.name)}/latest`, base).toString();
|
|
10788
|
+
}
|
|
10789
|
+
async function fetchLatestVersion() {
|
|
10790
|
+
const controller = new AbortController;
|
|
10791
|
+
const timer = setTimeout(() => controller.abort(), UPDATE_REQUEST_TIMEOUT_MS);
|
|
10792
|
+
timer.unref?.();
|
|
10793
|
+
try {
|
|
10794
|
+
const response = await fetch(updateRegistryUrl(), {
|
|
10795
|
+
headers: { accept: "application/json" },
|
|
10796
|
+
signal: controller.signal
|
|
10797
|
+
});
|
|
10798
|
+
if (!response.ok)
|
|
10799
|
+
throw new Error(`npm registry returned HTTP ${response.status}`);
|
|
10800
|
+
const body = await response.json();
|
|
10801
|
+
if (typeof body.version !== "string" || compareVersions(body.version, body.version) === null) {
|
|
10802
|
+
throw new Error("npm registry returned an invalid package version");
|
|
10803
|
+
}
|
|
10804
|
+
return body.version;
|
|
10805
|
+
} finally {
|
|
10806
|
+
clearTimeout(timer);
|
|
10807
|
+
}
|
|
10808
|
+
}
|
|
10809
|
+
function updateCacheIsStale(now = Date.now()) {
|
|
10810
|
+
const cache = readUpdateCache();
|
|
10811
|
+
return !cache || now - cache.checkedAt >= UPDATE_CHECK_INTERVAL_MS;
|
|
10812
|
+
}
|
|
10813
|
+
async function refreshUpdateCache(options = {}) {
|
|
10814
|
+
const now = options.now ?? Date.now();
|
|
10815
|
+
try {
|
|
10816
|
+
const latest = await fetchLatestVersion();
|
|
10817
|
+
writeUpdateCache({ checkedAt: now, latest });
|
|
10818
|
+
return latest;
|
|
10819
|
+
} catch (error) {
|
|
10820
|
+
const previous = readUpdateCache();
|
|
10821
|
+
writeUpdateCache({ checkedAt: now, latest: previous?.latest });
|
|
10822
|
+
if (options.silent)
|
|
10823
|
+
return null;
|
|
10824
|
+
throw error;
|
|
10825
|
+
}
|
|
10826
|
+
}
|
|
10827
|
+
function startBackgroundUpdateRefresh() {
|
|
10828
|
+
if (!updateCacheIsStale())
|
|
10829
|
+
return;
|
|
10830
|
+
const script = process.argv[1];
|
|
10831
|
+
if (!script)
|
|
10832
|
+
return;
|
|
10833
|
+
try {
|
|
10834
|
+
const child2 = spawn(process.execPath, [script, "__update-cache"], {
|
|
10835
|
+
detached: true,
|
|
10836
|
+
stdio: "ignore",
|
|
10837
|
+
windowsHide: true,
|
|
10838
|
+
env: process.env
|
|
10839
|
+
});
|
|
10840
|
+
child2.unref();
|
|
10841
|
+
} catch {}
|
|
10842
|
+
}
|
|
10843
|
+
function getCachedUpdateNotice(currentVersion) {
|
|
10844
|
+
const cache = readUpdateCache();
|
|
10845
|
+
if (!cache?.latest)
|
|
10846
|
+
return null;
|
|
10847
|
+
const comparison = compareVersions(cache.latest, currentVersion);
|
|
10848
|
+
if (comparison === null || comparison <= 0)
|
|
10849
|
+
return null;
|
|
10850
|
+
return { current: currentVersion, latest: cache.latest };
|
|
10851
|
+
}
|
|
10852
|
+
async function checkForUpdatesNow(currentVersion) {
|
|
10853
|
+
const latest = await refreshUpdateCache();
|
|
10854
|
+
if (!latest)
|
|
10855
|
+
throw new Error("Could not check npm for updates");
|
|
10856
|
+
const comparison = compareVersions(latest, currentVersion);
|
|
10857
|
+
if (comparison === null)
|
|
10858
|
+
throw new Error(`Could not compare installed version ${currentVersion} with ${latest}`);
|
|
10859
|
+
return { latest, updateAvailable: comparison > 0 };
|
|
10860
|
+
}
|
|
10861
|
+
|
|
10862
|
+
// src/update-install.ts
|
|
10863
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
10864
|
+
import { fileURLToPath } from "url";
|
|
10865
|
+
function normalizedPath(filename) {
|
|
10866
|
+
return filename.replaceAll("\\", "/");
|
|
10867
|
+
}
|
|
10868
|
+
function updateInstallCommandForPath(filename) {
|
|
10869
|
+
const normalized = normalizedPath(filename);
|
|
10870
|
+
const spec = `${package_default.name}@latest`;
|
|
10871
|
+
if (normalized.includes("/.bun/install/global/node_modules/")) {
|
|
10872
|
+
return {
|
|
10873
|
+
manager: "bun",
|
|
10874
|
+
command: "bun",
|
|
10875
|
+
args: ["add", "-g", spec],
|
|
10876
|
+
display: `bun add -g ${spec}`
|
|
10877
|
+
};
|
|
10878
|
+
}
|
|
10879
|
+
if (normalized.includes("/.bun/install/cache/") || normalized.includes("/.npm/_npx/"))
|
|
10880
|
+
return null;
|
|
10881
|
+
if (normalized.includes("/node_modules/")) {
|
|
10882
|
+
return {
|
|
10883
|
+
manager: "npm",
|
|
10884
|
+
command: "npm",
|
|
10885
|
+
args: ["install", "-g", spec],
|
|
10886
|
+
display: `npm install -g ${spec}`
|
|
10887
|
+
};
|
|
10888
|
+
}
|
|
10889
|
+
return null;
|
|
10890
|
+
}
|
|
10891
|
+
function currentUpdateInstallCommand() {
|
|
10892
|
+
return updateInstallCommandForPath(fileURLToPath(import.meta.url));
|
|
10893
|
+
}
|
|
10894
|
+
function installLatestVersion(command) {
|
|
10895
|
+
const result = spawnSync3(command.command, command.args, {
|
|
10896
|
+
stdio: "inherit",
|
|
10897
|
+
windowsHide: true
|
|
10898
|
+
});
|
|
10899
|
+
if (result.error)
|
|
10900
|
+
throw result.error;
|
|
10901
|
+
if (result.status !== 0)
|
|
10902
|
+
throw new Error(`${command.display} exited with code ${result.status ?? "unknown"}`);
|
|
10903
|
+
}
|
|
10904
|
+
|
|
10701
10905
|
// src/fix-examples.ts
|
|
10702
10906
|
var examples = {
|
|
10703
10907
|
"react-luau/parse-error": {
|
|
@@ -11184,6 +11388,7 @@ Usage:
|
|
|
11184
11388
|
react-luau-doctor [directory] [options]
|
|
11185
11389
|
react-luau-doctor ci <install|config|upgrade>
|
|
11186
11390
|
react-luau-doctor why <file:line>
|
|
11391
|
+
react-luau-doctor update [--check]
|
|
11187
11392
|
react-luau-doctor rules <command>
|
|
11188
11393
|
|
|
11189
11394
|
Scan options:
|
|
@@ -11212,6 +11417,7 @@ Scan options:
|
|
|
11212
11417
|
--no-color Disable automatic ANSI colors
|
|
11213
11418
|
--no-cache Disable the persistent OS-level analysis cache
|
|
11214
11419
|
--no-parallel Disable parallel file analysis
|
|
11420
|
+
--no-update-check Disable the automatic update notice
|
|
11215
11421
|
|
|
11216
11422
|
React-Luau Doctor options:
|
|
11217
11423
|
--min-severity <level> suggestion, warning, or error
|
|
@@ -11224,6 +11430,10 @@ CI commands:
|
|
|
11224
11430
|
ci upgrade [--provider github|gitlab] [--pr] [-y] [--cwd <cwd>]
|
|
11225
11431
|
Reporting toggles: --comment/--no-comment, --review-comments/--no-review-comments, --commit-status/--no-commit-status
|
|
11226
11432
|
|
|
11433
|
+
Update commands:
|
|
11434
|
+
update Update the global installation to the latest release
|
|
11435
|
+
update --check Check npm for a newer release without updating
|
|
11436
|
+
|
|
11227
11437
|
Rules commands:
|
|
11228
11438
|
rules list [--category <name>] [--configured] [--json]
|
|
11229
11439
|
rules explain <rule> [--json]
|
|
@@ -11236,6 +11446,53 @@ Config:
|
|
|
11236
11446
|
react-luau-doctor.config.json
|
|
11237
11447
|
`;
|
|
11238
11448
|
}
|
|
11449
|
+
function automaticUpdateNoticeEnabled(options, machineReadable) {
|
|
11450
|
+
return !options.noUpdateCheck && !machineReadable && Boolean(process.stdout.isTTY) && !process.env.CI && process.env.NO_UPDATE_NOTIFIER === undefined && process.env.REACT_LUAU_DOCTOR_NO_UPDATE_CHECK === undefined;
|
|
11451
|
+
}
|
|
11452
|
+
function renderUpdateNotice(current, latest, colorized) {
|
|
11453
|
+
const label = whyPaint(colorized, "Update available:", WHY_ANSI.bold, WHY_ANSI.yellow);
|
|
11454
|
+
const oldVersion = whyPaint(colorized, `v${current}`, WHY_ANSI.dim);
|
|
11455
|
+
const newVersion = whyPaint(colorized, `v${latest}`, WHY_ANSI.bold);
|
|
11456
|
+
return `${label} ${oldVersion} \u2192 ${newVersion}
|
|
11457
|
+
Run \`react-luau-doctor update\` to update.`;
|
|
11458
|
+
}
|
|
11459
|
+
async function runUpdateCommand(argv) {
|
|
11460
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
11461
|
+
process.stdout.write(`Usage: react-luau-doctor update [--check]
|
|
11462
|
+
`);
|
|
11463
|
+
return;
|
|
11464
|
+
}
|
|
11465
|
+
if (argv.length > 1 || argv.length === 1 && argv[0] !== "--check") {
|
|
11466
|
+
throw new Error("Usage: react-luau-doctor update [--check]");
|
|
11467
|
+
}
|
|
11468
|
+
const result = await checkForUpdatesNow(VERSION2);
|
|
11469
|
+
if (!result.updateAvailable) {
|
|
11470
|
+
process.stdout.write(`React-Luau Doctor v${VERSION2} is up to date.
|
|
11471
|
+
`);
|
|
11472
|
+
return;
|
|
11473
|
+
}
|
|
11474
|
+
const colorized = shouldUseColor(false, false);
|
|
11475
|
+
if (argv[0] === "--check") {
|
|
11476
|
+
process.stdout.write(`${renderUpdateNotice(VERSION2, result.latest, colorized)}
|
|
11477
|
+
`);
|
|
11478
|
+
return;
|
|
11479
|
+
}
|
|
11480
|
+
const command = currentUpdateInstallCommand();
|
|
11481
|
+
if (!command) {
|
|
11482
|
+
throw new Error(`Could not determine the global package manager for this installation. Run \`npm install -g ${package_default.name}@latest\` manually.`);
|
|
11483
|
+
}
|
|
11484
|
+
const label = whyPaint(colorized, "Updating React-Luau Doctor:", WHY_ANSI.bold, WHY_ANSI.yellow);
|
|
11485
|
+
const oldVersion = whyPaint(colorized, `v${VERSION2}`, WHY_ANSI.dim);
|
|
11486
|
+
const newVersion = whyPaint(colorized, `v${result.latest}`, WHY_ANSI.bold);
|
|
11487
|
+
process.stdout.write(`${label} ${oldVersion} \u2192 ${newVersion}
|
|
11488
|
+
Using \`${command.display}\`
|
|
11489
|
+
|
|
11490
|
+
`);
|
|
11491
|
+
installLatestVersion(command);
|
|
11492
|
+
process.stdout.write(`
|
|
11493
|
+
Updated React-Luau Doctor to v${result.latest}.
|
|
11494
|
+
`);
|
|
11495
|
+
}
|
|
11239
11496
|
function splitLongOption(arg) {
|
|
11240
11497
|
if (!arg.startsWith("--"))
|
|
11241
11498
|
return { name: arg };
|
|
@@ -11641,6 +11898,7 @@ function parseArgs(argv) {
|
|
|
11641
11898
|
noColor: false,
|
|
11642
11899
|
noCache: false,
|
|
11643
11900
|
noParallel: false,
|
|
11901
|
+
noUpdateCheck: false,
|
|
11644
11902
|
help: false,
|
|
11645
11903
|
version: false
|
|
11646
11904
|
};
|
|
@@ -11678,6 +11936,8 @@ function parseArgs(argv) {
|
|
|
11678
11936
|
options.noCache = true;
|
|
11679
11937
|
else if (arg === "--no-parallel")
|
|
11680
11938
|
options.noParallel = true;
|
|
11939
|
+
else if (arg === "--no-update-check")
|
|
11940
|
+
options.noUpdateCheck = true;
|
|
11681
11941
|
else if (arg === "--annotations")
|
|
11682
11942
|
options.annotations = true;
|
|
11683
11943
|
else if (arg === "--help" || arg === "-h")
|
|
@@ -11795,8 +12055,8 @@ function validateModeFlags(options, scope) {
|
|
|
11795
12055
|
throw new Error("--annotations cannot be combined with --json or --score");
|
|
11796
12056
|
}
|
|
11797
12057
|
function findProjectByName(root, name) {
|
|
11798
|
-
const direct =
|
|
11799
|
-
if (
|
|
12058
|
+
const direct = path13.resolve(root, name);
|
|
12059
|
+
if (fs11.existsSync(direct) && fs11.statSync(direct).isDirectory())
|
|
11800
12060
|
return direct;
|
|
11801
12061
|
const ignored = new Set([".git", "node_modules", "Packages", "DevPackages", "ServerPackages", "dist", "vendor"]);
|
|
11802
12062
|
const queue = [{ directory: root, depth: 0 }];
|
|
@@ -11805,17 +12065,17 @@ function findProjectByName(root, name) {
|
|
|
11805
12065
|
const current = queue.shift();
|
|
11806
12066
|
if (current.depth >= 3)
|
|
11807
12067
|
continue;
|
|
11808
|
-
for (const entry of
|
|
12068
|
+
for (const entry of fs11.readdirSync(current.directory, { withFileTypes: true })) {
|
|
11809
12069
|
if (!entry.isDirectory() || ignored.has(entry.name))
|
|
11810
12070
|
continue;
|
|
11811
|
-
const absolute =
|
|
12071
|
+
const absolute = path13.join(current.directory, entry.name);
|
|
11812
12072
|
if (entry.name === name)
|
|
11813
12073
|
matches.push(absolute);
|
|
11814
12074
|
queue.push({ directory: absolute, depth: current.depth + 1 });
|
|
11815
12075
|
}
|
|
11816
12076
|
}
|
|
11817
12077
|
if (matches.length > 1)
|
|
11818
|
-
throw new Error(`Project selector "${name}" is ambiguous: ${matches.map((match) =>
|
|
12078
|
+
throw new Error(`Project selector "${name}" is ambiguous: ${matches.map((match) => path13.relative(root, match)).join(", ")}`);
|
|
11819
12079
|
return matches[0] ?? null;
|
|
11820
12080
|
}
|
|
11821
12081
|
function resolveProjectRoots(root, projectFlag, config) {
|
|
@@ -11833,15 +12093,15 @@ function serializeReport(report, compact) {
|
|
|
11833
12093
|
return compact ? JSON.stringify(report) : JSON.stringify(report, null, 2);
|
|
11834
12094
|
}
|
|
11835
12095
|
function writeJsonFile(filename, value, compact = false) {
|
|
11836
|
-
|
|
11837
|
-
|
|
12096
|
+
fs11.mkdirSync(path13.dirname(filename), { recursive: true });
|
|
12097
|
+
fs11.writeFileSync(filename, `${compact ? JSON.stringify(value) : JSON.stringify(value, null, 2)}
|
|
11838
12098
|
`);
|
|
11839
12099
|
}
|
|
11840
12100
|
function writeDiagnosticsDump(directory, report) {
|
|
11841
|
-
|
|
11842
|
-
writeJsonFile(
|
|
11843
|
-
writeJsonFile(
|
|
11844
|
-
writeJsonFile(
|
|
12101
|
+
fs11.mkdirSync(directory, { recursive: true });
|
|
12102
|
+
writeJsonFile(path13.join(directory, "report.json"), report);
|
|
12103
|
+
writeJsonFile(path13.join(directory, "diagnostics.json"), report.diagnostics);
|
|
12104
|
+
writeJsonFile(path13.join(directory, "summary.json"), {
|
|
11845
12105
|
schemaVersion: report.schemaVersion,
|
|
11846
12106
|
root: report.root,
|
|
11847
12107
|
scope: report.scope ?? "full",
|
|
@@ -11877,7 +12137,7 @@ function parseCommandCwd(argv) {
|
|
|
11877
12137
|
const value = argv[++index];
|
|
11878
12138
|
if (!value)
|
|
11879
12139
|
throw new Error(`${arg} requires a path`);
|
|
11880
|
-
cwd =
|
|
12140
|
+
cwd = path13.resolve(value);
|
|
11881
12141
|
} else
|
|
11882
12142
|
remaining.push(arg);
|
|
11883
12143
|
}
|
|
@@ -11986,7 +12246,7 @@ function runRulesCommand(argv) {
|
|
|
11986
12246
|
if (!severity)
|
|
11987
12247
|
throw new Error("Rule severity must be off, suggestion, warning/warn, or error");
|
|
11988
12248
|
const filename = writeConfig(cwd, (current) => ({ ...current, rules: { ...current.rules, [rule.id]: severity } }));
|
|
11989
|
-
process.stdout.write(`Set ${rule.id} to ${severity} in ${
|
|
12249
|
+
process.stdout.write(`Set ${rule.id} to ${severity} in ${path13.relative(cwd, filename)}
|
|
11990
12250
|
`);
|
|
11991
12251
|
return;
|
|
11992
12252
|
}
|
|
@@ -12005,7 +12265,7 @@ function runRulesCommand(argv) {
|
|
|
12005
12265
|
severity = normalized;
|
|
12006
12266
|
}
|
|
12007
12267
|
const filename = writeConfig(cwd, (current) => ({ ...current, rules: { ...current.rules, [rule.id]: severity } }));
|
|
12008
|
-
process.stdout.write(`Enabled ${rule.id} at ${severity} in ${
|
|
12268
|
+
process.stdout.write(`Enabled ${rule.id} at ${severity} in ${path13.relative(cwd, filename)}
|
|
12009
12269
|
`);
|
|
12010
12270
|
return;
|
|
12011
12271
|
}
|
|
@@ -12015,7 +12275,7 @@ function runRulesCommand(argv) {
|
|
|
12015
12275
|
throw new Error("rules disable requires a rule id");
|
|
12016
12276
|
const rule = findRule(requested);
|
|
12017
12277
|
const filename = writeConfig(cwd, (current) => ({ ...current, rules: { ...current.rules, [rule.id]: "off" } }));
|
|
12018
|
-
process.stdout.write(`Disabled ${rule.id} in ${
|
|
12278
|
+
process.stdout.write(`Disabled ${rule.id} in ${path13.relative(cwd, filename)}
|
|
12019
12279
|
`);
|
|
12020
12280
|
return;
|
|
12021
12281
|
}
|
|
@@ -12038,7 +12298,7 @@ function runRulesCommand(argv) {
|
|
|
12038
12298
|
...categoryRules.map((rule) => [rule.id, severity])
|
|
12039
12299
|
])
|
|
12040
12300
|
}));
|
|
12041
|
-
process.stdout.write(`Set ${categoryRules.length} ${category} rules to ${severity} in ${
|
|
12301
|
+
process.stdout.write(`Set ${categoryRules.length} ${category} rules to ${severity} in ${path13.relative(cwd, filename)}
|
|
12042
12302
|
`);
|
|
12043
12303
|
return;
|
|
12044
12304
|
}
|
|
@@ -12122,7 +12382,7 @@ function whyCaretForLine(sourceLine, line, ranges) {
|
|
|
12122
12382
|
return value;
|
|
12123
12383
|
}
|
|
12124
12384
|
function renderWhyCodeFrame(filename, diagnostic, colorized) {
|
|
12125
|
-
const source =
|
|
12385
|
+
const source = fs11.readFileSync(filename, "utf8").split(/\r?\n/);
|
|
12126
12386
|
const ranges = whyDiagnosticRanges(diagnostic);
|
|
12127
12387
|
const intervals = whyFrameIntervals(ranges, source.length);
|
|
12128
12388
|
const width = String(Math.max(...intervals.map((interval) => interval.end), 1)).length;
|
|
@@ -12230,13 +12490,13 @@ async function runWhy(location, cwd, noColor = false, cache = true, onProgress,
|
|
|
12230
12490
|
const match = location.match(/^(.*):(\d+)(?::(\d+))?$/);
|
|
12231
12491
|
if (!match)
|
|
12232
12492
|
throw new Error("Location must be file:line or file:line:column");
|
|
12233
|
-
const filename =
|
|
12493
|
+
const filename = path13.resolve(cwd, match[1]);
|
|
12234
12494
|
const line = Number(match[2]);
|
|
12235
12495
|
const column = match[3] === undefined ? undefined : Number(match[3]);
|
|
12236
|
-
if (!
|
|
12496
|
+
if (!fs11.existsSync(filename))
|
|
12237
12497
|
throw new Error(`File does not exist: ${match[1]}`);
|
|
12238
12498
|
const colorized = shouldUseColor(noColor, false);
|
|
12239
|
-
const source =
|
|
12499
|
+
const source = fs11.readFileSync(filename, "utf8");
|
|
12240
12500
|
const isSuppressed = createInlineSuppressionChecker(source);
|
|
12241
12501
|
const auditReport = await scanWhyFile(filename, cwd, cache, onProgress);
|
|
12242
12502
|
beforeOutput?.();
|
|
@@ -12277,16 +12537,16 @@ async function runWhy(location, cwd, noColor = false, cache = true, onProgress,
|
|
|
12277
12537
|
}
|
|
12278
12538
|
}
|
|
12279
12539
|
function pathIsInside(parent, child2) {
|
|
12280
|
-
const relative =
|
|
12281
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
12540
|
+
const relative = path13.relative(parent, child2);
|
|
12541
|
+
return relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative);
|
|
12282
12542
|
}
|
|
12283
12543
|
async function runScan(options, onProgress) {
|
|
12284
12544
|
const commandRoot = process.cwd();
|
|
12285
|
-
const target =
|
|
12286
|
-
if (!
|
|
12545
|
+
const target = path13.resolve(commandRoot, options.target);
|
|
12546
|
+
if (!fs11.existsSync(target))
|
|
12287
12547
|
throw new Error(`Scan path does not exist: ${options.target}`);
|
|
12288
|
-
const targetStat =
|
|
12289
|
-
const scanRoot = targetStat.isFile() ?
|
|
12548
|
+
const targetStat = fs11.statSync(target);
|
|
12549
|
+
const scanRoot = targetStat.isFile() ? path13.dirname(target) : target;
|
|
12290
12550
|
const loaded = loadConfigWithSource(commandRoot);
|
|
12291
12551
|
const config = loaded.config;
|
|
12292
12552
|
const resolvedScope = resolveScope(options, config);
|
|
@@ -12316,7 +12576,7 @@ async function runScan(options, onProgress) {
|
|
|
12316
12576
|
const reports = [];
|
|
12317
12577
|
for (const { projectRoot, targetRoot } of projectTargets) {
|
|
12318
12578
|
let report2;
|
|
12319
|
-
const projectName = projectTargets.length > 1 ?
|
|
12579
|
+
const projectName = projectTargets.length > 1 ? path13.relative(displayRoot, projectRoot) || "." : undefined;
|
|
12320
12580
|
const projectProgress = onProgress ? (progress) => onProgress({
|
|
12321
12581
|
...progress,
|
|
12322
12582
|
phase: [projectName, progress.phase].filter(Boolean).join(":") || undefined,
|
|
@@ -12363,7 +12623,7 @@ async function runScan(options, onProgress) {
|
|
|
12363
12623
|
`[debug] target=${target}`,
|
|
12364
12624
|
`[debug] config=${loaded.filename ?? "none"}`,
|
|
12365
12625
|
`[debug] scope=${report.scope ?? scope} base=${report.base ?? resolvedScope.base ?? "auto"}`,
|
|
12366
|
-
`[debug] projects=${projectTargets.map(({ projectRoot }) =>
|
|
12626
|
+
`[debug] projects=${projectTargets.map(({ projectRoot }) => path13.relative(displayRoot, projectRoot) || ".").join(",")}`,
|
|
12367
12627
|
`[debug] candidates=${report.candidateFiles ?? 0} scanned=${report.scannedFiles} partial=${Boolean(report.partial)}`,
|
|
12368
12628
|
`[debug] parallel=${!options.noParallel}`
|
|
12369
12629
|
];
|
|
@@ -12376,6 +12636,14 @@ async function runScan(options, onProgress) {
|
|
|
12376
12636
|
async function main() {
|
|
12377
12637
|
try {
|
|
12378
12638
|
const argv = process.argv.slice(2);
|
|
12639
|
+
if (argv[0] === "__update-cache") {
|
|
12640
|
+
await refreshUpdateCache({ silent: true });
|
|
12641
|
+
return;
|
|
12642
|
+
}
|
|
12643
|
+
if (argv[0] === "update") {
|
|
12644
|
+
await runUpdateCommand(argv.slice(1));
|
|
12645
|
+
return;
|
|
12646
|
+
}
|
|
12379
12647
|
if (argv[0] === "ci") {
|
|
12380
12648
|
await runCiCommand(argv.slice(1));
|
|
12381
12649
|
return;
|
|
@@ -12426,6 +12694,9 @@ ${os2.release()}
|
|
|
12426
12694
|
}
|
|
12427
12695
|
const machineReadable = options.scoreOnly || options.json || options.annotations;
|
|
12428
12696
|
const colorized = shouldUseColor(options.noColor, machineReadable);
|
|
12697
|
+
const updateNoticeEnabled = automaticUpdateNoticeEnabled(options, machineReadable);
|
|
12698
|
+
if (updateNoticeEnabled)
|
|
12699
|
+
startBackgroundUpdateRefresh();
|
|
12429
12700
|
const progress = createProgressRenderer({
|
|
12430
12701
|
enabled: Boolean(process.stdout.isTTY && !process.env.CI && !machineReadable),
|
|
12431
12702
|
colorized
|
|
@@ -12440,12 +12711,12 @@ ${os2.release()}
|
|
|
12440
12711
|
const json = `${serializeReport(report, compactJson)}
|
|
12441
12712
|
`;
|
|
12442
12713
|
if (options.jsonOut) {
|
|
12443
|
-
const outputPath =
|
|
12444
|
-
|
|
12445
|
-
|
|
12714
|
+
const outputPath = path13.resolve(process.cwd(), options.jsonOut);
|
|
12715
|
+
fs11.mkdirSync(path13.dirname(outputPath), { recursive: true });
|
|
12716
|
+
fs11.writeFileSync(outputPath, json);
|
|
12446
12717
|
}
|
|
12447
12718
|
if (options.outputDir)
|
|
12448
|
-
writeDiagnosticsDump(
|
|
12719
|
+
writeDiagnosticsDump(path13.resolve(process.cwd(), options.outputDir), report);
|
|
12449
12720
|
const config = loadConfigWithSource(process.cwd()).config;
|
|
12450
12721
|
const showScore = options.showScore ?? true;
|
|
12451
12722
|
const verbose = options.verbose ?? config.verbose ?? false;
|
|
@@ -12462,6 +12733,13 @@ ${os2.release()}
|
|
|
12462
12733
|
} else
|
|
12463
12734
|
process.stdout.write(`${renderTextReport(report, showScore, colorized, verbose, process.stdout.columns ?? 120)}
|
|
12464
12735
|
`);
|
|
12736
|
+
if (updateNoticeEnabled) {
|
|
12737
|
+
const update = getCachedUpdateNotice(VERSION2);
|
|
12738
|
+
if (update)
|
|
12739
|
+
process.stdout.write(`
|
|
12740
|
+
${renderUpdateNotice(update.current, update.latest, colorized)}
|
|
12741
|
+
`);
|
|
12742
|
+
}
|
|
12465
12743
|
const blocking = options.blocking ?? config.blocking ?? "error";
|
|
12466
12744
|
if (shouldBlock2(report, blocking))
|
|
12467
12745
|
process.exitCode = 1;
|
|
@@ -12474,5 +12752,5 @@ ${os2.release()}
|
|
|
12474
12752
|
}
|
|
12475
12753
|
main();
|
|
12476
12754
|
|
|
12477
|
-
//# debugId=
|
|
12755
|
+
//# debugId=53584D6CB0EB00E064756E2164756E21
|
|
12478
12756
|
//# sourceMappingURL=cli.js.map
|