@stll/oxlint-config 1.1.0 → 1.2.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.
@@ -276,12 +276,17 @@ const importerDependencies = (value) => {
276
276
  }
277
277
  return result;
278
278
  };
279
+ const BUN_TEXT_LOCKFILE_VERSIONS = /* @__PURE__ */ new Set([
280
+ 0,
281
+ 1,
282
+ 2
283
+ ]);
279
284
  const parseChangedLock = ({ file, text }) => {
280
285
  const resolutions = [];
281
286
  const importers = {};
282
287
  if (file.endsWith("bun.lock")) {
283
288
  const parsed = parseChangedJson(text);
284
- if (!changedRecord(parsed) || ![0, 1].includes(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
289
+ if (!changedRecord(parsed) || !BUN_TEXT_LOCKFILE_VERSIONS.has(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
285
290
  for (const [directory, workspace] of Object.entries(parsed["workspaces"])) importers[directory || "."] = importerDependencies(workspace);
286
291
  for (const [location, value] of Object.entries(parsed["packages"])) {
287
292
  const dependency = dependencyName(location);
@@ -579,27 +584,93 @@ const snapshotText = ({ snapshot, file, visited = /* @__PURE__ */ new Set() }) =
579
584
  visited
580
585
  });
581
586
  };
582
- /** Read declared selector files too, without executing workflows or inspecting installed tools. */
587
+ /**
588
+ * What one `actions/checkout` step puts where, or `undefined` for any other step.
589
+ *
590
+ * A selector such as `base/package.json` after a checkout of this repository
591
+ * with `path: base` names the repository's own `package.json` at another ref,
592
+ * so it is read as that tracked file. A path built from an expression could
593
+ * replace any directory, so it is `unknown`.
594
+ */
595
+ const checkoutStep = (step) => {
596
+ if (!changedRecord(step)) return void 0;
597
+ const uses = step["uses"];
598
+ if (typeof uses !== "string" || !uses.startsWith("actions/checkout@")) return void 0;
599
+ const options = changedRecord(step["with"]) ? step["with"] : {};
600
+ const repository = options["repository"];
601
+ const sameRepository = repository === void 0 || repository === "${{ github.repository }}";
602
+ const checkoutPath = options["path"];
603
+ if (checkoutPath === void 0) return {
604
+ kind: "root",
605
+ sameRepository
606
+ };
607
+ if (typeof checkoutPath !== "string" || checkoutPath.includes("${{") || path.posix.isAbsolute(checkoutPath)) return { kind: "unknown" };
608
+ const normalized = path.posix.normalize(checkoutPath).replace(/\/+$/, "");
609
+ if (normalized === "" || normalized === ".") return {
610
+ kind: "root",
611
+ sameRepository
612
+ };
613
+ if (normalized.split("/").includes("..")) return { kind: "unknown" };
614
+ return {
615
+ kind: "path",
616
+ path: normalized,
617
+ sameRepository
618
+ };
619
+ };
620
+ /**
621
+ * The tracked file a declared selector names under the checkouts preceding
622
+ * its step. The most specific checkout directory decides; a selector inside
623
+ * another repository's checkout is not a tracked file, whatever this
624
+ * repository tracks at the same path.
625
+ */
626
+ const resolveCheckoutSelector = (declared, checkouts) => {
627
+ const file = path.posix.normalize(declared);
628
+ let owner;
629
+ for (const directory of checkouts.keys()) if ((directory === "" || file.startsWith(`${directory}/`)) && (owner === void 0 || directory.length > owner.length)) owner = directory;
630
+ if (owner === void 0) return file;
631
+ if (checkouts.get(owner) !== true) throw new Error(`Setup version-file names a file outside this repository: ${declared}`);
632
+ return owner === "" ? file : file.slice(owner.length + 1);
633
+ };
634
+ /** Visit each step with only the checkouts that precede it. */
635
+ const visitStepsInOrder = (steps, checkouts, visitStep) => {
636
+ const scope = new Map(checkouts);
637
+ for (const step of steps) {
638
+ visitStep(step, scope);
639
+ const checkout = checkoutStep(step);
640
+ if (checkout === void 0) continue;
641
+ if (checkout.kind !== "path") {
642
+ scope.clear();
643
+ scope.set("", checkout.kind === "root" && checkout.sameRepository);
644
+ continue;
645
+ }
646
+ for (const directory of scope.keys()) if (directory === checkout.path || directory.startsWith(`${checkout.path}/`)) scope.delete(directory);
647
+ scope.set(checkout.path, checkout.sameRepository);
648
+ }
649
+ };
583
650
  const selectorFiles = (snapshot) => {
584
651
  const files = /* @__PURE__ */ new Map();
585
- const visit = (value) => {
652
+ const visit = (value, checkouts = /* @__PURE__ */ new Map()) => {
586
653
  if (Array.isArray(value)) {
587
- for (const entry of value) visit(entry);
654
+ for (const entry of value) visit(entry, checkouts);
588
655
  return;
589
656
  }
590
657
  if (!changedRecord(value)) return;
591
658
  for (const [key, entry] of Object.entries(value)) {
659
+ if (key === "steps" && Array.isArray(entry)) {
660
+ visitStepsInOrder(entry, checkouts, visit);
661
+ continue;
662
+ }
592
663
  const input = key.toLowerCase();
593
664
  if (!/(?:^|-)version-file$/.test(input) && ![
594
665
  "toolchain-file",
595
666
  "rust-toolchain-file",
596
667
  "global-json-file"
597
668
  ].includes(input)) {
598
- visit(entry);
669
+ visit(entry, checkouts);
599
670
  continue;
600
671
  }
601
672
  if (typeof entry !== "string" || entry.trim() === "" || entry.includes("${{") || path.posix.isAbsolute(entry) || entry.split("/").includes("..")) throw new Error("Unclassifiable setup version-file declaration");
602
- const file = path.posix.normalize(entry);
673
+ const file = resolveCheckoutSelector(entry, checkouts);
603
674
  if (file === "." || file.split("/").some((part) => part === "vendor" || part === "node_modules")) throw new Error("Setup version-file leaves the tracked toolchain scope");
604
675
  let tool = "shared";
605
676
  if (input === "node-version-file") tool = "node";
@@ -955,7 +1026,7 @@ const setupRuntimeFileVersion = ({ snapshot, file, runtime }) => {
955
1026
  };
956
1027
  const setupRuntimeVersions = (snapshot) => {
957
1028
  const versions = [];
958
- const step = (value, file) => {
1029
+ const step = (value, file, checkouts) => {
959
1030
  if (!changedRecord(value) || typeof value["uses"] !== "string") return;
960
1031
  const action = value["uses"].split("@").at(0)?.toLowerCase();
961
1032
  let runtime = /(?:^|\/)setup-([^/]+)$/.exec(action ?? "")?.[1];
@@ -1006,7 +1077,7 @@ const setupRuntimeVersions = (snapshot) => {
1006
1077
  if (typeof input !== "string" || input.trim() === "" || input.includes("${{")) throw new Error("Unclassifiable setup version-file declaration");
1007
1078
  version = setupRuntimeFileVersion({
1008
1079
  snapshot,
1009
- file: path.posix.normalize(input),
1080
+ file: resolveCheckoutSelector(input, checkouts),
1010
1081
  runtime: inputRuntime
1011
1082
  });
1012
1083
  } else version = setupRuntimeVersion(input);
@@ -1024,7 +1095,7 @@ const setupRuntimeVersions = (snapshot) => {
1024
1095
  return;
1025
1096
  }
1026
1097
  if (!changedRecord(value)) return;
1027
- for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry)) for (const child of entry) step(child, file);
1098
+ for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry)) visitStepsInOrder(entry, /* @__PURE__ */ new Map(), (child, checkouts) => step(child, file, checkouts));
1028
1099
  else visit(entry, file);
1029
1100
  };
1030
1101
  for (const file of snapshot.entries.keys()) {