@stll/oxlint-config 1.5.2 → 1.6.0

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.
Files changed (36) hide show
  1. package/README.md +89 -6
  2. package/dist/dependabot-cli.cjs +3 -1
  3. package/dist/dependabot-cli.cjs.map +1 -1
  4. package/dist/dependabot-cli.mjs +4 -2
  5. package/dist/dependabot-cli.mjs.map +1 -1
  6. package/dist/dependabot.cjs +2 -0
  7. package/dist/dependabot.d.cts +17 -2
  8. package/dist/dependabot.d.mts +17 -2
  9. package/dist/dependabot.mjs +2 -2
  10. package/dist/engine-support-cli.cjs +96 -0
  11. package/dist/engine-support-cli.cjs.map +1 -0
  12. package/dist/engine-support-cli.d.cts +1 -0
  13. package/dist/engine-support-cli.d.mts +1 -0
  14. package/dist/engine-support-cli.mjs +94 -0
  15. package/dist/engine-support-cli.mjs.map +1 -0
  16. package/dist/engine-support.cjs +29 -0
  17. package/dist/engine-support.cjs.map +1 -0
  18. package/dist/engine-support.d.cts +21 -0
  19. package/dist/engine-support.d.mts +21 -0
  20. package/dist/engine-support.mjs +26 -0
  21. package/dist/engine-support.mjs.map +1 -0
  22. package/dist/toolchain-dependabot.cjs +119 -13
  23. package/dist/toolchain-dependabot.cjs.map +1 -1
  24. package/dist/toolchain-dependabot.mjs +96 -14
  25. package/dist/toolchain-dependabot.mjs.map +1 -1
  26. package/dist/toolchain-guard.cjs +16 -4
  27. package/dist/toolchain-guard.cjs.map +1 -1
  28. package/dist/toolchain-guard.mjs +17 -5
  29. package/dist/toolchain-guard.mjs.map +1 -1
  30. package/dist/wasi-loader-normalizer-cli.cjs +290 -0
  31. package/dist/wasi-loader-normalizer-cli.cjs.map +1 -0
  32. package/dist/wasi-loader-normalizer-cli.d.cts +1 -0
  33. package/dist/wasi-loader-normalizer-cli.d.mts +1 -0
  34. package/dist/wasi-loader-normalizer-cli.mjs +290 -0
  35. package/dist/wasi-loader-normalizer-cli.mjs.map +1 -0
  36. package/package.json +19 -2
package/README.md CHANGED
@@ -323,10 +323,47 @@ Shared `toolchain.json` owns the schedule, cooldown, groups, and tooling-owned
323
323
  package/action/image ignores. The input rejects policy overrides. Without
324
324
  `--config`, the tracked manifest inventory supplies ecosystem roots.
325
325
 
326
+ A repository that deliberately holds a dependency declares the decision in
327
+ tracked root `stll-toolchain.json`:
328
+
329
+ ```json
330
+ {
331
+ "dependabotIgnores": [
332
+ {
333
+ "ecosystem": "bun",
334
+ "dependency": "graphql",
335
+ "updateTypes": ["version-update:semver-major"],
336
+ "reason": "Payload 3 requires graphql ^16."
337
+ },
338
+ {
339
+ "ecosystem": "github-actions",
340
+ "dependency": "owner/repo/.github/workflows/reusable.yml",
341
+ "updateTypes": [
342
+ "version-update:semver-major",
343
+ "version-update:semver-minor",
344
+ "version-update:semver-patch"
345
+ ],
346
+ "reason": "Newer commits no longer ship this reusable workflow."
347
+ }
348
+ ]
349
+ }
350
+ ```
351
+
352
+ `dependency` is Dependabot's `dependency-name`; `*` is the only wildcard
353
+ (`@babel/*`). `updateTypes` is a nonempty set of version-update types, so
354
+ security updates stay enabled. Each declaration needs a supported ecosystem with
355
+ a generated update entry and a nonempty reason; duplicates fail. A declaration
356
+ that names or matches a shared pin fails configuration validation: the shared
357
+ policy owns those ignores. The generator appends declarations after the shared
358
+ pins in code-unit order with canonical update types, so output stays
359
+ byte-stable. `stll-toolchain-check` accepts exactly the shared pins plus these
360
+ declarations; any other ignore fails.
361
+
326
362
  For programmatic generation, the `@stll/oxlint-config/dependabot` subpath exports
327
- `generateDependabotConfig({ files, policy, updates? })`, `parseDependabotInput`,
328
- and `parseToolchainPolicy`. `parseDependabotInput` validates the JSON shape above
329
- and returns the `updates` array:
363
+ `generateDependabotConfig({ files, policy, updates?, ignores? })`,
364
+ `parseDependabotInput`, `parseDependabotIgnores` and `parseToolchainPolicy`.
365
+ `parseDependabotInput` validates the JSON shape above and returns the `updates`
366
+ array; `parseDependabotIgnores` validates `dependabotIgnores` for `ignores`:
330
367
 
331
368
  ```ts
332
369
  import {
@@ -477,9 +514,9 @@ prints usage without reading repository configuration.
477
514
 
478
515
  | Environment phase | Command |
479
516
  | ----------------------- | ------------------------------------- |
480
- | Networked install | `bash .agents/cloud-setup.sh install` |
481
- | Offline session startup | `bash .agents/cloud-setup.sh start` |
482
- | Startup with exports | `bash .agents/cloud-setup.sh session` |
517
+ | Networked install | `bash .agents/cloud-setup.sh install` |
518
+ | Offline session startup | `bash .agents/cloud-setup.sh start` |
519
+ | Startup with exports | `bash .agents/cloud-setup.sh session` |
483
520
 
484
521
  Runtime installation repairs and verifies a missing or empty system CA bundle
485
522
  offline before any apt refresh or download, including when the certificate package
@@ -555,6 +592,19 @@ performs no downloads.
555
592
 
556
593
  ## Published package contracts
557
594
 
595
+ ### Engine support releases
596
+
597
+ Run `stll-engine-support --base <git ref>` in pull request CI to require a major
598
+ changeset when an existing published package narrows its `engines.node` range.
599
+ Base engine ranges are read from the manifest at each HEAD package directory.
600
+ Packages moved or renamed between the base and HEAD are therefore treated as new
601
+ packages and skipped. A missing range means unrestricted Node support.
602
+
603
+ Only published workspace packages managed by Changesets and absent from its
604
+ `ignore` list are checked. Derived platform packages and ignored packages are
605
+ not checked separately; their owner package carries the engine range users
606
+ install against.
607
+
558
608
  Run `stll-publish-contract` in PR CI. Every published root or declared workspace
559
609
  package commits `publish-contract.json`, recording engines, peer support ranges,
560
610
  resolved JavaScript targets, and entry points. `stll-publish-contract --write`
@@ -1014,3 +1064,36 @@ from an exact tooling commit; it does not install consumer dependencies to
1014
1064
  perform enforcement or pruning. Its stable removal branch updates one PR per
1015
1065
  repository. See the [root guide](../../README.md#package-quarantine) for the
1016
1066
  inline annotation format and adoption boundary.
1067
+
1068
+ ## Normalize generated WASI loaders
1069
+
1070
+ Run `stll-normalize-wasi-loaders <loader-1> <loader-2>` after `@napi-rs/cli`
1071
+ generates the two WASI loaders. Arguments may appear in either order: the
1072
+ `.wasi-browser.js` and `.wasi.cjs` suffixes select the loader kind, and any other
1073
+ suffix produces an unsupported-file error.
1074
+
1075
+ The normalizer applies these exact transformations:
1076
+
1077
+ - **cleanup handshake:** wraps the cleanup macrotask scheduler so synchronous
1078
+ completion settles safely and thrown scheduler errors reject the promise.
1079
+ - **runtime poll promise:** adds the rejection path used by the scheduler wrapper.
1080
+ - **runtime poll timer:** runs the paced runtime timer through the scheduler wrapper.
1081
+ - **runtime poll macrotask:** runs the early runtime macrotask through the scheduler
1082
+ wrapper.
1083
+ - **async work poll:** runs the async-work timer through the scheduler wrapper.
1084
+ - **worker construction:** builds named worker data and options objects; the browser
1085
+ loader receives the add-on crash flag, while the CommonJS loader keeps its crash
1086
+ data and retries invalid `execArgv` by updating the shared options.
1087
+ - **scheduler helper:** adds the wrapper that handles synchronous completion and
1088
+ converts thrown scheduler errors into promise rejections.
1089
+ - **artifact metadata:** keeps napi-rs artifact metadata on line 1 when present.
1090
+ - **generated-file header:** removes leading generator directives and writes the
1091
+ standard `@ts-nocheck` header immediately after metadata, or first when metadata
1092
+ is absent.
1093
+
1094
+ Each named transformation must have its exact expected count. The command fails
1095
+ closed and writes nothing unless both inputs normalize successfully.
1096
+
1097
+ Use `stll-normalize-wasi-loaders --check <loader-1> <loader-2>` in CI. Check mode
1098
+ does not write files and exits non-zero if either loader differs from the normalized
1099
+ output.
@@ -63,10 +63,12 @@ const main = async () => {
63
63
  });
64
64
  if (remainingDiagnostics.length !== 0) throw new Error(remainingDiagnostics.map(({ path, message }) => `${path}: ${message}`).join("\n"));
65
65
  const declarations = config === void 0 ? void 0 : require_toolchain_dependabot.parseDependabotInput(JSON.parse(await (0, node_fs_promises.readFile)((0, node_path.resolve)(root, config), "utf8")));
66
+ const dependabotIgnores = require_toolchain_dependabot.readDependabotIgnores(files["stll-toolchain.json"]);
66
67
  const text = require_toolchain_dependabot.generateDependabotConfig({
67
68
  files,
68
69
  policy: policy.dependabot,
69
- updates: declarations
70
+ updates: declarations,
71
+ ignores: dependabotIgnores
70
72
  });
71
73
  const destination = selected.path;
72
74
  if (mode === "check") {
@@ -1 +1 @@
1
- {"version":3,"file":"dependabot-cli.cjs","names":["realpath","readToolchainInputs","parseToolchainPolicy","readFile","join","checkGeneratedOutput","generationDiagnostics","parseDependabotInput","resolve","generateDependabotConfig","writeGeneratedFile"],"sources":["../src/dependabot-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n generateDependabotConfig,\n parseDependabotInput,\n parseToolchainPolicy,\n} from \"./dependabot\";\nimport {\n checkGeneratedOutput,\n generationDiagnostics,\n writeGeneratedFile,\n} from \"./generated-file\";\nimport { readToolchainInputs } from \"./toolchain-guard\";\n\nconst usage =\n \"Usage: stll-dependabot [--check] [--config <path>] (run from repository root)\\n stll-dependabot --help\";\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n let mode: \"write\" | \"check\" = \"write\";\n let config: string | undefined;\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (arg === \"--check\" && mode === \"write\") {\n mode = \"check\";\n continue;\n }\n if (arg === \"--config\" && config === undefined) {\n const next = args.at(index + 1);\n if (next === undefined || next.startsWith(\"--\")) throw new Error(usage);\n config = next;\n index++;\n continue;\n }\n throw new Error(usage);\n }\n const root = await realpath(process.cwd());\n const { files, trackedFiles, diagnostics } = readToolchainInputs(root);\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const yaml = join(root, \".github/dependabot.yaml\");\n const yml = join(root, \".github/dependabot.yml\");\n const yamlStat = await checkGeneratedOutput(yaml);\n const ymlStat = await checkGeneratedOutput(yml);\n const candidates = [\n { relative: \".github/dependabot.yaml\", path: yaml, stat: yamlStat },\n { relative: \".github/dependabot.yml\", path: yml, stat: ymlStat },\n ].filter(\n ({ relative, stat }) => stat !== undefined || trackedFiles.has(relative),\n );\n if (candidates.length > 1)\n throw new Error(\"keep exactly one Dependabot configuration: .yml or .yaml\");\n const selected = candidates.at(0) ?? {\n relative: \".github/dependabot.yml\",\n path: yml,\n stat: ymlStat,\n };\n const remainingDiagnostics = await generationDiagnostics({\n diagnostics,\n outputs: [{ relative: selected.relative, destination: selected.path }],\n });\n if (remainingDiagnostics.length !== 0)\n throw new Error(\n remainingDiagnostics\n .map(({ path, message }) => `${path}: ${message}`)\n .join(\"\\n\"),\n );\n const declarations =\n config === undefined\n ? undefined\n : parseDependabotInput(\n JSON.parse(await readFile(resolve(root, config), \"utf8\")),\n );\n const text = generateDependabotConfig({\n files,\n policy: policy.dependabot,\n updates: declarations,\n });\n const destination = selected.path;\n if (mode === \"check\") {\n if (\n selected.stat === undefined ||\n (await readFile(destination, \"utf8\")) !== text\n )\n throw new Error(\n `${selected.relative} has drifted; run stll-dependabot${config === undefined ? \"\" : ` --config ${config}`}`,\n );\n process.stdout.write(`Verified ${selected.relative}\\n`);\n return;\n }\n const permissions = selected.stat?.mode;\n await writeGeneratedFile({\n destination,\n text,\n mode: permissions === undefined ? 0o644 : permissions & 0o777,\n });\n process.stdout.write(`Generated ${selected.relative}\\n`);\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `dependabot: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"dependabot-cli.cjs","names":["realpath","readToolchainInputs","parseToolchainPolicy","readFile","join","checkGeneratedOutput","generationDiagnostics","parseDependabotInput","resolve","readDependabotIgnores","generateDependabotConfig","writeGeneratedFile"],"sources":["../src/dependabot-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n generateDependabotConfig,\n parseDependabotInput,\n parseToolchainPolicy,\n} from \"./dependabot\";\nimport {\n checkGeneratedOutput,\n generationDiagnostics,\n writeGeneratedFile,\n} from \"./generated-file\";\nimport { readDependabotIgnores } from \"./toolchain-dependabot\";\nimport { readToolchainInputs } from \"./toolchain-guard\";\n\nconst usage =\n \"Usage: stll-dependabot [--check] [--config <path>] (run from repository root)\\n stll-dependabot --help\";\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n let mode: \"write\" | \"check\" = \"write\";\n let config: string | undefined;\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (arg === \"--check\" && mode === \"write\") {\n mode = \"check\";\n continue;\n }\n if (arg === \"--config\" && config === undefined) {\n const next = args.at(index + 1);\n if (next === undefined || next.startsWith(\"--\")) throw new Error(usage);\n config = next;\n index++;\n continue;\n }\n throw new Error(usage);\n }\n const root = await realpath(process.cwd());\n const { files, trackedFiles, diagnostics } = readToolchainInputs(root);\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const yaml = join(root, \".github/dependabot.yaml\");\n const yml = join(root, \".github/dependabot.yml\");\n const yamlStat = await checkGeneratedOutput(yaml);\n const ymlStat = await checkGeneratedOutput(yml);\n const candidates = [\n { relative: \".github/dependabot.yaml\", path: yaml, stat: yamlStat },\n { relative: \".github/dependabot.yml\", path: yml, stat: ymlStat },\n ].filter(\n ({ relative, stat }) => stat !== undefined || trackedFiles.has(relative),\n );\n if (candidates.length > 1)\n throw new Error(\"keep exactly one Dependabot configuration: .yml or .yaml\");\n const selected = candidates.at(0) ?? {\n relative: \".github/dependabot.yml\",\n path: yml,\n stat: ymlStat,\n };\n const remainingDiagnostics = await generationDiagnostics({\n diagnostics,\n outputs: [{ relative: selected.relative, destination: selected.path }],\n });\n if (remainingDiagnostics.length !== 0)\n throw new Error(\n remainingDiagnostics\n .map(({ path, message }) => `${path}: ${message}`)\n .join(\"\\n\"),\n );\n const declarations =\n config === undefined\n ? undefined\n : parseDependabotInput(\n JSON.parse(await readFile(resolve(root, config), \"utf8\")),\n );\n // Shared-pin conflicts and invalid declarations still throw in the generator and parser.\n const dependabotIgnores = readDependabotIgnores(files[\"stll-toolchain.json\"]);\n const text = generateDependabotConfig({\n files,\n policy: policy.dependabot,\n updates: declarations,\n ignores: dependabotIgnores,\n });\n const destination = selected.path;\n if (mode === \"check\") {\n if (\n selected.stat === undefined ||\n (await readFile(destination, \"utf8\")) !== text\n )\n throw new Error(\n `${selected.relative} has drifted; run stll-dependabot${config === undefined ? \"\" : ` --config ${config}`}`,\n );\n process.stdout.write(`Verified ${selected.relative}\\n`);\n return;\n }\n const permissions = selected.stat?.mode;\n await writeGeneratedFile({\n destination,\n text,\n mode: permissions === undefined ? 0o644 : permissions & 0o777,\n });\n process.stdout.write(`Generated ${selected.relative}\\n`);\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `dependabot: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as generationDiagnostics, r as writeGeneratedFile, t as checkGeneratedOutput } from "./generated-file.mjs";
3
3
  import { r as readToolchainInputs } from "./toolchain-guard.mjs";
4
- import { i as parseDependabotInput, r as generateDependabotConfig } from "./toolchain-dependabot.mjs";
4
+ import { a as generateDependabotConfig, c as readDependabotIgnores, s as parseDependabotInput } from "./toolchain-dependabot.mjs";
5
5
  import { t as parseToolchainPolicy } from "./toolchain-schema.mjs";
6
6
  import "./dependabot.mjs";
7
7
  import { readFile, realpath } from "node:fs/promises";
@@ -62,10 +62,12 @@ const main = async () => {
62
62
  });
63
63
  if (remainingDiagnostics.length !== 0) throw new Error(remainingDiagnostics.map(({ path, message }) => `${path}: ${message}`).join("\n"));
64
64
  const declarations = config === void 0 ? void 0 : parseDependabotInput(JSON.parse(await readFile(resolve(root, config), "utf8")));
65
+ const dependabotIgnores = readDependabotIgnores(files["stll-toolchain.json"]);
65
66
  const text = generateDependabotConfig({
66
67
  files,
67
68
  policy: policy.dependabot,
68
- updates: declarations
69
+ updates: declarations,
70
+ ignores: dependabotIgnores
69
71
  });
70
72
  const destination = selected.path;
71
73
  if (mode === "check") {
@@ -1 +1 @@
1
- {"version":3,"file":"dependabot-cli.mjs","names":[],"sources":["../src/dependabot-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n generateDependabotConfig,\n parseDependabotInput,\n parseToolchainPolicy,\n} from \"./dependabot\";\nimport {\n checkGeneratedOutput,\n generationDiagnostics,\n writeGeneratedFile,\n} from \"./generated-file\";\nimport { readToolchainInputs } from \"./toolchain-guard\";\n\nconst usage =\n \"Usage: stll-dependabot [--check] [--config <path>] (run from repository root)\\n stll-dependabot --help\";\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n let mode: \"write\" | \"check\" = \"write\";\n let config: string | undefined;\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (arg === \"--check\" && mode === \"write\") {\n mode = \"check\";\n continue;\n }\n if (arg === \"--config\" && config === undefined) {\n const next = args.at(index + 1);\n if (next === undefined || next.startsWith(\"--\")) throw new Error(usage);\n config = next;\n index++;\n continue;\n }\n throw new Error(usage);\n }\n const root = await realpath(process.cwd());\n const { files, trackedFiles, diagnostics } = readToolchainInputs(root);\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const yaml = join(root, \".github/dependabot.yaml\");\n const yml = join(root, \".github/dependabot.yml\");\n const yamlStat = await checkGeneratedOutput(yaml);\n const ymlStat = await checkGeneratedOutput(yml);\n const candidates = [\n { relative: \".github/dependabot.yaml\", path: yaml, stat: yamlStat },\n { relative: \".github/dependabot.yml\", path: yml, stat: ymlStat },\n ].filter(\n ({ relative, stat }) => stat !== undefined || trackedFiles.has(relative),\n );\n if (candidates.length > 1)\n throw new Error(\"keep exactly one Dependabot configuration: .yml or .yaml\");\n const selected = candidates.at(0) ?? {\n relative: \".github/dependabot.yml\",\n path: yml,\n stat: ymlStat,\n };\n const remainingDiagnostics = await generationDiagnostics({\n diagnostics,\n outputs: [{ relative: selected.relative, destination: selected.path }],\n });\n if (remainingDiagnostics.length !== 0)\n throw new Error(\n remainingDiagnostics\n .map(({ path, message }) => `${path}: ${message}`)\n .join(\"\\n\"),\n );\n const declarations =\n config === undefined\n ? undefined\n : parseDependabotInput(\n JSON.parse(await readFile(resolve(root, config), \"utf8\")),\n );\n const text = generateDependabotConfig({\n files,\n policy: policy.dependabot,\n updates: declarations,\n });\n const destination = selected.path;\n if (mode === \"check\") {\n if (\n selected.stat === undefined ||\n (await readFile(destination, \"utf8\")) !== text\n )\n throw new Error(\n `${selected.relative} has drifted; run stll-dependabot${config === undefined ? \"\" : ` --config ${config}`}`,\n );\n process.stdout.write(`Verified ${selected.relative}\\n`);\n return;\n }\n const permissions = selected.stat?.mode;\n await writeGeneratedFile({\n destination,\n text,\n mode: permissions === undefined ? 0o644 : permissions & 0o777,\n });\n process.stdout.write(`Generated ${selected.relative}\\n`);\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `dependabot: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":";;;;;;;;;AAgBA,MAAM,QACJ;AACF,MAAM,OAAO,YAAY;CACvB,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;CACjC,IAAI,KAAK,WAAW,KAAK,KAAK,GAAG,CAAC,MAAM,UAAU;EAChD,QAAQ,OAAO,MAAM,GAAG,MAAM,GAAG;EACjC;CACF;CACA,IAAI,OAA0B;CAC9B,IAAI;CACJ,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;EAChD,MAAM,MAAM,KAAK;EACjB,IAAI,QAAQ,aAAa,SAAS,SAAS;GACzC,OAAO;GACP;EACF;EACA,IAAI,QAAQ,cAAc,WAAW,KAAA,GAAW;GAC9C,MAAM,OAAO,KAAK,GAAG,QAAQ,CAAC;GAC9B,IAAI,SAAS,KAAA,KAAa,KAAK,WAAW,IAAI,GAAG,MAAM,IAAI,MAAM,KAAK;GACtE,SAAS;GACT;GACA;EACF;EACA,MAAM,IAAI,MAAM,KAAK;CACvB;CACA,MAAM,OAAO,MAAM,SAAS,QAAQ,IAAI,CAAC;CACzC,MAAM,EAAE,OAAO,cAAc,gBAAgB,oBAAoB,IAAI;CACrE,MAAM,SAAS,qBACb,KAAK,MACH,MAAM,SAAS,IAAI,IAAI,qBAAqB,YAAY,GAAG,GAAG,MAAM,CACtE,CACF;CACA,MAAM,OAAO,KAAK,MAAM,yBAAyB;CACjD,MAAM,MAAM,KAAK,MAAM,wBAAwB;CAC/C,MAAM,WAAW,MAAM,qBAAqB,IAAI;CAChD,MAAM,UAAU,MAAM,qBAAqB,GAAG;CAC9C,MAAM,aAAa,CACjB;EAAE,UAAU;EAA2B,MAAM;EAAM,MAAM;CAAS,GAClE;EAAE,UAAU;EAA0B,MAAM;EAAK,MAAM;CAAQ,CACjE,CAAC,CAAC,QACC,EAAE,UAAU,WAAW,SAAS,KAAA,KAAa,aAAa,IAAI,QAAQ,CACzE;CACA,IAAI,WAAW,SAAS,GACtB,MAAM,IAAI,MAAM,0DAA0D;CAC5E,MAAM,WAAW,WAAW,GAAG,CAAC,KAAK;EACnC,UAAU;EACV,MAAM;EACN,MAAM;CACR;CACA,MAAM,uBAAuB,MAAM,sBAAsB;EACvD;EACA,SAAS,CAAC;GAAE,UAAU,SAAS;GAAU,aAAa,SAAS;EAAK,CAAC;CACvE,CAAC;CACD,IAAI,qBAAqB,WAAW,GAClC,MAAM,IAAI,MACR,qBACG,KAAK,EAAE,MAAM,cAAc,GAAG,KAAK,IAAI,SAAS,CAAC,CACjD,KAAK,IAAI,CACd;CACF,MAAM,eACJ,WAAW,KAAA,IACP,KAAA,IACA,qBACE,KAAK,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,GAAG,MAAM,CAAC,CAC1D;CACN,MAAM,OAAO,yBAAyB;EACpC;EACA,QAAQ,OAAO;EACf,SAAS;CACX,CAAC;CACD,MAAM,cAAc,SAAS;CAC7B,IAAI,SAAS,SAAS;EACpB,IACE,SAAS,SAAS,KAAA,KACjB,MAAM,SAAS,aAAa,MAAM,MAAO,MAE1C,MAAM,IAAI,MACR,GAAG,SAAS,SAAS,mCAAmC,WAAW,KAAA,IAAY,KAAK,aAAa,UACnG;EACF,QAAQ,OAAO,MAAM,YAAY,SAAS,SAAS,GAAG;EACtD;CACF;CACA,MAAM,cAAc,SAAS,MAAM;CACnC,MAAM,mBAAmB;EACvB;EACA;EACA,MAAM,gBAAgB,KAAA,IAAY,MAAQ,cAAc;CAC1D,CAAC;CACD,QAAQ,OAAO,MAAM,aAAa,SAAS,SAAS,GAAG;AACzD;AAEA,KAAK,CAAC,CAAC,OAAO,UAAmB;CAC/B,QAAQ,OAAO,MACb,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GACxE;CACA,QAAQ,WAAW;AACrB,CAAC"}
1
+ {"version":3,"file":"dependabot-cli.mjs","names":[],"sources":["../src/dependabot-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n generateDependabotConfig,\n parseDependabotInput,\n parseToolchainPolicy,\n} from \"./dependabot\";\nimport {\n checkGeneratedOutput,\n generationDiagnostics,\n writeGeneratedFile,\n} from \"./generated-file\";\nimport { readDependabotIgnores } from \"./toolchain-dependabot\";\nimport { readToolchainInputs } from \"./toolchain-guard\";\n\nconst usage =\n \"Usage: stll-dependabot [--check] [--config <path>] (run from repository root)\\n stll-dependabot --help\";\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n let mode: \"write\" | \"check\" = \"write\";\n let config: string | undefined;\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (arg === \"--check\" && mode === \"write\") {\n mode = \"check\";\n continue;\n }\n if (arg === \"--config\" && config === undefined) {\n const next = args.at(index + 1);\n if (next === undefined || next.startsWith(\"--\")) throw new Error(usage);\n config = next;\n index++;\n continue;\n }\n throw new Error(usage);\n }\n const root = await realpath(process.cwd());\n const { files, trackedFiles, diagnostics } = readToolchainInputs(root);\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const yaml = join(root, \".github/dependabot.yaml\");\n const yml = join(root, \".github/dependabot.yml\");\n const yamlStat = await checkGeneratedOutput(yaml);\n const ymlStat = await checkGeneratedOutput(yml);\n const candidates = [\n { relative: \".github/dependabot.yaml\", path: yaml, stat: yamlStat },\n { relative: \".github/dependabot.yml\", path: yml, stat: ymlStat },\n ].filter(\n ({ relative, stat }) => stat !== undefined || trackedFiles.has(relative),\n );\n if (candidates.length > 1)\n throw new Error(\"keep exactly one Dependabot configuration: .yml or .yaml\");\n const selected = candidates.at(0) ?? {\n relative: \".github/dependabot.yml\",\n path: yml,\n stat: ymlStat,\n };\n const remainingDiagnostics = await generationDiagnostics({\n diagnostics,\n outputs: [{ relative: selected.relative, destination: selected.path }],\n });\n if (remainingDiagnostics.length !== 0)\n throw new Error(\n remainingDiagnostics\n .map(({ path, message }) => `${path}: ${message}`)\n .join(\"\\n\"),\n );\n const declarations =\n config === undefined\n ? undefined\n : parseDependabotInput(\n JSON.parse(await readFile(resolve(root, config), \"utf8\")),\n );\n // Shared-pin conflicts and invalid declarations still throw in the generator and parser.\n const dependabotIgnores = readDependabotIgnores(files[\"stll-toolchain.json\"]);\n const text = generateDependabotConfig({\n files,\n policy: policy.dependabot,\n updates: declarations,\n ignores: dependabotIgnores,\n });\n const destination = selected.path;\n if (mode === \"check\") {\n if (\n selected.stat === undefined ||\n (await readFile(destination, \"utf8\")) !== text\n )\n throw new Error(\n `${selected.relative} has drifted; run stll-dependabot${config === undefined ? \"\" : ` --config ${config}`}`,\n );\n process.stdout.write(`Verified ${selected.relative}\\n`);\n return;\n }\n const permissions = selected.stat?.mode;\n await writeGeneratedFile({\n destination,\n text,\n mode: permissions === undefined ? 0o644 : permissions & 0o777,\n });\n process.stdout.write(`Generated ${selected.relative}\\n`);\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `dependabot: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":";;;;;;;;;AAiBA,MAAM,QACJ;AACF,MAAM,OAAO,YAAY;CACvB,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;CACjC,IAAI,KAAK,WAAW,KAAK,KAAK,GAAG,CAAC,MAAM,UAAU;EAChD,QAAQ,OAAO,MAAM,GAAG,MAAM,GAAG;EACjC;CACF;CACA,IAAI,OAA0B;CAC9B,IAAI;CACJ,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;EAChD,MAAM,MAAM,KAAK;EACjB,IAAI,QAAQ,aAAa,SAAS,SAAS;GACzC,OAAO;GACP;EACF;EACA,IAAI,QAAQ,cAAc,WAAW,KAAA,GAAW;GAC9C,MAAM,OAAO,KAAK,GAAG,QAAQ,CAAC;GAC9B,IAAI,SAAS,KAAA,KAAa,KAAK,WAAW,IAAI,GAAG,MAAM,IAAI,MAAM,KAAK;GACtE,SAAS;GACT;GACA;EACF;EACA,MAAM,IAAI,MAAM,KAAK;CACvB;CACA,MAAM,OAAO,MAAM,SAAS,QAAQ,IAAI,CAAC;CACzC,MAAM,EAAE,OAAO,cAAc,gBAAgB,oBAAoB,IAAI;CACrE,MAAM,SAAS,qBACb,KAAK,MACH,MAAM,SAAS,IAAI,IAAI,qBAAqB,YAAY,GAAG,GAAG,MAAM,CACtE,CACF;CACA,MAAM,OAAO,KAAK,MAAM,yBAAyB;CACjD,MAAM,MAAM,KAAK,MAAM,wBAAwB;CAC/C,MAAM,WAAW,MAAM,qBAAqB,IAAI;CAChD,MAAM,UAAU,MAAM,qBAAqB,GAAG;CAC9C,MAAM,aAAa,CACjB;EAAE,UAAU;EAA2B,MAAM;EAAM,MAAM;CAAS,GAClE;EAAE,UAAU;EAA0B,MAAM;EAAK,MAAM;CAAQ,CACjE,CAAC,CAAC,QACC,EAAE,UAAU,WAAW,SAAS,KAAA,KAAa,aAAa,IAAI,QAAQ,CACzE;CACA,IAAI,WAAW,SAAS,GACtB,MAAM,IAAI,MAAM,0DAA0D;CAC5E,MAAM,WAAW,WAAW,GAAG,CAAC,KAAK;EACnC,UAAU;EACV,MAAM;EACN,MAAM;CACR;CACA,MAAM,uBAAuB,MAAM,sBAAsB;EACvD;EACA,SAAS,CAAC;GAAE,UAAU,SAAS;GAAU,aAAa,SAAS;EAAK,CAAC;CACvE,CAAC;CACD,IAAI,qBAAqB,WAAW,GAClC,MAAM,IAAI,MACR,qBACG,KAAK,EAAE,MAAM,cAAc,GAAG,KAAK,IAAI,SAAS,CAAC,CACjD,KAAK,IAAI,CACd;CACF,MAAM,eACJ,WAAW,KAAA,IACP,KAAA,IACA,qBACE,KAAK,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,GAAG,MAAM,CAAC,CAC1D;CAEN,MAAM,oBAAoB,sBAAsB,MAAM,sBAAsB;CAC5E,MAAM,OAAO,yBAAyB;EACpC;EACA,QAAQ,OAAO;EACf,SAAS;EACT,SAAS;CACX,CAAC;CACD,MAAM,cAAc,SAAS;CAC7B,IAAI,SAAS,SAAS;EACpB,IACE,SAAS,SAAS,KAAA,KACjB,MAAM,SAAS,aAAa,MAAM,MAAO,MAE1C,MAAM,IAAI,MACR,GAAG,SAAS,SAAS,mCAAmC,WAAW,KAAA,IAAY,KAAK,aAAa,UACnG;EACF,QAAQ,OAAO,MAAM,YAAY,SAAS,SAAS,GAAG;EACtD;CACF;CACA,MAAM,cAAc,SAAS,MAAM;CACnC,MAAM,mBAAmB;EACvB;EACA;EACA,MAAM,gBAAgB,KAAA,IAAY,MAAQ,cAAc;CAC1D,CAAC;CACD,QAAQ,OAAO,MAAM,aAAa,SAAS,SAAS,GAAG;AACzD;AAEA,KAAK,CAAC,CAAC,OAAO,UAAmB;CAC/B,QAAQ,OAAO,MACb,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GACxE;CACA,QAAQ,WAAW;AACrB,CAAC"}
@@ -1,7 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_toolchain_dependabot = require("./toolchain-dependabot.cjs");
3
3
  const require_toolchain_schema = require("./toolchain-schema.cjs");
4
+ exports.dependabotIgnoreUpdateTypes = require_toolchain_dependabot.dependabotIgnoreUpdateTypes;
4
5
  exports.generateDependabotConfig = require_toolchain_dependabot.generateDependabotConfig;
6
+ exports.parseDependabotIgnores = require_toolchain_dependabot.parseDependabotIgnores;
5
7
  exports.parseDependabotInput = require_toolchain_dependabot.parseDependabotInput;
6
8
  exports.parseToolchainPolicy = require_toolchain_schema.parseToolchainPolicy;
7
9
  exports.supportedDependabotEcosystems = require_toolchain_dependabot.supportedDependabotEcosystems;
@@ -19,9 +19,24 @@ type DependabotPolicy = {
19
19
  ignoredActions: readonly string[];
20
20
  ignoredImages: readonly string[];
21
21
  };
22
+ declare const dependabotIgnoreUpdateTypes: readonly ["version-update:semver-major", "version-update:semver-minor", "version-update:semver-patch"];
23
+ type DependabotIgnoreUpdateType = (typeof dependabotIgnoreUpdateTypes)[number];
24
+ /** A reviewed repository decision to skip some version updates of one dependency. */
25
+ type DependabotIgnoreDeclaration = {
26
+ readonly ecosystem: DependabotEcosystem;
27
+ /** Dependabot `dependency-name`; `*` is the only wildcard. */
28
+ readonly dependency: string;
29
+ /** Nonempty, unique and in canonical major, minor, patch order. */
30
+ readonly updateTypes: readonly [DependabotIgnoreUpdateType, ...DependabotIgnoreUpdateType[]];
31
+ readonly reason: string;
32
+ };
33
+ /** Parse `dependabotIgnores` from stll-toolchain.json; malformed decisions fail closed. */
34
+ declare const parseDependabotIgnores: (input: unknown) => DependabotIgnoreDeclaration[];
22
35
  type CheckDependabotOptions = {
23
36
  files: Record<string, string>;
24
37
  policy: DependabotPolicy;
38
+ /** Parsed stll-toolchain.json `dependabotIgnores`. */
39
+ ignores?: readonly DependabotIgnoreDeclaration[] | undefined;
25
40
  };
26
41
  /** Repository declarations own coverage only; shared policy owns every update option. */
27
42
  declare const parseDependabotInput: (input: unknown) => {
@@ -32,7 +47,7 @@ type GenerateDependabotOptions = CheckDependabotOptions & {
32
47
  updates?: ReturnType<typeof parseDependabotInput> | undefined;
33
48
  };
34
49
  /** Generate canonical YAML from the same ecosystem enumeration used by the guard. */
35
- declare const generateDependabotConfig: ({ files, policy, updates: declarations }: GenerateDependabotOptions) => string;
50
+ declare const generateDependabotConfig: ({ files, policy, updates: declarations, ignores }: GenerateDependabotOptions) => string;
36
51
  //#endregion
37
52
  //#region src/toolchain-schema.d.ts
38
53
  /** Reject unsupported or incomplete installed policies before inspecting a consumer. */
@@ -114,5 +129,5 @@ declare const parseToolchainPolicy: (input: unknown) => {
114
129
  };
115
130
  };
116
131
  //#endregion
117
- export { type DependabotEcosystem, generateDependabotConfig, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
132
+ export { type DependabotEcosystem, type DependabotIgnoreDeclaration, type DependabotIgnoreUpdateType, dependabotIgnoreUpdateTypes, generateDependabotConfig, parseDependabotIgnores, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
118
133
  //# sourceMappingURL=dependabot.d.cts.map
@@ -19,9 +19,24 @@ type DependabotPolicy = {
19
19
  ignoredActions: readonly string[];
20
20
  ignoredImages: readonly string[];
21
21
  };
22
+ declare const dependabotIgnoreUpdateTypes: readonly ["version-update:semver-major", "version-update:semver-minor", "version-update:semver-patch"];
23
+ type DependabotIgnoreUpdateType = (typeof dependabotIgnoreUpdateTypes)[number];
24
+ /** A reviewed repository decision to skip some version updates of one dependency. */
25
+ type DependabotIgnoreDeclaration = {
26
+ readonly ecosystem: DependabotEcosystem;
27
+ /** Dependabot `dependency-name`; `*` is the only wildcard. */
28
+ readonly dependency: string;
29
+ /** Nonempty, unique and in canonical major, minor, patch order. */
30
+ readonly updateTypes: readonly [DependabotIgnoreUpdateType, ...DependabotIgnoreUpdateType[]];
31
+ readonly reason: string;
32
+ };
33
+ /** Parse `dependabotIgnores` from stll-toolchain.json; malformed decisions fail closed. */
34
+ declare const parseDependabotIgnores: (input: unknown) => DependabotIgnoreDeclaration[];
22
35
  type CheckDependabotOptions = {
23
36
  files: Record<string, string>;
24
37
  policy: DependabotPolicy;
38
+ /** Parsed stll-toolchain.json `dependabotIgnores`. */
39
+ ignores?: readonly DependabotIgnoreDeclaration[] | undefined;
25
40
  };
26
41
  /** Repository declarations own coverage only; shared policy owns every update option. */
27
42
  declare const parseDependabotInput: (input: unknown) => {
@@ -32,7 +47,7 @@ type GenerateDependabotOptions = CheckDependabotOptions & {
32
47
  updates?: ReturnType<typeof parseDependabotInput> | undefined;
33
48
  };
34
49
  /** Generate canonical YAML from the same ecosystem enumeration used by the guard. */
35
- declare const generateDependabotConfig: ({ files, policy, updates: declarations }: GenerateDependabotOptions) => string;
50
+ declare const generateDependabotConfig: ({ files, policy, updates: declarations, ignores }: GenerateDependabotOptions) => string;
36
51
  //#endregion
37
52
  //#region src/toolchain-schema.d.ts
38
53
  /** Reject unsupported or incomplete installed policies before inspecting a consumer. */
@@ -114,5 +129,5 @@ declare const parseToolchainPolicy: (input: unknown) => {
114
129
  };
115
130
  };
116
131
  //#endregion
117
- export { type DependabotEcosystem, generateDependabotConfig, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
132
+ export { type DependabotEcosystem, type DependabotIgnoreDeclaration, type DependabotIgnoreUpdateType, dependabotIgnoreUpdateTypes, generateDependabotConfig, parseDependabotIgnores, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
118
133
  //# sourceMappingURL=dependabot.d.mts.map
@@ -1,3 +1,3 @@
1
- import { a as supportedDependabotEcosystems, i as parseDependabotInput, r as generateDependabotConfig } from "./toolchain-dependabot.mjs";
1
+ import { a as generateDependabotConfig, l as supportedDependabotEcosystems, o as parseDependabotIgnores, r as dependabotIgnoreUpdateTypes, s as parseDependabotInput } from "./toolchain-dependabot.mjs";
2
2
  import { t as parseToolchainPolicy } from "./toolchain-schema.mjs";
3
- export { generateDependabotConfig, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
3
+ export { dependabotIgnoreUpdateTypes, generateDependabotConfig, parseDependabotIgnores, parseDependabotInput, parseToolchainPolicy, supportedDependabotEcosystems };
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_rolldown_runtime = require("./rolldown-runtime.cjs");
4
+ const require_engine_support = require("./engine-support.cjs");
5
+ let node_path = require("node:path");
6
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
7
+ let node_child_process = require("node:child_process");
8
+ let _changesets_assemble_release_plan = require("@changesets/assemble-release-plan");
9
+ let _changesets_config = require("@changesets/config");
10
+ let _changesets_read = require("@changesets/read");
11
+ let _manypkg_get_packages = require("@manypkg/get-packages");
12
+ //#region src/engine-support-cli.ts
13
+ const MAX_MANIFEST_BUFFER = 104857600;
14
+ const git = (root, args) => (0, node_child_process.execFileSync)("git", args, {
15
+ cwd: root,
16
+ encoding: "utf8",
17
+ maxBuffer: MAX_MANIFEST_BUFFER
18
+ });
19
+ const parseBase = (args) => {
20
+ if (args.length === 1 && args.at(0) === "--help") return void 0;
21
+ if (args.length === 2 && args.at(0) === "--base" && args.at(1) !== "") return args.at(1);
22
+ throw new Error("Usage: stll-engine-support --base <git ref>");
23
+ };
24
+ const packageNodeRange = ({ packageJson }) => {
25
+ const engines = "engines" in packageJson ? packageJson.engines : void 0;
26
+ return typeof engines === "object" && engines !== null && "node" in engines && typeof engines.node === "string" ? engines.node : void 0;
27
+ };
28
+ const publishedPackages = (packages, ignored) => {
29
+ const collected = /* @__PURE__ */ new Map();
30
+ for (const pkg of packages) {
31
+ const { name, private: isPrivate } = pkg.packageJson;
32
+ if (isPrivate === true || typeof name !== "string") continue;
33
+ if (collected.has(name)) throw new Error(`Duplicate published package name: ${name}`);
34
+ const node = packageNodeRange(pkg);
35
+ collected.set(name, {
36
+ name,
37
+ ...node === void 0 ? {} : { node },
38
+ changesetsManaged: !ignored.has(name)
39
+ });
40
+ }
41
+ return collected;
42
+ };
43
+ const basePackage = (root, base, pkg) => {
44
+ const relativeManifest = node_path.default.relative(root, node_path.default.join(pkg.dir, "package.json")).split(node_path.default.sep).join(node_path.default.posix.sep);
45
+ if (git(root, [
46
+ "ls-tree",
47
+ "--name-only",
48
+ base,
49
+ "--",
50
+ relativeManifest
51
+ ]).trim() === "") return void 0;
52
+ const packageJson = JSON.parse(git(root, ["show", `${base}:${relativeManifest}`]));
53
+ if (typeof packageJson !== "object" || packageJson === null) throw new Error(`Invalid package manifest at ${base}:${relativeManifest}`);
54
+ return {
55
+ ...pkg,
56
+ packageJson
57
+ };
58
+ };
59
+ const main = async () => {
60
+ const base = parseBase(process.argv.slice(2));
61
+ if (base === void 0) {
62
+ process.stdout.write("Usage: stll-engine-support --base <git ref>\n");
63
+ return;
64
+ }
65
+ const root = process.cwd();
66
+ git(root, [
67
+ "cat-file",
68
+ "-e",
69
+ `${base}^{commit}`
70
+ ]);
71
+ const workspace = (0, _manypkg_get_packages.getPackagesSync)(root);
72
+ const discovered = workspace.packages;
73
+ const configResult = await (0, _changesets_config.readConfig)(root, workspace);
74
+ if (configResult.errors !== void 0) throw new Error(configResult.errors.join("\n"));
75
+ const config = configResult.config;
76
+ const ignored = new Set(config.ignore);
77
+ const releasePlan = (0, _changesets_assemble_release_plan.assembleReleasePlan)(await (0, _changesets_read.readChangesets)(root), workspace, config, void 0);
78
+ const basePackages = discovered.flatMap((pkg) => {
79
+ const found = basePackage(root, base, pkg);
80
+ return found === void 0 ? [] : [found];
81
+ });
82
+ const failures = require_engine_support.checkEngineSupport({
83
+ base: publishedPackages(basePackages, ignored),
84
+ head: publishedPackages(discovered, ignored),
85
+ majorReleases: new Set(releasePlan.releases.filter(({ type }) => type === "major").map(({ name }) => name))
86
+ });
87
+ for (const failure of failures) process.stderr.write(`[engine-support] ${failure.packageName} narrows Node support from ${failure.baseRange} to ${failure.headRange}; ${failure.packageName} requires a pending major changeset\n`);
88
+ if (failures.length > 0) process.exitCode = 1;
89
+ };
90
+ main().catch((error) => {
91
+ process.stderr.write(`engine-support: ${error instanceof Error ? error.message : String(error)}\n`);
92
+ process.exitCode = 1;
93
+ });
94
+ //#endregion
95
+
96
+ //# sourceMappingURL=engine-support-cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-support-cli.cjs","names":["execFileSync","path","getPackagesSync","readConfig","assembleReleasePlan","readChangesets","checkEngineSupport"],"sources":["../src/engine-support-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { assembleReleasePlan } from \"@changesets/assemble-release-plan\";\nimport { readConfig } from \"@changesets/config\";\nimport { readChangesets } from \"@changesets/read\";\nimport { getPackagesSync, type Package } from \"@manypkg/get-packages\";\nimport { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\n\nimport { checkEngineSupport, type EnginePackage } from \"./engine-support\";\n\nconst MAX_MANIFEST_BUFFER = 100 * 1024 * 1024;\n\nconst git = (root: string, args: string[]) =>\n execFileSync(\"git\", args, {\n cwd: root,\n encoding: \"utf8\",\n maxBuffer: MAX_MANIFEST_BUFFER,\n });\n\nconst parseBase = (args: string[]) => {\n if (args.length === 1 && args.at(0) === \"--help\") return undefined;\n if (args.length === 2 && args.at(0) === \"--base\" && args.at(1) !== \"\")\n return args.at(1);\n throw new Error(\"Usage: stll-engine-support --base <git ref>\");\n};\n\nconst packageNodeRange = ({ packageJson }: Package) => {\n const engines = \"engines\" in packageJson ? packageJson.engines : undefined;\n return typeof engines === \"object\" &&\n engines !== null &&\n \"node\" in engines &&\n typeof engines.node === \"string\"\n ? engines.node\n : undefined;\n};\n\nconst publishedPackages = (packages: Package[], ignored: Set<string>) => {\n const collected = new Map<string, EnginePackage>();\n for (const pkg of packages) {\n const { name, private: isPrivate } = pkg.packageJson;\n if (isPrivate === true || typeof name !== \"string\") continue;\n if (collected.has(name))\n throw new Error(`Duplicate published package name: ${name}`);\n const node = packageNodeRange(pkg);\n collected.set(name, {\n name,\n ...(node === undefined ? {} : { node }),\n changesetsManaged: !ignored.has(name),\n });\n }\n return collected;\n};\n\nconst basePackage = (root: string, base: string, pkg: Package) => {\n const relativeManifest = path\n .relative(root, path.join(pkg.dir, \"package.json\"))\n .split(path.sep)\n .join(path.posix.sep);\n if (\n git(root, [\"ls-tree\", \"--name-only\", base, \"--\", relativeManifest]).trim() ===\n \"\"\n )\n return undefined;\n const packageJson = JSON.parse(\n git(root, [\"show\", `${base}:${relativeManifest}`]),\n );\n if (typeof packageJson !== \"object\" || packageJson === null)\n throw new Error(\n `Invalid package manifest at ${base}:${relativeManifest}`,\n );\n return { ...pkg, packageJson };\n};\n\nconst main = async () => {\n const base = parseBase(process.argv.slice(2));\n if (base === undefined) {\n process.stdout.write(\"Usage: stll-engine-support --base <git ref>\\n\");\n return;\n }\n const root = process.cwd();\n git(root, [\"cat-file\", \"-e\", `${base}^{commit}`]);\n const workspace = getPackagesSync(root);\n const discovered = workspace.packages;\n const configResult = await readConfig(root, workspace);\n if (configResult.errors !== undefined)\n throw new Error(configResult.errors.join(\"\\n\"));\n const config = configResult.config;\n const ignored = new Set(config.ignore);\n const releasePlan = assembleReleasePlan(\n await readChangesets(root),\n workspace,\n config,\n undefined,\n );\n const basePackages = discovered.flatMap((pkg) => {\n const found = basePackage(root, base, pkg);\n return found === undefined ? [] : [found];\n });\n const failures = checkEngineSupport({\n base: publishedPackages(basePackages, ignored),\n head: publishedPackages(discovered, ignored),\n majorReleases: new Set(\n releasePlan.releases\n .filter(({ type }) => type === \"major\")\n .map(({ name }) => name),\n ),\n });\n for (const failure of failures)\n process.stderr.write(\n `[engine-support] ${failure.packageName} narrows Node support from ${failure.baseRange} to ${failure.headRange}; ${failure.packageName} requires a pending major changeset\\n`,\n );\n if (failures.length > 0) process.exitCode = 1;\n};\n\nvoid main().catch((error: unknown) => {\n process.stderr.write(\n `engine-support: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ import { checkEngineSupport } from "./engine-support.mjs";
3
+ import path from "node:path";
4
+ import { execFileSync } from "node:child_process";
5
+ import { assembleReleasePlan } from "@changesets/assemble-release-plan";
6
+ import { readConfig } from "@changesets/config";
7
+ import { readChangesets } from "@changesets/read";
8
+ import { getPackagesSync } from "@manypkg/get-packages";
9
+ //#region src/engine-support-cli.ts
10
+ const MAX_MANIFEST_BUFFER = 104857600;
11
+ const git = (root, args) => execFileSync("git", args, {
12
+ cwd: root,
13
+ encoding: "utf8",
14
+ maxBuffer: MAX_MANIFEST_BUFFER
15
+ });
16
+ const parseBase = (args) => {
17
+ if (args.length === 1 && args.at(0) === "--help") return void 0;
18
+ if (args.length === 2 && args.at(0) === "--base" && args.at(1) !== "") return args.at(1);
19
+ throw new Error("Usage: stll-engine-support --base <git ref>");
20
+ };
21
+ const packageNodeRange = ({ packageJson }) => {
22
+ const engines = "engines" in packageJson ? packageJson.engines : void 0;
23
+ return typeof engines === "object" && engines !== null && "node" in engines && typeof engines.node === "string" ? engines.node : void 0;
24
+ };
25
+ const publishedPackages = (packages, ignored) => {
26
+ const collected = /* @__PURE__ */ new Map();
27
+ for (const pkg of packages) {
28
+ const { name, private: isPrivate } = pkg.packageJson;
29
+ if (isPrivate === true || typeof name !== "string") continue;
30
+ if (collected.has(name)) throw new Error(`Duplicate published package name: ${name}`);
31
+ const node = packageNodeRange(pkg);
32
+ collected.set(name, {
33
+ name,
34
+ ...node === void 0 ? {} : { node },
35
+ changesetsManaged: !ignored.has(name)
36
+ });
37
+ }
38
+ return collected;
39
+ };
40
+ const basePackage = (root, base, pkg) => {
41
+ const relativeManifest = path.relative(root, path.join(pkg.dir, "package.json")).split(path.sep).join(path.posix.sep);
42
+ if (git(root, [
43
+ "ls-tree",
44
+ "--name-only",
45
+ base,
46
+ "--",
47
+ relativeManifest
48
+ ]).trim() === "") return void 0;
49
+ const packageJson = JSON.parse(git(root, ["show", `${base}:${relativeManifest}`]));
50
+ if (typeof packageJson !== "object" || packageJson === null) throw new Error(`Invalid package manifest at ${base}:${relativeManifest}`);
51
+ return {
52
+ ...pkg,
53
+ packageJson
54
+ };
55
+ };
56
+ const main = async () => {
57
+ const base = parseBase(process.argv.slice(2));
58
+ if (base === void 0) {
59
+ process.stdout.write("Usage: stll-engine-support --base <git ref>\n");
60
+ return;
61
+ }
62
+ const root = process.cwd();
63
+ git(root, [
64
+ "cat-file",
65
+ "-e",
66
+ `${base}^{commit}`
67
+ ]);
68
+ const workspace = getPackagesSync(root);
69
+ const discovered = workspace.packages;
70
+ const configResult = await readConfig(root, workspace);
71
+ if (configResult.errors !== void 0) throw new Error(configResult.errors.join("\n"));
72
+ const config = configResult.config;
73
+ const ignored = new Set(config.ignore);
74
+ const releasePlan = assembleReleasePlan(await readChangesets(root), workspace, config, void 0);
75
+ const basePackages = discovered.flatMap((pkg) => {
76
+ const found = basePackage(root, base, pkg);
77
+ return found === void 0 ? [] : [found];
78
+ });
79
+ const failures = checkEngineSupport({
80
+ base: publishedPackages(basePackages, ignored),
81
+ head: publishedPackages(discovered, ignored),
82
+ majorReleases: new Set(releasePlan.releases.filter(({ type }) => type === "major").map(({ name }) => name))
83
+ });
84
+ for (const failure of failures) process.stderr.write(`[engine-support] ${failure.packageName} narrows Node support from ${failure.baseRange} to ${failure.headRange}; ${failure.packageName} requires a pending major changeset\n`);
85
+ if (failures.length > 0) process.exitCode = 1;
86
+ };
87
+ main().catch((error) => {
88
+ process.stderr.write(`engine-support: ${error instanceof Error ? error.message : String(error)}\n`);
89
+ process.exitCode = 1;
90
+ });
91
+ //#endregion
92
+ export {};
93
+
94
+ //# sourceMappingURL=engine-support-cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-support-cli.mjs","names":[],"sources":["../src/engine-support-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { assembleReleasePlan } from \"@changesets/assemble-release-plan\";\nimport { readConfig } from \"@changesets/config\";\nimport { readChangesets } from \"@changesets/read\";\nimport { getPackagesSync, type Package } from \"@manypkg/get-packages\";\nimport { execFileSync } from \"node:child_process\";\nimport path from \"node:path\";\n\nimport { checkEngineSupport, type EnginePackage } from \"./engine-support\";\n\nconst MAX_MANIFEST_BUFFER = 100 * 1024 * 1024;\n\nconst git = (root: string, args: string[]) =>\n execFileSync(\"git\", args, {\n cwd: root,\n encoding: \"utf8\",\n maxBuffer: MAX_MANIFEST_BUFFER,\n });\n\nconst parseBase = (args: string[]) => {\n if (args.length === 1 && args.at(0) === \"--help\") return undefined;\n if (args.length === 2 && args.at(0) === \"--base\" && args.at(1) !== \"\")\n return args.at(1);\n throw new Error(\"Usage: stll-engine-support --base <git ref>\");\n};\n\nconst packageNodeRange = ({ packageJson }: Package) => {\n const engines = \"engines\" in packageJson ? packageJson.engines : undefined;\n return typeof engines === \"object\" &&\n engines !== null &&\n \"node\" in engines &&\n typeof engines.node === \"string\"\n ? engines.node\n : undefined;\n};\n\nconst publishedPackages = (packages: Package[], ignored: Set<string>) => {\n const collected = new Map<string, EnginePackage>();\n for (const pkg of packages) {\n const { name, private: isPrivate } = pkg.packageJson;\n if (isPrivate === true || typeof name !== \"string\") continue;\n if (collected.has(name))\n throw new Error(`Duplicate published package name: ${name}`);\n const node = packageNodeRange(pkg);\n collected.set(name, {\n name,\n ...(node === undefined ? {} : { node }),\n changesetsManaged: !ignored.has(name),\n });\n }\n return collected;\n};\n\nconst basePackage = (root: string, base: string, pkg: Package) => {\n const relativeManifest = path\n .relative(root, path.join(pkg.dir, \"package.json\"))\n .split(path.sep)\n .join(path.posix.sep);\n if (\n git(root, [\"ls-tree\", \"--name-only\", base, \"--\", relativeManifest]).trim() ===\n \"\"\n )\n return undefined;\n const packageJson = JSON.parse(\n git(root, [\"show\", `${base}:${relativeManifest}`]),\n );\n if (typeof packageJson !== \"object\" || packageJson === null)\n throw new Error(\n `Invalid package manifest at ${base}:${relativeManifest}`,\n );\n return { ...pkg, packageJson };\n};\n\nconst main = async () => {\n const base = parseBase(process.argv.slice(2));\n if (base === undefined) {\n process.stdout.write(\"Usage: stll-engine-support --base <git ref>\\n\");\n return;\n }\n const root = process.cwd();\n git(root, [\"cat-file\", \"-e\", `${base}^{commit}`]);\n const workspace = getPackagesSync(root);\n const discovered = workspace.packages;\n const configResult = await readConfig(root, workspace);\n if (configResult.errors !== undefined)\n throw new Error(configResult.errors.join(\"\\n\"));\n const config = configResult.config;\n const ignored = new Set(config.ignore);\n const releasePlan = assembleReleasePlan(\n await readChangesets(root),\n workspace,\n config,\n undefined,\n );\n const basePackages = discovered.flatMap((pkg) => {\n const found = basePackage(root, base, pkg);\n return found === undefined ? [] : [found];\n });\n const failures = checkEngineSupport({\n base: publishedPackages(basePackages, ignored),\n head: publishedPackages(discovered, ignored),\n majorReleases: new Set(\n releasePlan.releases\n .filter(({ type }) => type === \"major\")\n .map(({ name }) => name),\n ),\n });\n for (const failure of failures)\n process.stderr.write(\n `[engine-support] ${failure.packageName} narrows Node support from ${failure.baseRange} to ${failure.headRange}; ${failure.packageName} requires a pending major changeset\\n`,\n );\n if (failures.length > 0) process.exitCode = 1;\n};\n\nvoid main().catch((error: unknown) => {\n process.stderr.write(\n `engine-support: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("./rolldown-runtime.cjs");
3
+ let semver = require("semver");
4
+ semver = require_rolldown_runtime.__toESM(semver, 1);
5
+ //#region src/engine-support.ts
6
+ const displayedRange = (range) => range ?? "unrestricted";
7
+ /** Returns engine-support changes that require a pending major release. */
8
+ const checkEngineSupport = ({ base, head, majorReleases }) => {
9
+ const failures = [];
10
+ for (const [name, current] of head) {
11
+ if (!current.changesetsManaged) continue;
12
+ const previous = base.get(name);
13
+ if (previous === void 0) continue;
14
+ const baseRange = previous.node ?? "*";
15
+ const headRange = current.node ?? "*";
16
+ if (semver.default.subset(baseRange, headRange)) continue;
17
+ if (majorReleases.has(name)) continue;
18
+ failures.push({
19
+ packageName: name,
20
+ baseRange: displayedRange(previous.node),
21
+ headRange: displayedRange(current.node)
22
+ });
23
+ }
24
+ return failures;
25
+ };
26
+ //#endregion
27
+ exports.checkEngineSupport = checkEngineSupport;
28
+
29
+ //# sourceMappingURL=engine-support.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-support.cjs","names":[],"sources":["../src/engine-support.ts"],"sourcesContent":["import semver from \"semver\";\n\nexport type EnginePackage = {\n name: string;\n node?: string;\n changesetsManaged: boolean;\n};\n\nexport type EngineSupportInput = {\n base: ReadonlyMap<string, EnginePackage>;\n head: ReadonlyMap<string, EnginePackage>;\n majorReleases: ReadonlySet<string>;\n};\n\nexport type EngineSupportFailure = {\n packageName: string;\n baseRange: string;\n headRange: string;\n};\n\nconst displayedRange = (range: string | undefined) => range ?? \"unrestricted\";\n\n/** Returns engine-support changes that require a pending major release. */\nexport const checkEngineSupport = ({\n base,\n head,\n majorReleases,\n}: EngineSupportInput): EngineSupportFailure[] => {\n const failures: EngineSupportFailure[] = [];\n for (const [name, current] of head) {\n if (!current.changesetsManaged) continue;\n const previous = base.get(name);\n if (previous === undefined) continue;\n const baseRange = previous.node ?? \"*\";\n const headRange = current.node ?? \"*\";\n if (semver.subset(baseRange, headRange)) continue;\n\n if (majorReleases.has(name)) continue;\n failures.push({\n packageName: name,\n baseRange: displayedRange(previous.node),\n headRange: displayedRange(current.node),\n });\n }\n return failures;\n};\n"],"mappings":";;;;;AAoBA,MAAM,kBAAkB,UAA8B,SAAS;;AAG/D,MAAa,sBAAsB,EACjC,MACA,MACA,oBACgD;CAChD,MAAM,WAAmC,CAAC;CAC1C,KAAK,MAAM,CAAC,MAAM,YAAY,MAAM;EAClC,IAAI,CAAC,QAAQ,mBAAmB;EAChC,MAAM,WAAW,KAAK,IAAI,IAAI;EAC9B,IAAI,aAAa,KAAA,GAAW;EAC5B,MAAM,YAAY,SAAS,QAAQ;EACnC,MAAM,YAAY,QAAQ,QAAQ;EAClC,IAAI,OAAA,QAAO,OAAO,WAAW,SAAS,GAAG;EAEzC,IAAI,cAAc,IAAI,IAAI,GAAG;EAC7B,SAAS,KAAK;GACZ,aAAa;GACb,WAAW,eAAe,SAAS,IAAI;GACvC,WAAW,eAAe,QAAQ,IAAI;EACxC,CAAC;CACH;CACA,OAAO;AACT"}
@@ -0,0 +1,21 @@
1
+ //#region src/engine-support.d.ts
2
+ type EnginePackage = {
3
+ name: string;
4
+ node?: string;
5
+ changesetsManaged: boolean;
6
+ };
7
+ type EngineSupportInput = {
8
+ base: ReadonlyMap<string, EnginePackage>;
9
+ head: ReadonlyMap<string, EnginePackage>;
10
+ majorReleases: ReadonlySet<string>;
11
+ };
12
+ type EngineSupportFailure = {
13
+ packageName: string;
14
+ baseRange: string;
15
+ headRange: string;
16
+ };
17
+ /** Returns engine-support changes that require a pending major release. */
18
+ declare const checkEngineSupport: ({ base, head, majorReleases }: EngineSupportInput) => EngineSupportFailure[];
19
+ //#endregion
20
+ export { EnginePackage, EngineSupportFailure, EngineSupportInput, checkEngineSupport };
21
+ //# sourceMappingURL=engine-support.d.cts.map