masto
Version:
Mastodon API client for JavaScript, TypeScript, Node.js, browsers
82 lines (81 loc) • 2.07 kB
JavaScript
import { snakeCase } from "change-case";
import { noop } from "../../utils/noop.js";
export const createActionProxy = (actionDispatcher, options = {}) => {
const { context = [], applicable = false } = options;
let target = {};
const handler = {
get: get(actionDispatcher, context),
};
if (applicable) {
target = noop;
handler.apply = apply(actionDispatcher, context);
}
return new Proxy(target, handler);
};
const SPECIAL_PROPERTIES = new Set([
"then",
"catch",
"finally",
"inspect",
"toString",
"valueOf",
"toJSON",
"constructor",
"prototype",
"length",
"name",
"caller",
"callee",
"arguments",
"bind",
"apply",
"call",
]);
const get = (actionDispatcher, context) => (_, property) => {
if (typeof property === "string" && SPECIAL_PROPERTIES.has(property)) {
return;
}
if (property === Symbol.dispose) {
return actionDispatcher[Symbol.dispose];
}
if (typeof property === "symbol") {
return;
}
if (property.startsWith("$")) {
return createActionProxy(actionDispatcher, {
context: [...context, property],
applicable: true,
});
}
return createActionProxy(actionDispatcher, {
context: [...context, snakeCase(property)],
applicable: true,
});
};
const apply = (actionDispatcher, context) => (_1, _2, args) => {
let action = context.pop();
let raw = false;
if (action === "$select") {
return createActionProxy(actionDispatcher, {
context: [...context, ...args],
applicable: true,
});
}
if (action === "$raw") {
action = context.pop();
raw = true;
}
/* c8 ignore next 3 */
if (!action) {
throw new Error("No action specified");
}
const path = "/" + context.join("/");
const [data, meta] = args;
return actionDispatcher.dispatch({
type: action,
path,
data,
meta: meta,
raw,
});
};