mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 01:37:24 +00:00
e44c9a2070
* ci: move custom oxlint rules to typescript and alternative API * ci: add to test sharding
58 lines
1.7 KiB
TypeScript
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' });
|
|
}
|
|
},
|
|
};
|
|
},
|
|
});
|