@stll/oxlint-config 1.2.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.
@@ -584,27 +584,93 @@ const snapshotText = ({ snapshot, file, visited = /* @__PURE__ */ new Set() }) =
584
584
  visited
585
585
  });
586
586
  };
587
- /** 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
+ };
588
650
  const selectorFiles = (snapshot) => {
589
651
  const files = /* @__PURE__ */ new Map();
590
- const visit = (value) => {
652
+ const visit = (value, checkouts = /* @__PURE__ */ new Map()) => {
591
653
  if (Array.isArray(value)) {
592
- for (const entry of value) visit(entry);
654
+ for (const entry of value) visit(entry, checkouts);
593
655
  return;
594
656
  }
595
657
  if (!changedRecord(value)) return;
596
658
  for (const [key, entry] of Object.entries(value)) {
659
+ if (key === "steps" && Array.isArray(entry)) {
660
+ visitStepsInOrder(entry, checkouts, visit);
661
+ continue;
662
+ }
597
663
  const input = key.toLowerCase();
598
664
  if (!/(?:^|-)version-file$/.test(input) && ![
599
665
  "toolchain-file",
600
666
  "rust-toolchain-file",
601
667
  "global-json-file"
602
668
  ].includes(input)) {
603
- visit(entry);
669
+ visit(entry, checkouts);
604
670
  continue;
605
671
  }
606
672
  if (typeof entry !== "string" || entry.trim() === "" || entry.includes("${{") || path.posix.isAbsolute(entry) || entry.split("/").includes("..")) throw new Error("Unclassifiable setup version-file declaration");
607
- const file = path.posix.normalize(entry);
673
+ const file = resolveCheckoutSelector(entry, checkouts);
608
674
  if (file === "." || file.split("/").some((part) => part === "vendor" || part === "node_modules")) throw new Error("Setup version-file leaves the tracked toolchain scope");
609
675
  let tool = "shared";
610
676
  if (input === "node-version-file") tool = "node";
@@ -960,7 +1026,7 @@ const setupRuntimeFileVersion = ({ snapshot, file, runtime }) => {
960
1026
  };
961
1027
  const setupRuntimeVersions = (snapshot) => {
962
1028
  const versions = [];
963
- const step = (value, file) => {
1029
+ const step = (value, file, checkouts) => {
964
1030
  if (!changedRecord(value) || typeof value["uses"] !== "string") return;
965
1031
  const action = value["uses"].split("@").at(0)?.toLowerCase();
966
1032
  let runtime = /(?:^|\/)setup-([^/]+)$/.exec(action ?? "")?.[1];
@@ -1011,7 +1077,7 @@ const setupRuntimeVersions = (snapshot) => {
1011
1077
  if (typeof input !== "string" || input.trim() === "" || input.includes("${{")) throw new Error("Unclassifiable setup version-file declaration");
1012
1078
  version = setupRuntimeFileVersion({
1013
1079
  snapshot,
1014
- file: path.posix.normalize(input),
1080
+ file: resolveCheckoutSelector(input, checkouts),
1015
1081
  runtime: inputRuntime
1016
1082
  });
1017
1083
  } else version = setupRuntimeVersion(input);
@@ -1029,7 +1095,7 @@ const setupRuntimeVersions = (snapshot) => {
1029
1095
  return;
1030
1096
  }
1031
1097
  if (!changedRecord(value)) return;
1032
- 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));
1033
1099
  else visit(entry, file);
1034
1100
  };
1035
1101
  for (const file of snapshot.entries.keys()) {