UNPKG

patronum

Version:

☄️ Effector utility library delivering modularity and convenience

434 lines (426 loc) 13.3 kB
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } import { is, createNode, step, clearNode } from 'effector'; var defaultConfig = { trace: false, // default logger to console.info handler: context => { if (isEffectChild(context.node) && context.node.meta.named === 'finally') { // skip effect.finally logs, it can be useful for other custom handlers // but not for default console.info logger return; } var { scope, scopeName, name, kind, value, loc, trace, node, logType } = context; var scopeLog = scope ? " (scope: ".concat(scopeName, ")") : ''; var logName = name !== null && name !== void 0 ? name : loc ? "".concat(loc.file, ":").concat(loc.line, ":").concat(loc.column) : ''; var logPrintType = logType === 'initial' ? ' [getState]' : ''; console.info("[".concat(kind, "]").concat(scopeLog, " ").concat(logName).concat(logPrintType), value); if ( // logging trace only if there is something to log trace && trace.length > 0 && // do not log trace for effect children, as it is always the same effect internals !isEffectChild(node)) { console.groupCollapsed("[".concat(kind, "]").concat(scopeLog, " ").concat(logName, " trace")); trace.forEach(update => { var { name: traceName, kind, value, loc } = update; var logTraceName = traceName !== null && traceName !== void 0 ? traceName : loc ? "".concat(loc.file, ":").concat(loc.line, ":").concat(loc.column) : ''; console.info("<- [".concat(kind, "] ").concat(logTraceName), value); }); console.groupEnd(); } } }; export function debug() { var { config, units } = resolveParams(...arguments); units.forEach(unit => { if (is.store(unit, { sid: "-foynff" }) || is.event(unit, { sid: "apy28p" }) || is.effect(unit, { sid: "apy3od" })) { watchUnit(unit, config); } else if (is.domain(unit, { sid: "-rsqe9t" })) { watchDomain(unit, config); } else { /** * Let unknown stuff pass through as noop * * It's useful for debug of custom entities: * debug(myFarfetchedQuery) */ } }); } // Log node function watchDomain(domain, config) { domain.onCreateStore(store => watchUnit(store, config)); domain.onCreateEvent(event => watchUnit(event, config)); domain.onCreateEffect(effect => watchUnit(effect, config)); domain.onCreateDomain(domain => watchDomain(domain, config)); } function watchUnit(unit, config) { if (is.store(unit, { sid: "w7ds2s" })) { // store has its initial/current value - we can log it right away watchStoreInit(unit, config); watch(unit, config); } else if (is.event(unit, { sid: "fretyd" })) { watch(unit, config); } else if (is.effect(unit, { sid: "gpi2qr" })) { watch(unit, config); watch(unit.finally, config); watch(unit.done, config); watch(unit.fail, config); } } function watch(unit, config) { var watcher = createNode({ parent: [unit], // debug watchers should behave like normal watchers meta: { op: 'watch' }, family: { owners: unit }, regional: true, // node only gets all required data node: [step.run({ fn(value, _internal, stack) { var _stack$scope; var scope = (_stack$scope = stack === null || stack === void 0 ? void 0 : stack.scope) !== null && _stack$scope !== void 0 ? _stack$scope : null; var context = { logType: 'update', scope, scopeName: getScopeName(scope), node: getNode(unit), kind: getType(unit), value, name: getName(unit), loc: getLoc(unit), // Use stack meta of actual unit, not of debug node stackMeta: getStackMeta(stack.parent), trace: config.trace ? collectTrace(stack) : [] }; if (!config.handler) { throw Error('patronum/debug must have the handler'); } config.handler(context); } })] }); return () => clearNode(watcher); } function collectTrace(stack) { var trace = []; var parent = stack === null || stack === void 0 ? void 0 : stack.parent; while (parent) { var { node, value } = parent; var entry = { node, value, name: getName(node), loc: getLoc(node), kind: getType(node), stackMeta: getStackMeta(parent) }; trace.push(entry); parent = parent.parent; } return trace; } function watchStoreInit(store, config) { if (!config.handler) { throw Error('patronum/debug must have the handler'); } var node = getNode(store); // current state var context = { logType: 'initial', scope: null, scopeName: null, node, kind: getType(store), value: store.getState(), name: getName(store), loc: getLoc(store), // nothing to trace for store.getState() - it is one-step call trace: [], // no stackMeta for initial state stackMeta: {} }; config.handler(context); // current state in every known scope scopes.forEach(scope => watchStoreInitInScope(store, config, scope)); // subscribe to new scopes watchScopeRegister(newScope => watchStoreInitInScope(store, config, newScope)); } function watchStoreInitInScope(store, config, scope) { if (!config.handler) { throw Error('patronum/debug must have the handler'); } var node = getNode(store); // current state var context = { logType: 'initial', scope, scopeName: getScopeName(scope), node, kind: getType(store), value: scope.getState(store), name: getName(store), loc: getLoc(store), // nothing to trace for scope.getState(store) - it is one-step call trace: [], // no stackMeta for initial state stackMeta: {} }; config.handler(context); } // Config function resolveParams() { var config = defaultConfig; for (var _len = arguments.length, entry = new Array(_len), _key = 0; _key < _len; _key++) { entry[_key] = arguments[_key]; } var [maybeConfig, ...restUnits] = entry; var units = []; if (isConfig(maybeConfig)) { config = _objectSpread(_objectSpread({}, defaultConfig), maybeConfig); } else if (!is.unit(maybeConfig)) { for (var [name, unit] of Object.entries(maybeConfig)) { customNames.set(getGraph(unit).id, name); units.push(unit); } } else { units.push(maybeConfig); } for (var maybeUnit of restUnits) { if (is.unit(maybeUnit)) { units.push(maybeUnit); } else { for (var [_name, _unit] of Object.entries(maybeUnit)) { customNames.set(getGraph(_unit).id, _name); units.push(_unit); } } } return { config, units }; } function isConfig(maybeConfig) { if (!is.unit(maybeConfig)) { return !Object.values(maybeConfig).every(is.unit); } return false; } // Scopes var watchers = new Set(); var watchScopeRegister = cb => { watchers.add(cb); return () => { watchers.delete(cb); }; }; function registerScope(scope, config) { scopes.save(scope, { name: config.name }); watchers.forEach(cb => cb(scope)); return () => { scopes.delete(scope); }; } function unregisterAllScopes() { scopes.clear(); } var unknownScopes = 0; function getDefaultScopeName() { unknownScopes += 1; return "unknown_".concat(unknownScopes); } var cache = new Map(); var scopes = { save(scope, meta) { if (!scopes.get(scope)) { cache.set(scope, meta); } }, get(scope) { var _cache$get; if (!scope) return null; return (_cache$get = cache.get(scope)) !== null && _cache$get !== void 0 ? _cache$get : null; }, delete(scope) { cache.delete(scope); }, forEach(callback) { cache.forEach((meta, scope) => callback(scope, meta)); }, clear() { cache.clear(); } }; debug.registerScope = registerScope; debug.unregisterAllScopes = unregisterAllScopes; function getScopeName(scope) { if (!scope) return null; var meta = scopes.get(scope); if (!meta) { // @ts-expect-error var fallbackId = scope._debugId || (scope._debugId = getDefaultScopeName()); return fallbackId; } return meta.name; } // Utils function isEffectChild(node) { var actualNode = getNode(node); var { sid, named } = actualNode.meta; return Boolean(!sid && (named === 'finally' || named === 'done' || named === 'doneData' || named === 'fail' || named === 'failData' || named === 'inFlight' || named === 'pending')); } function isStoreOn(node) { var actualNode = getNode(node); var { op } = actualNode.meta; if (op === 'on') return true; return false; } function getType(unit) { if (is.store(unit, { sid: "4o7s04" })) { return 'store'; } if (is.effect(unit, { sid: "4pv5s7" }) || isEffectChild(unit)) { return 'effect'; } if (is.event(unit, { sid: "4rijka" })) { return 'event'; } if (is.domain(unit, { sid: "54plsy" })) { return 'domain'; } if (is.unit(unit)) { return 'unit'; } var node = getNode(unit); if (node.meta.op) { return node.meta.op; } return 'unknown'; } var getGraph = graph => graph.graphite || graph; var customNames = new Map(); function getName(unit) { var _getNode, _getNode$meta; var custom = customNames.get(getGraph(unit).id); if (custom) { return custom; } if (isEffectChild(unit)) { var node = getNode(unit); var parentEffect = node.family.owners.find(n => n.meta.op === 'effect'); if (parentEffect) { var closestParentDomainName = getOwningDomainName(parentEffect); var formattedDomainName = closestParentDomainName ? "".concat(closestParentDomainName, "/") : ''; return "".concat(formattedDomainName).concat(getName(parentEffect), ".").concat(node.meta.named); } return node.meta.named; } if (isStoreOn(unit)) { var _node = getNode(unit); var targetStoreName = getName(_node.next[0]); var triggerEventName = getName(_node.family.owners[0]); return "".concat(targetStoreName, ".on(").concat(triggerEventName, ")"); } if (is.unit(unit)) { var _compositeName; if (unit !== null && unit !== void 0 && (_compositeName = unit.compositeName) !== null && _compositeName !== void 0 && _compositeName.fullName) { return unit.compositeName.fullName; } var _closestParentDomainName = getOwningDomainName(unit); var _formattedDomainName = _closestParentDomainName ? "".concat(_closestParentDomainName, "/") : ''; if (unit !== null && unit !== void 0 && unit.shortName) { return "".concat(_formattedDomainName).concat(unit.shortName); } if (unit !== null && unit !== void 0 && unit.name) { return "".concat(_formattedDomainName).concat(unit.name); } } if ((_getNode = getNode(unit)) !== null && _getNode !== void 0 && (_getNode$meta = _getNode.meta) !== null && _getNode$meta !== void 0 && _getNode$meta.name) { return getNode(unit).meta.name; } return null; } function getOwningDomainName(unit) { var closestParentDomain = getNode(unit).family.owners.find(n => n.meta.op === 'domain'); if (!closestParentDomain) return null; return getName(closestParentDomain); } function readLoc(_ref) { var { meta } = _ref; var loc = 'config' in meta ? meta.config.loc : meta.loc; return loc; } function getLoc(unit) { var loc = readLoc(getNode(unit)); if (!loc) return undefined; return loc; } function getNode(node) { var actualNode = 'graphite' in node ? node.graphite : node; return actualNode; } function getStackMeta(stack) { if (!stack) return {}; var meta = stack.meta || {}; return meta; }