UNPKG

effector

Version:

Business logic with ease

1 lines 168 kB
{"version":3,"file":"effector.mjs","sources":["effector/collection.ts","effector/throw.ts","effector/region.ts","effector/createNode.ts","effector/tag.ts","effector/kernel.ts","effector/naming.ts","effector/config.ts","effector/subscription.ts","effector/template.ts","effector/createUnit.ts","effector/combine.ts","effector/defer.ts","effector/createEffect.ts","effector/attach.ts","effector/createApi.ts","effector/createDomain.ts","effector/fromObservable.ts","effector/sample.ts","effector/guard.ts","effector/merge.ts","effector/restore.ts","effector/split.ts","effector/fork/allSettled.ts","effector/fork/util.ts","effector/fork/fork.ts","effector/fork/createScope.ts","effector/fork/hydrate.ts","effector/fork/scopeBind.ts","effector/fork/serialize.ts","effector/createWatch.ts","effector/observable.ts","effector/getter.ts","effector/validate.ts","effector/id.ts","effector/own.ts","effector/is.ts","effector/caller.ts","effector/step.ts","effector/stateRef.ts","effector/clearNode.ts","effector/forward.ts","effector/watch.ts","effector/debug_traces.ts","effector/private_api_do_not_touch.ts"],"sourcesContent":["export function forIn<T, Key extends string = string>(\n obj: Record<Key, T>,\n cb: (value: T, key: Key) => void,\n) {\n for (const key in obj) {\n cb(obj[key], key)\n }\n}\n\nexport const includes = <T>(list: T[], item: T) => list.includes(item)\n\nexport const removeItem = <T>(list: T[], item: T) => {\n const pos = list.indexOf(item)\n if (pos !== -1) {\n list.splice(pos, 1)\n }\n}\n\nexport const add = <T>(list: T[], item: T) => list.push(item)\n\nexport function forEach<T>(\n list: T[],\n fn: (item: T, index: number, list: T[]) => void,\n): void\nexport function forEach<K, T>(\n list: Map<K, T>,\n fn: (item: T, key: K) => void,\n): void\nexport function forEach<T>(list: Set<T>, fn: (item: T) => void): void\nexport function forEach(list: any, fn: Function) {\n list.forEach(fn)\n}\n","import {getMeta} from './getter'\nimport {Node} from './index.h'\n\nexport function assert(\n condition: unknown,\n message: string,\n errorTitle?: string,\n): asserts condition {\n if (!condition)\n throw Error(`${errorTitle ? errorTitle + ': ' : ''}${message}`)\n}\n\nexport const deprecate = (\n condition: unknown,\n subject: string,\n suggestion?: string,\n errorTitle?: string,\n) =>\n !condition &&\n console.error(\n `${errorTitle ? errorTitle + ': ' : ''}${subject} is deprecated${\n suggestion ? `, use ${suggestion} instead` : ''\n }`,\n )\n\nexport const printErrorWithNodeDetails = (message: string, node: Node) => {\n const stack = getMeta(node, 'unitTrace')\n const config = getMeta(node, 'config')\n const locString = config?.loc\n ? ` at ${config.loc.file}`\n : null\n const name = config?.name\n\n let finalMessage = message\n if (name) {\n finalMessage = `${name}: ${message}`\n }\n if (locString) {\n finalMessage = `${name}${locString}: ${message}`\n }\n\n const error = Error(finalMessage)\n\n if (stack) {\n error.stack = stack\n }\n\n if (!stack && !name && !locString) {\n console.log(\n `Add effector's Babel or SWC plugin to your config for more detailed debug information or \"import \"effector/enable_debug_traces\" to your code entry module to see full stack traces`,\n )\n }\n console.error(error)\n}\n","import type {Template} from '../forest/index.h'\nimport type {NodeUnit, Node, ID} from './index.h'\nimport {getParent, getGraph} from './getter'\nimport {createNode} from './createNode'\nimport {is} from './is'\n\ntype DeclarationSourceReporter = (\n node: Node | 'region',\n regionStack: RegionStack | null,\n) => void\n\nlet reporter: DeclarationSourceReporter\n\nexport const setGraphInspector = (fn: DeclarationSourceReporter) => {\n reporter = fn\n}\n\ntype RegionStack = {\n id: ID\n parent: RegionStack | null\n value: any\n template: Template | null\n sidRoot?: string\n meta:\n | Record<string, unknown>\n | {\n type: 'factory'\n sid?: string\n name?: string\n loc: unknown\n method?: string\n }\n}\n\nexport let regionStack: RegionStack | null = null\n\nexport const reportDeclaration = (node: Node | 'region') => {\n if (reporter) {\n reporter(node, regionStack)\n }\n}\n\nexport const readTemplate = (): Template | null =>\n regionStack && regionStack.template\nexport const readSidRoot = (sid?: string | null) => {\n if (sid && regionStack && regionStack.sidRoot)\n sid = `${regionStack.sidRoot}|${sid}`\n return sid\n}\n\nexport function withRegion<T = void>(unit: NodeUnit, cb: () => T): T {\n const node = getGraph(unit)\n const meta = node.meta || {}\n\n if (!is.domain(unit)) {\n meta.isRegion = true\n }\n\n regionStack = {\n id: node.id,\n parent: regionStack,\n value: unit,\n template: meta.template || readTemplate(),\n sidRoot: meta.sidRoot || (regionStack && regionStack.sidRoot),\n meta: meta,\n }\n try {\n return cb()\n } finally {\n reportDeclaration('region')\n regionStack = getParent(regionStack)\n }\n}\n\nexport const withFactory = ({\n sid,\n name,\n loc,\n method,\n fn,\n}: {\n sid: string\n name?: string\n loc?: any\n method?: string\n fn: () => any\n}) => {\n const factoryRootNode = createNode({\n meta: {sidRoot: readSidRoot(sid), sid, name, loc, method, type: 'factory'},\n regional: true,\n })\n\n return withRegion(factoryRootNode, fn)\n}\n","import type {Node, NodeUnit, Cmd} from './index.h'\nimport {getGraph, getOwners, getLinks, getValue} from './getter'\nimport {nextNodeID} from './id'\nimport {CROSSLINK} from './tag'\nimport {regionStack} from './region'\nimport {own} from './own'\nimport {add, forEach} from './collection'\n\nexport const arrifyNodes = (\n list: NodeUnit | Array<NodeUnit | NodeUnit[]> = [],\n): Node[] => (Array.isArray(list) ? list : [list]).flat().map(getGraph)\n\nexport function createNode({\n node = [],\n from,\n source,\n parent = from || source,\n to,\n target,\n child = to || target,\n scope = {},\n meta = {},\n family: familyRaw = {type: 'regular'},\n regional,\n}: {\n node?: Array<Cmd | false | void | null>\n from?: NodeUnit | NodeUnit[]\n source?: NodeUnit | NodeUnit[]\n parent?: NodeUnit | NodeUnit[]\n to?: NodeUnit | NodeUnit[]\n target?: NodeUnit | NodeUnit[]\n child?: NodeUnit | NodeUnit[]\n scope?: {[name: string]: any}\n meta?: {[name: string]: any}\n family?: {\n type?: 'regular' | 'crosslink' | 'domain'\n links?: NodeUnit | NodeUnit[]\n owners?: NodeUnit | Array<NodeUnit | NodeUnit[]>\n }\n regional?: boolean\n} = {}): Node {\n const sources = arrifyNodes(parent)\n const links = arrifyNodes(familyRaw.links)\n const owners = arrifyNodes(familyRaw.owners)\n const seq: Cmd[] = []\n forEach(node, item => item && add(seq, item))\n const result: Node = {\n id: nextNodeID(),\n seq,\n next: arrifyNodes(child),\n meta,\n scope,\n family: {\n triggers: sources.length,\n type: familyRaw.type || CROSSLINK,\n links,\n owners,\n },\n }\n forEach(links, link => add(getOwners(link), result))\n forEach(owners, owner => add(getLinks(owner), result))\n forEach(sources, source => add(source.next, result))\n if (regional && regionStack) {\n own(getValue(regionStack), [result])\n }\n return result\n}\n","export const STORE = 'store'\nexport const EVENT = 'event'\nexport const EFFECT = 'effect'\nexport const DOMAIN = 'domain'\nexport const SCOPE = 'scope'\nexport const SAMPLER = 'sampler'\nexport const CROSSLINK = 'crosslink'\nexport const MAP = 'map'\nexport const STACK = 'stack'\nexport const VALUE = 'value'\nexport const REG_A = 'a'\n","import type {Leaf} from '../forest/index.h'\n\nimport type {Node, NodeUnit, StateRef, Stack} from './index.h'\nimport {readRef} from './stateRef'\nimport {getForkPage, getGraph, getValue} from './getter'\nimport type {Scope} from './unit.h'\nimport {add, forEach} from './collection'\n\n/** Names of priority groups */\ntype PriorityTag = 'child' | 'pure' | 'read' | 'barrier' | 'sampler' | 'effect'\n\nexport type BarrierPriorityTag = 'read' | 'barrier' | 'sampler' | 'effect'\n\n/**\n * Position in the current branch,\n * including call stack, priority type\n * and index of next step in the executed Node\n */\ntype Layer = {\n idx: number\n stack: Stack\n type: PriorityTag\n id: number\n}\n\n/** Queue as linked list or skew heap */\ntype QueueItem = {\n /** node value */\n v: Layer\n /** left node. always null in queue but used in skew heap */\n l: QueueItem | null\n /** right node */\n r: QueueItem | null\n}\ntype QueueBucket = {\n first: QueueItem | null\n last: QueueItem | null\n size: number\n}\n\n/** Dedicated local metadata */\ntype Local = {\n fail: boolean\n failReason?: unknown\n scope: {[key: string]: any}\n}\n\nlet heap: QueueItem | null = null\n\nconst merge = (a: QueueItem | null, b: QueueItem | null): QueueItem | null => {\n if (!a) return b\n if (!b) return a\n\n let ret\n if (\n /**\n * if both nodes has the same PriorityType\n * and first node is created after second one\n */\n (a.v.type === b.v.type && a.v.id > b.v.id) ||\n /**\n * greater priority mean bucket of first node is executed later\n * e.g a: \"sampler\", b: \"barrier\"\n */\n getPriority(a.v.type) > getPriority(b.v.type)\n ) {\n ret = a\n a = b\n b = ret\n }\n ret = merge(a.r, b)\n a.r = a.l\n a.l = ret\n\n return a\n}\n\n/** queue buckets for each PriorityType */\nconst queue: QueueBucket[] = []\nlet ix = 0\nwhile (ix < 6) {\n /**\n * although \"sampler\" and \"barrier\" are using heap instead of linked list,\n * their buckets are still useful: they maintains size of heap queue\n */\n add(queue, {first: null, last: null, size: 0})\n ix += 1\n}\n\nconst deleteMin = () => {\n for (let i = 0; i < 6; i++) {\n const list = queue[i]\n if (list.size > 0) {\n /**\n * bucket 3 is for \"barrier\" PriorityType (used in combine)\n * bucket 4 is for \"sampler\" PriorityType (used in sample and guard)\n */\n if (i === 3 || i === 4) {\n list.size -= 1\n const value = heap!.v\n heap = merge(heap!.l, heap!.r)\n return value\n }\n if (list.size === 1) {\n list.last = null\n }\n const item = list.first\n list.first = item!.r\n list.size -= 1\n return item!.v\n }\n }\n}\nconst pushFirstHeapItem = (\n type: PriorityTag,\n page: Leaf | null,\n node: Node,\n parent: Stack | null,\n value: any,\n scope?: Scope | null | void,\n meta?: Record<string, any> | void,\n) =>\n pushHeap(\n 0,\n {\n a: null,\n b: null,\n node,\n parent,\n value,\n page,\n scope,\n meta,\n },\n type,\n 0,\n )\nconst pushHeap = (idx: number, stack: Stack, type: PriorityTag, id: number) => {\n const priority = getPriority(type)\n const bucket: QueueBucket = queue[priority]\n const item: QueueItem = {\n v: {idx, stack, type, id},\n l: null,\n r: null,\n }\n /**\n * bucket 3 is for \"barrier\" PriorityType (used in combine)\n * bucket 4 is for \"sampler\" PriorityType (used in sample and guard)\n */\n if (priority === 3 || priority === 4) {\n heap = merge(heap, item)\n } else {\n if (bucket.size === 0) {\n bucket.first = item\n } else {\n bucket.last!.r = item\n }\n bucket.last = item\n }\n bucket.size += 1\n}\n\nconst getPriority = (t: PriorityTag) => {\n switch (t) {\n case 'child':\n return 0\n case 'pure':\n return 1\n case 'read':\n return 2\n case 'barrier':\n return 3\n case 'sampler':\n return 4\n case 'effect':\n return 5\n default:\n return -1\n }\n}\n\nconst barriers = new Set<string | number>()\n\nlet isRoot = true\nexport let isWatch = false\nexport let isPure = false\nexport let currentPage: Leaf | null = null\nexport let forkPage: Scope | void | null\nexport const setForkPage = (newForkPage: Scope | void | null) => {\n forkPage = newForkPage\n}\nexport const setCurrentPage = (newPage: Leaf | null) => {\n currentPage = newPage\n}\n\nconst getPageForRef = (page: Leaf | null, id: string) => {\n if (page) {\n while (page && !page.reg[id]) {\n page = page.parent\n }\n if (page) return page\n }\n return null\n}\nexport const getPageRef = (\n page: Leaf | null,\n forkPage: Scope | null | void,\n ref: StateRef,\n isGetState: boolean,\n) => {\n const pageForRef = getPageForRef(page, ref.id)\n if (pageForRef) return pageForRef.reg[ref.id]\n if (forkPage) {\n initRefInScope(forkPage!, ref, isGetState)\n return forkPage.reg[ref.id]\n }\n return ref\n}\n\n/** Introspection api internals */\ntype Inspector = (stack: Stack, local: Local) => void\nlet inspector: Inspector\nexport const setInspector = (newInspector: Inspector) => {\n inspector = newInspector\n}\n\nexport function launch(config: {\n target: NodeUnit | NodeUnit[]\n params?: any\n defer?: boolean\n page?: Leaf | void | null\n scope?: Scope | void | null\n stack?: Stack | void\n meta?: Record<string, any> | void\n}): void\nexport function launch(unit: NodeUnit, payload?: any, upsert?: boolean): void\nexport function launch(unit: any, payload?: any, upsert?: boolean) {\n let pageForLaunch = currentPage\n let stackForLaunch = null\n let forkPageForLaunch = forkPage\n let meta: Record<string, any> | undefined\n if (unit.target) {\n payload = unit.params\n upsert = unit.defer\n meta = unit.meta\n pageForLaunch = 'page' in unit ? unit.page : pageForLaunch\n if (unit.stack) stackForLaunch = unit.stack\n forkPageForLaunch = getForkPage(unit) || forkPageForLaunch\n unit = unit.target\n }\n if (forkPageForLaunch && forkPage && forkPageForLaunch !== forkPage) {\n forkPage = null\n }\n if (Array.isArray(unit)) {\n for (let i = 0; i < unit.length; i++) {\n pushFirstHeapItem(\n 'pure',\n pageForLaunch,\n getGraph(unit[i]),\n stackForLaunch,\n payload[i],\n forkPageForLaunch,\n meta,\n )\n }\n } else {\n pushFirstHeapItem(\n 'pure',\n pageForLaunch,\n getGraph(unit),\n stackForLaunch,\n payload,\n forkPageForLaunch,\n meta,\n )\n }\n if (upsert && !isRoot) return\n /** main execution code */\n const lastStartedState = {\n isRoot,\n currentPage,\n scope: forkPage,\n isWatch,\n isPure,\n }\n isRoot = false\n let stop: boolean\n let skip: boolean\n let node: Node\n let value: Layer | undefined\n let page: Leaf | null\n let reg: Record<string, StateRef> | undefined\n kernelLoop: while ((value = deleteMin())) {\n const {idx, stack, type} = value\n node = stack.node\n currentPage = page = stack.page\n forkPage = getForkPage(stack)\n if (page) reg = page.reg\n else if (forkPage) reg = forkPage.reg\n // reg = (page ? page : forkPage ? forkPage : node).reg\n const hasPageReg = !!page\n const hasScopeReg = !!forkPage\n const local: Local = {\n fail: false,\n scope: node.scope,\n }\n stop = skip = false\n for (let stepn = idx; stepn < node.seq.length && !stop; stepn++) {\n const step = node.seq[stepn]\n if (step.order) {\n const {priority, barrierID} = step.order\n const id = barrierID\n ? page\n ? `${page.fullID}_${barrierID}`\n : barrierID\n : 0\n if (stepn !== idx || type !== priority) {\n if (barrierID) {\n if (!barriers.has(id)) {\n barriers.add(id)\n pushHeap(stepn, stack, priority, barrierID)\n }\n } else {\n pushHeap(stepn, stack, priority, 0)\n }\n continue kernelLoop\n }\n barrierID && barriers.delete(id)\n }\n switch (step.type) {\n case 'mov': {\n const data = step.data\n let value\n //prettier-ignore\n switch (data.from) {\n case 'stack': value = getValue(stack); break\n case 'a': /** fall-through case */\n case 'b':\n value = stack[data.from]\n break\n case 'value': value = data.store; break\n case 'store':\n if (reg && !reg[data.store.id]) {\n // if (!page.parent) {\n if (hasPageReg) {\n const pageForRef = getPageForRef(page, data.store.id)\n stack.page = page = pageForRef\n if (pageForRef) {\n reg = pageForRef.reg\n } else if (hasScopeReg) {\n initRefInScope(forkPage!, data.store, false, true, data.softRead)\n reg = forkPage!.reg\n } else {\n reg = undefined //node.reg\n }\n } else if (hasScopeReg) {\n /** StateRef in Scope.reg created only when needed */\n initRefInScope(forkPage!, data.store, false, true, data.softRead)\n } else {\n // console.error('should not happen')\n /** StateRef should exists at least in Node itself, but it is not found */\n }\n // }\n }\n // value = getPageRef(page, forkPage, data.store.id, false).current\n value = readRef(reg ? reg[data.store.id] || data.store : data.store)\n break\n }\n //prettier-ignore\n switch (data.to) {\n case 'stack': stack.value = value; break\n case 'a': /** fall-through case */\n case 'b':\n stack[data.to] = value\n break\n case 'store':\n getPageRef(page, forkPage, data.target, false).current = value\n break\n }\n break\n }\n case 'compute':\n const data = step.data\n if (data.fn) {\n isWatch = node.meta.op === 'watch'\n isPure = data.pure\n const computationResult = data.safe\n ? (0 as any, data.fn)(getValue(stack), local.scope, stack)\n : tryRun(local, data.fn, stack)\n if (data.filter) {\n /**\n * handled edge case: if step.fn will throw,\n * tryRun will return null\n * thereby forcing that branch to stop\n */\n skip = !computationResult\n } else {\n stack.value = computationResult\n }\n isWatch = lastStartedState.isWatch\n isPure = lastStartedState.isPure\n }\n break\n }\n stop = local.fail || skip\n }\n if (inspector) {\n inspector(stack, local)\n }\n if (!stop) {\n const finalValue = getValue(stack)\n const forkPage = getForkPage(stack)\n forEach(node.next, nextNode => {\n pushFirstHeapItem('child', page, nextNode, stack, finalValue, forkPage)\n })\n if (forkPage) {\n if (node.meta.needFxCounter)\n pushFirstHeapItem(\n 'child',\n page,\n forkPage.fxCount,\n stack,\n finalValue,\n forkPage,\n )\n if (node.meta.storeChange)\n pushFirstHeapItem(\n 'child',\n page,\n forkPage.storeChange,\n stack,\n finalValue,\n forkPage,\n )\n if (node.meta.warnSerialize)\n pushFirstHeapItem(\n 'child',\n page,\n forkPage.warnSerializeNode,\n stack,\n finalValue,\n forkPage,\n )\n const additionalLinks = forkPage.additionalLinks[node.id]\n if (additionalLinks) {\n forEach(additionalLinks, nextNode => {\n pushFirstHeapItem(\n 'child',\n page,\n nextNode,\n stack,\n finalValue,\n forkPage,\n )\n })\n }\n }\n }\n }\n isRoot = lastStartedState.isRoot\n currentPage = lastStartedState.currentPage\n forkPage = getForkPage(lastStartedState)\n}\n\nconst noopParser = (x: any) => x\n\nexport const initRefInScope = (\n scope: Scope,\n sourceRef: StateRef,\n isGetState?: boolean,\n isKernelCall?: boolean,\n softRead?: boolean,\n) => {\n const refsMap = scope.reg\n if (refsMap[sourceRef.id]) return\n const sid = sourceRef.sid\n const ref: StateRef = {\n id: sourceRef.id,\n current: sourceRef.initial!,\n meta: sourceRef.meta,\n }\n\n if (ref.id in scope.values.idMap) {\n ref.current = scope.values.idMap[ref.id]\n } else if (sid && sid in scope.values.sidMap && !(sid in scope.sidIdMap)) {\n const serialize = sourceRef?.meta?.serialize\n const parser =\n scope.fromSerialize && serialize !== 'ignore'\n ? serialize?.read || noopParser\n : noopParser\n ref.current = parser(scope.values.sidMap[sid])\n } else {\n if (sourceRef.before && !softRead) {\n let isFresh = false\n const needToAssign = isGetState || !sourceRef.noInit || isKernelCall\n forEach(sourceRef.before, cmd => {\n switch (cmd.type) {\n case 'map': {\n const from = cmd.from\n if (from || cmd.fn) {\n if (from) initRefInScope(scope, from, isGetState, isKernelCall)\n if (needToAssign) {\n const value = from && refsMap[from.id].current\n ref.current = cmd.fn ? cmd.fn(value) : value\n }\n }\n break\n }\n case 'field': {\n initRefInScope(scope, cmd.from, isGetState, isKernelCall)\n if (!isFresh) {\n isFresh = true\n if (Array.isArray(ref.current)) {\n ref.current = [...ref.current]\n } else {\n ref.current = {...ref.current}\n }\n }\n if (needToAssign) {\n const from = refsMap[cmd.from.id]\n ref.current[cmd.field] = refsMap[from.id].current\n }\n break\n }\n // case 'closure':\n // break\n }\n })\n }\n }\n if (sid) scope.sidIdMap[sid] = sourceRef.id\n refsMap[sourceRef.id] = ref\n}\n\n/** try catch for external functions */\nconst tryRun = (local: Local, fn: Function, stack: Stack) => {\n try {\n return fn(getValue(stack), local.scope, stack)\n } catch (err) {\n console.error(err)\n local.fail = true\n local.failReason = err\n }\n}\n","import type {Store, CommonUnit, Domain} from './unit.h'\nimport {is} from './is'\nimport {getParent, getCompositeName} from './getter'\nimport {forIn} from './collection'\n\nexport function unitObjectName(objOrArr: any, method: string = 'combine') {\n let name = method + '('\n let comma = ''\n let i = 0\n forIn(objOrArr, unit => {\n /* inlined max object names constant */\n if (i < 25) {\n if (unit != null) {\n name += comma\n name += is.unit(unit)\n ? getCompositeName(unit as CommonUnit | Domain).fullName\n : (unit as any).toString()\n }\n i += 1\n comma = ', '\n }\n })\n return name + ')'\n}\n\nexport function setStoreName<State>(store: Store<State>, rawName: string) {\n store.shortName = rawName\n Object.assign(getCompositeName(store), createName(rawName, getParent(store)))\n}\n\nexport type CompositeName = {\n shortName: string\n fullName: string\n path: string[]\n}\n\nexport function createName(name: string, parent?: Domain): CompositeName {\n let path: string[]\n let fullName\n const shortName = name\n if (!parent) {\n path = name.length === 0 ? [] : [name]\n fullName = name\n } else {\n const composite = getCompositeName(parent)\n if (name.length === 0) {\n path = composite.path\n fullName = composite.fullName\n } else {\n path = composite.path.concat([name])\n fullName =\n composite.fullName.length === 0\n ? name\n : '' + composite.fullName + '/' + name\n }\n }\n return {shortName, fullName, path}\n}\n\nexport function generateErrorTitle(method: string, metadata: any) {\n if (!metadata) return method\n if (!metadata.name && !metadata.named && !metadata.loc) return method\n let result = `[${method}]`\n const name = metadata.named || metadata.name\n if (name) {\n result += ` unit '${name}'`\n }\n const loc = metadata.loc\n if (!name && loc) {\n result += ` (${loc.file}:${loc.line}:${loc.column})`\n }\n return result\n}\n","import {forIn} from './collection'\nimport {assertObject, isObject, isVoid} from './is'\n\nexport function processArgsToConfig(\n arg: any,\n singleArgument: true,\n): [any, any | void]\nexport function processArgsToConfig(args: any[]): [any[], any | void]\nexport function processArgsToConfig(\n args: any[],\n singleArgument?: boolean,\n): [any[], any | void] {\n const rawConfig = singleArgument ? args : args[0]\n assertObject(rawConfig)\n let metadata = rawConfig.or\n const childConfig = rawConfig.and\n if (childConfig) {\n const unwrappedNestedValue = singleArgument ? childConfig : childConfig[0]\n /**\n * if there is no \"and\" field then we reached the leaf of the tree\n * and this is an original user-defined argument\n *\n * note that in this case we're returning all arguments, not the only one been unwrapped\n **/\n if (!isObject(unwrappedNestedValue) || !('and' in unwrappedNestedValue)) {\n args = childConfig\n } else {\n //@ts-expect-error\n const nested = processArgsToConfig(childConfig, singleArgument)\n\n args = nested[0]\n metadata = {...metadata, ...nested[1]}\n }\n }\n return [args, metadata]\n}\n\n/**\nprocessed fields:\n\n'name',\n'sid',\n'loc',\n'handler',\n'updateFilter',\n'parent',\n'serialize',\n'named',\n'derived',\n*/\nexport const flattenConfig = (part: any, config: Record<string, any> = {}) => {\n if (isObject(part)) {\n flattenConfig(part.or, config)\n forIn(part, (value, field) => {\n if (!isVoid(value) && field !== 'or' && field !== 'and') {\n config[field] = value\n }\n })\n flattenConfig(part.and, config)\n }\n return config\n}\n","import type {Subscription, NodeUnit} from './index.h'\nimport {clearNode} from './clearNode'\n\nexport const createSubscription = (node: NodeUnit): Subscription =>\n addUnsubscribe(() => clearNode(node))\n\nexport function addUnsubscribe(callback: () => void): Subscription {\n const subscription: Subscription = () => callback()\n subscription.unsubscribe = () => callback()\n\n return subscription\n}\n","import {readTemplate} from './region'\nimport type {Template, TemplateHandlers} from '../forest/index.h'\n\nexport function applyTemplate<K extends keyof TemplateHandlers>(\n method: K,\n ...args: Parameters<TemplateHandlers[K]> extends [Template, ...infer Args]\n ? Args\n : never\n): ReturnType<TemplateHandlers[K]> | void {\n const template = readTemplate()\n if (template) {\n const fn = template.handlers[method]\n // @ts-expect-error\n if (fn) return fn(template, ...args)\n }\n}\n","import type {Template} from '../forest/index.h'\nimport type {Store, Event, CommonUnit, Effect} from './unit.h'\nimport type {Subscriber, Config, Cmd, Kind} from './index.h'\n\nimport {observableSymbol} from './observable'\n\nimport {\n is,\n isObject,\n isFunction,\n assertObject,\n assertNodeSet,\n isVoid,\n} from './is'\nimport {calc, mov, read, userFnCall} from './step'\nimport {createStateRef, readRef, addRefOp} from './stateRef'\nimport {nextUnitID} from './id'\nimport {callStackAReg, callARegStack, callStack} from './caller'\nimport {own} from './own'\nimport {createNode} from './createNode'\nimport {\n launch,\n currentPage,\n forkPage,\n setCurrentPage,\n initRefInScope,\n isPure,\n} from './kernel'\n\nimport {createName, generateErrorTitle} from './naming'\nimport {createLinkNode} from './forward'\nimport {watchUnit} from './watch'\nimport {readTemplate, readSidRoot, reportDeclaration} from './region'\nimport {getStoreState, getGraph, getParent, setMeta, getMeta} from './getter'\nimport {assert, deprecate, printErrorWithNodeDetails} from './throw'\nimport {DOMAIN, STORE, EVENT, MAP, STACK, REG_A} from './tag'\nimport {applyTemplate} from './template'\nimport {forEach} from './collection'\nimport {flattenConfig} from './config'\nimport {clearNode} from './clearNode'\nimport {debugTracesEnabled} from './debug_traces'\n\nexport const applyParentHook = (\n source: CommonUnit,\n target: CommonUnit,\n hookType: 'event' | 'effect' = EVENT,\n) => {\n if (getParent(source)) getParent(source).hooks[hookType](target)\n}\n\nexport const setUnitTrace = (unit: any, unitTrace: string) =>\n setMeta(unit, 'unitTrace', unitTrace)\n\nexport const getUnitTrace = (caller: (...args: any[]) => void) => {\n if (!debugTracesEnabled()) return ''\n\n const traceError = Error('unit trace')\n if (Error.captureStackTrace) {\n Error.captureStackTrace(traceError, caller)\n }\n return traceError.stack!\n}\n\nexport const initUnit = (\n kind: Kind,\n unit: any,\n rawConfig: any,\n unitTrace: string,\n) => {\n const config = flattenConfig(rawConfig)\n const isDomain = kind === DOMAIN\n const id = nextUnitID()\n const {sid = null, named = null, domain = null, parent = domain} = config\n const name = named ? named : config.name || (isDomain ? '' : id)\n const compositeName = createName(name, parent)\n const meta: Record<string, any> = {\n op: (unit.kind = kind),\n name: (unit.shortName = name),\n sid: (unit.sid = readSidRoot(sid)),\n named,\n unitId: (unit.id = id),\n serialize: config.serialize,\n derived: config.derived,\n config,\n unitTrace,\n }\n unit.targetable = !config.derived\n unit.parent = parent\n unit.compositeName = compositeName\n unit.defaultConfig = config\n unit.getType = () => {\n deprecate(false, 'getType', 'compositeName.fullName')\n return compositeName.fullName\n }\n if (!isDomain) {\n unit.subscribe = (observer: Subscriber<any>) => {\n assertObject(observer)\n return unit.watch(\n isFunction(observer)\n ? observer\n : (upd: any) => observer.next && observer.next(upd),\n )\n }\n unit[observableSymbol] = () => unit\n const template = readTemplate()\n if (template) meta.nativeTemplate = template\n }\n return meta\n}\nexport const createNamedEvent = (named: string) => createEvent({named})\n\nconst deriveEvent = (\n event: Event<any>,\n op: 'map' | 'filterMap' | 'filter',\n fn: Function,\n node: Cmd[],\n) => {\n let config\n if (isObject(fn)) {\n config = fn\n fn = (fn as unknown as {fn: Function}).fn\n }\n const mapped = createEvent({\n name: `${event.shortName} → *`,\n derived: true,\n and: config,\n })\n createLinkNode(event, mapped, node, op, fn)\n return mapped\n}\n\nfunction callCreate<T>(\n unit: Event<T> | Effect<T, any, any>,\n template: Template | null,\n payload: T,\n args: any[],\n) {\n const oldPage = currentPage\n let page = null\n if (template) {\n page = currentPage\n while (page && page.template !== template) {\n page = getParent(page)\n }\n }\n setCurrentPage(page)\n const result = unit.create(payload, args)\n setCurrentPage(oldPage)\n return result\n}\n\nexport function createEvent<Payload = any>(\n nameOrConfig?: any,\n maybeConfig?: any,\n): Event<Payload> {\n const config = flattenConfig({\n or: maybeConfig,\n and: typeof nameOrConfig === 'string' ? {name: nameOrConfig} : nameOrConfig,\n }) as any\n const errorTitle = generateErrorTitle('event', config)\n const event = ((payload: Payload, ...args: unknown[]) => {\n assert(\n !getMeta(event, 'derived'),\n 'call of derived event is not supported, use createEvent instead',\n errorTitle,\n )\n assert(\n !isPure,\n 'unit call from pure function is not supported, use operators like sample instead',\n errorTitle,\n )\n if (currentPage) {\n return callCreate(event, template, payload, args)\n }\n return event.create(payload, args)\n }) as Event<Payload>\n const template = readTemplate()\n const finalEvent = Object.assign(event, {\n graphite: createNode({\n meta: initUnit(\n config.actualOp || EVENT,\n event,\n config,\n getUnitTrace(createEvent),\n ),\n regional: true,\n }),\n create(params: Payload, _: any[]) {\n launch({target: event, params, scope: forkPage!})\n return params\n },\n watch: (fn: (payload: Payload) => any) => watchUnit(event, fn),\n map: (fn: Function) => deriveEvent(event, MAP, fn, [userFnCall()]),\n filter: (fn: {fn: Function}) =>\n //@ts-expect-error\n deriveEvent(event, 'filter', fn.fn ? fn : fn.fn, [\n userFnCall(callStack, true),\n ]),\n filterMap: (fn: Function) =>\n deriveEvent(event, 'filterMap', fn, [\n userFnCall(),\n calc(value => !isVoid(value), true),\n ]),\n prepend(fn: Function) {\n assert(\n // @ts-expect-error\n event.targetable,\n '.prepend of derived event is not supported, call source event instead',\n errorTitle,\n )\n const contramapped: Event<any> = createEvent('* → ' + event.shortName, {\n parent: getParent(event),\n })\n applyTemplate('eventPrepend', getGraph(contramapped))\n createLinkNode(contramapped, event, [userFnCall()], 'prepend', fn)\n applyParentHook(event, contramapped)\n return contramapped\n },\n })\n if (config?.domain) {\n config.domain.hooks.event(finalEvent)\n }\n setMeta(finalEvent, 'id', finalEvent.graphite.id)\n reportDeclaration(finalEvent.graphite)\n return finalEvent\n}\nfunction on<State>(\n store: Store<State>,\n methodName: string,\n nodeSet: CommonUnit | CommonUnit[],\n fn: Function,\n errorTitle: string,\n) {\n assertNodeSet(nodeSet, `${errorTitle} ${methodName}`, 'first argument')\n assert(isFunction(fn), 'second argument should be a function', errorTitle)\n deprecate(\n !getMeta(store, 'derived'),\n `${methodName} in derived store`,\n `${methodName} in store created via createStore`,\n errorTitle,\n )\n forEach(Array.isArray(nodeSet) ? nodeSet : [nodeSet], trigger => {\n store.off(trigger)\n updateStore(trigger, store, 'on', callARegStack, fn)\n })\n return store\n}\n\nexport const requireExplicitSkipVoidMessage =\n 'undefined is used to skip updates. To allow undefined as a value provide explicit { skipVoid: false } option'\n\nexport function createStore<State>(\n defaultState: State,\n props?: Config,\n): Store<State> {\n const config = flattenConfig(props)\n const plainState = createStateRef(defaultState)\n const errorTitle = generateErrorTitle('store', config)\n const updates = createEvent({named: 'updates', derived: true})\n applyTemplate('storeBase', plainState)\n const plainStateId = plainState.id\n\n // skipVoid deprecation rules\n const explicitSkipVoid = 'skipVoid' in config\n const voidValueAllowed = explicitSkipVoid && !config.skipVoid\n const skipVoidTrueSet = explicitSkipVoid && config.skipVoid\n\n deprecate(!skipVoidTrueSet, '{skipVoid: true}', 'updateFilter', errorTitle)\n\n const store = {\n updates,\n defaultState,\n stateRef: plainState,\n getState() {\n let targetRef = plainState\n let reachedPage\n if (currentPage) {\n let page = currentPage\n while (page && !page.reg[plainStateId]) {\n page = getParent(page)\n }\n if (page) reachedPage = page\n }\n if (!reachedPage && forkPage) {\n initRefInScope(forkPage, plainState, true)\n reachedPage = forkPage\n }\n if (reachedPage) targetRef = reachedPage.reg[plainStateId]\n return readRef(targetRef)\n },\n setState: (state: State) =>\n launch({\n target: store,\n params: state,\n defer: true,\n scope: forkPage!,\n }),\n reset(...units: CommonUnit[]) {\n assert(\n // @ts-expect-error\n store.targetable,\n '.reset of derived store is not supported',\n errorTitle,\n )\n forEach(units, unit =>\n on(store, '.reset', unit, () => store.defaultState, errorTitle),\n )\n return store\n },\n on(nodeSet: CommonUnit | CommonUnit[], fn: Function) {\n assert(\n // @ts-expect-error\n store.targetable,\n '.on of derived store is not supported',\n errorTitle,\n )\n return on(store, '.on', nodeSet, fn, errorTitle)\n },\n off(unit: CommonUnit) {\n const triggerUnitId = getGraph(unit).id\n const oldLink = getGraph(store).family.links.find(\n e => e.meta.onTrigger === triggerUnitId,\n )\n if (oldLink) {\n clearNode(oldLink)\n }\n return store\n },\n map(fn: (value: any) => any, outerConfig: Config) {\n let mapConfig: Config | undefined\n if (isObject(fn)) {\n mapConfig = fn as any\n fn = (fn as unknown as {fn: (value: any) => any}).fn\n }\n let lastResult\n const storeState = store.getState()\n const parentStateVoid = isVoid(storeState)\n const template = readTemplate()\n if (template) {\n lastResult = null\n } else if (!parentStateVoid || (parentStateVoid && voidValueAllowed)) {\n lastResult = fn(storeState)\n }\n\n const innerStore: Store<any> = createStore(lastResult, {\n name: `${store.shortName} → *`,\n derived: true,\n ...outerConfig,\n and: mapConfig,\n })\n const linkNode = updateStore(store, innerStore, MAP, callStack, fn)\n addRefOp(getStoreState(innerStore), {\n type: MAP,\n fn,\n from: plainState,\n })\n getStoreState(innerStore).noInit = true\n applyTemplate('storeMap', plainState, linkNode)\n return innerStore\n },\n watch(eventOrFn: any, fn?: Function) {\n deprecate(!fn, 'watch second argument', 'sample', errorTitle)\n if (!fn || !is.unit(eventOrFn)) {\n const subscription = watchUnit(store, eventOrFn)\n if (!applyTemplate('storeWatch', plainState, eventOrFn)) {\n eventOrFn(store.getState())\n }\n return subscription\n }\n assert(isFunction(fn), 'second argument should be a function', errorTitle)\n return (eventOrFn as CommonUnit).watch((payload: any) =>\n fn(store.getState(), payload),\n )\n },\n } as unknown as Store<State>\n const meta = initUnit(STORE, store, config, getUnitTrace(createStore))\n const updateFilter = store.defaultConfig.updateFilter\n store.graphite = createNode({\n scope: {state: plainState, fn: updateFilter},\n node: [\n calc((upd, _, stack) => {\n if (stack.scope && !stack.scope.reg[plainState.id]) {\n stack.b = true\n }\n return upd\n }),\n read(plainState),\n calc((upd, _, {a, b}) => {\n const isVoidUpdate = isVoid(upd)\n\n if (isVoidUpdate && !explicitSkipVoid) {\n printErrorWithNodeDetails(\n `${requireExplicitSkipVoidMessage}`,\n store.graphite,\n )\n }\n\n return (\n ((isVoidUpdate && voidValueAllowed) || !isVoidUpdate) &&\n (upd !== a || b)\n )\n }, true),\n updateFilter && userFnCall(callStackAReg, true),\n mov({from: STACK, target: plainState}),\n ],\n child: updates,\n meta: {\n ...meta,\n defaultState,\n stateRef: plainState,\n },\n regional: true,\n })\n setMeta(store, 'id', store.graphite.id)\n setMeta(store, 'rootStateRefId', plainStateId)\n const serializeMeta = getMeta(store, 'serialize')\n const derived = getMeta(store, 'derived')\n const ignored = serializeMeta === 'ignore'\n const sid: string | null = getMeta(store, 'sid')\n if (sid) {\n setMeta(store, 'storeChange', true)\n plainState.sid = sid\n }\n if (!sid && !ignored && !derived) {\n setMeta(store, 'warnSerialize', true)\n }\n const isVoidDefaultState = isVoid(defaultState)\n const canVoid = isVoidDefaultState && voidValueAllowed\n assert(\n derived || !isVoidDefaultState || canVoid,\n requireExplicitSkipVoidMessage,\n errorTitle,\n )\n if (derived && isVoidDefaultState && !explicitSkipVoid) {\n console.error(`${errorTitle}: ${requireExplicitSkipVoidMessage}`)\n }\n own(store, [updates])\n if (config?.domain) {\n config.domain.hooks.store(store)\n }\n\n if (!derived) {\n store.reinit = createEvent<void>({\n named: 'reinit',\n })\n store.reset(store.reinit)\n }\n\n plainState.meta = store.graphite.meta\n\n reportDeclaration(store.graphite)\n\n return store\n}\n\nconst updateStore = (\n from: CommonUnit,\n store: Store<any>,\n op: string,\n caller: typeof callStackAReg,\n fn: Function,\n) => {\n const storeRef = getStoreState(store)\n const reader = mov({\n store: storeRef,\n to: REG_A,\n priority: 'read',\n })\n /**\n * Store reading is not needed for store.map anymore\n * but there is a fine tuning of \"wire lengths\"\n * lack of which leads to a lot of reordering and retriggering issues\n **/\n if (op === MAP) reader.data.softRead = true\n const node = [reader, userFnCall(caller)]\n applyTemplate(\n 'storeOnMap',\n storeRef,\n node,\n is.store(from) && getStoreState(from),\n )\n const result = createLinkNode(from, store, node, op, fn)\n if (op !== MAP) {\n setMeta(result, 'onTrigger', getGraph(from).id)\n }\n return result\n}\n","import type {Store} from './unit.h'\nimport {\n createStore,\n getUnitTrace,\n requireExplicitSkipVoidMessage,\n setUnitTrace,\n} from './createUnit'\nimport {createStateRef, addRefOp} from './stateRef'\nimport {mov, calc, read, userFnCall} from './step'\nimport {processArgsToConfig} from './config'\nimport {getStoreState, setMeta} from './getter'\nimport {is, isFunction, isObject, isVoid} from './is'\nimport {generateErrorTitle, unitObjectName} from './naming'\nimport {createLinkNode} from './forward'\nimport {assert} from './throw'\nimport {readTemplate} from './region'\nimport {forIn} from './collection'\nimport {MAP, REG_A, VALUE} from './tag'\nimport {applyTemplate} from './template'\nimport type {Config} from './index.h'\nimport {createNode} from './createNode'\nimport {own} from './own'\n\nexport function combine(...args: any[]): Store<any> {\n let handler\n let stores\n let config\n ;[args, config] = processArgsToConfig(args)\n const errorTitle = generateErrorTitle('combine', config)\n // skipVoid support, to be removed in effector 24\n const maybeExtConfig = args[args.length - 1]\n /**\n * if there only one argument then it's a store or object with stores\n * else if last argument is a store, then its `combine($foo, $bar)`\n * else if last argument is not an object, then it's a handler\n * else it's a config object\n */\n const isExtendedConfig =\n args.length > 1 && !is.store(maybeExtConfig) && isObject(maybeExtConfig)\n const extConfig = isExtendedConfig && maybeExtConfig\n const rawHandler = isExtendedConfig ? args[args.length - 2] : maybeExtConfig\n if (isFunction(rawHandler)) {\n stores = args.slice(0, isExtendedConfig ? -2 : -1)\n handler = rawHandler\n } else {\n stores = args\n }\n\n let structStoreShape\n let shapeReady\n if (stores.length === 1) {\n const obj = stores[0]\n /*\n without edge case combine(Color, (Color) => '~')\n */\n if (!is.store(obj)) {\n /*\n case combine([R,G,B], ([R,G,B]) => '~')\n case combine({R,G,B}, ({R,G,B}) => '~')\n\n edge case combine([Color], ([Color]) => '~')\n edge case combine({Color}, ({Color}) => '~')\n\n edge case combine([R,G,B])\n edge case combine({R,G,B})\n\n edge case combine([Color])\n edge case combine({Color})\n */\n structStoreShape = obj\n shapeReady = true\n }\n }\n let noArraySpread: boolean | undefined\n if (!shapeReady) {\n /*\n case combine(R,G,B, (R,G,B) => '~')\n */\n structStoreShape = stores\n /*\n without edge case combine(R,G,B)\n without edge case combine(Color)\n */\n if (handler) {\n noArraySpread = true\n const fn = handler\n handler = (list: any[]) => fn(...list)\n }\n }\n assert(isObject(structStoreShape), `${errorTitle}: shape should be an object`)\n return storeCombination(\n Array.isArray(structStoreShape),\n !noArraySpread,\n structStoreShape,\n getUnitTrace(combine),\n config,\n handler,\n extConfig,\n )\n}\n\nconst storeCombination = (\n isArray: boolean,\n needSpread: boolean,\n obj: any,\n unitTrace: string,\n config?: Config,\n fn?: (upd: any) => any,\n extConfig?: false | {skipVoid?: boolean},\n) => {\n const errorTitle = generateErrorTitle('combine', config)\n const clone = isArray ? (list: any) => [...list] : (obj: any) => ({...obj})\n const defaultState: Record<string, any> = isArray ? [] : {}\n\n const stateNew = clone(defaultState)\n const rawShape = createStateRef(stateNew)\n const isFresh = createStateRef(true)\n rawShape.type = isArray ? 'list' : 'shape'\n rawShape.noInit = true\n applyTemplate('combineBase', rawShape, isFresh)\n const store = createStore(stateNew, {\n name: unitObjectName(obj),\n derived: true,\n ...extConfig,\n and: config,\n })\n setUnitTrace(store, unitTrace)\n const storeStateRef = getStoreState(store)\n storeStateRef.noInit = true\n setMeta(store, 'isCombine', true)\n /**\n * Easiest way to clean orphaned stateRefs which participate in initialization graph\n * (has `addRefOp` calls).\n * If you need to distinguish these nodes during graph analysis,\n * note that they are not regional\n * (because they belong explicitly to the unit) which is pretty uncommon\n */\n own(store, [createNode({meta: {stateRef: rawShape}})])\n const rawShapeReader = read(rawShape)\n /**\n * usual ref reading has very high priority, which leads to data races\n * ref reading for combine should have same \"barrier\" priority but without batching\n * (thats why order has no \"barrierID\" field, which assume batching)\n **/\n rawShapeReader.order = {priority: 'barrier'}\n /**\n * Soft store reading is required for\n * setting target store as inited in scope\n * for preventing retriggering issues\n **/\n const softReader = mov({\n store: storeStateRef,\n to: 'b',\n priority: 'read',\n })\n softReader.data.softRead = true\n const node = [\n calc((upd, _, stack) => {\n if (stack.scope && !stack.scope.reg[rawShape.id]) {\n stack.c = true\n }\n return upd\n }),\n rawShapeReader,\n mov({store: isFresh, to: 'b'}),\n calc((upd, {key}, reg) => {\n if (reg.c || upd !== reg.a[key]) {\n if (needSpread && reg.b) {\n reg.a = clone(reg.a)\n }\n reg.a[key] = upd\n return true\n }\n }, true),\n mov({from: REG_A, target: rawShape}),\n mov({from: VALUE, store: false, target: isFresh}),\n mov({\n from: VALUE,\n store: true,\n target: isFresh,\n priority: 'barrier',\n batch: true,\n }),\n /**\n * `read` with `sampler` priority is used to prevent cases,\n * where `combine` triggers are duplicated\n *\n * basically, this makes `sample` and `combine` priorities equal\n */\n read(rawShape, true, true),\n fn && userFnCall(),\n softReader,\n ]\n forIn(obj, (child: Store<any> | any, key) => {\n if (!is.store(child)) {\n assert(\n !is.unit(child) && !isVoid(child),\n `combine expects a store in a field ${key}`,\n errorTitle,\n )\n stateNew[key] = defaultState[key] = child\n return\n }\n defaultState[key] = child.defaultState\n stateNew[key] = child.getState()\n const linkNode = createLinkNode(child, store, node, 'combine', fn)\n linkNode.scope.key = key\n const childRef = getStoreState(child)\n addRefOp(rawShape, {type: 'field', field: key, from: childRef})\n applyTemplate('combineField', childRef, linkNode)\n })\n\n store.defaultShape = obj\n setMeta(store, 'defaultShape', obj)\n addRefOp(storeStateRef, {\n type: MAP,\n from: rawShape,\n fn,\n })\n if (!readTemplate()) {\n if (fn) {\n const computedValue = fn(stateNew)\n\n if (isVoid(computedValue) && (!extConfig || !('skipVoid' in extConfig))) {\n console.error(`${errorTitle}: ${requireExplicitSkipVoidMessage}`)\n }\n\n storeStateRef.current = computedValue\n storeStateRef.initial = computedValue\n store.defaultState = computedValue\n } else {\n store.defaultState = defaultState\n }\n }\n return store\n}\n","import type {Defer} from './unit.h'\n\nexport function createDefer(): Defer {\n const result = {} as Defer\n result.req = new Promise((rs, rj) => {\n result.rs = rs\n result.rj = rj\n })\n result.req.catch(() => {})\n return result\n}\n","import type {Unit, Stack} from './index.h'\nimport type {Effect} from './unit.h'\nimport {calc, run} from './step'\nimport {getForkPage, getGraph, getMeta, getParent, setMeta} from './getter'\nimport {own} from './own'\nimport {createNode} from './createNode'\nimport {launch, setForkPage, forkPage, isWatch} from './kernel'\nimport {\n createStore,\n createEvent,\n setUnitTrace,\n getUnitTrace,\n} from './createUnit'\nimport {createDefer} from './defer'\nimport {isObject, isFunction} from './is'\nimport {assert} from './throw'\nimport {EFFE