Files
renovate/lib/modules/manager/mise/lockfile.ts
Sebastian Poxhofer e0cec3dc95 refactor(lint): add types-location rule and enable it for lib/modules (#45497)
feat(lint): add `types-location` rule and enable it for `lib/modules`

Reviewers consistently ask for exported types to be moved into a
colocated `types.ts`. Add a `renovate/types-location` oxlint rule that
reports `export interface` / `export type` declarations outside such a
file, and turn it on across `lib/modules`.

Re-exports (`export type { X }`, `export type *`), file-local types, and
values (enums, classes, functions) are left alone. `schema.ts` files and
`schema/` directories are excluded via config, matching how
`zod-schema-location` is configured — inferred types belong next to the
schema they are derived from.

Relocating the 87 existing violations means:

- new `types.ts` files for the modules that had none
- `terragrunt/common.ts` folded into its `types.ts`, as it held nothing
  else
- `RangeBound` in `versioning/gradle/compare.ts` un-exported, since only
  a file-local interface referenced it
- `bazel-module/parser/fragments.ts` split from its inferred types, which
  now live in `parser/types.ts` and infer through a namespace import so
  each schema keeps its merged name
2026-08-27 19:52:09 +00:00

96 lines
3.6 KiB
TypeScript

import upath from 'upath';
import { regEx } from '../../../util/regex.ts';
import type { MiseLockFile } from './schema.ts';
import type { MiseConfigType } from './types.ts';
/**
* Parses the config file name to determine its type (local, env-specific, or default).
* Used to derive the correct lock file name and `mise lock` flags.
*/
export function getConfigType(configPath: string): MiseConfigType {
const filename = upath.basename(configPath);
const isLocal = filename.endsWith('.local.toml');
// Patterns: mise.{env}.toml, mise.{env}.local.toml, .mise.{env}.toml, config.{env}.toml
const envMatch = regEx(
/^(?:\.?mise|config)\.(?<env>[^.]+)(?:\.local)?\.toml$/,
).exec(filename);
const env =
envMatch?.groups?.env === 'local' ? undefined : envMatch?.groups?.env;
return { isLocal, env };
}
/**
* Derives the lock file path from a mise config file path.
* Matches mise's lockfile_path_for_config() logic from src/lockfile.rs
*/
export function getLockFileName(configPath: string): string {
const dirname = upath.dirname(configPath);
const parentDirname = upath.basename(dirname);
// For conf.d files, lock file goes in parent directory
const lockDir = parentDirname === 'conf.d' ? upath.dirname(dirname) : dirname;
const { isLocal, env } = getConfigType(configPath);
let lockFileName: string;
if (env && isLocal) {
lockFileName = `mise.${env}.local.lock`;
} else if (env) {
lockFileName = `mise.${env}.lock`;
} else if (isLocal) {
lockFileName = 'mise.local.lock';
} else {
lockFileName = 'mise.lock';
}
return upath.join(lockDir, lockFileName);
}
/**
* Get the locked version for a dependency from the parsed lock file.
*
* Mise lock files use different key formats depending on whether a tool is in
* the mise registry:
* - Registry tools (e.g., node, python): key is the short name ("node")
* - Non-registry tools (e.g., ubi:owner/repo): key is the full name ("ubi:owner/repo")
*
* When a user specifies "core:node" in their config, mise resolves it to the
* registry short name "node" in the lock file. But "aqua:cli/cli" (not in
* registry) stays as "aqua:cli/cli" in the lock file.
*
* We use a fallback approach (Option A) rather than checking the registry (Option B):
*
* Option A (implemented): Try full depName first, then try stripped short name.
* Pros: Simple, no registry dependency, works even if Renovate's registry
* is out of sync with mise's registry.
* Cons: Theoretical collision risk if both "foo" and "backend:foo" exist
* in the same lock file (practically impossible - mise wouldn't generate this).
*
* Option B (not implemented): Check miseTooling/asdfTooling to determine if
* the tool is in the registry, then use short name or full name accordingly.
* Pros: Matches mise's exact logic.
* Cons: More complex, requires passing registry data, fails if Renovate's
* registry doesn't include a tool that mise's registry does.
*
* Option A is preferred because it's simpler, has no practical downsides, and
* doesn't couple lock file parsing to Renovate's registry coverage.
*/
export function getLockedVersion(
lockFileData: MiseLockFile,
depName: string,
): string | undefined {
// Try full name first (for non-registry tools like ubi:, aqua:)
let lockedTools = lockFileData.tools[depName];
// If not found and has backend prefix, try stripped name (for registry tools)
if (!lockedTools) {
const delimiterIndex = depName.indexOf(':');
if (delimiterIndex !== -1) {
const shortName = depName.substring(delimiterIndex + 1);
lockedTools = lockFileData.tools[shortName];
}
}
return lockedTools?.[0]?.version;
}