@getforma/core 1.1.0 → 1.2.0

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.
package/dist/runtime.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkJRQNDXX7_cjs = require('./chunk-JRQNDXX7.cjs');
3
+ var chunkE3FV2VSU_cjs = require('./chunk-E3FV2VSU.cjs');
4
4
  var chunk263HW3KN_cjs = require('./chunk-263HW3KN.cjs');
5
- var chunk2Y5US35K_cjs = require('./chunk-2Y5US35K.cjs');
6
- var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.cjs');
5
+ var chunkKUXNZ5MG_cjs = require('./chunk-KUXNZ5MG.cjs');
6
+ var chunkH7MDUHS5_cjs = require('./chunk-H7MDUHS5.cjs');
7
7
 
8
8
  // src/dom/reconcile.ts
9
9
  function getBindTargets(el) {
@@ -974,7 +974,7 @@ function parseIfHandler(expr, scope) {
974
974
  }
975
975
  if (rest.length > 0) return null;
976
976
  return (e) => {
977
- chunk2Y5US35K_cjs.batch(() => {
977
+ chunkKUXNZ5MG_cjs.batch(() => {
978
978
  if (condExpr()) thenHandler(e);
979
979
  else elseHandler?.(e);
980
980
  });
@@ -1728,7 +1728,7 @@ function parseHandler(expr, scope) {
1728
1728
  const handlers = stmts.map((s) => parseHandler(s, scope));
1729
1729
  if (handlers.every((h) => h !== null)) {
1730
1730
  return (e) => {
1731
- chunk2Y5US35K_cjs.batch(() => {
1731
+ chunkKUXNZ5MG_cjs.batch(() => {
1732
1732
  for (const h of handlers) h(e);
1733
1733
  });
1734
1734
  };
@@ -1741,7 +1741,7 @@ function parseHandler(expr, scope) {
1741
1741
  const name = incrMatch[1];
1742
1742
  const op = incrMatch[2];
1743
1743
  return () => {
1744
- chunk2Y5US35K_cjs.batch(() => {
1744
+ chunkKUXNZ5MG_cjs.batch(() => {
1745
1745
  const val = scope.getters[name]?.() ?? 0;
1746
1746
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1747
1747
  });
@@ -1752,7 +1752,7 @@ function parseHandler(expr, scope) {
1752
1752
  const op = preIncrMatch[1];
1753
1753
  const name = preIncrMatch[2];
1754
1754
  return () => {
1755
- chunk2Y5US35K_cjs.batch(() => {
1755
+ chunkKUXNZ5MG_cjs.batch(() => {
1756
1756
  const val = scope.getters[name]?.() ?? 0;
1757
1757
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1758
1758
  });
@@ -1762,7 +1762,7 @@ function parseHandler(expr, scope) {
1762
1762
  if (toggleMatch && toggleMatch[1] === toggleMatch[2]) {
1763
1763
  const name = toggleMatch[1];
1764
1764
  return () => {
1765
- chunk2Y5US35K_cjs.batch(() => {
1765
+ chunkKUXNZ5MG_cjs.batch(() => {
1766
1766
  scope.setters[name]?.(!scope.getters[name]?.());
1767
1767
  });
1768
1768
  };
@@ -1774,7 +1774,7 @@ function parseHandler(expr, scope) {
1774
1774
  if (valExpr) {
1775
1775
  if (_debug) dbg(`parseHandler: assignment "${name} = ..." \u2014 setter exists:`, !!scope.setters[name], ", getter exists:", !!scope.getters[name]);
1776
1776
  return () => {
1777
- chunk2Y5US35K_cjs.batch(() => {
1777
+ chunkKUXNZ5MG_cjs.batch(() => {
1778
1778
  const val = valExpr();
1779
1779
  if (_debug) dbg(`SETTER: ${name} = ${val} (was: ${scope.getters[name]?.()})`);
1780
1780
  scope.setters[name]?.(val);
@@ -1789,7 +1789,7 @@ function parseHandler(expr, scope) {
1789
1789
  const valExpr = parseExpression(compoundMatch[3].trim(), scope);
1790
1790
  if (valExpr) {
1791
1791
  return () => {
1792
- chunk2Y5US35K_cjs.batch(() => {
1792
+ chunkKUXNZ5MG_cjs.batch(() => {
1793
1793
  const current = scope.getters[name]?.() ?? 0;
1794
1794
  const val = valExpr();
1795
1795
  switch (op) {
@@ -1870,7 +1870,7 @@ function buildHandler(expr, scope) {
1870
1870
  }
1871
1871
  });
1872
1872
  const unsafeHandler = (e) => {
1873
- chunk2Y5US35K_cjs.batch(() => fn(proxy, e, e));
1873
+ chunkKUXNZ5MG_cjs.batch(() => fn(proxy, e, e));
1874
1874
  };
1875
1875
  const result = {
1876
1876
  handler: unsafeHandler,
@@ -1918,7 +1918,7 @@ function initScope(stateEl) {
1918
1918
  const getters = {};
1919
1919
  const setters = {};
1920
1920
  for (const [key, initial] of Object.entries(state)) {
1921
- const [get, set] = chunkW7OUWVRA_cjs.createSignal(initial);
1921
+ const [get, set] = chunkH7MDUHS5_cjs.createSignal(initial);
1922
1922
  getters[key] = get;
1923
1923
  setters[key] = set;
1924
1924
  }
@@ -2030,7 +2030,7 @@ function bindElement(el, scope, disposers) {
2030
2030
  const prevGetter = scope.getters[name];
2031
2031
  delete scope.getters[name];
2032
2032
  const evaluate = buildEvaluator(`{${expr}}`, scope);
2033
- const getter = chunkW7OUWVRA_cjs.createComputed(evaluate);
2033
+ const getter = chunkH7MDUHS5_cjs.createComputed(evaluate);
2034
2034
  scope.getters[name] = getter;
2035
2035
  if (!prevGetter) {
2036
2036
  delete scope.setters[name];
@@ -2041,7 +2041,7 @@ function bindElement(el, scope, disposers) {
2041
2041
  const textExpr = !known || known.has("data-text") ? el.getAttribute("data-text") : null;
2042
2042
  if (textExpr) {
2043
2043
  const evaluate = buildEvaluator(textExpr, scope);
2044
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2044
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2045
2045
  setElementTextFast(el, toTextValue(evaluate()));
2046
2046
  });
2047
2047
  disposers.push(dispose);
@@ -2056,7 +2056,7 @@ function bindElement(el, scope, disposers) {
2056
2056
  dbg(`bindElement: data-show="${showExpr}" on <${tag}${cls}>`);
2057
2057
  }
2058
2058
  let initialized = false;
2059
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2059
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2060
2060
  const visible = !!evaluate();
2061
2061
  if (_debug) dbg(`data-show effect: "${showExpr}" \u2192 ${visible}`);
2062
2062
  applyShowVisibility(el, visible, transition, !initialized);
@@ -2075,7 +2075,7 @@ function bindElement(el, scope, disposers) {
2075
2075
  const parent = el.parentNode;
2076
2076
  let inserted = true;
2077
2077
  let initialized = false;
2078
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2078
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2079
2079
  const show = !!evaluate();
2080
2080
  if (show && !inserted) {
2081
2081
  clearTransitionState(el);
@@ -2114,7 +2114,7 @@ function bindElement(el, scope, disposers) {
2114
2114
  const setter = scope.setters[prop];
2115
2115
  if (getter && setter) {
2116
2116
  const input = el;
2117
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2117
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2118
2118
  const val = getter();
2119
2119
  if (input.type === "checkbox") {
2120
2120
  input.checked = !!val;
@@ -2178,14 +2178,14 @@ function bindElement(el, scope, disposers) {
2178
2178
  } else if (name.startsWith("data-class:")) {
2179
2179
  const cls = name.slice(11);
2180
2180
  const evaluate = buildEvaluator(attr.value, scope);
2181
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2181
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2182
2182
  el.classList.toggle(cls, !!evaluate());
2183
2183
  });
2184
2184
  disposers.push(dispose);
2185
2185
  } else if (name.startsWith("data-bind:")) {
2186
2186
  const attrName = name.slice(10);
2187
2187
  const evaluate = buildEvaluator(attr.value, scope);
2188
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2188
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2189
2189
  const val = evaluate();
2190
2190
  if (val == null || val === false) {
2191
2191
  el.removeAttribute(attrName);
@@ -2213,7 +2213,7 @@ function bindElement(el, scope, disposers) {
2213
2213
  if (saved !== null) setter(JSON.parse(saved));
2214
2214
  } catch {
2215
2215
  }
2216
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2216
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2217
2217
  try {
2218
2218
  localStorage.setItem(key, JSON.stringify(getter()));
2219
2219
  } catch {
@@ -2300,7 +2300,7 @@ function bindElement(el, scope, disposers) {
2300
2300
  });
2301
2301
  }
2302
2302
  } : void 0;
2303
- const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2303
+ const dispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
2304
2304
  const rawItems = evaluate();
2305
2305
  if (!Array.isArray(rawItems)) {
2306
2306
  for (const n of oldNodes) {
@@ -2321,7 +2321,7 @@ function bindElement(el, scope, disposers) {
2321
2321
  }
2322
2322
  const prevNodes = new Set(oldNodes);
2323
2323
  if (keyProp) {
2324
- const result = chunkJRQNDXX7_cjs.reconcileList(
2324
+ const result = chunkE3FV2VSU_cjs.reconcileList(
2325
2325
  el,
2326
2326
  oldItems,
2327
2327
  rawItems,
@@ -2351,7 +2351,7 @@ function bindElement(el, scope, disposers) {
2351
2351
  } else {
2352
2352
  const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
2353
2353
  const oldWrapped = oldItems;
2354
- const result = chunkJRQNDXX7_cjs.reconcileList(
2354
+ const result = chunkE3FV2VSU_cjs.reconcileList(
2355
2355
  el,
2356
2356
  oldWrapped,
2357
2357
  wrapped,
@@ -2400,16 +2400,16 @@ function bindElement(el, scope, disposers) {
2400
2400
  else if (k === "error") errorTarget = v;
2401
2401
  else if (k === "poll") interval = parseInt(v ?? "0", 10);
2402
2402
  }
2403
- const [getTarget, setTarget] = chunkW7OUWVRA_cjs.createSignal(null);
2403
+ const [getTarget, setTarget] = chunkH7MDUHS5_cjs.createSignal(null);
2404
2404
  scope.getters[target] = getTarget;
2405
2405
  scope.setters[target] = setTarget;
2406
2406
  if (loadingTarget) {
2407
- const [gl, sl] = chunkW7OUWVRA_cjs.createSignal(false);
2407
+ const [gl, sl] = chunkH7MDUHS5_cjs.createSignal(false);
2408
2408
  scope.getters[loadingTarget] = gl;
2409
2409
  scope.setters[loadingTarget] = sl;
2410
2410
  }
2411
2411
  if (errorTarget) {
2412
- const [ge, se] = chunkW7OUWVRA_cjs.createSignal(null);
2412
+ const [ge, se] = chunkH7MDUHS5_cjs.createSignal(null);
2413
2413
  scope.getters[errorTarget] = ge;
2414
2414
  scope.setters[errorTarget] = se;
2415
2415
  }
@@ -2738,7 +2738,7 @@ function getScopes() {
2738
2738
  function setScopeValue(element, key, value) {
2739
2739
  const scope = element.__formaScope;
2740
2740
  if (!scope?.setters[key]) return;
2741
- chunk2Y5US35K_cjs.batch(() => {
2741
+ chunkKUXNZ5MG_cjs.batch(() => {
2742
2742
  scope.setters[key](value);
2743
2743
  });
2744
2744
  }
@@ -2747,7 +2747,7 @@ function resetScope(element) {
2747
2747
  const initialJSON = element.__formaInitialState;
2748
2748
  if (!scope || !initialJSON) return;
2749
2749
  const initial = parseState(initialJSON);
2750
- chunk2Y5US35K_cjs.batch(() => {
2750
+ chunkKUXNZ5MG_cjs.batch(() => {
2751
2751
  for (const [key, val] of Object.entries(initial)) {
2752
2752
  scope.setters[key]?.(val);
2753
2753
  }
@@ -2777,7 +2777,7 @@ function getReconciler() {
2777
2777
  }
2778
2778
  }
2779
2779
  },
2780
- batch: chunk2Y5US35K_cjs.batch
2780
+ batch: chunkKUXNZ5MG_cjs.batch
2781
2781
  });
2782
2782
  }
2783
2783
  return _reconciler;
package/dist/runtime.js CHANGED
@@ -1,7 +1,7 @@
1
- import { reconcileList } from './chunk-MIOMT2CB.js';
1
+ import { reconcileList } from './chunk-YRNYOZF3.js';
2
2
  import { isEventHandlerAttr, isUrlAttr, isDangerousUrl } from './chunk-2QQBKQIF.js';
3
- import { internalEffect, batch } from './chunk-INNOI6TG.js';
4
- import { createSignal, createComputed } from './chunk-XLVBYXOU.js';
3
+ import { internalEffect, batch } from './chunk-Y3A2EVVS.js';
4
+ import { createSignal, createComputed } from './chunk-ETPJTPYD.js';
5
5
 
6
6
  // src/dom/reconcile.ts
7
7
  function getBindTargets(el) {
package/dist/server.cjs CHANGED
@@ -1,25 +1,25 @@
1
1
  'use strict';
2
2
 
3
- var chunk2Y5US35K_cjs = require('./chunk-2Y5US35K.cjs');
4
- var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.cjs');
3
+ var chunkKUXNZ5MG_cjs = require('./chunk-KUXNZ5MG.cjs');
4
+ var chunkH7MDUHS5_cjs = require('./chunk-H7MDUHS5.cjs');
5
5
 
6
6
  // src/server/action.ts
7
7
  function createAction(serverFn, options) {
8
- const [pending, setPending] = chunkW7OUWVRA_cjs.createSignal(false);
9
- const [error, setError] = chunkW7OUWVRA_cjs.createSignal(void 0);
8
+ const [pending, setPending] = chunkH7MDUHS5_cjs.createSignal(false);
9
+ const [error, setError] = chunkH7MDUHS5_cjs.createSignal(void 0);
10
10
  const action = async (...args) => {
11
11
  setPending(true);
12
12
  setError(void 0);
13
13
  if (options?.optimistic) {
14
14
  try {
15
- chunk2Y5US35K_cjs.batch(() => options.optimistic(...args));
15
+ chunkKUXNZ5MG_cjs.batch(() => options.optimistic(...args));
16
16
  } catch {
17
17
  }
18
18
  }
19
19
  try {
20
20
  const result = await serverFn(...args);
21
21
  if (options?.onSuccess) {
22
- chunk2Y5US35K_cjs.batch(() => options.onSuccess(result, ...args));
22
+ chunkKUXNZ5MG_cjs.batch(() => options.onSuccess(result, ...args));
23
23
  }
24
24
  if (options?.invalidates) {
25
25
  for (const resource of options.invalidates) {
@@ -31,7 +31,7 @@ function createAction(serverFn, options) {
31
31
  } catch (err) {
32
32
  if (options?.onError) {
33
33
  try {
34
- chunk2Y5US35K_cjs.batch(() => options.onError(err, ...args));
34
+ chunkKUXNZ5MG_cjs.batch(() => options.onError(err, ...args));
35
35
  } catch {
36
36
  }
37
37
  }
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { batch } from './chunk-INNOI6TG.js';
2
- import { createSignal } from './chunk-XLVBYXOU.js';
1
+ import { batch } from './chunk-Y3A2EVVS.js';
2
+ import { createSignal } from './chunk-ETPJTPYD.js';
3
3
 
4
4
  // src/server/action.ts
5
5
  function createAction(serverFn, options) {
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.cjs');
3
+ var chunkH7MDUHS5_cjs = require('./chunk-H7MDUHS5.cjs');
4
4
 
5
5
  // src/reactive/tc39-compat.ts
6
6
  var State = class {
7
7
  _get;
8
8
  _set;
9
9
  constructor(initialValue, options) {
10
- const [getter, setter] = chunkW7OUWVRA_cjs.createSignal(initialValue, options);
10
+ const [getter, setter] = chunkH7MDUHS5_cjs.createSignal(initialValue, options);
11
11
  this._get = getter;
12
12
  this._set = setter;
13
13
  }
@@ -21,7 +21,7 @@ var State = class {
21
21
  var Computed = class {
22
22
  _get;
23
23
  constructor(fn) {
24
- this._get = chunkW7OUWVRA_cjs.createComputed(fn);
24
+ this._get = chunkH7MDUHS5_cjs.createComputed(fn);
25
25
  }
26
26
  get() {
27
27
  return this._get();
@@ -1,4 +1,4 @@
1
- import { createSignal, createComputed } from './chunk-XLVBYXOU.js';
1
+ import { createSignal, createComputed } from './chunk-ETPJTPYD.js';
2
2
 
3
3
  // src/reactive/tc39-compat.ts
4
4
  var State = class {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getforma/core",
3
3
  "author": "Forma <victor@getforma.dev>",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "description": "Real DOM reactive library — fine-grained signals, islands architecture, SSR hydration. No virtual DOM, no diffing. Core entry ~8KB gzipped; full HTML runtime ~24KB gzipped.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/dev.ts","../src/reactive/signal.ts","../src/reactive/computed.ts"],"names":["prevSub","setActiveSub","prev","trigger","createRawSignal","rawComputed"],"mappings":"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","file":"chunk-W7OUWVRA.cjs","sourcesContent":["/**\n * Forma Reactive - Dev Mode\n *\n * Development utilities stripped from production builds via __DEV__ flag.\n * Bundlers replace __DEV__ with false → dead-code elimination removes all dev paths.\n */\n\n// __DEV__ is replaced by the bundler (tsup define) for dead-code elimination in\n// dist. For unbundled/raw-source usage it derives from NODE_ENV, and — when the\n// environment is indeterminate — defaults to *false* (production-safe: no console\n// noise) unless a consumer opts in via a global __FORMA_DEV__.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\ndeclare const __FORMA_DEV__: boolean | undefined;\n\n/**\n * Lazily evaluate whether we're in a dev environment. Read per-call (not frozen\n * at import) so runtime NODE_ENV changes are honored and so official prod dist\n * builds — where tsup hard-defines __DEV__ = false — stay quiet regardless.\n */\nfunction isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process!.env?.NODE_ENV !== 'production';\n }\n return typeof __FORMA_DEV__ !== 'undefined' ? !!__FORMA_DEV__ : false;\n}\n\nexport const __DEV__: boolean = isDev();\n\n// ---------------------------------------------------------------------------\n// Global error handlers\n// ---------------------------------------------------------------------------\n\n/** Callback signature for a global {@link onError} handler. */\nexport type ErrorHandler = (error: unknown, info?: { source?: string }) => void;\n\nconst _errorHandlers = new Set<ErrorHandler>();\n\n/**\n * Install a global error handler for FormaJS reactive errors. Called when\n * effects, computeds, or event handlers throw. Multiple handlers may be\n * registered; returns an unsubscribe function that removes only this handler.\n *\n * ```ts\n * const off = onError((err, info) => {\n * Sentry.captureException(err, { tags: { source: info?.source } });\n * });\n * // later: off();\n * ```\n */\nexport function onError(handler: ErrorHandler): () => void {\n _errorHandlers.add(handler);\n return () => { _errorHandlers.delete(handler); };\n}\n\n/** @internal */\nexport function reportError(error: unknown, source?: string): void {\n for (const handler of _errorHandlers) {\n try { handler(error, source ? { source } : {}); } catch { /* prevent infinite loop */ }\n }\n if (isDev()) {\n console.error(`[forma] ${source ?? 'Unknown'} error:`, error);\n }\n}\n","/**\n * Forma Reactive - Signal\n *\n * Fine-grained reactive primitive backed by alien-signals.\n * API: createSignal returns [getter, setter] tuple following SolidJS conventions.\n *\n * TC39 Signals equivalent: Signal.State\n */\n\nimport { signal as createRawSignal, setActiveSub, trigger } from 'alien-signals';\nimport { __DEV__ } from './dev.js';\n\n// Debug names live in a side table rather than on the getter's `.name`, so\n// alien-signals' isSignal() (which keys off the bound function name) still\n// recognizes named signals.\nconst signalNames = new WeakMap<object, string>();\n\n/** Debug name of a signal getter, if one was provided (dev-only). */\nexport function getSignalName(fn: unknown): string | undefined {\n return typeof fn === 'function' ? signalNames.get(fn as object) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** A function that reads the current value of a signal. */\nexport type SignalGetter<T> = () => T;\n/** A function that updates a signal — accepts a value or an updater function. */\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;\n\nexport interface SignalOptions<T> {\n /** Debug name — attached to getter in dev mode for devtools inspection. */\n name?: string;\n /**\n * Custom equality check. When provided, the setter will read the current\n * value and only update the signal if `equals(prev, next)` returns `false`.\n *\n * Default: none (alien-signals uses strict inequality `!==` internally).\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n *\n * setPos({ x: 0, y: 0 }); // skipped — equals returns true\n * setPos({ x: 1, y: 0 }); // applied — equals returns false\n * ```\n */\n equals?: (prev: T, next: T) => boolean;\n}\n\n/**\n * Wrap a value so the setter treats it as a literal value, not a functional updater.\n *\n * When `T` is itself a function type, passing a function to the setter is\n * ambiguous -- it looks like a functional update (`prev => next`). Use\n * `value()` to disambiguate:\n *\n * ```ts\n * const [getFn, setFn] = createSignal<() => void>(() => console.log('a'));\n *\n * // BUG: interpreted as a functional update -- calls the arrow with prev\n * // setFn(() => console.log('b'));\n *\n * // Correct: wraps in a thunk so the setter stores it as-is\n * setFn(value(() => console.log('b')));\n * ```\n */\nexport function value<T>(v: T): () => T {\n return () => v;\n}\n\ntype RawSignal<T> = {\n (): T;\n (value: T): void;\n};\n\nfunction applySignalSet<T>(\n s: RawSignal<T>,\n v: T | ((prev: T) => T),\n equals?: (prev: T, next: T) => boolean,\n): void {\n // Fast path: plain value, no equals — no prev read needed. (A running effect\n // writing its own dependency is detected at the effect level via the Pending\n // flag, so signal.ts does not need to do anything special here.)\n if (typeof v !== 'function') {\n if (!equals) {\n s(v);\n return;\n }\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n if (equals(prev, v)) return; // suppressed by custom equality\n s(v);\n if (Object.is(prev, v)) forceNotify(s);\n return;\n }\n\n // Functional update: read prev without tracking.\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n const next = (v as (prev: T) => T)(prev);\n if (equals && equals(prev, next)) return; // suppressed by custom equality\n s(next);\n if (equals && Object.is(prev, next)) forceNotify(s);\n}\n\n/**\n * When a custom `equals` decided to APPLY (returned false) but the value is the\n * identical reference, alien-signals suppresses propagation (its guard is\n * `pendingValue !== value`). Force-notify subscribers so `equals: () => false`\n * (\"always notify\") works for mutate-in-place patterns.\n */\nfunction forceNotify<T>(s: RawSignal<T>): void {\n trigger(() => { s(); });\n}\n\n/**\n * Create a reactive signal.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * console.log(count()); // 0\n * setCount(1);\n * setCount(prev => prev + 1);\n * ```\n *\n * With custom equality:\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n * ```\n */\nexport function createSignal<T>(initialValue: T, options?: SignalOptions<T>): [get: SignalGetter<T>, set: SignalSetter<T>] {\n const s = createRawSignal<T>(initialValue) as RawSignal<T>;\n const getter = s as unknown as SignalGetter<T>;\n if (__DEV__ && options?.name) {\n signalNames.set(getter as object, options.name);\n }\n const eq = options?.equals;\n const setter: SignalSetter<T> = (v: T | ((prev: T) => T)) => applySignalSet(s, v, eq);\n\n return [getter, setter];\n}\n","/**\n * Forma Reactive - Computed\n *\n * Lazy, cached derived value that participates in the reactive graph.\n * Backed by alien-signals for automatic dependency tracking\n * and cache invalidation.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { computed as rawComputed } from 'alien-signals';\nimport { reportError } from './dev.js';\n\n/** Unique per-throw marker so alien-signals sees a value change and propagates. */\nconst ERR = Symbol('formaComputedError');\ninterface ErrBox { [ERR]: unknown; }\nfunction isErrBox(v: unknown): v is ErrBox {\n return typeof v === 'object' && v !== null && ERR in (v as object);\n}\n\n/**\n * Create a lazy, cached computed value.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), this is a lazy cached derivation — equivalent to\n * SolidJS's createMemo. Both createComputed and createMemo in FormaJS\n * are identical.\n *\n * The getter receives the previous value as an argument, enabling\n * efficient diffing patterns without a separate signal:\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createComputed(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n *\n * With previous value (for diffing):\n *\n * ```ts\n * const changes = createComputed((prev) => {\n * const next = items();\n * if (prev) console.log(`changed from ${prev.length} to ${next.length} items`);\n * return next;\n * });\n * ```\n */\nexport function createComputed<T>(fn: (previousValue?: T) => T): () => T {\n // alien-signals' updateComputed leaves a throwing computed flagged clean with a\n // stale value, so a later read silently returns the stale value and never\n // rethrows. We cache the error in closure and rethrow on read until a\n // dependency changes (TC39/Solid). On throw we return a FRESH sentinel object so\n // alien-signals sees a value change and propagates the error to subscribers; the\n // user getter only ever sees the last GOOD value as `previousValue`.\n let errored = false;\n let error: unknown;\n let lastGood: T | undefined;\n\n const raw = rawComputed<T | ErrBox>(() => {\n try {\n const v = fn(lastGood);\n errored = false;\n error = undefined;\n lastGood = v;\n return v;\n } catch (e) {\n errored = true;\n error = e;\n reportError(e, 'computed');\n return { [ERR]: e };\n }\n });\n\n const reader = () => {\n const v = raw();\n if (errored || isErrBox(v)) throw error;\n return v as T;\n };\n // Preserve alien-signals' isComputed() recognition, which keys off the bound\n // function name (`bound computedOper`). Our reader wraps the raw computed, so\n // copy the raw name onto it.\n Object.defineProperty(reader, 'name', { value: raw.name, configurable: true });\n return reader;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/dev.ts","../src/reactive/signal.ts","../src/reactive/computed.ts"],"names":["prevSub","prev","createRawSignal","rawComputed"],"mappings":"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","file":"chunk-XLVBYXOU.js","sourcesContent":["/**\n * Forma Reactive - Dev Mode\n *\n * Development utilities stripped from production builds via __DEV__ flag.\n * Bundlers replace __DEV__ with false → dead-code elimination removes all dev paths.\n */\n\n// __DEV__ is replaced by the bundler (tsup define) for dead-code elimination in\n// dist. For unbundled/raw-source usage it derives from NODE_ENV, and — when the\n// environment is indeterminate — defaults to *false* (production-safe: no console\n// noise) unless a consumer opts in via a global __FORMA_DEV__.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\ndeclare const __FORMA_DEV__: boolean | undefined;\n\n/**\n * Lazily evaluate whether we're in a dev environment. Read per-call (not frozen\n * at import) so runtime NODE_ENV changes are honored and so official prod dist\n * builds — where tsup hard-defines __DEV__ = false — stay quiet regardless.\n */\nfunction isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process!.env?.NODE_ENV !== 'production';\n }\n return typeof __FORMA_DEV__ !== 'undefined' ? !!__FORMA_DEV__ : false;\n}\n\nexport const __DEV__: boolean = isDev();\n\n// ---------------------------------------------------------------------------\n// Global error handlers\n// ---------------------------------------------------------------------------\n\n/** Callback signature for a global {@link onError} handler. */\nexport type ErrorHandler = (error: unknown, info?: { source?: string }) => void;\n\nconst _errorHandlers = new Set<ErrorHandler>();\n\n/**\n * Install a global error handler for FormaJS reactive errors. Called when\n * effects, computeds, or event handlers throw. Multiple handlers may be\n * registered; returns an unsubscribe function that removes only this handler.\n *\n * ```ts\n * const off = onError((err, info) => {\n * Sentry.captureException(err, { tags: { source: info?.source } });\n * });\n * // later: off();\n * ```\n */\nexport function onError(handler: ErrorHandler): () => void {\n _errorHandlers.add(handler);\n return () => { _errorHandlers.delete(handler); };\n}\n\n/** @internal */\nexport function reportError(error: unknown, source?: string): void {\n for (const handler of _errorHandlers) {\n try { handler(error, source ? { source } : {}); } catch { /* prevent infinite loop */ }\n }\n if (isDev()) {\n console.error(`[forma] ${source ?? 'Unknown'} error:`, error);\n }\n}\n","/**\n * Forma Reactive - Signal\n *\n * Fine-grained reactive primitive backed by alien-signals.\n * API: createSignal returns [getter, setter] tuple following SolidJS conventions.\n *\n * TC39 Signals equivalent: Signal.State\n */\n\nimport { signal as createRawSignal, setActiveSub, trigger } from 'alien-signals';\nimport { __DEV__ } from './dev.js';\n\n// Debug names live in a side table rather than on the getter's `.name`, so\n// alien-signals' isSignal() (which keys off the bound function name) still\n// recognizes named signals.\nconst signalNames = new WeakMap<object, string>();\n\n/** Debug name of a signal getter, if one was provided (dev-only). */\nexport function getSignalName(fn: unknown): string | undefined {\n return typeof fn === 'function' ? signalNames.get(fn as object) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** A function that reads the current value of a signal. */\nexport type SignalGetter<T> = () => T;\n/** A function that updates a signal — accepts a value or an updater function. */\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;\n\nexport interface SignalOptions<T> {\n /** Debug name — attached to getter in dev mode for devtools inspection. */\n name?: string;\n /**\n * Custom equality check. When provided, the setter will read the current\n * value and only update the signal if `equals(prev, next)` returns `false`.\n *\n * Default: none (alien-signals uses strict inequality `!==` internally).\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n *\n * setPos({ x: 0, y: 0 }); // skipped — equals returns true\n * setPos({ x: 1, y: 0 }); // applied — equals returns false\n * ```\n */\n equals?: (prev: T, next: T) => boolean;\n}\n\n/**\n * Wrap a value so the setter treats it as a literal value, not a functional updater.\n *\n * When `T` is itself a function type, passing a function to the setter is\n * ambiguous -- it looks like a functional update (`prev => next`). Use\n * `value()` to disambiguate:\n *\n * ```ts\n * const [getFn, setFn] = createSignal<() => void>(() => console.log('a'));\n *\n * // BUG: interpreted as a functional update -- calls the arrow with prev\n * // setFn(() => console.log('b'));\n *\n * // Correct: wraps in a thunk so the setter stores it as-is\n * setFn(value(() => console.log('b')));\n * ```\n */\nexport function value<T>(v: T): () => T {\n return () => v;\n}\n\ntype RawSignal<T> = {\n (): T;\n (value: T): void;\n};\n\nfunction applySignalSet<T>(\n s: RawSignal<T>,\n v: T | ((prev: T) => T),\n equals?: (prev: T, next: T) => boolean,\n): void {\n // Fast path: plain value, no equals — no prev read needed. (A running effect\n // writing its own dependency is detected at the effect level via the Pending\n // flag, so signal.ts does not need to do anything special here.)\n if (typeof v !== 'function') {\n if (!equals) {\n s(v);\n return;\n }\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n if (equals(prev, v)) return; // suppressed by custom equality\n s(v);\n if (Object.is(prev, v)) forceNotify(s);\n return;\n }\n\n // Functional update: read prev without tracking.\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n const next = (v as (prev: T) => T)(prev);\n if (equals && equals(prev, next)) return; // suppressed by custom equality\n s(next);\n if (equals && Object.is(prev, next)) forceNotify(s);\n}\n\n/**\n * When a custom `equals` decided to APPLY (returned false) but the value is the\n * identical reference, alien-signals suppresses propagation (its guard is\n * `pendingValue !== value`). Force-notify subscribers so `equals: () => false`\n * (\"always notify\") works for mutate-in-place patterns.\n */\nfunction forceNotify<T>(s: RawSignal<T>): void {\n trigger(() => { s(); });\n}\n\n/**\n * Create a reactive signal.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * console.log(count()); // 0\n * setCount(1);\n * setCount(prev => prev + 1);\n * ```\n *\n * With custom equality:\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n * ```\n */\nexport function createSignal<T>(initialValue: T, options?: SignalOptions<T>): [get: SignalGetter<T>, set: SignalSetter<T>] {\n const s = createRawSignal<T>(initialValue) as RawSignal<T>;\n const getter = s as unknown as SignalGetter<T>;\n if (__DEV__ && options?.name) {\n signalNames.set(getter as object, options.name);\n }\n const eq = options?.equals;\n const setter: SignalSetter<T> = (v: T | ((prev: T) => T)) => applySignalSet(s, v, eq);\n\n return [getter, setter];\n}\n","/**\n * Forma Reactive - Computed\n *\n * Lazy, cached derived value that participates in the reactive graph.\n * Backed by alien-signals for automatic dependency tracking\n * and cache invalidation.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { computed as rawComputed } from 'alien-signals';\nimport { reportError } from './dev.js';\n\n/** Unique per-throw marker so alien-signals sees a value change and propagates. */\nconst ERR = Symbol('formaComputedError');\ninterface ErrBox { [ERR]: unknown; }\nfunction isErrBox(v: unknown): v is ErrBox {\n return typeof v === 'object' && v !== null && ERR in (v as object);\n}\n\n/**\n * Create a lazy, cached computed value.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), this is a lazy cached derivation — equivalent to\n * SolidJS's createMemo. Both createComputed and createMemo in FormaJS\n * are identical.\n *\n * The getter receives the previous value as an argument, enabling\n * efficient diffing patterns without a separate signal:\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createComputed(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n *\n * With previous value (for diffing):\n *\n * ```ts\n * const changes = createComputed((prev) => {\n * const next = items();\n * if (prev) console.log(`changed from ${prev.length} to ${next.length} items`);\n * return next;\n * });\n * ```\n */\nexport function createComputed<T>(fn: (previousValue?: T) => T): () => T {\n // alien-signals' updateComputed leaves a throwing computed flagged clean with a\n // stale value, so a later read silently returns the stale value and never\n // rethrows. We cache the error in closure and rethrow on read until a\n // dependency changes (TC39/Solid). On throw we return a FRESH sentinel object so\n // alien-signals sees a value change and propagates the error to subscribers; the\n // user getter only ever sees the last GOOD value as `previousValue`.\n let errored = false;\n let error: unknown;\n let lastGood: T | undefined;\n\n const raw = rawComputed<T | ErrBox>(() => {\n try {\n const v = fn(lastGood);\n errored = false;\n error = undefined;\n lastGood = v;\n return v;\n } catch (e) {\n errored = true;\n error = e;\n reportError(e, 'computed');\n return { [ERR]: e };\n }\n });\n\n const reader = () => {\n const v = raw();\n if (errored || isErrBox(v)) throw error;\n return v as T;\n };\n // Preserve alien-signals' isComputed() recognition, which keys off the bound\n // function name (`bound computedOper`). Our reader wraps the raw computed, so\n // copy the raw name onto it.\n Object.defineProperty(reader, 'name', { value: raw.name, configurable: true });\n return reader;\n}\n"]}