Files
renovate/tools/lint/rules/require-regex-util.ts
Sebastian Poxhofer e44c9a2070 ci(oxlint): move custom oxlint rules to typescript and alternative API (#45337)
* ci: move custom oxlint rules to typescript and alternative API

* ci: add  to test sharding
2026-08-19 05:37:56 +00:00

58 lines
1.7 KiB
TypeScript

import type { ESTree } from '@oxlint/plugins';
import { defineRule } from '@oxlint/plugins';
export default defineRule({
meta: {
type: 'problem',
messages: {
requireRegexUtil:
'Use regEx() from lib/util/regex.ts instead of raw RegExp — it uses the RE2 engine for ReDoS-safe matching.',
},
},
createOnce(context) {
/**
* Regex literals passed directly as the first argument of regEx(...).
* Collected in the CallExpression visitor (which runs before its argument
* Literal in the pre-order traversal) so the Literal visitor can skip them.
*/
let wrappedLiterals = new Set<ESTree.RegExpLiteral>();
return {
before() {
const filename = context.filename ?? context.physicalFilename ?? '';
// Only enforce in lib/, but not in the regEx implementation itself
if (
!filename.includes('/lib/') ||
filename.endsWith('lib/util/regex.ts')
) {
return false;
}
wrappedLiterals = new Set();
},
NewExpression(node) {
if (
node.callee.type === 'Identifier' &&
node.callee.name === 'RegExp'
) {
context.report({ node, messageId: 'requireRegexUtil' });
}
},
CallExpression(node) {
if (
node.callee.type === 'Identifier' &&
node.callee.name === 'regEx' &&
node.arguments.length > 0 &&
node.arguments[0].type === 'Literal' &&
'regex' in node.arguments[0]
) {
wrappedLiterals.add(node.arguments[0]);
}
},
Literal(node) {
if ('regex' in node && !wrappedLiterals.has(node)) {
context.report({ node, messageId: 'requireRegexUtil' });
}
},
};
},
});