Files
renovate/lib/modules/manager/gleam/extract.ts
Sebastian Poxhofer c32e2391a0 refactor(linters): add prefer-coerce-object rule (#45493)
Refs #45216

The object counterpart to `prefer-coerce-array`: `x ?? {}` becomes
`coerceObject(x)`. The rule flags a `??` whose default is a bare `{}`
literal, so a populated default or an asserted `({} as Foo)` still
passes; a `x ?? y ?? {}` chain maps onto `coerceObject(x, y)`.

Every hit across `lib/` converted cleanly, so no disable comments were
needed.
2026-08-28 09:27:59 +00:00

114 lines
3.2 KiB
TypeScript

import { logger } from '../../../logger/index.ts';
import { coerceArray } from '../../../util/array.ts';
import { getSiblingFileName, localPathExists } from '../../../util/fs/index.ts';
import { coerceObject } from '../../../util/object.ts';
import { HexDatasource } from '../../datasource/hex/index.ts';
import { api as versioning } from '../../versioning/hex/index.ts';
import type { PackageDependency, PackageFileContent } from '../types.ts';
import { extractLockFileVersions } from './locked-version.ts';
import { GleamToml } from './schema.ts';
const dependencySections = ['dependencies', 'dev-dependencies'] as const;
// map gleam.toml section keys to standard renovate depType's
// this allows us to leverage renovate built-in configurations and presets
function mapSectionKey(sectionKey: string): string {
switch (sectionKey) {
case 'dev-dependencies':
return 'devDependencies';
default:
return sectionKey;
}
}
function toPackageDep({
name,
sectionKey,
version,
}: {
name: string;
sectionKey: string;
version: string;
}): PackageDependency {
return {
depName: name,
depType: mapSectionKey(sectionKey),
datasource: HexDatasource.id,
currentValue: version,
};
}
function toPackageDeps({
deps,
sectionKey,
}: {
deps?: Record<string, string>;
sectionKey: string;
}): PackageDependency[] {
return Object.entries(coerceObject(deps)).map(([name, version]) =>
toPackageDep({ name, sectionKey, version }),
);
}
function extractGleamTomlDeps(gleamToml: GleamToml): PackageDependency[] {
return dependencySections.flatMap((sectionKey) =>
toPackageDeps({
deps: gleamToml[sectionKey],
sectionKey,
}),
);
}
export async function extractPackageFile(
content: string,
packageFile: string,
): Promise<PackageFileContent | null> {
const result = GleamToml.safeParse(content);
if (!result.success) {
logger.debug(
{ err: result.error, packageFile },
'Error parsing Gleam package file content',
);
return null;
}
const deps = extractGleamTomlDeps(result.data);
if (!deps.length) {
logger.debug(`No dependencies found in Gleam package file ${packageFile}`);
return null;
}
const packageFileContent: PackageFileContent = { deps };
const lockFileName = getSiblingFileName(packageFile, 'manifest.toml');
const lockFileExists = await localPathExists(lockFileName);
if (!lockFileExists) {
logger.debug(`Lock file ${lockFileName} does not exist.`);
return packageFileContent;
}
const versionsByPackage = await extractLockFileVersions(lockFileName);
if (!versionsByPackage) {
return packageFileContent;
}
packageFileContent.lockFiles = [lockFileName];
for (const dep of packageFileContent.deps) {
const packageName = dep.depName!;
const versions = coerceArray(versionsByPackage.get(packageName));
const lockedVersion = versioning.getSatisfyingVersion(
versions,
dep.currentValue!,
);
if (lockedVersion) {
dep.lockedVersion = lockedVersion;
} else {
logger.debug(
`No locked version found for package ${dep.depName} in the range of ${dep.currentValue}.`,
);
}
}
return packageFileContent;
}