import type { lexer, parser } from '@renovatebot/good-enough-parser'; import { query as q } from '@renovatebot/good-enough-parser'; import { regEx } from '../../../../util/regex.ts'; import type { Ctx } from '../types.ts'; import { qApplyFrom } from './apply-from.ts'; import { qAssignments } from './assignments.ts'; import { REGISTRY_URLS, cleanupTempVars, qArtifactId, qGroupId, qValueMatcher, qVersion, storeInTokenMap, storeVarToken, } from './common.ts'; import { handleRegistryContent, handleRegistryUrl } from './handlers.ts'; import { qPlugins } from './plugins.ts'; function cleanupTmpContentSpec(ctx: Ctx): Ctx { ctx.tmpRegistryContent = []; return ctx; } function qContentDescriptorSpec( methodName: RegExp, matcher: q.QueryBuilder, ): q.QueryBuilder { return q .sym(methodName, storeVarToken) .handler((ctx) => storeInTokenMap(ctx, 'methodName')) .alt( // includeGroup "foo.bar" matcher, // includeGroup("foo.bar") q.tree({ type: 'wrapped-tree', maxDepth: 1, startsWith: '(', endsWith: ')', search: q.begin().join(matcher).end(), }), ); } // includeModule('foo') // excludeModuleByRegex('bar') function qContentDescriptor( mode: 'include' | 'exclude', ): q.QueryBuilder { return q .alt( qContentDescriptorSpec( regEx( `^(?:${mode}Group|${mode}GroupByRegex|${mode}GroupAndSubgroups)$`, ), qGroupId, ), qContentDescriptorSpec( regEx(`^(?:${mode}Module|${mode}ModuleByRegex)$`), q.join(qGroupId, q.op(','), qArtifactId), ), qContentDescriptorSpec( regEx(`^(?:${mode}Version|${mode}VersionByRegex)$`), q.join(qGroupId, q.op(','), qArtifactId, q.op(','), qVersion), ), ) .handler(handleRegistryContent); } // content { includeModule('foo'); excludeModule('bar') } const qRegistryContent = q.sym('content').tree({ type: 'wrapped-tree', maxDepth: 1, startsWith: '{', endsWith: '}', search: q.alt(qContentDescriptor('include'), qContentDescriptor('exclude')), }); // uri("https://foo.bar/baz") // "https://foo.bar/baz" const qUri = q .alt( q.sym('uri').tree({ maxDepth: 1, search: qValueMatcher, }), qValueMatcher, ) .handler((ctx) => storeInTokenMap(ctx, 'registryUrl')); // mavenCentral() // mavenCentral { ... } const qPredefinedRegistries = q .sym( regEx(`^(?:${Object.keys(REGISTRY_URLS).join('|')})$`), (ctx: Ctx, node: lexer.Token) => { const nodeTransformed: lexer.Token = { ...node, type: 'string-value', value: REGISTRY_URLS[node.value as keyof typeof REGISTRY_URLS], }; storeVarToken(ctx, nodeTransformed); return ctx; }, ) .handler((ctx) => storeInTokenMap(ctx, 'registryUrl')) .alt( q .tree({ type: 'wrapped-tree', startsWith: '(', endsWith: ')', search: q.begin().end(), }) .opt(q.op('.').join(qRegistryContent)), q.tree({ type: 'wrapped-tree', startsWith: '{', endsWith: '}', search: q.opt(qRegistryContent), }), ); // { url = "https://some.repo"; content { ... } } const qMavenArtifactRegistry = q.tree({ type: 'wrapped-tree', maxDepth: 1, startsWith: '{', endsWith: '}', search: q.alt( q .sym('name') .opt(q.op('=')) .join(qValueMatcher) .handler((ctx) => storeInTokenMap(ctx, 'name')), q.sym('url').opt(q.op('=')).join(qUri), q.sym('setUrl').tree({ maxDepth: 1, startsWith: '(', endsWith: ')', search: q.begin().join(qUri).end(), }), qRegistryContent, ), }); // maven(url = uri("https://foo.bar/baz")) // maven("https://foo.bar/baz") { content { ... } } // maven { name = some; url = "https://foo.bar/${name}" } const qCustomRegistryUrl = q.sym('maven').alt( q .tree({ type: 'wrapped-tree', maxDepth: 1, startsWith: '(', endsWith: ')', search: q.begin().opt(q.sym('url').op('=')).join(qUri).end(), }) .opt(qMavenArtifactRegistry), qMavenArtifactRegistry, ); // forRepository { maven { ... } } const qForRepository = q.sym('forRepository').tree({ type: 'wrapped-tree', maxDepth: 1, maxMatches: 1, startsWith: '{', endsWith: '}', search: q.alt(qPredefinedRegistries, qCustomRegistryUrl), }); // filter { includeGroup(...); includeModule(...) } const qFilter = q.sym('filter').tree({ type: 'wrapped-tree', maxDepth: 1, startsWith: '{', endsWith: '}', search: qContentDescriptor('include'), }); // exclusiveContent { forRepository { ... }; filter { ... } } const qExclusiveContent = q .sym('exclusiveContent', storeVarToken) .handler((ctx) => storeInTokenMap(ctx, 'registryType')) .tree({ type: 'wrapped-tree', maxDepth: 1, maxMatches: 1, startsWith: '{', endsWith: '}', search: q.alt( q.join(qForRepository, qFilter), q.join(qFilter, qForRepository), ), }); const qRegistries = q .alt(qExclusiveContent, qPredefinedRegistries, qCustomRegistryUrl) .handler(handleRegistryUrl) .handler(cleanupTmpContentSpec) .handler(cleanupTempVars); const qPluginManagement = q.sym('pluginManagement', storeVarToken).tree({ type: 'wrapped-tree', startsWith: '{', endsWith: '}', preHandler: (ctx) => { ctx.tmpTokenStore.registryScope = ctx.varTokens; ctx.varTokens = []; return ctx; }, search: q .handler((ctx) => { if (ctx.tmpTokenStore.registryScope) { ctx.tokenMap.registryScope = ctx.tmpTokenStore.registryScope; } return ctx; }) .alt(qAssignments, qApplyFrom, qPlugins, qRegistries), postHandler: (ctx) => { delete ctx.tmpTokenStore.registryScope; return ctx; }, }); export const qRegistryUrls = q.alt( q.sym('publishing').tree(), qPluginManagement, qRegistries, );