Files
renovate/tools/lint/rules/prefer-json-pipe.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

60 lines
1.6 KiB
TypeScript

import type { ESTree } from '@oxlint/plugins';
import { defineRule } from '@oxlint/plugins';
/**
* Return the method/function name of a non-computed member call like
* `.parse()` or `JSON.parse()`, or null if the node is not such a call.
*/
function getCalleeName(node: ESTree.Node): string | null {
if (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
!node.callee.computed &&
node.callee.property.type === 'Identifier'
) {
return node.callee.property.name;
}
return null;
}
/**
* True for a `JSON.parse(...)` call expression.
*/
function isJsonParseCall(node: ESTree.Node): boolean {
return (
getCalleeName(node) === 'parse' &&
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'JSON'
);
}
export default defineRule({
meta: {
type: 'suggestion',
messages: {
preferJsonPipe:
'Use `Json.pipe(Schema)` from schema-utils instead of `Schema.{{method}}(JSON.parse(...))` — it folds the parse and validation into a single schema.',
},
},
createOnce(context) {
return {
CallExpression(node) {
const method = getCalleeName(node);
if (method !== 'parse' && method !== 'safeParse') {
return;
}
const [arg] = node.arguments;
if (arg && isJsonParseCall(arg)) {
context.report({
node,
messageId: 'preferJsonPipe',
data: { method },
});
}
},
};
},
});