aislop 0.5.0 → 0.5.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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as ENGINE_INFO, r as getEngineLabel, t as APP_VERSION } from "./version-CxBRws3M.js";
1
+ import { n as ENGINE_INFO, r as getEngineLabel, t as APP_VERSION } from "./version-CIlgPf8Q.js";
2
2
  import { n as runSubprocess, t as isToolInstalled } from "./subprocess-CQUJDGgn.js";
3
3
  import { r as runGenericLinter, t as fixRubyLint } from "./generic-BrcWMW7E.js";
4
4
  import { n as runExpoDoctor } from "./expo-doctor-Bz0LZhQ6.js";
@@ -1568,7 +1568,7 @@ const detectSwallowedExceptions = async (context) => {
1568
1568
  };
1569
1569
 
1570
1570
  //#endregion
1571
- //#region src/engines/ai-slop/narrative-comments.ts
1571
+ //#region src/engines/ai-slop/narrative-comments-patterns.ts
1572
1572
  const DECORATIVE_SEPARATOR = /^[-=─━~_*#]{6,}$/;
1573
1573
  const DECORATIVE_SECTION_HEADER = /^[-=─━~_*#]{3,}[\s\S]+?[-=─━~_*#]{3,}$/;
1574
1574
  const SECTION_HEADER = /^(Phase|Step|Section|Part)\s+\d+[:.-]/i;
@@ -1627,6 +1627,19 @@ const SUPPORTED_EXTS = new Set([
1627
1627
  ".java",
1628
1628
  ".php"
1629
1629
  ]);
1630
+ const DECL_START = /^(\s*)(export\s+)?(async\s+)?(const|let|var|function|class|type|interface|enum|abstract\s+class)\s+/;
1631
+ const EXPORT_DEFAULT = /^\s*export\s+default\b/;
1632
+ const TS_MEMBER_DECL_START = /^\s*(?:readonly\s+|static\s+|public\s+|private\s+|protected\s+|abstract\s+|override\s+)*[\w$]+\??\s*:/;
1633
+ const PY_DECL_START = /^\s*(async\s+def|def|class)\s+/;
1634
+ const GO_DECL_START = /^\s*(func|type|var|const)\s+/;
1635
+ const RUST_DECL_START = /^\s*(pub\s+)?(async\s+)?(fn|struct|enum|trait|impl|const|static|type|mod)\s+/;
1636
+ const RUBY_DECL_START = /^\s*(class|module|def)\s+/;
1637
+ const JAVA_DECL_START = /^\s*(?:public|private|protected|static|final|abstract|sealed|non-sealed|\s)+(?:class|interface|enum|record|@interface|\w[^(){};=]*\s+\w+\s*\()/;
1638
+ const JAVA_DECL_START_FALLBACK = /^\s*(class|interface|enum|record|@interface)\s+/;
1639
+ const PHP_DECL_START = /^\s*(?:public|private|protected|static|final|abstract|readonly\s+)*(function|class|interface|trait|enum|const)\s+/;
1640
+
1641
+ //#endregion
1642
+ //#region src/engines/ai-slop/narrative-comments.ts
1630
1643
  const stripJsdocLine = (line) => line.replace(/^\s*\/\*\*+\s?/, "").replace(/\s*\*+\/\s*$/, "").replace(/^\s*\*\s?/, "").trim();
1631
1644
  const stripLineComment = (line) => line.replace(/^\s*(?:(?:\/\/)|#)\s?/, "");
1632
1645
  const getCommentSyntax = (ext) => {
@@ -1718,16 +1731,6 @@ const collectBlocks = (sourceLines, syntax) => {
1718
1731
  }
1719
1732
  return blocks;
1720
1733
  };
1721
- const DECL_START = /^(\s*)(export\s+)?(async\s+)?(const|let|var|function|class|type|interface|enum|abstract\s+class)\s+/;
1722
- const EXPORT_DEFAULT = /^\s*export\s+default\b/;
1723
- const TS_MEMBER_DECL_START = /^\s*(?:readonly\s+|static\s+|public\s+|private\s+|protected\s+|abstract\s+|override\s+)*[\w$]+\??\s*:/;
1724
- const PY_DECL_START = /^\s*(async\s+def|def|class)\s+/;
1725
- const GO_DECL_START = /^\s*(func|type|var|const)\s+/;
1726
- const RUST_DECL_START = /^\s*(pub\s+)?(async\s+)?(fn|struct|enum|trait|impl|const|static|type|mod)\s+/;
1727
- const RUBY_DECL_START = /^\s*(class|module|def)\s+/;
1728
- const JAVA_DECL_START = /^\s*(?:public|private|protected|static|final|abstract|sealed|non-sealed|\s)+(?:class|interface|enum|record|@interface|\w[^(){};=]*\s+\w+\s*\()/;
1729
- const JAVA_DECL_START_FALLBACK = /^\s*(class|interface|enum|record|@interface)\s+/;
1730
- const PHP_DECL_START = /^\s*(?:public|private|protected|static|final|abstract|readonly\s+)*(function|class|interface|trait|enum|const)\s+/;
1731
1734
  const looksLikeDeclarationPreamble = (nextLine, ext) => {
1732
1735
  if (nextLine === null) return false;
1733
1736
  if (DECL_START.test(nextLine) || EXPORT_DEFAULT.test(nextLine)) return true;
@@ -2256,72 +2259,12 @@ const architectureEngine = {
2256
2259
  };
2257
2260
 
2258
2261
  //#endregion
2259
- //#region src/engines/code-quality/complexity.ts
2260
- const FUNCTION_PATTERNS = [
2261
- {
2262
- regex: /^\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/,
2263
- langFilter: [
2264
- ".js",
2265
- ".ts",
2266
- ".jsx",
2267
- ".tsx",
2268
- ".mjs",
2269
- ".cjs"
2270
- ]
2271
- },
2272
- {
2273
- regex: /^\s*(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*(?:=>|:\s*\w)/,
2274
- langFilter: [
2275
- ".js",
2276
- ".ts",
2277
- ".jsx",
2278
- ".tsx",
2279
- ".mjs",
2280
- ".cjs"
2281
- ]
2282
- },
2283
- {
2284
- regex: /^\s*def\s+(\w+)\s*\(([^)]*)\)/,
2285
- langFilter: [".py"]
2286
- },
2287
- {
2288
- regex: /^\s*func\s+(?:\([^)]*\)\s+)?(\w+)\s*\(([^)]*)\)/,
2289
- langFilter: [".go"]
2290
- },
2291
- {
2292
- regex: /^\s*fn\s+(\w+)\s*\(([^)]*)\)/,
2293
- langFilter: [".rs"]
2294
- },
2295
- {
2296
- regex: /^\s*(?:public|private|protected)?\s*(?:static\s+)?(?:\w+\s+)(\w+)\s*\(([^)]*)\)/,
2297
- langFilter: [
2298
- ".java",
2299
- ".cs",
2300
- ".cpp",
2301
- ".c",
2302
- ".php"
2303
- ]
2304
- }
2305
- ];
2306
- const countParams = (p) => p.trim() ? p.split(",").length : 0;
2307
- const matchFunctionOnLine = (line, ext) => {
2308
- for (let i = 0; i < FUNCTION_PATTERNS.length; i++) {
2309
- const pattern = FUNCTION_PATTERNS[i];
2310
- if (!pattern.langFilter.includes(ext)) continue;
2311
- const match = line.match(pattern.regex);
2312
- if (match) return {
2313
- name: match[1],
2314
- params: match[2] ?? "",
2315
- patternIndex: i
2316
- };
2317
- }
2318
- return null;
2319
- };
2262
+ //#region src/engines/code-quality/function-boundaries.ts
2320
2263
  const PYTHON_CONTROL_FLOW_RE = /^\s*(?:if|for|while|with|try|except|else|elif|finally|def|class)\b/;
2321
- const findFunctionEnd = (lines, startIndex, isPython) => {
2322
- if (isPython) return findPythonFunctionEnd(lines, startIndex);
2323
- return findBraceFunctionEnd(lines, startIndex);
2324
- };
2264
+ const ARROW_BLOCK_RE = /* @__PURE__ */ new RegExp("=>\\s*\\{");
2265
+ const ARROW_END_RE = /* @__PURE__ */ new RegExp("=>\\s*$");
2266
+ const BRACE_START_RE = /* @__PURE__ */ new RegExp("^\\s*\\{");
2267
+ const NEW_STATEMENT_RE = /* @__PURE__ */ new RegExp("^(?:export\\s+)?(?:const|let|var|function|class)\\s");
2325
2268
  const isControlFlowBrace = (lineText, braceIndex) => {
2326
2269
  const before = lineText.substring(0, braceIndex).trimEnd();
2327
2270
  if (before.endsWith(")")) return true;
@@ -2401,16 +2344,10 @@ const findPythonFunctionEnd = (lines, startIndex) => {
2401
2344
  maxNesting
2402
2345
  };
2403
2346
  };
2404
- const isDataFile = (content) => {
2405
- const nonEmpty = content.split("\n").filter((l) => l.trim().length > 0);
2406
- if (nonEmpty.length === 0) return false;
2407
- const dataLinePattern = /^\s*[{}[\]"']/;
2408
- return nonEmpty.filter((l) => dataLinePattern.test(l)).length / nonEmpty.length > .8;
2347
+ const findFunctionEnd = (lines, startIndex, isPython) => {
2348
+ if (isPython) return findPythonFunctionEnd(lines, startIndex);
2349
+ return findBraceFunctionEnd(lines, startIndex);
2409
2350
  };
2410
- const ARROW_BLOCK_RE = /* @__PURE__ */ new RegExp("=>\\s*\\{");
2411
- const ARROW_END_RE = /* @__PURE__ */ new RegExp("=>\\s*$");
2412
- const BRACE_START_RE = /* @__PURE__ */ new RegExp("^\\s*\\{");
2413
- const NEW_STATEMENT_RE = /* @__PURE__ */ new RegExp("^(?:export\\s+)?(?:const|let|var|function|class)\\s");
2414
2351
  const isBlockArrow = (lines, startIndex) => {
2415
2352
  if (ARROW_BLOCK_RE.test(lines[startIndex])) return true;
2416
2353
  if (ARROW_END_RE.test(lines[startIndex])) {
@@ -2446,6 +2383,75 @@ const countTemplateLines = (bodyLines) => {
2446
2383
  }
2447
2384
  return templateLineCount;
2448
2385
  };
2386
+
2387
+ //#endregion
2388
+ //#region src/engines/code-quality/complexity.ts
2389
+ const FUNCTION_PATTERNS = [
2390
+ {
2391
+ regex: /^\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/,
2392
+ langFilter: [
2393
+ ".js",
2394
+ ".ts",
2395
+ ".jsx",
2396
+ ".tsx",
2397
+ ".mjs",
2398
+ ".cjs"
2399
+ ]
2400
+ },
2401
+ {
2402
+ regex: /^\s*(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*(?:=>|:\s*\w)/,
2403
+ langFilter: [
2404
+ ".js",
2405
+ ".ts",
2406
+ ".jsx",
2407
+ ".tsx",
2408
+ ".mjs",
2409
+ ".cjs"
2410
+ ]
2411
+ },
2412
+ {
2413
+ regex: /^\s*def\s+(\w+)\s*\(([^)]*)\)/,
2414
+ langFilter: [".py"]
2415
+ },
2416
+ {
2417
+ regex: /^\s*func\s+(?:\([^)]*\)\s+)?(\w+)\s*\(([^)]*)\)/,
2418
+ langFilter: [".go"]
2419
+ },
2420
+ {
2421
+ regex: /^\s*fn\s+(\w+)\s*\(([^)]*)\)/,
2422
+ langFilter: [".rs"]
2423
+ },
2424
+ {
2425
+ regex: /^\s*(?:public|private|protected)?\s*(?:static\s+)?(?:\w+\s+)(\w+)\s*\(([^)]*)\)/,
2426
+ langFilter: [
2427
+ ".java",
2428
+ ".cs",
2429
+ ".cpp",
2430
+ ".c",
2431
+ ".php"
2432
+ ]
2433
+ }
2434
+ ];
2435
+ const countParams = (p) => p.trim() ? p.split(",").length : 0;
2436
+ const matchFunctionOnLine = (line, ext) => {
2437
+ for (let i = 0; i < FUNCTION_PATTERNS.length; i++) {
2438
+ const pattern = FUNCTION_PATTERNS[i];
2439
+ if (!pattern.langFilter.includes(ext)) continue;
2440
+ const match = line.match(pattern.regex);
2441
+ if (match) return {
2442
+ name: match[1],
2443
+ params: match[2] ?? "",
2444
+ patternIndex: i
2445
+ };
2446
+ }
2447
+ return null;
2448
+ };
2449
+ const isDataFile = (content) => {
2450
+ const nonEmpty = content.split("\n").filter((l) => l.trim().length > 0);
2451
+ if (nonEmpty.length === 0) return false;
2452
+ const dataLinePattern = /^\s*[{}[\]"']/;
2453
+ return nonEmpty.filter((l) => dataLinePattern.test(l)).length / nonEmpty.length > .8;
2454
+ };
2449
2455
  const analyzeFunctions = (content, ext) => {
2450
2456
  const lines = content.split("\n");
2451
2457
  const functions = [];
@@ -2468,13 +2474,14 @@ const analyzeFunctions = (content, ext) => {
2468
2474
  }
2469
2475
  return functions;
2470
2476
  };
2477
+ const JSX_FILE_LOC_MULTIPLIER = 1.5;
2471
2478
  const checkFileDiagnostics = (relativePath, content, limits) => {
2472
2479
  const results = [];
2473
2480
  const lineCount = content.split("\n").length;
2474
2481
  const ext = path.extname(relativePath).toLowerCase();
2475
2482
  if (isDataFile(content)) return results;
2476
- const effectiveMax = ext === ".jsx" || ext === ".tsx" ? limits.maxFileLoc * 2 : limits.maxFileLoc;
2477
- if (lineCount > Math.ceil(effectiveMax * 1.1)) results.push({
2483
+ const effectiveMax = ext === ".jsx" || ext === ".tsx" ? Math.ceil(limits.maxFileLoc * JSX_FILE_LOC_MULTIPLIER) : limits.maxFileLoc;
2484
+ if (lineCount > effectiveMax) results.push({
2478
2485
  filePath: relativePath,
2479
2486
  engine: "code-quality",
2480
2487
  rule: "complexity/file-too-large",
@@ -3957,6 +3964,216 @@ const runCargoAudit = async (rootDir, timeout) => {
3957
3964
  }
3958
3965
  };
3959
3966
 
3967
+ //#endregion
3968
+ //#region src/utils/source-masker.ts
3969
+ const JS_EXTS = new Set([
3970
+ ".ts",
3971
+ ".tsx",
3972
+ ".js",
3973
+ ".jsx",
3974
+ ".mjs",
3975
+ ".cjs"
3976
+ ]);
3977
+ const PY_EXTS = new Set([".py"]);
3978
+ const RB_EXTS = new Set([".rb"]);
3979
+ const PHP_EXTS = new Set([".php"]);
3980
+ const familyForExt = (ext) => {
3981
+ if (JS_EXTS.has(ext)) return "js";
3982
+ if (PY_EXTS.has(ext)) return "py";
3983
+ if (RB_EXTS.has(ext)) return "rb";
3984
+ if (PHP_EXTS.has(ext)) return "php";
3985
+ return "none";
3986
+ };
3987
+ const maskStringsAndComments = (content, ext) => {
3988
+ const family = familyForExt(ext);
3989
+ if (family === "none") return content;
3990
+ if (family === "js") return maskJs(content);
3991
+ return maskSimple(content, family);
3992
+ };
3993
+ const maskJs = (content) => {
3994
+ const out = content.split("");
3995
+ const len = content.length;
3996
+ const tplStack = [];
3997
+ let i = 0;
3998
+ const mask = (start, end) => {
3999
+ for (let k = start; k < end; k++) if (out[k] !== "\n") out[k] = " ";
4000
+ };
4001
+ while (i < len) {
4002
+ const c = content[i];
4003
+ const next = content[i + 1];
4004
+ if (tplStack.length > 0) {
4005
+ if (c === "{") {
4006
+ tplStack[tplStack.length - 1]++;
4007
+ i++;
4008
+ continue;
4009
+ }
4010
+ if (c === "}") {
4011
+ if (tplStack[tplStack.length - 1] === 0) {
4012
+ tplStack.pop();
4013
+ const scan = consumeTemplateString(content, i + 1);
4014
+ mask(i + 1, scan.maskEnd);
4015
+ if (scan.openedInterp) tplStack.push(0);
4016
+ i = scan.resumeAt;
4017
+ continue;
4018
+ }
4019
+ tplStack[tplStack.length - 1]--;
4020
+ i++;
4021
+ continue;
4022
+ }
4023
+ if (c === "\"" || c === "'") {
4024
+ const strStart = i;
4025
+ i = consumeQuotedString(content, i, c);
4026
+ mask(strStart + 1, i - 1);
4027
+ continue;
4028
+ }
4029
+ if (c === "`") {
4030
+ const scan = consumeTemplateString(content, i + 1);
4031
+ mask(i + 1, scan.maskEnd);
4032
+ if (scan.openedInterp) tplStack.push(0);
4033
+ i = scan.resumeAt;
4034
+ continue;
4035
+ }
4036
+ if (c === "/" && next === "/") {
4037
+ const strStart = i;
4038
+ while (i < len && content[i] !== "\n") i++;
4039
+ mask(strStart, i);
4040
+ continue;
4041
+ }
4042
+ if (c === "/" && next === "*") {
4043
+ const strStart = i;
4044
+ i += 2;
4045
+ while (i < len - 1 && !(content[i] === "*" && content[i + 1] === "/")) i++;
4046
+ if (i < len - 1) i += 2;
4047
+ mask(strStart, i);
4048
+ continue;
4049
+ }
4050
+ i++;
4051
+ continue;
4052
+ }
4053
+ if (c === "\"" || c === "'") {
4054
+ const strStart = i;
4055
+ i = consumeQuotedString(content, i, c);
4056
+ mask(strStart + 1, i - 1);
4057
+ continue;
4058
+ }
4059
+ if (c === "`") {
4060
+ const scan = consumeTemplateString(content, i + 1);
4061
+ mask(i + 1, scan.maskEnd);
4062
+ if (scan.openedInterp) tplStack.push(0);
4063
+ i = scan.resumeAt;
4064
+ continue;
4065
+ }
4066
+ if (c === "/" && next === "/") {
4067
+ const strStart = i;
4068
+ while (i < len && content[i] !== "\n") i++;
4069
+ mask(strStart, i);
4070
+ continue;
4071
+ }
4072
+ if (c === "/" && next === "*") {
4073
+ const strStart = i;
4074
+ i += 2;
4075
+ while (i < len - 1 && !(content[i] === "*" && content[i + 1] === "/")) i++;
4076
+ if (i < len - 1) i += 2;
4077
+ mask(strStart, i);
4078
+ continue;
4079
+ }
4080
+ i++;
4081
+ }
4082
+ return out.join("");
4083
+ };
4084
+ const consumeQuotedString = (content, start, quote) => {
4085
+ const len = content.length;
4086
+ let i = start + 1;
4087
+ while (i < len) {
4088
+ const c = content[i];
4089
+ if (c === "\\" && i + 1 < len) {
4090
+ i += 2;
4091
+ continue;
4092
+ }
4093
+ if (c === quote) return i + 1;
4094
+ if (c === "\n") return i;
4095
+ i++;
4096
+ }
4097
+ return i;
4098
+ };
4099
+ const consumeTemplateString = (content, start) => {
4100
+ const len = content.length;
4101
+ let i = start;
4102
+ while (i < len) {
4103
+ const c = content[i];
4104
+ if (c === "\\" && i + 1 < len) {
4105
+ i += 2;
4106
+ continue;
4107
+ }
4108
+ if (c === "`") return {
4109
+ maskEnd: i,
4110
+ resumeAt: i + 1,
4111
+ openedInterp: false
4112
+ };
4113
+ if (c === "$" && content[i + 1] === "{") return {
4114
+ maskEnd: i,
4115
+ resumeAt: i + 2,
4116
+ openedInterp: true
4117
+ };
4118
+ i++;
4119
+ }
4120
+ return {
4121
+ maskEnd: i,
4122
+ resumeAt: i,
4123
+ openedInterp: false
4124
+ };
4125
+ };
4126
+ const maskSimple = (content, family) => {
4127
+ const out = content.split("");
4128
+ const len = content.length;
4129
+ let i = 0;
4130
+ const mask = (start, end) => {
4131
+ for (let k = start; k < end; k++) if (out[k] !== "\n") out[k] = " ";
4132
+ };
4133
+ while (i < len) {
4134
+ const c = content[i];
4135
+ const next = content[i + 1];
4136
+ if (family === "py" && (c === "\"" || c === "'")) {
4137
+ if (content[i + 1] === c && content[i + 2] === c) {
4138
+ const triple = c + c + c;
4139
+ const end = content.indexOf(triple, i + 3);
4140
+ const stop = end === -1 ? len : end + 3;
4141
+ mask(i + 3, stop - 3);
4142
+ i = stop;
4143
+ continue;
4144
+ }
4145
+ }
4146
+ if (c === "\"" || c === "'") {
4147
+ const strStart = i;
4148
+ i = consumeQuotedString(content, i, c);
4149
+ mask(strStart + 1, i - 1);
4150
+ continue;
4151
+ }
4152
+ if ((family === "py" || family === "rb" || family === "php") && c === "#") {
4153
+ const strStart = i;
4154
+ while (i < len && content[i] !== "\n") i++;
4155
+ mask(strStart, i);
4156
+ continue;
4157
+ }
4158
+ if (family === "php" && c === "/" && next === "/") {
4159
+ const strStart = i;
4160
+ while (i < len && content[i] !== "\n") i++;
4161
+ mask(strStart, i);
4162
+ continue;
4163
+ }
4164
+ if (family === "php" && c === "/" && next === "*") {
4165
+ const strStart = i;
4166
+ i += 2;
4167
+ while (i < len - 1 && !(content[i] === "*" && content[i + 1] === "/")) i++;
4168
+ if (i < len - 1) i += 2;
4169
+ mask(strStart, i);
4170
+ continue;
4171
+ }
4172
+ i++;
4173
+ }
4174
+ return out.join("");
4175
+ };
4176
+
3960
4177
  //#endregion
3961
4178
  //#region src/engines/security/risky.ts
3962
4179
  const ev = "eval";
@@ -4086,12 +4303,13 @@ const detectRiskyConstructs = async (context) => {
4086
4303
  const relativePath = path.relative(context.rootDirectory, filePath);
4087
4304
  const normalizedPath = relativePath.split(path.sep).join("/");
4088
4305
  const isMigrationOrSeeder = /(?:^|\/)(migrations|seeders|seeds|migrate)\//.test(normalizedPath);
4306
+ const masked = maskStringsAndComments(content, ext);
4089
4307
  for (const { pattern, extensions, name, message, help } of RISKY_PATTERNS) {
4090
4308
  if (!extensions.includes(ext)) continue;
4091
4309
  if (isMigrationOrSeeder && name === "sql-injection") continue;
4092
4310
  const regex = new RegExp(pattern.source, pattern.flags);
4093
4311
  let match;
4094
- while ((match = regex.exec(content)) !== null) {
4312
+ while ((match = regex.exec(masked)) !== null) {
4095
4313
  const line = content.slice(0, match.index).split("\n").length;
4096
4314
  if (name === "innerhtml") {
4097
4315
  const beforeMatch = content.slice(Math.max(0, match.index - 200), match.index);
@@ -4915,7 +5133,7 @@ const scanCommand = async (directory, config, options) => {
4915
5133
  });
4916
5134
  }
4917
5135
  if (options.json) {
4918
- const { buildJsonOutput } = await import("./json-BScQXSOX.js");
5136
+ const { buildJsonOutput } = await import("./json-D_i2_5_-.js");
4919
5137
  const jsonOut = buildJsonOutput(results, scoreResult, projectInfo.sourceFileCount, elapsedMs);
4920
5138
  console.log(JSON.stringify(jsonOut, null, 2));
4921
5139
  return { exitCode };
@@ -5686,42 +5904,40 @@ const removeUnusedDeclarations = (rootDirectory, declarations) => {
5686
5904
 
5687
5905
  //#endregion
5688
5906
  //#region src/commands/fix-force.ts
5689
- const getJsAuditFixCommand = (rootDirectory) => {
5690
- if (fs.existsSync(path.join(rootDirectory, "pnpm-lock.yaml"))) return {
5691
- command: "pnpm",
5692
- args: ["audit", "--fix"]
5693
- };
5694
- if (fs.existsSync(path.join(rootDirectory, "package-lock.json")) || fs.existsSync(path.join(rootDirectory, "package.json"))) return {
5695
- command: "npm",
5696
- args: ["audit", "fix"]
5697
- };
5907
+ const INSTALL_TIMEOUT = 1800 * 1e3;
5908
+ const AUDIT_TIMEOUT = 60 * 1e3;
5909
+ const detectPackageManager = (rootDirectory) => {
5910
+ if (fs.existsSync(path.join(rootDirectory, "pnpm-lock.yaml"))) return "pnpm";
5911
+ if (fs.existsSync(path.join(rootDirectory, "package-lock.json")) || fs.existsSync(path.join(rootDirectory, "package.json"))) return "npm";
5698
5912
  return null;
5699
5913
  };
5700
- const INSTALL_TIMEOUT = 1800 * 1e3;
5701
5914
  const fixDependencyAudit = async (context, onProgress) => {
5702
- const auditFix = getJsAuditFixCommand(context.rootDirectory);
5703
- if (!auditFix) return;
5704
- onProgress?.(`Dependency audit fixes · running ${auditFix.command} audit fix (can take a few minutes)`);
5705
- const result = await runSubprocess(auditFix.command, auditFix.args, {
5706
- cwd: context.rootDirectory,
5915
+ const pm = detectPackageManager(context.rootDirectory);
5916
+ if (!pm) return;
5917
+ if (pm === "npm") {
5918
+ await runNpmAuditFix(context.rootDirectory, onProgress);
5919
+ await tryNpmOverrides(context.rootDirectory, onProgress);
5920
+ return;
5921
+ }
5922
+ await tryPnpmOverrides(context.rootDirectory, onProgress);
5923
+ };
5924
+ const runNpmAuditFix = async (rootDir, onProgress) => {
5925
+ onProgress?.("Dependency audit fixes · running npm audit fix (can take a few minutes)");
5926
+ const result = await runSubprocess("npm", ["audit", "fix"], {
5927
+ cwd: rootDir,
5707
5928
  timeout: INSTALL_TIMEOUT
5708
5929
  });
5709
- if (result.exitCode !== 0 && !result.stdout && !result.stderr) throw new Error(`${auditFix.command} audit fix failed`);
5710
- onProgress?.(`Dependency audit fixes · running ${auditFix.command} install`);
5711
- const installResult = await runSubprocess(auditFix.command, ["install"], {
5712
- cwd: context.rootDirectory,
5930
+ if (result.exitCode !== 0 && !result.stdout && !result.stderr) throw new Error("npm audit fix failed");
5931
+ onProgress?.("Dependency audit fixes · running npm install");
5932
+ const installResult = await runSubprocess("npm", ["install"], {
5933
+ cwd: rootDir,
5713
5934
  timeout: INSTALL_TIMEOUT
5714
5935
  });
5715
- if (installResult.exitCode !== 0) throw new Error(installResult.stderr || installResult.stdout || `${auditFix.command} install failed after audit fix`);
5716
- if (auditFix.command === "npm") await tryNpmOverrides(context.rootDirectory, onProgress);
5936
+ if (installResult.exitCode !== 0) throw new Error(installResult.stderr || installResult.stdout || "npm install failed after audit fix");
5717
5937
  };
5718
- /**
5719
- * For unresolvable transitive vulnerabilities, attempt to add npm overrides
5720
- * in package.json. This forces a newer version of the vulnerable transitive dep.
5721
- */
5722
- const fetchLatestVersion = async (rootDir, pkgName) => {
5938
+ const fetchLatestVersion = async (rootDir, pkgName, pm) => {
5723
5939
  try {
5724
- const result = await runSubprocess("npm", [
5940
+ const result = await runSubprocess(pm, [
5725
5941
  "view",
5726
5942
  pkgName,
5727
5943
  "version",
@@ -5735,11 +5951,11 @@ const fetchLatestVersion = async (rootDir, pkgName) => {
5735
5951
  return null;
5736
5952
  }
5737
5953
  };
5738
- const collectOverrides = async (rootDir, vulnerabilities) => {
5954
+ const collectNpmOverrides = async (rootDir, vulnerabilities) => {
5739
5955
  const overrides = {};
5740
5956
  for (const [pkgName, vuln] of Object.entries(vulnerabilities)) {
5741
5957
  if (vuln.fixAvailable !== false || !vuln.range) continue;
5742
- const latest = await fetchLatestVersion(rootDir, pkgName);
5958
+ const latest = await fetchLatestVersion(rootDir, pkgName, "npm");
5743
5959
  if (latest) overrides[pkgName] = latest;
5744
5960
  }
5745
5961
  return overrides;
@@ -5748,12 +5964,12 @@ const tryNpmOverrides = async (rootDir, onProgress) => {
5748
5964
  try {
5749
5965
  const auditResult = await runSubprocess("npm", ["audit", "--json"], {
5750
5966
  cwd: rootDir,
5751
- timeout: 3e4
5967
+ timeout: AUDIT_TIMEOUT
5752
5968
  });
5753
5969
  if (!auditResult.stdout) return;
5754
5970
  const vulnerabilities = JSON.parse(auditResult.stdout).vulnerabilities;
5755
5971
  if (!vulnerabilities) return;
5756
- const overrides = await collectOverrides(rootDir, vulnerabilities);
5972
+ const overrides = await collectNpmOverrides(rootDir, vulnerabilities);
5757
5973
  if (Object.keys(overrides).length === 0) return;
5758
5974
  const pkgPath = path.join(rootDir, "package.json");
5759
5975
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
@@ -5761,7 +5977,7 @@ const tryNpmOverrides = async (rootDir, onProgress) => {
5761
5977
  ...pkg.overrides || {},
5762
5978
  ...overrides
5763
5979
  };
5764
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
5980
+ fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
5765
5981
  onProgress?.("Dependency audit fixes · applying npm overrides (npm install)");
5766
5982
  await runSubprocess("npm", ["install"], {
5767
5983
  cwd: rootDir,
@@ -5769,6 +5985,61 @@ const tryNpmOverrides = async (rootDir, onProgress) => {
5769
5985
  });
5770
5986
  } catch {}
5771
5987
  };
5988
+ const patchedRangeToVersion = (patched) => {
5989
+ const match = patched.match(/^\s*>=?\s*([0-9]+\.[0-9]+\.[0-9]+[^\s]*)/);
5990
+ return match ? `^${match[1]}` : null;
5991
+ };
5992
+ const overrideKey = (name, vulnerable, patched) => {
5993
+ if (vulnerable && vulnerable.trim().length > 0 && !/^\*$/.test(vulnerable.trim())) return `${name}@${vulnerable.trim()}`;
5994
+ const first = patched.match(/([0-9]+\.[0-9]+\.[0-9]+)/)?.[1];
5995
+ return first ? `${name}@<${first}` : name;
5996
+ };
5997
+ const collectPnpmOverrides = (advisories) => {
5998
+ const overrides = {};
5999
+ for (const adv of Object.values(advisories)) {
6000
+ if (!adv.module_name || !adv.patched_versions) continue;
6001
+ const target = patchedRangeToVersion(adv.patched_versions);
6002
+ if (!target) continue;
6003
+ const key = overrideKey(adv.module_name, adv.vulnerable_versions, adv.patched_versions);
6004
+ overrides[key] = target;
6005
+ }
6006
+ return overrides;
6007
+ };
6008
+ const tryPnpmOverrides = async (rootDir, onProgress) => {
6009
+ onProgress?.("Dependency audit fixes · running pnpm audit");
6010
+ const auditResult = await runSubprocess("pnpm", ["audit", "--json"], {
6011
+ cwd: rootDir,
6012
+ timeout: AUDIT_TIMEOUT
6013
+ });
6014
+ if (!auditResult.stdout) return;
6015
+ let parsed;
6016
+ try {
6017
+ parsed = JSON.parse(auditResult.stdout);
6018
+ } catch {
6019
+ return;
6020
+ }
6021
+ const advisories = parsed.advisories;
6022
+ if (!advisories || Object.keys(advisories).length === 0) return;
6023
+ const overrides = collectPnpmOverrides(advisories);
6024
+ if (Object.keys(overrides).length === 0) return;
6025
+ const pkgPath = path.join(rootDir, "package.json");
6026
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
6027
+ const pnpmBlock = pkg.pnpm ?? {};
6028
+ const existing = pnpmBlock.overrides ?? {};
6029
+ pkg.pnpm = {
6030
+ ...pnpmBlock,
6031
+ overrides: {
6032
+ ...existing,
6033
+ ...overrides
6034
+ }
6035
+ };
6036
+ fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
6037
+ onProgress?.("Dependency audit fixes · applying pnpm overrides (pnpm install)");
6038
+ await runSubprocess("pnpm", ["install"], {
6039
+ cwd: rootDir,
6040
+ timeout: INSTALL_TIMEOUT
6041
+ });
6042
+ };
5772
6043
  const fixExpoDependencies = async (context, onProgress) => {
5773
6044
  await removeDisallowedExpoPackages(context.rootDirectory, onProgress);
5774
6045
  onProgress?.("Expo dependency alignment · running expo install --fix (can take a few minutes)");
@@ -5793,10 +6064,6 @@ const fixExpoDependencies = async (context, onProgress) => {
5793
6064
  });
5794
6065
  if (checkResult.exitCode !== 0) throw new Error(checkResult.stderr || checkResult.stdout || "expo dependency check failed");
5795
6066
  };
5796
- /**
5797
- * Run expo-doctor to detect packages that should not be installed directly,
5798
- * then uninstall them. No hardcoded list — expo-doctor is the source of truth.
5799
- */
5800
6067
  const removeDisallowedExpoPackages = async (rootDir, onProgress) => {
5801
6068
  try {
5802
6069
  onProgress?.("Expo dependency alignment · running expo-doctor");
@@ -5883,8 +6150,9 @@ const runFormattingStep = async (deps) => {
5883
6150
  const runForceSteps = async (deps) => {
5884
6151
  if (!deps.force) return;
5885
6152
  if (deps.config.engines["code-quality"] && hasJsOrTs(deps.projectInfo)) await deps.runStep("Remove unused files", () => runKnipUnusedFiles(deps.resolvedDir), () => fixUnusedFiles(deps.resolvedDir));
5886
- if (deps.config.engines.security) await deps.runStep("Dependency audit fixes", () => runDependencyAudit(deps.context), () => fixDependencyAudit(deps.context, deps.rail.setActiveLabel));
5887
- if (deps.projectInfo.frameworks.includes("expo")) await deps.runStep("Expo dependency alignment", () => runExpoDoctor(deps.context), () => fixExpoDependencies(deps.context, deps.rail.setActiveLabel));
6153
+ const railUpdate = (label) => deps.rail.setActiveLabel(label);
6154
+ if (deps.config.engines.security) await deps.runStep("Dependency audit fixes", () => runDependencyAudit(deps.context), () => fixDependencyAudit(deps.context, railUpdate));
6155
+ if (deps.projectInfo.frameworks.includes("expo")) await deps.runStep("Expo dependency alignment", () => runExpoDoctor(deps.context), () => fixExpoDependencies(deps.context, railUpdate));
5888
6156
  };
5889
6157
 
5890
6158
  //#endregion
@@ -1,4 +1,4 @@
1
- import { n as ENGINE_INFO, t as APP_VERSION } from "./version-CxBRws3M.js";
1
+ import { n as ENGINE_INFO, t as APP_VERSION } from "./version-CIlgPf8Q.js";
2
2
 
3
3
  //#region src/output/json.ts
4
4
  const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs) => {
@@ -33,7 +33,7 @@ const getEngineLabel = (engine) => ENGINE_INFO[engine].label;
33
33
  * Application version — injected at build time by tsdown from package.json.
34
34
  * The fallback should always match the "version" field in package.json.
35
35
  */
36
- const APP_VERSION = "0.5.0";
36
+ const APP_VERSION = "0.5.1";
37
37
 
38
38
  //#endregion
39
39
  export { ENGINE_INFO as n, getEngineLabel as r, APP_VERSION as t };