* feat(lint): add renovate/zod-schema-location and renovate/prefer-json-pipe rules Backlog item #23: reviewers repeatedly ask for consistent Zod schema structure. Two new oxlint JS-plugin rules, both at "warn": - renovate/zod-schema-location flags `export const X = <zod schema>` at module scope in lib/modules/**/ files that aren't schema.ts (or a colocated schema/ directory), reusing the leftmost-identifier schema detection from zod-schema-naming.js / prefer-nullish-util.js. Only exported top-level schemas are flagged — non-exported ones are treated as intentionally local/trivial (e.g. tightly coupled to file-local helpers), which keeps the rule's signal high. - renovate/prefer-json-pipe flags `Schema.parse(JSON.parse(x))` / `Schema.safeParse(JSON.parse(x))` and suggests `Json.pipe(Schema)` from lib/util/schema-utils instead. A third mined slice (require a matching `z.infer` type export for every exported schema) was evaluated and skipped: ~275+ exported schema-like consts in schema.ts files vs. 231 existing z.infer exports repo-wide is too high a mismatch to flag mechanically without heavy per-site judgment, so it would be mostly false positives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fix a clean subset of renovate/zod-schema-location and renovate/prefer-json-pipe violations renovate/prefer-json-pipe: fixed all 5 safe `.parse(JSON.parse(...))` call sites (bazel datasource, generate-mise-registry script, a hook spec) by switching to `Json.pipe(Schema).parse(...)`. Left the 2 `.safeParse(JSON.parse(...))` sites (pretooluse-check.ts, github-query-items.ts) unfixed: JSON.parse throwing before safeParse is reached today crashes the script, whereas Json.pipe folds the bad-JSON case into a graceful `{ success: false }`, which is an observable behavior change, not just a mechanical rewrite. renovate/zod-schema-location: fixed the one clean, self-contained violation (platform/github's GithubIssue schema, moved into the already-existing platform/github/schema.ts) as a representative example. Left the other 20: they require moving exported schemas out of files where they're built from local helper functions/config tables (manager/github-actions/community.ts) or restructuring an entire directory into a new schema.ts with import-graph updates across many files (manager/bazel/rules/*.ts, manager/bazel-module/parser/*.ts) — real refactors needing per-site judgment, not mechanical fixes. Both rules stay at "warn": renovate/prefer-json-pipe has 2 remaining violations that shouldn't be auto-fixed, and renovate/zod-schema-location has 20. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: resolve remaining prefer-json-pipe and zod-schema-location findings - github-actions: move the derived `CommunityActions` union into the existing colocated `schema.ts`; the action config table and the `actionSchema` builder stay in `community.ts` and are now exported. - tools/docs: fold `JSON.parse` + `safeParse`/rethrow of the `gh` CLI output into `Json.pipe(...)`. Invalid JSON now surfaces as a ZodError instead of a SyntaxError; the only consumer catches generically, so behavior is preserved. - tools/agents/hooks: keep `JSON.parse` + `safeParse` with a reasoned disable comment — hook scripts must stay dependency-light, and the `Json` helper lives in lib/util/schema-utils, which drags in the full lib import graph (logger, yaml, toml). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): enforce zod-schema-location and prefer-json-pipe as errors Narrow `renovate/zod-schema-location` to files whose directory already contains a colocated `schema.ts`. The mined reviewer feedback ("move this to schema.ts") presumes the module follows that convention and the schema leaked into a logic file. Modules that deliberately export schemas from differently-named schema-only files — bazel `rules/*.ts` Target schemas, bazel-module `parser/fragments.ts` — are a different, accepted layout, not "schema mixed into logic", and are no longer flagged. With that narrowing and the preceding migrations, both rules are clean repo-wide, so promote them from "warn" to "error". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: drop GithubIssue re-export from issue.ts Consumers now import the schema directly from schema.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(lint): register zod-schema-location rule The rule registration was lost while merging main, so oxlint failed to parse .oxlintrc.json with "Rule 'zod-schema-location' not found in plugin 'renovate'". Re-add the import and rules entry, and restore alphabetical ordering for prefer-json-pipe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(lint): allow sync fs in zod-schema-location rule ESLint rules execute synchronously, so the sibling `schema.ts` lookup cannot use async fs. Silence `no-sync` with a justification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Datasources
Datasources are used in Renovate primarily to fetch released versions of packages.
Follow the class-based programming style
New datasources must follow the class-based programming style.
Use the java-version datasource as a reference.
Add the datasource to the API in api.ts so that the new datasource is usable.
If you find Unused HTTP mocks errors in the Vitest tests and your mocked URLs are correct, make sure the datasource is correctly registered.
getReleases
The minimum exported interface for a datasource is a function called getReleases that takes a lookup config as input.
The config has:
packageName: the package's full name including scope if present (e.g.@foo/bar)registryUrls: an array of registry URLs to try
getReleases should return an object having:
releases: an array of strings of matched versions. This is the only mandatory fielddeprecationMessage: a string description of the package's deprecation notice, if applicablesourceUrl: a HTTP URL pointing to the source code (for example on GitHub)homepage: a HTTP URL for the package's homepage. Ideally should be empty if the homepage andsourceUrlare the samechangelogUrl: a URL pointing to the package's changelog (could be a Markdown file, for example). If not present then Renovate will search thesourceUrlfor a changelog filetags: an object mapping tag → version, for exampletags: { latest: '3.0.0' }. This is only used by thefollowTagsfunction
getDigest
Datasources that support digests (like Docker digests and Git commit hashes) can export a getDigest function.
The getDigest function has two inputs:
config: the Renovate config for the package being updated, has the same fields asgetReleasesnewValue: the version or value to retrieve the digest for
The getDigest function returns a string output representing the digest value.
If no digest is found, the getDigest function should return null.