renovate/lib/modules/manager/bazel-module/parser/maven.ts

154 lines
4.3 KiB
TypeScript

import { query as q } from 'good-enough-parser';
import { z } from 'zod';
import { regEx } from '../../../../util/regex';
import { MavenDatasource } from '../../../datasource/maven';
import { id as versioning } from '../../../versioning/gradle';
import type { PackageDependency } from '../../types';
import type { Ctx } from '../context';
import {
RecordFragmentSchema,
StringArrayFragmentSchema,
StringFragmentSchema,
} from '../fragments';
const artifactMethod = 'artifact';
const installMethod = 'install';
const commonDepType = 'maven_install';
const mavenVariableRegex = regEx(/^maven.*/);
const bzlmodMavenMethods = [installMethod, artifactMethod];
const methodRegex = regEx(`^${bzlmodMavenMethods.join('|')}$`);
function getParsedRuleByMethod(method: string): string {
return `maven_${method}`;
}
const ArtifactSpec = z.object({
group: z.string(),
artifact: z.string(),
version: z.string(),
});
type ArtifactSpec = z.infer<typeof ArtifactSpec>;
const MavenArtifactTarget = RecordFragmentSchema.extend({
children: z.object({
rule: StringFragmentSchema.extend({
value: z.literal(getParsedRuleByMethod(artifactMethod)),
}),
artifact: StringFragmentSchema,
group: StringFragmentSchema,
version: StringFragmentSchema,
}),
}).transform(
({ children: { rule, artifact, group, version } }): PackageDependency[] => [
{
datasource: MavenDatasource.id,
versioning,
depName: `${group.value}:${artifact.value}`,
currentValue: version.value,
depType: rule.value,
},
],
);
const MavenInstallTarget = RecordFragmentSchema.extend({
children: z.object({
rule: StringFragmentSchema.extend({
value: z.literal(getParsedRuleByMethod(installMethod)),
}),
artifacts: StringArrayFragmentSchema.transform((artifacts) => {
const result: ArtifactSpec[] = [];
for (const { value } of artifacts.items) {
const [group, artifact, version] = value.split(':');
if (group && artifact && version) {
result.push({ group, artifact, version });
}
}
return result;
}),
repositories: StringArrayFragmentSchema,
}),
}).transform(
({ children: { rule, artifacts, repositories } }): PackageDependency[] =>
artifacts.map(({ group, artifact, version: currentValue }) => ({
datasource: MavenDatasource.id,
versioning,
depName: `${group}:${artifact}`,
currentValue,
depType: rule.value,
registryUrls: repositories.items.map((i) => i.value),
})),
);
export const RuleToMavenPackageDep = z.union([
MavenArtifactTarget,
MavenInstallTarget,
]);
export function fillRegistryUrls(
packageDeps: PackageDependency[][],
): PackageDependency[] {
const artifactRules: PackageDependency[] = [];
const registryUrls: string[] = [];
const result: PackageDependency[] = [];
// registry urls are specified only in maven.install, not in maven.artifact
packageDeps.flat().forEach((dep) => {
if (dep.depType === getParsedRuleByMethod(installMethod)) {
if (Array.isArray(dep.registryUrls)) {
registryUrls.push(...dep.registryUrls);
result.push(dep);
}
} else if (dep.depType === getParsedRuleByMethod(artifactMethod)) {
artifactRules.push(dep);
}
});
const uniqUrls = [...new Set(registryUrls)];
for (const artifactRule of artifactRules) {
artifactRule.registryUrls = uniqUrls;
artifactRule.depType = commonDepType;
result.push(artifactRule);
}
return result;
}
const kvParams = q
.sym<Ctx>((ctx, token) => ctx.startAttribute(token.value))
.op('=')
.alt(
q.str((ctx, token) => ctx.addString(token.value)),
q.tree({
type: 'wrapped-tree',
maxDepth: 1,
startsWith: '[',
endsWith: ']',
postHandler: (ctx) => ctx.endArray(),
preHandler: (ctx) => ctx.startArray(),
search: q.many(q.str<Ctx>((ctx, token) => ctx.addString(token.value))),
}),
);
export const mavenRules = q
.sym<Ctx>(mavenVariableRegex, (ctx, token) => {
return ctx.startRule(token.value);
})
.op('.')
.sym(methodRegex, (ctx, token) => {
const rule = ctx.currentRecord.children.rule;
if (rule.type === 'string') {
rule.value = getParsedRuleByMethod(token.value);
}
return ctx;
})
.join(
q.tree({
type: 'wrapped-tree',
maxDepth: 1,
search: kvParams,
postHandler: (ctx) => ctx.endRule(),
}),
);