mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 01:37:24 +00:00
58771bb183
* refactor(oxlint): enable func-style Enable the built-in func-style rule as ["warn", "declaration"] so that named functions are written as function declarations instead of arrow or function expressions assigned to variables, matching the convention in docs/development/best-practices.md (Functions section). Inline arrow callbacks are unaffected; prefer-arrow-callback continues to cover the callback direction. Severity is "warn" instead of "error" as a fallback: a repo-wide run found 196 pre-existing violations (70 in spec files, 126 in production code), exceeding the 80-violation fix threshold for this change, so no violations were fixed here. Follow-up work can convert the offenders (largest clusters: lib/modules/versioning/ruby, lib/util/cache/package, lib/modules/versioning/maven, lib/modules/versioning/gradle) and then raise the rule to "error". Note oxlint 1.72 also supports an allowTypeAnnotation option if typed consts should remain arrows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): enforce func-style at error * refactor(func-style): convert const-arrow functions to declarations in with-cache spec and ruby versioning * refactor(func-style): convert const-arrow functions to declarations in maven/gradle modules * refactor(func-style): convert const-arrow functions to declarations in remaining versioning modules * refactor(func-style): convert const-arrow functions to declarations in platform modules Discriminated-union closures (ensureCommentRemoval byTopic/byContent helpers in github, gitlab, bitbucket, bitbucket-server) needed the narrowed field passed explicitly as a parameter, since function declarations are hoisted and lose the outer if-narrowing that inline arrow-function closures previously relied on. * refactor(func-style): convert const-arrow functions to declarations across util/manager/datasource modules One case (logger/renovate-logger.ts logOnceFn) is kept as an arrow function with a documented oxlint-disable: it is stored on this.logger.once[level] and relies on lexically-bound this, which a hoisted function declaration would not preserve. * refactor(func-style): convert remaining const-arrow test helpers to declarations get-updated.spec.ts: hoisted expectPipCompilePackageAndLockFile to module scope (it only closes over the module-level pipCompile mock) and added a documented oxlint-disable for vitest/expect-expect on its caller test, since oxlint's expect-expect check does not trace assertions through an externally-defined helper function. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
233 lines
5.9 KiB
TypeScript
233 lines
5.9 KiB
TypeScript
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<Ctx, parser.Node>,
|
|
): q.QueryBuilder<Ctx, parser.Node> {
|
|
return q
|
|
.sym<Ctx>(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<Ctx>().join(matcher).end(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
// includeModule('foo')
|
|
// excludeModuleByRegex('bar')
|
|
function qContentDescriptor(
|
|
mode: 'include' | 'exclude',
|
|
): q.QueryBuilder<Ctx, parser.Node> {
|
|
return q
|
|
.alt<Ctx>(
|
|
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<Ctx>('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<Ctx>('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<Ctx>().end(),
|
|
})
|
|
.opt(q.op<Ctx>('.').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<Ctx>('name')
|
|
.opt(q.op('='))
|
|
.join(qValueMatcher)
|
|
.handler((ctx) => storeInTokenMap(ctx, 'name')),
|
|
q.sym<Ctx>('url').opt(q.op('=')).join(qUri),
|
|
q.sym<Ctx>('setUrl').tree({
|
|
maxDepth: 1,
|
|
startsWith: '(',
|
|
endsWith: ')',
|
|
search: q.begin<Ctx>().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<Ctx>('maven').alt(
|
|
q
|
|
.tree<Ctx>({
|
|
type: 'wrapped-tree',
|
|
maxDepth: 1,
|
|
startsWith: '(',
|
|
endsWith: ')',
|
|
search: q.begin<Ctx>().opt(q.sym<Ctx>('url').op('=')).join(qUri).end(),
|
|
})
|
|
.opt(qMavenArtifactRegistry),
|
|
qMavenArtifactRegistry,
|
|
);
|
|
|
|
// forRepository { maven { ... } }
|
|
const qForRepository = q.sym<Ctx>('forRepository').tree({
|
|
type: 'wrapped-tree',
|
|
maxDepth: 1,
|
|
maxMatches: 1,
|
|
startsWith: '{',
|
|
endsWith: '}',
|
|
search: q.alt<Ctx>(qPredefinedRegistries, qCustomRegistryUrl),
|
|
});
|
|
|
|
// filter { includeGroup(...); includeModule(...) }
|
|
const qFilter = q.sym<Ctx>('filter').tree({
|
|
type: 'wrapped-tree',
|
|
maxDepth: 1,
|
|
startsWith: '{',
|
|
endsWith: '}',
|
|
search: qContentDescriptor('include'),
|
|
});
|
|
|
|
// exclusiveContent { forRepository { ... }; filter { ... } }
|
|
const qExclusiveContent = q
|
|
.sym<Ctx>('exclusiveContent', storeVarToken)
|
|
.handler((ctx) => storeInTokenMap(ctx, 'registryType'))
|
|
.tree({
|
|
type: 'wrapped-tree',
|
|
maxDepth: 1,
|
|
maxMatches: 1,
|
|
startsWith: '{',
|
|
endsWith: '}',
|
|
search: q.alt<Ctx>(
|
|
q.join<Ctx>(qForRepository, qFilter),
|
|
q.join<Ctx>(qFilter, qForRepository),
|
|
),
|
|
});
|
|
|
|
const qRegistries = q
|
|
.alt(qExclusiveContent, qPredefinedRegistries, qCustomRegistryUrl)
|
|
.handler(handleRegistryUrl)
|
|
.handler(cleanupTmpContentSpec)
|
|
.handler(cleanupTempVars);
|
|
|
|
const qPluginManagement = q.sym<Ctx>('pluginManagement', storeVarToken).tree({
|
|
type: 'wrapped-tree',
|
|
startsWith: '{',
|
|
endsWith: '}',
|
|
preHandler: (ctx) => {
|
|
ctx.tmpTokenStore.registryScope = ctx.varTokens;
|
|
ctx.varTokens = [];
|
|
return ctx;
|
|
},
|
|
search: q
|
|
.handler<Ctx>((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<Ctx>(
|
|
q.sym<Ctx>('publishing').tree(),
|
|
qPluginManagement,
|
|
qRegistries,
|
|
);
|