import { getPropertyName, isIdentifier, unwrapExpression } from "../utils.js"; const promiseRejectMessage = "Do not use Promise.reject(). Model async failures with Effect.fail or Effect.tryPromise. Skill: wrdn-effect-typed-errors.";const rejectCallbackMessage = "Do not call Promise executor reject(). Model async failures with Effect.fail or Effect.tryPromise. Skill: wrdn-effect-typed-errors."; const isPromiseReject = (node) => { const expression = unwrapExpression(node); return ( expression?.type === "MemberExpression" && isIdentifier(unwrapExpression(expression.object), "Promise") && getPropertyName(expression.property) === "reject" );}; const isPromiseConstructor = (node) => node?.type === "NewExpression" && isIdentifier(unwrapExpression(node.callee), "Promise"); const isFunction = (node) => node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression" || node?.type === "FunctionDeclaration"; export default { meta: { type: "problem", docs: { description: "Disallow Promise rejection APIs.", }, }, create(context) { const promiseExecutors = new WeakSet(); const rejectNames = []; const enterFunction = (node) => { if (!promiseExecutors.has(node)) return; const rejectParam = node.params?.[1]; if (isIdentifier(rejectParam)) { rejectNames.push(rejectParam.name); } else { rejectNames.push(undefined); } }; const exitFunction = (node) => { if (promiseExecutors.has(node)) rejectNames.pop(); }; return { NewExpression(node) { if (!isPromiseConstructor(node)) return; const executor = node.arguments?.[0]; if (isFunction(executor)) promiseExecutors.add(executor); }, CallExpression(node) { if (isPromiseReject(node.callee)) { context.report({ node, message: promiseRejectMessage }); return; } if (isIdentifier(node.callee) && rejectNames.includes(node.callee.name)) { context.report({ node, message: rejectCallbackMessage }); } }, FunctionDeclaration: enterFunction, "FunctionDeclaration:exit": exitFunction, FunctionExpression: enterFunction, "FunctionExpression:exit": exitFunction, ArrowFunctionExpression: enterFunction, "ArrowFunctionExpression:exit": exitFunction, }; },};
import { getPropertyName, isIdentifier, unwrapExpression } from "../utils.js";
const promiseRejectMessage =
"Do not use Promise.reject(). Model async failures with Effect.fail or Effect.tryPromise. Skill: wrdn-effect-typed-errors.";
const rejectCallbackMessage =
"Do not call Promise executor reject(). Model async failures with Effect.fail or Effect.tryPromise. Skill: wrdn-effect-typed-errors.";
const isPromiseReject = (node) => {
const expression = unwrapExpression(node);
return (
expression?.type === "MemberExpression" &&
isIdentifier(unwrapExpression(expression.object), "Promise") &&
getPropertyName(expression.property) === "reject"
);
};
const isPromiseConstructor = (node) =>
node?.type === "NewExpression" && isIdentifier(unwrapExpression(node.callee), "Promise");
const isFunction = (node) =>
node?.type === "ArrowFunctionExpression" ||
node?.type === "FunctionExpression" ||
node?.type === "FunctionDeclaration";
export default {
meta: {
type: "problem",
docs: {
description: "Disallow Promise rejection APIs.",
},
},
create(context) {
const promiseExecutors = new WeakSet();
const rejectNames = [];
const enterFunction = (node) => {
if (!promiseExecutors.has(node)) return;
const rejectParam = node.params?.[1];
if (isIdentifier(rejectParam)) {
rejectNames.push(rejectParam.name);
} else {
rejectNames.push(undefined);
}
};
const exitFunction = (node) => {
if (promiseExecutors.has(node)) rejectNames.pop();
};
return {
NewExpression(node) {
if (!isPromiseConstructor(node)) return;
const executor = node.arguments?.[0];
if (isFunction(executor)) promiseExecutors.add(executor);
},
CallExpression(node) {
if (isPromiseReject(node.callee)) {
context.report({ node, message: promiseRejectMessage });
return;
}
if (isIdentifier(node.callee) && rejectNames.includes(node.callee.name)) {
context.report({ node, message: rejectCallbackMessage });
}
},
FunctionDeclaration: enterFunction,
"FunctionDeclaration:exit": exitFunction,
FunctionExpression: enterFunction,
"FunctionExpression:exit": exitFunction,
ArrowFunctionExpression: enterFunction,
"ArrowFunctionExpression:exit": exitFunction,
};
},
};