@manyducks.co/dolla 2.0.0-alpha.64 → 2.0.0-alpha.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/core/app.d.ts +24 -0
  2. package/dist/core/index.d.ts +3 -2
  3. package/dist/core/markup.d.ts +9 -1
  4. package/dist/core/nodes/element.d.ts +1 -0
  5. package/dist/core/scheduler.d.ts +12 -4
  6. package/dist/core/signals.d.ts +10 -9
  7. package/dist/core/views/portal.d.ts +17 -0
  8. package/dist/hooks/index.d.ts +21 -5
  9. package/dist/hooks.js +27 -21
  10. package/dist/hooks.js.map +1 -1
  11. package/dist/http.js +1 -1
  12. package/dist/i18n.js +3 -3
  13. package/dist/index-BEDDzyd9.js +556 -0
  14. package/dist/index-BEDDzyd9.js.map +1 -0
  15. package/dist/index.js +125 -70
  16. package/dist/index.js.map +1 -1
  17. package/dist/jsx-dev-runtime.js +1 -1
  18. package/dist/jsx-runtime.js +1 -1
  19. package/dist/{logger-B7RBYtzP.js → logger-CmXtRdEI.js} +7 -7
  20. package/dist/{logger-B7RBYtzP.js.map → logger-CmXtRdEI.js.map} +1 -1
  21. package/dist/markup-DjDexAN5.js +1179 -0
  22. package/dist/markup-DjDexAN5.js.map +1 -0
  23. package/dist/router/hooks.d.ts +2 -0
  24. package/dist/router/index.d.ts +1 -0
  25. package/dist/router/router.d.ts +1 -0
  26. package/dist/router.js +3 -5
  27. package/dist/router.js.map +1 -1
  28. package/dist/{signals-DbDmN2gr.js → signals-CkfFHd0d.js} +264 -255
  29. package/dist/signals-CkfFHd0d.js.map +1 -0
  30. package/dist/typeChecking-_dGK_0uR.js +62 -0
  31. package/dist/{typeChecking-CbltMOUt.js.map → typeChecking-_dGK_0uR.js.map} +1 -1
  32. package/dist/utils.d.ts +5 -0
  33. package/docs/components.md +21 -0
  34. package/docs/hooks.md +3 -3
  35. package/docs/signals.md +67 -53
  36. package/docs/stores.md +13 -4
  37. package/package.json +4 -4
  38. package/dist/core/mount.d.ts +0 -15
  39. package/dist/core/mount.test.d.ts +0 -0
  40. package/dist/markup-DeZDwQ9F.js +0 -1117
  41. package/dist/markup-DeZDwQ9F.js.map +0 -1
  42. package/dist/router-C35XmU3k.js +0 -543
  43. package/dist/router-C35XmU3k.js.map +0 -1
  44. package/dist/signals-DbDmN2gr.js.map +0 -1
  45. package/dist/typeChecking-CbltMOUt.js +0 -71
  46. package/docs/state.md +0 -141
  47. package/examples/webcomponent/index.html +0 -14
  48. package/examples/webcomponent/main.js +0 -165
  49. package/notes/TODO.md +0 -6
  50. package/notes/context-routes.md +0 -61
  51. package/notes/custom-nodes.md +0 -17
  52. package/notes/effection-idea.md +0 -34
  53. package/notes/mixins.md +0 -22
  54. package/notes/molecule.md +0 -35
  55. package/notes/readme-scratch.md +0 -260
  56. package/notes/route-middleware.md +0 -42
  57. package/notes/stores.md +0 -79
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals-CkfFHd0d.js","sources":["../src/utils.ts","../src/core/env.ts","../node_modules/alien-signals/esm/system.mjs","../src/core/signals.ts"],"sourcesContent":["import { isFunction, isObject, typeOf } from \"./typeChecking.js\";\n\nexport const noOp = () => {};\n\n// Guarantee unique ID by incrementing a global counter.\nlet idCounter = 1;\nexport function getUniqueId(): string {\n idCounter = (idCounter % Number.MAX_SAFE_INTEGER) + 1;\n return idCounter.toString(36) + Date.now().toString(36);\n}\n\nlet intCounter = 0;\nexport function getIntegerId(): number {\n intCounter = (intCounter % Number.MAX_SAFE_INTEGER) + 1;\n return intCounter;\n}\n\n/*=============================*\\\n|| Object Equality ||\n\\*=============================*/\n\n/**\n * Equality check that passes if both values are the same object.\n * This is the default equality check for states.\n */\nexport function strictEqual(a: any, b: any): boolean {\n return Object.is(a, b);\n}\n\n/**\n * Equality check that passes if both values are the same object, or if both are objects or arrays with equal keys and values.\n */\nexport function shallowEqual(a: any, b: any): boolean {\n if (Object.is(a, b)) return true;\n\n // Must be same type\n const t = typeOf(a);\n if (t !== typeOf(b)) {\n return false;\n }\n\n switch (t) {\n case \"object\":\n // Objects must have same number of keys with strict equal values\n let size = 0;\n for (const key in a) {\n if (a[key] !== b[key]) return false;\n size++;\n }\n return Object.keys(b).length === size;\n case \"array\":\n // Arrays must be the same length with strict equal values\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n case \"map\":\n if (a.size !== b.size) return false;\n for (const key of a.keys()) {\n if (a[key] !== b[key]) return false;\n }\n return true;\n case \"set\":\n if (isFunction(a.symmetricDifference)) {\n return a.symmetricDifference(b).size === 0;\n } else {\n for (const key of a.keys()) {\n if (a[key] !== b.get(key)) return false;\n }\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Equality check that passes if two objects have equal values, even if they are not the same object.\n */\n// NOTE: This code is https://github.com/epoberezkin/fast-deep-equal licensed under MIT.\n// I imported it because I couldn't get the old school module to play nice with my modern ES code as an external dependency.\nexport function deepEqual(a: any, b: any): boolean {\n if (a === b) return true;\n\n if (a && b && typeof a == \"object\" && typeof b == \"object\") {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0; ) if (!deepEqual(a[i], b[i])) return false;\n return true;\n }\n\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (i of a.entries()) if (!b.has(i[0])) return false;\n for (i of a.entries()) if (!deepEqual(i[1], b.get(i[0]))) return false;\n return true;\n }\n\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n for (i of a.entries()) if (!b.has(i[0])) return false;\n return true;\n }\n\n if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {\n length = (a as any).length;\n if (length != (b as any).length) return false;\n for (i = length; i-- !== 0; ) if ((a as any)[i] !== (b as any)[i]) return false;\n return true;\n }\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0; ) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0; ) {\n var key = keys[i];\n\n if (!deepEqual(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a !== a && b !== b;\n}\n\n/*=============================*\\\n|| Object Utils ||\n\\*=============================*/\n\n/**\n * Takes an old value and a new value. Returns a merged copy if both are objects, otherwise returns the new value.\n */\nexport function merge(one: unknown, two: unknown) {\n if (isObject(one)) {\n if (!isObject(two)) {\n return two;\n }\n\n const merged = Object.assign({}, one) as any;\n\n for (const key in two) {\n merged[key] = merge(merged[key], two[key]);\n }\n\n return merged;\n } else {\n return two;\n }\n}\n\n/**\n * Returns a new object without the specified keys.\n * If called without object, returns a function that takes an object\n * and returns a version with the original keys omitted.\n *\n * @param keys - An array of keys to omit.\n * @param object - An object to clone without the omitted keys.\n */\nexport function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any> {\n const newObject: Record<any, any> = {};\n\n for (const key in object) {\n if (!keys.includes(key)) {\n newObject[key] = object[key];\n }\n }\n\n return newObject;\n}\n\n/*=============================*\\\n|| Misc Utils ||\n\\*=============================*/\n\nexport function toArray<T>(value: T | T[]): T[] {\n if (Array.isArray(value)) {\n return value;\n } else {\n return [value];\n }\n}\n\nexport function toCamelCase(s: string) {\n return s.replace(/-./g, (x) => x[1].toUpperCase());\n}\n\n// export function deepFreeze<T>(obj: T): T {\n\n// }\n\n/**\n * Moves an element using `moveBefore` if the browser supports it, otherwise falls back to `insertBefore`.\n */\nexport function moveBefore(parent: Node, node: Node, child: Node | null) {\n if (\"moveBefore\" in parent) {\n (parent as any).moveBefore(node, child);\n } else {\n parent.insertBefore(node, child);\n }\n}\n\n/**\n * Takes any string and returns an OKLCH color.\n */\nexport function okhash(value: string) {\n let hue = 0;\n for (let i = 0; i < value.length; i++) {\n hue = (hue + value.charCodeAt(i) * 10) % 360;\n }\n return `oklch(0.68 0.15 ${hue}deg)`;\n}\n\nexport type MatcherFunction = (value: string) => boolean;\n\n/**\n * Parses a filter string into a matcher function.\n *\n * @param pattern - A string or regular expression that specifies a pattern for names of loggers whose messages you want to display.\n */\nexport function createMatcher(pattern: string | RegExp): MatcherFunction {\n if (pattern instanceof RegExp) {\n return (value: string) => pattern.test(value);\n }\n\n const matchers: Record<\"positive\" | \"negative\", MatcherFunction[]> = {\n positive: [],\n negative: [],\n };\n\n const parts = pattern\n .split(\",\")\n .map((p) => p.trim())\n .filter((p) => p !== \"\");\n\n for (let part of parts) {\n let section: \"positive\" | \"negative\" = \"positive\";\n\n if (part.startsWith(\"-\")) {\n section = \"negative\";\n part = part.slice(1);\n }\n\n if (part === \"*\") {\n matchers[section].push(function () {\n return true;\n });\n } else if (part.endsWith(\"*\")) {\n matchers[section].push(function (value) {\n return value.startsWith(part.slice(0, part.length - 1));\n });\n } else {\n matchers[section].push(function (value) {\n return value === part;\n });\n }\n }\n\n return function (name: string) {\n const { positive, negative } = matchers;\n\n // Matching any negative matcher disqualifies.\n if (negative.some((fn) => fn(name))) {\n return false;\n }\n\n // Matching at least one positive matcher is required if any are specified.\n if (positive.length > 0 && !positive.some((fn) => fn(name))) {\n return false;\n }\n\n return true;\n };\n}\n","import type { Env } from \"../types\";\n\nlet currentEnv = \"production\";\n\nexport function getEnv() {\n return currentEnv;\n}\n\nexport function setEnv(value: Env) {\n currentEnv = value;\n}\n","export var ReactiveFlags;\n(function (ReactiveFlags) {\n ReactiveFlags[ReactiveFlags[\"None\"] = 0] = \"None\";\n ReactiveFlags[ReactiveFlags[\"Mutable\"] = 1] = \"Mutable\";\n ReactiveFlags[ReactiveFlags[\"Watching\"] = 2] = \"Watching\";\n ReactiveFlags[ReactiveFlags[\"RecursedCheck\"] = 4] = \"RecursedCheck\";\n ReactiveFlags[ReactiveFlags[\"Recursed\"] = 8] = \"Recursed\";\n ReactiveFlags[ReactiveFlags[\"Dirty\"] = 16] = \"Dirty\";\n ReactiveFlags[ReactiveFlags[\"Pending\"] = 32] = \"Pending\";\n})(ReactiveFlags || (ReactiveFlags = {}));\nexport function createReactiveSystem({ update, notify, unwatched, }) {\n return {\n link,\n unlink,\n propagate,\n checkDirty,\n endTracking,\n startTracking,\n shallowPropagate,\n };\n function link(dep, sub) {\n const prevDep = sub.depsTail;\n if (prevDep !== undefined && prevDep.dep === dep) {\n return;\n }\n let nextDep = undefined;\n const recursedCheck = sub.flags & 4;\n if (recursedCheck) {\n nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps;\n if (nextDep !== undefined && nextDep.dep === dep) {\n sub.depsTail = nextDep;\n return;\n }\n }\n const prevSub = dep.subsTail;\n if (prevSub !== undefined\n && prevSub.sub === sub\n && (!recursedCheck || isValidLink(prevSub, sub))) {\n return;\n }\n const newLink = sub.depsTail\n = dep.subsTail\n = {\n dep,\n sub,\n prevDep,\n nextDep,\n prevSub,\n nextSub: undefined,\n };\n if (nextDep !== undefined) {\n nextDep.prevDep = newLink;\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = newLink;\n }\n else {\n sub.deps = newLink;\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = newLink;\n }\n else {\n dep.subs = newLink;\n }\n }\n function unlink(link, sub = link.sub) {\n const dep = link.dep;\n const prevDep = link.prevDep;\n const nextDep = link.nextDep;\n const nextSub = link.nextSub;\n const prevSub = link.prevSub;\n if (nextDep !== undefined) {\n nextDep.prevDep = prevDep;\n }\n else {\n sub.depsTail = prevDep;\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = nextDep;\n }\n else {\n sub.deps = nextDep;\n }\n if (nextSub !== undefined) {\n nextSub.prevSub = prevSub;\n }\n else {\n dep.subsTail = prevSub;\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = nextSub;\n }\n else if ((dep.subs = nextSub) === undefined) {\n unwatched(dep);\n }\n return nextDep;\n }\n function propagate(link) {\n let next = link.nextSub;\n let stack;\n top: do {\n const sub = link.sub;\n let flags = sub.flags;\n if (flags & 3) {\n if (!(flags & 60)) {\n sub.flags = flags | 32;\n }\n else if (!(flags & 12)) {\n flags = 0;\n }\n else if (!(flags & 4)) {\n sub.flags = (flags & ~8) | 32;\n }\n else if (!(flags & 48) && isValidLink(link, sub)) {\n sub.flags = flags | 40;\n flags &= 1;\n }\n else {\n flags = 0;\n }\n if (flags & 2) {\n notify(sub);\n }\n if (flags & 1) {\n const subSubs = sub.subs;\n if (subSubs !== undefined) {\n link = subSubs;\n if (subSubs.nextSub !== undefined) {\n stack = { value: next, prev: stack };\n next = link.nextSub;\n }\n continue;\n }\n }\n }\n if ((link = next) !== undefined) {\n next = link.nextSub;\n continue;\n }\n while (stack !== undefined) {\n link = stack.value;\n stack = stack.prev;\n if (link !== undefined) {\n next = link.nextSub;\n continue top;\n }\n }\n break;\n } while (true);\n }\n function startTracking(sub) {\n sub.depsTail = undefined;\n sub.flags = (sub.flags & ~56) | 4;\n }\n function endTracking(sub) {\n const depsTail = sub.depsTail;\n let toRemove = depsTail !== undefined ? depsTail.nextDep : sub.deps;\n while (toRemove !== undefined) {\n toRemove = unlink(toRemove, sub);\n }\n sub.flags &= ~4;\n }\n function checkDirty(link, sub) {\n let stack;\n let checkDepth = 0;\n top: do {\n const dep = link.dep;\n const depFlags = dep.flags;\n let dirty = false;\n if (sub.flags & 16) {\n dirty = true;\n }\n else if ((depFlags & 17) === 17) {\n if (update(dep)) {\n const subs = dep.subs;\n if (subs.nextSub !== undefined) {\n shallowPropagate(subs);\n }\n dirty = true;\n }\n }\n else if ((depFlags & 33) === 33) {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack };\n }\n link = dep.deps;\n sub = dep;\n ++checkDepth;\n continue;\n }\n if (!dirty && link.nextDep !== undefined) {\n link = link.nextDep;\n continue;\n }\n while (checkDepth) {\n --checkDepth;\n const firstSub = sub.subs;\n const hasMultipleSubs = firstSub.nextSub !== undefined;\n if (hasMultipleSubs) {\n link = stack.value;\n stack = stack.prev;\n }\n else {\n link = firstSub;\n }\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) {\n shallowPropagate(firstSub);\n }\n sub = link.sub;\n continue;\n }\n }\n else {\n sub.flags &= ~32;\n }\n sub = link.sub;\n if (link.nextDep !== undefined) {\n link = link.nextDep;\n continue top;\n }\n dirty = false;\n }\n return dirty;\n } while (true);\n }\n function shallowPropagate(link) {\n do {\n const sub = link.sub;\n const nextSub = link.nextSub;\n const subFlags = sub.flags;\n if ((subFlags & 48) === 32) {\n sub.flags = subFlags | 16;\n if (subFlags & 2) {\n notify(sub);\n }\n }\n link = nextSub;\n } while (link !== undefined);\n }\n function isValidLink(checkLink, sub) {\n const depsTail = sub.depsTail;\n if (depsTail !== undefined) {\n let link = sub.deps;\n do {\n if (link === checkLink) {\n return true;\n }\n if (link === depsTail) {\n break;\n }\n link = link.nextDep;\n } while (link !== undefined);\n }\n return false;\n }\n}\n","import type { ReactiveFlags, ReactiveNode } from \"alien-signals\";\nimport { createReactiveSystem } from \"alien-signals/system\";\nimport { isFunction } from \"../typeChecking\";\nimport { strictEqual } from \"../utils\";\nimport { Context } from \"./context\";\nimport { getEnv } from \"./env\";\n\nconst enum EffectFlags {\n Queued = 1 << 6,\n}\n\ninterface EffectScope extends ReactiveNode {}\n\ninterface Effect extends ReactiveNode {\n fn(): void | (() => void);\n cleanup?: () => void;\n}\n\ninterface ComputedGetterState<T> {\n value?: T;\n}\n\ninterface Computed<T = any> extends ReactiveNode {\n value: T | undefined;\n getter: (this: ComputedGetterState<T>) => T;\n equals: EqualityFn<T>;\n}\n\ninterface Value<T = any> extends ReactiveNode {\n previousValue: T;\n value: T;\n equals: EqualityFn<T>;\n}\n\nconst queuedEffects: (Effect | EffectScope | undefined)[] = [];\nconst { link, unlink, propagate, checkDirty, endTracking, startTracking, shallowPropagate } = createReactiveSystem({\n update(signal: Value | Computed): boolean {\n if (\"getter\" in signal) {\n return updateComputed(signal);\n } else {\n return updateSignal(signal, signal.value);\n }\n },\n notify,\n unwatched(node: Value | Computed | Effect | EffectScope) {\n if (\"getter\" in node) {\n let toRemove = node.deps;\n if (toRemove !== undefined) {\n node.flags = 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty;\n do {\n toRemove = unlink(toRemove, node);\n } while (toRemove !== undefined);\n }\n } else if (!(\"previousValue\" in node)) {\n _effect.call(node);\n }\n },\n});\n\nlet batchDepth = 0;\n\nlet notifyIndex = 0;\nlet queuedEffectsLength = 0;\nlet activeSub: ReactiveNode | undefined;\nlet activeScope: EffectScope | undefined;\nlet activeContext: Context | undefined;\n\nfunction getCurrentSub(): ReactiveNode | undefined {\n return activeSub;\n}\n\nfunction setCurrentSub(sub: ReactiveNode | undefined) {\n const prevSub = activeSub;\n activeSub = sub;\n return prevSub;\n}\n\nexport function getCurrentContext(): Context | undefined {\n return activeContext;\n}\n\nexport function setCurrentContext(context: Context | undefined) {\n const prevContext = activeContext;\n activeContext = context;\n return prevContext;\n}\n\n// function getCurrentScope(): EffectScope | undefined {\n// return activeScope;\n// }\n\n// function setCurrentScope(scope: EffectScope | undefined) {\n// const prevScope = activeScope;\n// activeScope = scope;\n// return prevScope;\n// }\n\n// export function effectScope(fn: () => void): () => void {\n// const e: EffectScope = {\n// deps: undefined,\n// depsTail: undefined,\n// subs: undefined,\n// subsTail: undefined,\n// flags: 0 satisfies ReactiveFlags.None,\n// };\n// if (activeScope !== undefined) {\n// link(e, activeScope);\n// }\n// const prevSub = setCurrentSub(undefined);\n// const prevScope = setCurrentScope(e);\n// try {\n// fn();\n// } finally {\n// setCurrentScope(prevScope);\n// setCurrentSub(prevSub);\n// }\n// return effectOper.bind(e);\n// }\n\nfunction updateComputed(c: Computed): boolean {\n const prevSub = setCurrentSub(c);\n startTracking(c);\n try {\n const oldValue = c.value;\n const state: ComputedGetterState<any> = { value: c.value };\n // return oldValue !== (c.value = c.getter.call(state));\n return !c.equals(oldValue, (c.value = c.getter.call(state)));\n } finally {\n setCurrentSub(prevSub);\n endTracking(c);\n }\n}\n\nfunction updateSignal(s: Value, value: any): boolean {\n s.flags = 1 satisfies ReactiveFlags.Mutable;\n // return s.previousValue !== (s.previousValue = value);\n return !s.equals(s.previousValue, (s.previousValue = value));\n}\n\nfunction notify(e: Effect | EffectScope) {\n const flags = e.flags;\n if (!(flags & EffectFlags.Queued)) {\n e.flags = flags | EffectFlags.Queued;\n const subs = e.subs;\n if (subs !== undefined) {\n notify(subs.sub as Effect | EffectScope);\n } else {\n queuedEffects[queuedEffectsLength++] = e;\n }\n }\n}\n\nfunction run(e: Effect | EffectScope, flags: ReactiveFlags): void {\n if (\n flags & (16 satisfies ReactiveFlags.Dirty) ||\n (flags & (32 satisfies ReactiveFlags.Pending) && checkDirty(e.deps!, e))\n ) {\n const prev = setCurrentSub(e);\n startTracking(e);\n try {\n if (\"cleanup\" in e && e.cleanup !== undefined) {\n e.cleanup();\n }\n const result = (e as Effect).fn();\n if (\"cleanup\" in e && isFunction(result)) {\n e.cleanup = result;\n }\n } finally {\n setCurrentSub(prev);\n endTracking(e);\n }\n return;\n } else if (flags & (32 satisfies ReactiveFlags.Pending)) {\n e.flags = flags & ~(32 satisfies ReactiveFlags.Pending);\n }\n let link = e.deps;\n while (link !== undefined) {\n const dep = link.dep;\n const depFlags = dep.flags;\n if (depFlags & EffectFlags.Queued) {\n run(dep, (dep.flags = depFlags & ~EffectFlags.Queued));\n }\n link = link.nextDep;\n }\n}\n\nfunction flush(): void {\n while (notifyIndex < queuedEffectsLength) {\n const effect = queuedEffects[notifyIndex]!;\n queuedEffects[notifyIndex++] = undefined;\n run(effect, (effect.flags &= ~EffectFlags.Queued));\n }\n notifyIndex = 0;\n queuedEffectsLength = 0;\n}\n\nfunction _computed<T>(this: Computed<T>): T {\n const flags = this.flags;\n if (\n flags & (16 satisfies ReactiveFlags.Dirty) ||\n (flags & (32 satisfies ReactiveFlags.Pending) && checkDirty(this.deps!, this))\n ) {\n if (updateComputed(this)) {\n const subs = this.subs;\n if (subs !== undefined) {\n shallowPropagate(subs);\n }\n }\n } else if (flags & (32 satisfies ReactiveFlags.Pending)) {\n this.flags = flags & ~(32 satisfies ReactiveFlags.Pending);\n }\n if (activeSub !== undefined) {\n link(this, activeSub);\n } else if (activeScope !== undefined) {\n link(this, activeScope);\n }\n return this.value!;\n}\n\nfunction _getter<T>(this: Value<T>): T {\n const value = this.value;\n if (this.flags & (16 satisfies ReactiveFlags.Dirty)) {\n if (updateSignal(this, value)) {\n const subs = this.subs;\n if (subs !== undefined) {\n shallowPropagate(subs);\n }\n }\n }\n if (activeSub !== undefined) {\n link(this, activeSub);\n }\n return value;\n}\n\nfunction _setter<T>(this: Value<T>, value: T | ((current: T) => T)): void {\n let next = isFunction(value) ? (get(value(this.value)) as T) : (value as T);\n if (!this.equals(this.value, next)) {\n this.value = next;\n this.flags = 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty;\n const subs = this.subs;\n if (subs !== undefined) {\n propagate(subs);\n if (!batchDepth) {\n flush();\n }\n }\n }\n}\n\nfunction _effect(this: Effect | EffectScope): void {\n let dep = this.deps;\n while (dep !== undefined) {\n dep = unlink(dep, this);\n }\n const sub = this.subs;\n if (sub !== undefined) {\n unlink(sub);\n }\n this.flags = 0 satisfies ReactiveFlags.None;\n\n if (\"cleanup\" in this && this.cleanup != null) {\n this.cleanup();\n }\n}\n\n/*===================================*\\\n|| API ||\n\\*===================================*/\n\n/* -------------- TYPES --------------- */\n\n/**\n * A function that returns the current value of a signal.\n * Automatically tracked as a dependency when called within a tracking scope (such as `memo` or `effect` functions).\n */\nexport interface Signal<T> {\n (): T;\n}\n\n/**\n * A function that sets the value of the signal.\n */\nexport interface Setter<T> {\n // This signature is required for Immer `produce` to infer types correctly.\n (value: T | ((previousValue: T) => T)): void;\n\n // (value: T): void;\n // (update: (current: T) => T): void;\n}\n\n/**\n * A getter and setter in a single object. Callable like a getter, but includes a `set` method for updating the signal's value.\n */\nexport interface Writable<T> extends Signal<T> {\n set: Setter<T>;\n}\n\n/**\n * Utility type for a value that may be a getter or a plain value.\n * This value can be unwrapped to a plain value with `get` or `untracked` (depending on whether you're in a tracking context and need to track it).\n */\nexport type MaybeSignal<T> = Signal<T> | T;\n\nexport type EqualityFn<T> = (previousValue: T, nextValue: T) => boolean;\n\nexport interface SignalOptions<T> {\n /**\n * A function to compare the current and next values. Returning `true` means the value has changed.\n */\n equals?: EqualityFn<T>;\n}\n\n/* -------------- PUBLIC API --------------- */\n\nexport function $<T>(compute: (previousValue?: T) => MaybeSignal<T>, options?: MemoOptions<T>): Signal<T>;\n\nexport function $<T>(): Writable<T | undefined>;\nexport function $<T>(initialValue: undefined, options: SignalOptions<T | undefined>): Writable<T | undefined>;\nexport function $<T>(initialValue: T, options?: SignalOptions<T>): Writable<T>;\n\nexport function $(...args: any) {\n if (isFunction(args[0])) {\n return memo(args[0], args[1]);\n } else {\n return writable(args[0], args[1]);\n }\n}\n\nexport function writable<T>(): Writable<T | undefined>;\nexport function writable<T>(initialValue: undefined, options: SignalOptions<T | undefined>): Writable<T | undefined>;\nexport function writable<T>(initialValue: T, options?: SignalOptions<T>): Writable<T>;\n\nexport function writable<T>(initialValue?: T, options?: SignalOptions<T>): Writable<T> {\n const v: Value<unknown> = {\n previousValue: initialValue as T,\n value: initialValue as T,\n equals: (options?.equals as EqualityFn<unknown>) ?? strictEqual,\n subs: undefined,\n subsTail: undefined,\n flags: 1 satisfies ReactiveFlags.Mutable,\n };\n const fn = _getter.bind(v) as Writable<T>;\n fn.set = _setter.bind(v);\n return fn;\n}\n\nexport function readable<T>(signal: MaybeSignal<T>): Signal<T> {\n return memo(() => signal);\n}\n\nexport interface MemoOptions<T> extends SignalOptions<T> {\n /**\n * An array of signals this `memo` depends on. If this is passed, calls to signals within `fn` will NOT be tracked.\n * Instead the `deps` array will be tracked and `fn` will re-run when any value in `deps` changes.\n */\n deps?: Signal<any>[];\n}\n\n/**\n * Creates a derived signal that recomputes its value only when its dependencies change.\n * Subsequent calls will return a cached value.\n * Dependencies are tracked when called inside `fn` by default,\n * but can be overridden by passing a `deps` array in the options object.\n */\nexport function memo<T>(compute: (previousValue?: T) => MaybeSignal<T>, options?: MemoOptions<T>): Signal<T> {\n return _computed.bind({\n value: undefined,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: 17 as ReactiveFlags.Mutable | ReactiveFlags.Dirty,\n getter: function (this: ComputedGetterState<any>) {\n if (options?.deps) {\n for (let dep of options.deps) get(dep);\n return get(untracked(() => compute(this.value)));\n }\n return get(compute(this.value));\n },\n equals: (options?.equals as EqualityFn<unknown>) ?? strictEqual,\n }) as () => T;\n}\n\n/**\n * Suspends effects during `fn`. Effects for all updated Signal values are called at the end of the batch.\n */\nexport function batch(fn: () => void): void {\n ++batchDepth;\n fn();\n if (!--batchDepth) flush();\n}\n\n/**\n * Call a Signal function without tracking its value.\n */\nexport function untracked<T>(value: MaybeSignal<T>): T {\n if (isFunction(value)) {\n let result: T;\n const pausedSub = setCurrentSub(undefined);\n result = value();\n setCurrentSub(pausedSub);\n return result;\n } else {\n return value;\n }\n}\n\n/**\n * Unwraps the plain value from a Signal. If the value is not a Signal it is returned as-is.\n */\nexport function get<T>(value: MaybeSignal<T>): T {\n if (isFunction(value)) {\n return (value as () => T)();\n } else {\n return value;\n }\n}\n\n/**\n * Function to be invoked for the effect. Can return an optional cleanup function to be called between invocations.\n */\nexport type EffectFn = () => void | (() => void);\n\nexport type UnsubscribeFn = () => void;\n\nexport const INTERNAL_EFFECT = Symbol(\"INTERNAL_EFFECT\");\n\nexport interface EffectOptions {\n /**\n * An array of signals this effect depends on. If this is passed, calls to signals within `fn` will NOT be tracked.\n * Instead the `deps` array will be tracked and `fn` will re-run when any value in `deps` changes.\n */\n deps?: Signal<any>[];\n\n /**\n * For internal use.\n */\n _type?: symbol;\n}\n\n/**\n * Creates a tracked scope that re-runs whenever the values of any tracked reactives changes.\n * Reactives are tracked by accessing their `value` within the body of the function.\n *\n * NOTE: You must call the unsubscribe function to stop watching for changes.\n * If you are using an effect inside a View or Store, use `ctx.effect` instead, which cleans up automatically when the component unmounts.\n */\nexport function effect(fn: EffectFn, options?: EffectOptions): UnsubscribeFn {\n const internal = options?._type === INTERNAL_EFFECT;\n\n // Automatically bind to active context if called within one.\n if (!internal && activeContext) {\n return activeContext.effect(fn);\n }\n\n // Warn about memory leaks in dev mode.\n if (!internal && getEnv() === \"development\") {\n console.warn(\n `This effect is not bound to a scope. You must call the unsubscribe function when done to avoid memory leaks.`,\n );\n }\n\n const e: Effect = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: 2 satisfies ReactiveFlags.Watching,\n };\n if (activeSub !== undefined) {\n link(e, activeSub);\n } else if (activeScope !== undefined) {\n link(e, activeScope);\n }\n const prev = setCurrentSub(e);\n try {\n e.cleanup?.();\n const result = e.fn();\n e.cleanup = isFunction(result) ? result : undefined;\n } finally {\n setCurrentSub(prev);\n }\n return _effect.bind(e);\n}\n"],"names":["noOp","idCounter","getUniqueId","intCounter","getIntegerId","strictEqual","a","b","shallowEqual","t","typeOf","size","key","i","isFunction","deepEqual","length","keys","omit","object","newObject","toArray","value","toCamelCase","s","x","moveBefore","parent","node","child","okhash","hue","createMatcher","pattern","matchers","parts","p","part","section","name","positive","negative","fn","currentEnv","getEnv","setEnv","ReactiveFlags","createReactiveSystem","update","notify","unwatched","link","unlink","propagate","checkDirty","endTracking","startTracking","shallowPropagate","dep","sub","prevDep","nextDep","recursedCheck","prevSub","isValidLink","newLink","nextSub","next","stack","top","flags","subSubs","depsTail","toRemove","checkDepth","depFlags","dirty","subs","firstSub","hasMultipleSubs","subFlags","checkLink","queuedEffects","signal","updateComputed","updateSignal","_effect","batchDepth","notifyIndex","queuedEffectsLength","activeSub","activeContext","setCurrentSub","getCurrentContext","setCurrentContext","context","prevContext","c","oldValue","state","run","prev","result","flush","effect","_computed","_getter","_setter","get","$","args","memo","writable","initialValue","options","v","compute","untracked","batch","pausedSub","INTERNAL_EFFECT","internal","e","_a"],"mappings":"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","x_google_ignoreList":[2]}
@@ -0,0 +1,62 @@
1
+ function s(r) {
2
+ const t = typeof r;
3
+ switch (t) {
4
+ case "undefined":
5
+ return t;
6
+ case "number":
7
+ return isNaN(r) ? "NaN" : t;
8
+ case "function":
9
+ return /^\s*class\s+/.test(r.toString()) ? "class" : t;
10
+ case "object":
11
+ return r === null ? "null" : r instanceof Promise ? "promise" : r instanceof Map ? "map" : r instanceof Set ? "set" : Array.isArray(r) ? "array" : t;
12
+ default:
13
+ return t;
14
+ }
15
+ }
16
+ function o(r) {
17
+ return Array.isArray(r);
18
+ }
19
+ function c(r, t) {
20
+ return o(t) && t.every((n) => r(n));
21
+ }
22
+ function y(r, t, n) {
23
+ if (c(r, t))
24
+ return !0;
25
+ throw new TypeError(e(t, n));
26
+ }
27
+ function u(r) {
28
+ return typeof r == "string";
29
+ }
30
+ function p(r, t) {
31
+ if (u(r))
32
+ return !0;
33
+ throw new TypeError(e(r, t ?? "Expected a string. Got type: %t, value: %v"));
34
+ }
35
+ function g(r) {
36
+ return s(r) === "function";
37
+ }
38
+ function a(r) {
39
+ return r != null && typeof r == "object" && !o(r);
40
+ }
41
+ function A(r, t) {
42
+ if (a(r))
43
+ return !0;
44
+ throw new TypeError(e(r, t));
45
+ }
46
+ function e(r, t) {
47
+ var i;
48
+ const n = s(r), f = ((i = r == null ? void 0 : r.toString) == null ? void 0 : i.call(r)) || String(r);
49
+ return t.replaceAll("%t", n).replaceAll("%v", f);
50
+ }
51
+ export {
52
+ a,
53
+ g as b,
54
+ y as c,
55
+ p as d,
56
+ A as e,
57
+ o as f,
58
+ c as g,
59
+ u as i,
60
+ s as t
61
+ };
62
+ //# sourceMappingURL=typeChecking-_dGK_0uR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"typeChecking-CbltMOUt.js","sources":["../src/typeChecking.ts"],"sourcesContent":["type TypeNames =\n // These values can be returned by `typeof`.\n | \"string\"\n | \"number\"\n | \"bigint\"\n | \"boolean\"\n | \"symbol\"\n | \"undefined\"\n | \"object\"\n | \"function\"\n // These values are more specific ones that the `typeOf` function can return.\n | \"null\"\n | \"array\"\n | \"class\"\n | \"promise\"\n | \"map\"\n | \"set\"\n | \"NaN\";\n\n/**\n * Extends `typeof` operator with more specific and useful type distinctions.\n */\nexport function typeOf(value: any): TypeNames {\n const type = typeof value;\n switch (type) {\n case \"undefined\":\n return type;\n case \"number\":\n if (isNaN(value as any)) return \"NaN\";\n return type;\n case \"function\":\n if (/^\\s*class\\s+/.test(value.toString())) return \"class\";\n return type;\n case \"object\":\n if (value === null) return \"null\";\n if (value instanceof Promise) return \"promise\";\n if (value instanceof Map) return \"map\";\n if (value instanceof Set) return \"set\";\n if (Array.isArray(value)) return \"array\";\n return type;\n default:\n return type;\n }\n}\n\n/**\n * Throws a TypeError unless `condition` is truthy.\n *\n * @param condition - Value whose truthiness is in question.\n * @param errorMessage - Optional message for the thrown TypeError.\n */\nexport function assert(condition: any, errorMessage?: string): void {\n if (!condition) {\n throw new TypeError(\n formatError(condition, errorMessage || \"Failed assertion. Value is not truthy. Got type: %t, value: %v\"),\n );\n }\n}\n\n/**\n * Returns true if `value` is an array.\n */\nexport function isArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value);\n}\n\n/**\n * Throws an error if `value` is not an array.\n */\nexport function assertArray(value: unknown, errorMessage?: string): value is Array<unknown> {\n if (isArray(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage || \"Expected array. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true when `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n */\n\nexport function isArrayOf<T>(check: (item: unknown) => boolean, value: unknown): value is T[] {\n return isArray(value) && value.every((item) => check(item));\n}\n\n/**\n * Throws a TypeError unless `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n * @param errorMessage - A custom error message.\n */\nexport function assertArrayOf<T>(\n check: (item: unknown) => boolean,\n value: unknown,\n errorMessage?: string,\n): value is T[] {\n if (isArrayOf(check, value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an array of valid items. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a string.\n */\nexport function isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\n/**\n * Throws a TypeError unless `value` is a string.\n */\nexport function assertString(value: unknown, errorMessage?: string): value is string {\n if (isString(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a string. Got type: %t, value: %v\"));\n}\n\n// TODO: More specific validation for common types of strings? Email address, URL, UUID, etc?\n\n/**\n * Returns true if `value` is a function (but not a class).\n */\nexport function isFunction<T = (...args: unknown[]) => unknown>(value: unknown): value is T {\n return typeOf(value) === \"function\";\n}\n\n/**\n * Throws a TypeError unless `value` is a function.\n */\nexport function assertFunction<T = (...args: unknown[]) => unknown>(value: unknown, errorMessage?: string): value is T {\n if (isFunction(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a function. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a number.\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === \"number\" && !isNaN(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a number.\n */\nexport function assertNumber(value: unknown, errorMessage?: string): value is number {\n if (isNumber(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a number. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns a function that takes a `value` and returns true if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function isInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Returns `true` if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n */\nexport function isInstanceOf<T extends Function>(constructor: T, value: unknown): value is T;\n\nexport function isInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n\n const test = (value: unknown): value is T => {\n return value instanceof constructor;\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns a function that takes a `value` and throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n * @param errorMessage - A custom error message for when the assertion fails.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T, value: unknown, errorMessage?: string): value is T;\n\nexport function assertInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n const errorMessage = isString(args[2])\n ? args[2]\n : `Expected instance of ${constructor.name}. Got type: %t, value: %v`;\n\n const test = (value: unknown): value is T => {\n if (value instanceof constructor) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage));\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns true if `value` is a plain JavaScript object.\n */\nexport function isObject(value: unknown): value is Record<string | number | symbol, unknown> {\n return value != null && typeof value === \"object\" && !isArray(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a plain JavaScript object.\n */\nexport function assertObject(value: unknown, errorMessage?: string): value is object {\n if (isObject(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an object. Got type: %t, value: %v\"));\n}\n\n/**\n * Replaces `%t` and `%v` placeholders in a message with real values.\n */\nfunction formatError(value: unknown, message: string) {\n const typeName = typeOf(value);\n\n // TODO: Pretty format value as string based on type.\n const valueString = value?.toString?.() || String(value);\n\n return message.replaceAll(\"%t\", typeName).replaceAll(\"%v\", valueString);\n}\n"],"names":["typeOf","value","type","isArray","isArrayOf","check","item","assertArrayOf","errorMessage","formatError","isString","assertString","isFunction","assertInstanceOf","args","constructor","test","isObject","assertObject","message","_a","typeName","valueString"],"mappings":"AAsBO,SAASA,EAAOC,GAAuB;AAC5C,QAAMC,IAAO,OAAOD;AACpB,UAAQC,GAAM;AAAA,IACZ,KAAK;AACI,aAAAA;AAAA,IACT,KAAK;AACC,aAAA,MAAMD,CAAY,IAAU,QACzBC;AAAA,IACT,KAAK;AACH,aAAI,eAAe,KAAKD,EAAM,SAAU,CAAA,IAAU,UAC3CC;AAAA,IACT,KAAK;AACC,aAAAD,MAAU,OAAa,SACvBA,aAAiB,UAAgB,YACjCA,aAAiB,MAAY,QAC7BA,aAAiB,MAAY,QAC7B,MAAM,QAAQA,CAAK,IAAU,UAC1BC;AAAA,IACT;AACS,aAAAA;AAAA,EAAA;AAEb;AAmBO,SAASC,EAAQF,GAAyC;AACxD,SAAA,MAAM,QAAQA,CAAK;AAC5B;AAoBgB,SAAAG,EAAaC,GAAmCJ,GAA8B;AACrF,SAAAE,EAAQF,CAAK,KAAKA,EAAM,MAAM,CAACK,MAASD,EAAMC,CAAI,CAAC;AAC5D;AASgB,SAAAC,EACdF,GACAJ,GACAO,GACc;AACV,MAAAJ,EAAUC,GAAOJ,CAAK;AACjB,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA2E,CAAC;AACrH;AAKO,SAASE,EAAST,GAAiC;AACxD,SAAO,OAAOA,KAAU;AAC1B;AAKgB,SAAAU,EAAaV,GAAgBO,GAAwC;AAC/E,MAAAE,EAAST,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,KAAgB,4CAA4C,CAAC;AACtG;AAOO,SAASI,EAAgDX,GAA4B;AACnF,SAAAD,EAAOC,CAAK,MAAM;AAC3B;AA4EO,SAASY,KAAwCC,GAAiB;AACjE,QAAAC,IAAcD,EAAK,CAAC,GACpBN,IAAeE,EAASI,EAAK,CAAC,CAAC,IACjCA,EAAK,CAAC,IACN,wBAAwBC,EAAY,IAAI,6BAEtCC,IAAO,CAACf,MAA+B;AAC3C,QAAIA,aAAiBc;AACZ,aAAA;AAGT,UAAM,IAAI,UAAUN,EAAYR,GAAOO,CAAY,CAAC;AAAA,EACtD;AAEI,SAAAM,EAAK,SAAS,IACTE,IAEAA,EAAKF,EAAK,CAAC,CAAC;AAEvB;AAKO,SAASG,EAAShB,GAAoE;AAC3F,SAAOA,KAAS,QAAQ,OAAOA,KAAU,YAAY,CAACE,EAAQF,CAAK;AACrE;AAKgB,SAAAiB,EAAajB,GAAgBO,GAAwC;AAC/E,MAAAS,EAAShB,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA6D,CAAC;AACvG;AAKA,SAASC,EAAYR,GAAgBkB,GAAiB;AApO/C,MAAAC;AAqOC,QAAAC,IAAWrB,EAAOC,CAAK,GAGvBqB,MAAcF,IAAAnB,KAAA,gBAAAA,EAAO,aAAP,gBAAAmB,EAAA,KAAAnB,OAAuB,OAAOA,CAAK;AAEvD,SAAOkB,EAAQ,WAAW,MAAME,CAAQ,EAAE,WAAW,MAAMC,CAAW;AACxE;"}
1
+ {"version":3,"file":"typeChecking-_dGK_0uR.js","sources":["../src/typeChecking.ts"],"sourcesContent":["type TypeNames =\n // These values can be returned by `typeof`.\n | \"string\"\n | \"number\"\n | \"bigint\"\n | \"boolean\"\n | \"symbol\"\n | \"undefined\"\n | \"object\"\n | \"function\"\n // These values are more specific ones that the `typeOf` function can return.\n | \"null\"\n | \"array\"\n | \"class\"\n | \"promise\"\n | \"map\"\n | \"set\"\n | \"NaN\";\n\n/**\n * Extends `typeof` operator with more specific and useful type distinctions.\n */\nexport function typeOf(value: any): TypeNames {\n const type = typeof value;\n switch (type) {\n case \"undefined\":\n return type;\n case \"number\":\n if (isNaN(value as any)) return \"NaN\";\n return type;\n case \"function\":\n if (/^\\s*class\\s+/.test(value.toString())) return \"class\";\n return type;\n case \"object\":\n if (value === null) return \"null\";\n if (value instanceof Promise) return \"promise\";\n if (value instanceof Map) return \"map\";\n if (value instanceof Set) return \"set\";\n if (Array.isArray(value)) return \"array\";\n return type;\n default:\n return type;\n }\n}\n\n/**\n * Throws a TypeError unless `condition` is truthy.\n *\n * @param condition - Value whose truthiness is in question.\n * @param errorMessage - Optional message for the thrown TypeError.\n */\nexport function assert(condition: any, errorMessage?: string): void {\n if (!condition) {\n throw new TypeError(\n formatError(condition, errorMessage || \"Failed assertion. Value is not truthy. Got type: %t, value: %v\"),\n );\n }\n}\n\n/**\n * Returns true if `value` is an array.\n */\nexport function isArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value);\n}\n\n/**\n * Throws an error if `value` is not an array.\n */\nexport function assertArray(value: unknown, errorMessage?: string): value is Array<unknown> {\n if (isArray(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage || \"Expected array. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true when `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n */\n\nexport function isArrayOf<T>(check: (item: unknown) => boolean, value: unknown): value is T[] {\n return isArray(value) && value.every((item) => check(item));\n}\n\n/**\n * Throws a TypeError unless `value` is an array and `check` returns true for every item.\n *\n * @param check - Function to check items against.\n * @param value - A possible array.\n * @param errorMessage - A custom error message.\n */\nexport function assertArrayOf<T>(\n check: (item: unknown) => boolean,\n value: unknown,\n errorMessage?: string,\n): value is T[] {\n if (isArrayOf(check, value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an array of valid items. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a string.\n */\nexport function isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\n/**\n * Throws a TypeError unless `value` is a string.\n */\nexport function assertString(value: unknown, errorMessage?: string): value is string {\n if (isString(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a string. Got type: %t, value: %v\"));\n}\n\n// TODO: More specific validation for common types of strings? Email address, URL, UUID, etc?\n\n/**\n * Returns true if `value` is a function (but not a class).\n */\nexport function isFunction<T = (...args: unknown[]) => unknown>(value: unknown): value is T {\n return typeOf(value) === \"function\";\n}\n\n/**\n * Throws a TypeError unless `value` is a function.\n */\nexport function assertFunction<T = (...args: unknown[]) => unknown>(value: unknown, errorMessage?: string): value is T {\n if (isFunction(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a function. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns true if `value` is a number.\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === \"number\" && !isNaN(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a number.\n */\nexport function assertNumber(value: unknown, errorMessage?: string): value is number {\n if (isNumber(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected a number. Got type: %t, value: %v\"));\n}\n\n/**\n * Returns a function that takes a `value` and returns true if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function isInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Returns `true` if `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n */\nexport function isInstanceOf<T extends Function>(constructor: T, value: unknown): value is T;\n\nexport function isInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n\n const test = (value: unknown): value is T => {\n return value instanceof constructor;\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns a function that takes a `value` and throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor a value must be an instance of to match.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T): (value: unknown) => value is T;\n\n/**\n * Throws a TypeError unless `value` is an instance of `constructor`.\n *\n * @param constructor - The constructor `value` must be an instance of.\n * @param value - A value that may be an instance of `constructor`.\n * @param errorMessage - A custom error message for when the assertion fails.\n */\nexport function assertInstanceOf<T extends Function>(constructor: T, value: unknown, errorMessage?: string): value is T;\n\nexport function assertInstanceOf<T extends Function>(...args: unknown[]) {\n const constructor = args[0] as T;\n const errorMessage = isString(args[2])\n ? args[2]\n : `Expected instance of ${constructor.name}. Got type: %t, value: %v`;\n\n const test = (value: unknown): value is T => {\n if (value instanceof constructor) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage));\n };\n\n if (args.length < 2) {\n return test;\n } else {\n return test(args[1]);\n }\n}\n\n/**\n * Returns true if `value` is a plain JavaScript object.\n */\nexport function isObject(value: unknown): value is Record<string | number | symbol, unknown> {\n return value != null && typeof value === \"object\" && !isArray(value);\n}\n\n/**\n * Throws a TypeError unless `value` is a plain JavaScript object.\n */\nexport function assertObject(value: unknown, errorMessage?: string): value is object {\n if (isObject(value)) {\n return true;\n }\n\n throw new TypeError(formatError(value, errorMessage ?? \"Expected an object. Got type: %t, value: %v\"));\n}\n\n/**\n * Replaces `%t` and `%v` placeholders in a message with real values.\n */\nfunction formatError(value: unknown, message: string) {\n const typeName = typeOf(value);\n\n // TODO: Pretty format value as string based on type.\n const valueString = value?.toString?.() || String(value);\n\n return message.replaceAll(\"%t\", typeName).replaceAll(\"%v\", valueString);\n}\n"],"names":["typeOf","value","type","isArray","isArrayOf","check","item","assertArrayOf","errorMessage","formatError","isString","assertString","isFunction","isObject","assertObject","message","_a","typeName","valueString"],"mappings":"AAsBO,SAASA,EAAOC,GAAuB;AAC5C,QAAMC,IAAO,OAAOD;AACpB,UAAQC,GAAM;AAAA,IACZ,KAAK;AACI,aAAAA;AAAA,IACT,KAAK;AACC,aAAA,MAAMD,CAAY,IAAU,QACzBC;AAAA,IACT,KAAK;AACH,aAAI,eAAe,KAAKD,EAAM,SAAU,CAAA,IAAU,UAC3CC;AAAA,IACT,KAAK;AACC,aAAAD,MAAU,OAAa,SACvBA,aAAiB,UAAgB,YACjCA,aAAiB,MAAY,QAC7BA,aAAiB,MAAY,QAC7B,MAAM,QAAQA,CAAK,IAAU,UAC1BC;AAAA,IACT;AACS,aAAAA;AAAA,EAAA;AAEb;AAmBO,SAASC,EAAQF,GAAyC;AACxD,SAAA,MAAM,QAAQA,CAAK;AAC5B;AAoBgB,SAAAG,EAAaC,GAAmCJ,GAA8B;AACrF,SAAAE,EAAQF,CAAK,KAAKA,EAAM,MAAM,CAACK,MAASD,EAAMC,CAAI,CAAC;AAC5D;AASgB,SAAAC,EACdF,GACAJ,GACAO,GACc;AACV,MAAAJ,EAAUC,GAAOJ,CAAK;AACjB,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA2E,CAAC;AACrH;AAKO,SAASE,EAAST,GAAiC;AACxD,SAAO,OAAOA,KAAU;AAC1B;AAKgB,SAAAU,EAAaV,GAAgBO,GAAwC;AAC/E,MAAAE,EAAST,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,KAAgB,4CAA4C,CAAC;AACtG;AAOO,SAASI,EAAgDX,GAA4B;AACnF,SAAAD,EAAOC,CAAK,MAAM;AAC3B;AAoGO,SAASY,EAASZ,GAAoE;AAC3F,SAAOA,KAAS,QAAQ,OAAOA,KAAU,YAAY,CAACE,EAAQF,CAAK;AACrE;AAKgB,SAAAa,EAAab,GAAgBO,GAAwC;AAC/E,MAAAK,EAASZ,CAAK;AACT,WAAA;AAGT,QAAM,IAAI,UAAUQ,EAAYR,GAAOO,CAA6D,CAAC;AACvG;AAKA,SAASC,EAAYR,GAAgBc,GAAiB;AApO/C,MAAAC;AAqOC,QAAAC,IAAWjB,EAAOC,CAAK,GAGvBiB,MAAcF,IAAAf,KAAA,gBAAAA,EAAO,aAAP,gBAAAe,EAAA,KAAAf,OAAuB,OAAOA,CAAK;AAEvD,SAAOc,EAAQ,WAAW,MAAME,CAAQ,EAAE,WAAW,MAAMC,CAAW;AACxE;"}
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare const noOp: () => void;
2
2
  export declare function getUniqueId(): string;
3
+ export declare function getIntegerId(): number;
3
4
  /**
4
5
  * Equality check that passes if both values are the same object.
5
6
  * This is the default equality check for states.
@@ -28,6 +29,10 @@ export declare function merge(one: unknown, two: unknown): any;
28
29
  export declare function omit<O extends Record<any, any>>(keys: (keyof O)[], object: O): Record<any, any>;
29
30
  export declare function toArray<T>(value: T | T[]): T[];
30
31
  export declare function toCamelCase(s: string): string;
32
+ /**
33
+ * Moves an element using `moveBefore` if the browser supports it, otherwise falls back to `insertBefore`.
34
+ */
35
+ export declare function moveBefore(parent: Node, node: Node, child: Node | null): void;
31
36
  /**
32
37
  * Takes any string and returns an OKLCH color.
33
38
  */
@@ -0,0 +1,21 @@
1
+ # Components
2
+
3
+ Components in Dolla come in three forms; Views, Stores and Mixins. All three component types support hooks.
4
+
5
+ ## Views
6
+
7
+ Views are components that render DOM nodes that the user sees and interacts with.
8
+
9
+ In React, these are equivalent to components.
10
+
11
+ ## Stores
12
+
13
+ Stores are components that hold shared state accessible from other components.
14
+
15
+ In React, these are equivalent to contexts.
16
+
17
+ ## Mixins
18
+
19
+ Mixins are components that augment the behavior of a DOM node.
20
+
21
+ React has no equivalent. Mixins are modeled after Angular directives.
package/docs/hooks.md CHANGED
@@ -6,17 +6,17 @@ Dolla implements a React-style hooks API for use in Views, Stores and Mixins. In
6
6
  import { useState, useEffect, useLogger } from "@manyducks.co/dolla/hooks";
7
7
 
8
8
  export function CounterView() {
9
- const [count, setCount] = useState(0);
9
+ const [$count, setCount] = useState(0);
10
10
 
11
11
  const logger = useLogger();
12
12
  useEffect(() => {
13
13
  // Effect is triggered each time count changes; calling its getter tracks it.
14
- logger.info(`Count is now ${count()}`);
14
+ logger.info(`Count is now ${$count()}`);
15
15
  });
16
16
 
17
17
  return (
18
18
  <div>
19
- Count: {count}
19
+ Count: {$count}
20
20
  <button onClick={() => setCount((n) => n + 1)}>+1</button>
21
21
  <button onClick={() => setCount((n) => n - 1)}>-1</button>
22
22
  <button onClick={() => setCount(0)}>Reset</button>
package/docs/signals.md CHANGED
@@ -8,8 +8,7 @@ Dolla sets out to solve the challenge of keeping your UI in sync with your data.
8
8
 
9
9
  The Signals API consists of these functions:
10
10
 
11
- - `state`
12
- - `memo`
11
+ - `$` to create signals.
13
12
  - `effect` to run side effects when tracked signals change.
14
13
  - `get` to unwrap a possible signal value.
15
14
  - `untracked` to unwrap a possible signal value without tracking it.
@@ -17,78 +16,93 @@ The Signals API consists of these functions:
17
16
 
18
17
  ### Basic State API
19
18
 
20
- ```js
21
- import { state } from "@manyducks.co/dolla";
19
+ The core tool for working with state is the `$` function (hence the name of the library). The `$` function serves two purposes.
22
20
 
23
- const [$count, setCount] = state(72);
21
+ First, if you call it with a plain value it returns a `Writable` signal. A `Writable` is a signal object that can be called like a function to retrieve the currently stored value, and it also has a `set` method that can be used to update the stored value.
24
22
 
25
- // Get the current value.
26
- $count(): // 72
23
+ ```js
24
+ import { $ } from "@manyducks.co/dolla";
27
25
 
28
- // Set a new value.
29
- setCount(300);
26
+ const $count = $(0);
30
27
 
31
- // The State now reflects the latest value.
32
- $count(); // 300
28
+ // Call to get current value
29
+ $count(); // 0
33
30
 
34
- // Data can also be updated by passing an update function.
35
- // This function takes the current state and returns the next.
36
- setCount((value) => value + 1);
37
- $count(); // 301
38
- ```
31
+ // Set a new value
32
+ $count.set(1);
33
+ $count(); // 1
39
34
 
40
- ### Deriving States from other States
35
+ // Update the value with a mapping function
36
+ $count.set((current) => current + 1);
37
+ $count(); // 2
38
+ ````
41
39
 
42
- #### Example 1: Doubled
40
+ Dolla's naming convention is to prepend a `$` to signal names. This is because signals have special side effects to be aware of when they are called. An `effect` is one such _tracking context_. Any signals accessed within it will be tracked, causing the function to run again when a tracked signal receives a new value.
43
41
 
44
42
  ```js
45
- import { state, memo } from "@manyducks.co/dolla";
43
+ import { $, effect } from "@manyducks.co/dolla";
46
44
 
47
- // Passing a value to $() results in a Source...
48
- const [$count, setCount] = state(1);
45
+ const $count = $(0);
49
46
 
50
- // ...while passing a function results in a Signal with a derived value.
51
- const doubled = memo(() => $count() * 2);
47
+ // An effect is a function that implicitly subscribes to all $signal calls within it.
48
+ // Whenever any of these signals receives a new value the effect function will run again.
49
+ const unsubscribe = effect(() => {
50
+ console.log("count is now " + $count());
51
+ });
52
+ // prints: count is now 0
52
53
 
53
- count(10);
54
- doubled(); // 20
55
- ```
54
+ $count.set(1);
55
+ // prints: count is now 1
56
+ $count.set(2);
57
+ // prints: count is now 2
56
58
 
57
- ##### A note on derived signals.
59
+ // Effects can be cancelled by calling their unsubscribe function.
60
+ // This will unsubscribe the effect from all signal updates and it will not run again.
61
+ unsubscribe();
58
62
 
59
- Because signals are simply functions that return a value, you can also derive state by simply defining a function that returns a value. Any `Source` called in this function will therefore be tracked when this function is called in a tracked scope.
63
+ $count.set(3);
64
+ // does not print
65
+ ````
60
66
 
61
- The difference is that the value of the plain function is computed again each and every time that function is called. Wrapping it with `$()` will result in the computed value being cached until one of its dependencies changes. If you are coming from React then you may want to think of this like `useMemo`.
67
+ Another tracking context, and another use for the `$` function, is to create derived signals. If you pass a function to `$`, any signals called within that function are tracked and the resulting signal will be recomputed only when those signals receive new values.
62
68
 
63
69
  ```js
64
- // Plain getter: OK
65
- const plainCount = () => count() * 2;
70
+ import { $ } from "@manyducks.co/dolla";
66
71
 
67
- // Signal: OK
68
- const cachedCount = $(() => count() * 2);
69
- ```
72
+ const $count = $(5);
70
73
 
71
- Using plain getters to derive values is perfectly fine. It may be a waste to cache a very simple getter, but if the value is accessed frequently or involves expensive computations then you can get better performance by wrapping it in a Signal.
74
+ // Passing a function creates a computed signal.
75
+ // The function is called if any tracked signals have changed since its value was last accessed.
76
+ // For subsequent calls, the previous value is cached.
77
+ const $doubled = $(() => $count() * 2);
78
+ $doubled(); // 10
79
+ $doubled(); // 10 (cached)
80
+
81
+ // Technically, any function that calls a signal is a signal itself.
82
+ const $doubled2 = () => $count() * 2;
83
+ // This is another way to do a computed signal, although this value will be recomputed every time it's called.
84
+ // Prefer wrapping your computed signals with `$()` if you are doing expensive calculations.
85
+ ```
72
86
 
73
87
  #### Example 2: Selecting a User
74
88
 
75
89
  ```js
76
90
  import { $ } from "@manyducks.co/dolla";
77
91
 
78
- const users = $([
92
+ const $users = $([
79
93
  { id: 1, name: "Audie" },
80
94
  { id: 2, name: "Bob" },
81
95
  { id: 3, name: "Cabel" },
82
96
  ]);
83
- const userId = $(1);
97
+ const $userId = $(1);
84
98
 
85
- const selectedUser = $(() => users().find((user) => user.id === userId()));
99
+ const selectedUser = $(() => $users().find((user) => user.id === $userId()));
86
100
 
87
- selectedUser(); // { id: 1, name: "Audie" }
101
+ $selectedUser(); // { id: 1, name: "Audie" }
88
102
 
89
- userId(3);
103
+ $userId(3);
90
104
 
91
- selectedUser(); // { id: 3, name: "Cabel" }
105
+ $selectedUser(); // { id: 3, name: "Cabel" }
92
106
  ```
93
107
 
94
108
  That was a more realistic example you might actually use in real life. Here we are selecting a user from a list based on its `id` field. This is kind of similar to a `JOIN` operation in a SQL database. I use this kind of pattern constantly in my apps.
@@ -100,13 +114,13 @@ The strength of setting up a join like this is that the `$users` array can be up
100
114
  ```jsx
101
115
  import { $ } from "@manyducks.co/dolla";
102
116
 
103
- const user = $({ id: 1, name: "Audie" });
104
- const name = $(() => user().name);
117
+ const $user = $({ id: 1, name: "Audie" });
118
+ const $name = $(() => user().name);
105
119
 
106
- name(); // "Audie"
120
+ $name(); // "Audie"
107
121
 
108
122
  // In a view:
109
- <span class="user-name">{name}</span>;
123
+ <span class="user-name">{$name}</span>;
110
124
  ```
111
125
 
112
126
  Another common pattern. In a real app, most data is stored as arrays of objects. But what you need in order to slot it into a view is just a string. In the example above we've selected the user's name and slotted it into a `span`. If the `$user` value ever changes, the name will stay in sync.
@@ -116,10 +130,10 @@ Another common pattern. In a real app, most data is stored as arrays of objects.
116
130
  ```js
117
131
  import { $, get } from "@manyducks.co/dolla";
118
132
 
119
- const count = state(512);
133
+ const $count = $(512);
120
134
 
121
135
  // Unwrap the value of count. Returns 512.
122
- const value = get(count);
136
+ const value = get($count);
123
137
  // Passing a non-state value will simply return it.
124
138
  const name = get("World");
125
139
 
@@ -133,7 +147,7 @@ const value = () => "Hello";
133
147
  import { $ } from "@manyducks.co/dolla";
134
148
 
135
149
  function UserNameView(props, ctx) {
136
- const name = $(() => props.user().name);
150
+ const $name = $(() => props.$user().name);
137
151
 
138
152
  // Passing an object to `class` results in keys with a truthy value being applied as classes.
139
153
  // Those with falsy values will be ignored.
@@ -142,19 +156,19 @@ function UserNameView(props, ctx) {
142
156
  <span
143
157
  class={{
144
158
  "user-name": true,
145
- "is-selected": props.selected
159
+ "is-selected": props.$selected
146
160
  }}>
147
- {name}
161
+ {$name}
148
162
  </span>
149
163
  );
150
164
  })
151
165
 
152
166
  // In parent view:
153
167
 
154
- const selected = $(false);
155
- const user = $({ id: 1, name: "Audie" });
168
+ const $selected = $(false);
169
+ const $user = $({ id: 1, name: "Audie" });
156
170
 
157
- <UserNameView selected={selected} user={user} />
171
+ <UserNameView $selected={$selected} $user={$user} />
158
172
 
159
173
  // Changing signal values out here will now update the UserNameView internals.
160
174
  ```
package/docs/stores.md CHANGED
@@ -3,10 +3,12 @@
3
3
  > TODO: Write about stores
4
4
 
5
5
  ```tsx
6
- import Dolla, { createState } from "@manyducks.co/dolla";
6
+ import { createApp useSignal, mount } from "@manyducks.co/dolla";
7
+
8
+
7
9
 
8
10
  function CounterStore (initialValue, ctx) {
9
- const [$count, setCount] = createState(initialValue);
11
+ const [$count, setCount] = useSignal(initialValue);
10
12
 
11
13
  // Respond to context events which bubble up from views.
12
14
  ctx.on("counter:increment", (e) => {
@@ -25,8 +27,6 @@ function CounterStore (initialValue, ctx) {
25
27
  return $count;
26
28
  });
27
29
 
28
- // Stores can be provided by the app itself.
29
- Dolla.provide(CounterStore, 0);
30
30
 
31
31
  function CounterView(props, ctx) {
32
32
  // Store instances can also be provided at the view level to provide them to the current scope and those of child views.
@@ -51,6 +51,15 @@ function CounterView(props, ctx) {
51
51
  </div>
52
52
  );
53
53
  });
54
+
55
+ const app = createApp(() => {
56
+ const ctx = useContext();
57
+ ctx.addStore(CounterStore, 0);
58
+
59
+ return <CounterView />
60
+ });
61
+
62
+ app.mount(document.body);
54
63
  ```
55
64
 
56
65
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manyducks.co/dolla",
3
- "version": "2.0.0-alpha.64",
3
+ "version": "2.0.0-alpha.66",
4
4
  "description": "Front-end components, routing and state management.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/core/index.d.ts",
@@ -62,10 +62,10 @@
62
62
  "devDependencies": {
63
63
  "@types/node": "^22.12.0",
64
64
  "csstype": "^3.1.3",
65
- "prettier": "^3.4.2",
66
- "typescript": "^5.7.3",
65
+ "prettier": "^3.6.2",
66
+ "typescript": "^5.8.3",
67
67
  "vite": "^6.0.11",
68
68
  "vite-plugin-externalize-deps": "^0.9.0",
69
- "vitest": "^3.0.5"
69
+ "vitest": "^3.2.4"
70
70
  }
71
71
  }
@@ -1,15 +0,0 @@
1
- import { Router } from "../router/router";
2
- import type { View } from "../types";
3
- import { Context } from "./context";
4
- import { type LoggerCrashProps } from "./logger";
5
- export type UnmountFn = () => Promise<void>;
6
- export interface MountOptions {
7
- crashView?: View<LoggerCrashProps>;
8
- /**
9
- * An existing Context to use as the root, otherwise a new one will be created.
10
- * Use this to provide top-level stores and state to the whole app.
11
- */
12
- context?: Context;
13
- }
14
- export declare function mount(view: View<{}>, domNode: Element, options?: MountOptions): Promise<UnmountFn>;
15
- export declare function mount(router: Router, domNode: Element, options?: MountOptions): Promise<UnmountFn>;
File without changes