@getforma/core 0.3.1 → 0.6.1

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 (42) hide show
  1. package/README.md +190 -16
  2. package/dist/{chunk-KX5WRZH7.js → chunk-DPSAVBCP.js} +3 -4
  3. package/dist/chunk-DPSAVBCP.js.map +1 -0
  4. package/dist/{chunk-FPSLC62A.cjs → chunk-KH3F5NRU.cjs} +2 -4
  5. package/dist/chunk-KH3F5NRU.cjs.map +1 -0
  6. package/dist/{chunk-5H52PKGF.js → chunk-TKGUHASG.js} +20 -10
  7. package/dist/chunk-TKGUHASG.js.map +1 -0
  8. package/dist/{chunk-TSQ7AKFT.cjs → chunk-YSKF3VRA.cjs} +27 -17
  9. package/dist/chunk-YSKF3VRA.cjs.map +1 -0
  10. package/dist/forma-runtime-csp.js +1 -1
  11. package/dist/forma-runtime.js +1 -1
  12. package/dist/formajs-runtime-hardened.global.js +1 -1
  13. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  14. package/dist/formajs-runtime.global.js +1 -1
  15. package/dist/formajs-runtime.global.js.map +1 -1
  16. package/dist/formajs.global.js +1 -1
  17. package/dist/formajs.global.js.map +1 -1
  18. package/dist/index.cjs +102 -75
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +41 -9
  21. package/dist/index.d.ts +41 -9
  22. package/dist/index.js +46 -17
  23. package/dist/index.js.map +1 -1
  24. package/dist/runtime-hardened.cjs +61 -13
  25. package/dist/runtime-hardened.cjs.map +1 -1
  26. package/dist/runtime-hardened.js +62 -14
  27. package/dist/runtime-hardened.js.map +1 -1
  28. package/dist/runtime.cjs +85 -36
  29. package/dist/runtime.cjs.map +1 -1
  30. package/dist/runtime.js +63 -14
  31. package/dist/runtime.js.map +1 -1
  32. package/dist/ssr/index.cjs +18 -10
  33. package/dist/ssr/index.cjs.map +1 -1
  34. package/dist/ssr/index.js +18 -10
  35. package/dist/ssr/index.js.map +1 -1
  36. package/dist/tc39-compat.cjs +3 -3
  37. package/dist/tc39-compat.js +1 -1
  38. package/package.json +1 -1
  39. package/dist/chunk-5H52PKGF.js.map +0 -1
  40. package/dist/chunk-FPSLC62A.cjs.map +0 -1
  41. package/dist/chunk-KX5WRZH7.js.map +0 -1
  42. package/dist/chunk-TSQ7AKFT.cjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { computed, effect, signal, startBatch, endBatch, pauseTracking, resumeTracking } from 'alien-signals';
1
+ import { signal, computed, effect, startBatch, endBatch, pauseTracking, resumeTracking } from 'alien-signals';
2
2
 
3
3
  // src/reactive/signal.ts
4
4
  function applySignalSet(s, v) {
@@ -17,7 +17,6 @@ function createSignal(initialValue) {
17
17
  const setter = (v) => applySignalSet(s, v);
18
18
  return [getter, setter];
19
19
  }
20
- var createValueSignal = createSignal;
21
20
  function internalEffect(fn) {
22
21
  const dispose = effect(fn);
23
22
  return dispose;
@@ -850,12 +849,11 @@ var RE_TOGGLE = /^(\w+)\s*=\s*!(\w+)$/;
850
849
  var RE_ASSIGN = /^(\w+)\s*=\s*(.+)$/;
851
850
  var RE_COMPOUND = /^(\w+)\s*(\+=|-=|\*=|\/=)\s*(.+)$/;
852
851
  var RE_IF_PREFIX = /^if\b/;
853
- var RE_UNQUOTED_KEYS = /(\w+)\s*:/g;
854
852
  var RE_COMPUTED = /^(\w+)\s*=\s*(.+)$/;
855
853
  var RE_FETCH = /^(.+?)(?:→|->)\s*(\S+)(.*)$/;
856
854
  var RE_FETCH_METHOD = /^(GET|POST|PUT|PATCH|DELETE)\s+(.+)$/i;
857
855
  var RE_STRIP_ITEM_BRACES = /^\{item\.?|\}$/g;
858
- var RE_EVENT_REF = /\bevent\b|\$event\b/;
856
+ var RE_EVENT_REF = /\bevent\s*[.([]|\$event\b/;
859
857
  var RE_REFETCH_CALL = /^\$refetch\(\s*['"]([^'"]+)['"]\s*\)$/;
860
858
  var TRANSITION_STATE_SYM = /* @__PURE__ */ Symbol.for("forma-transition-state");
861
859
  var EXPRESSION_CACHE_MAX = 2048;
@@ -870,6 +868,14 @@ function cacheExpression(key, factory) {
870
868
  var scopeExpressionCache = /* @__PURE__ */ new WeakMap();
871
869
  var scopeHandlerCache = /* @__PURE__ */ new WeakMap();
872
870
  var compiledTemplateCache = /* @__PURE__ */ new Map();
871
+ var COMPILED_TEMPLATE_CACHE_MAX = 2048;
872
+ function cacheCompiledTemplate(key, template) {
873
+ if (compiledTemplateCache.size >= COMPILED_TEMPLATE_CACHE_MAX) {
874
+ const first = compiledTemplateCache.keys().next().value;
875
+ if (first !== void 0) compiledTemplateCache.delete(first);
876
+ }
877
+ compiledTemplateCache.set(key, template);
878
+ }
873
879
  var UNSAFE_METHOD_NAMES = /* @__PURE__ */ new Set([
874
880
  "constructor",
875
881
  "__proto__",
@@ -878,7 +884,8 @@ var UNSAFE_METHOD_NAMES = /* @__PURE__ */ new Set([
878
884
  "__defineSetter__",
879
885
  "__lookupGetter__",
880
886
  "__lookupSetter__",
881
- "eval"
887
+ "eval",
888
+ "Function"
882
889
  ]);
883
890
  var BLOCKED_METHOD_REGEXES = (() => {
884
891
  const result = [];
@@ -902,8 +909,36 @@ function findBlockedMethod(expr) {
902
909
  if (dotRe.test(cleaned)) return name;
903
910
  if (bracketRe.test(cleaned)) return name;
904
911
  }
912
+ if (cleaned.includes("[")) {
913
+ const bracketContents = extractBracketContents(cleaned);
914
+ for (const content of bracketContents) {
915
+ if (!content.includes("+")) continue;
916
+ const fragments = content.match(/['"`]([^'"`]*?)['"`]/g);
917
+ if (!fragments) continue;
918
+ const joined = fragments.map((f) => f.slice(1, -1)).join("");
919
+ if (UNSAFE_METHOD_NAMES.has(joined)) return joined;
920
+ }
921
+ }
905
922
  return null;
906
923
  }
924
+ function extractBracketContents(expr) {
925
+ const results = [];
926
+ let depth = 0;
927
+ let start = -1;
928
+ for (let i = 0; i < expr.length; i++) {
929
+ if (expr[i] === "[") {
930
+ if (depth === 0) start = i + 1;
931
+ depth++;
932
+ } else if (expr[i] === "]") {
933
+ depth--;
934
+ if (depth === 0 && start >= 0) {
935
+ results.push(expr.slice(start, i));
936
+ start = -1;
937
+ }
938
+ }
939
+ }
940
+ return results;
941
+ }
907
942
  var TEXT_BINDING_SYM = /* @__PURE__ */ Symbol.for("forma-text-binding-cache");
908
943
  function toTextValue(value2) {
909
944
  if (value2 == null) return "";
@@ -1239,7 +1274,7 @@ function compileTemplate(text) {
1239
1274
  dynamics,
1240
1275
  hasItemRef: dynamics.length > 0
1241
1276
  };
1242
- compiledTemplateCache.set(text, result);
1277
+ cacheCompiledTemplate(text, result);
1243
1278
  return result;
1244
1279
  }
1245
1280
  var templateTexts = /* @__PURE__ */ new WeakMap();
@@ -1927,6 +1962,7 @@ function buildEvaluator(expr, scope) {
1927
1962
  return key in scope.getters;
1928
1963
  },
1929
1964
  get(_, key) {
1965
+ if (UNSAFE_METHOD_NAMES.has(key)) return void 0;
1930
1966
  const g = scope.getters[key];
1931
1967
  return g ? g() : void 0;
1932
1968
  }
@@ -2082,6 +2118,7 @@ function buildHandler(expr, scope) {
2082
2118
  return key in scope.getters || key in scope.setters;
2083
2119
  },
2084
2120
  get(_, key) {
2121
+ if (UNSAFE_METHOD_NAMES.has(key)) return void 0;
2085
2122
  const g = scope.getters[key];
2086
2123
  return g ? g() : void 0;
2087
2124
  },
@@ -2117,11 +2154,10 @@ function parseState(raw) {
2117
2154
  try {
2118
2155
  parsed = JSON.parse(raw);
2119
2156
  } catch {
2120
- try {
2121
- parsed = JSON.parse(raw.replace(RE_UNQUOTED_KEYS, '"$1":'));
2122
- } catch {
2123
- return {};
2157
+ if (_debug) {
2158
+ dbg("parseState: Invalid JSON in data-forma-state \u2014 use valid JSON with quoted keys. Got:", raw.slice(0, 200));
2124
2159
  }
2160
+ return {};
2125
2161
  }
2126
2162
  for (const key of FORBIDDEN_STATE_KEYS) {
2127
2163
  if (key in parsed) delete parsed[key];
@@ -2141,7 +2177,7 @@ function initScope(stateEl) {
2141
2177
  const getters = {};
2142
2178
  const setters = {};
2143
2179
  for (const [key, initial] of Object.entries(state)) {
2144
- const [get, set] = createValueSignal(initial);
2180
+ const [get, set] = createSignal(initial);
2145
2181
  getters[key] = get;
2146
2182
  setters[key] = set;
2147
2183
  }
@@ -2149,6 +2185,18 @@ function initScope(stateEl) {
2149
2185
  return { getters, setters };
2150
2186
  }
2151
2187
  function bindElement(el, scope, disposers) {
2188
+ const elMagics = {
2189
+ $el: el,
2190
+ $dispatch: (name, detail) => {
2191
+ el.dispatchEvent(new CustomEvent(name, {
2192
+ bubbles: true,
2193
+ composed: true,
2194
+ // crosses Shadow DOM boundaries (important for <forma-stage>)
2195
+ detail
2196
+ }));
2197
+ }
2198
+ };
2199
+ scope = createChildScope(scope, elMagics);
2152
2200
  const known = getDirectives(el);
2153
2201
  const computedAttr = !known || known.has("data-computed") ? el.getAttribute("data-computed") : null;
2154
2202
  if (computedAttr) {
@@ -2528,16 +2576,16 @@ function bindElement(el, scope, disposers) {
2528
2576
  else if (k === "error") errorTarget = v;
2529
2577
  else if (k === "poll") interval = parseInt(v ?? "0", 10);
2530
2578
  }
2531
- const [getTarget, setTarget] = createValueSignal(null);
2579
+ const [getTarget, setTarget] = createSignal(null);
2532
2580
  scope.getters[target] = getTarget;
2533
2581
  scope.setters[target] = setTarget;
2534
2582
  if (loadingTarget) {
2535
- const [gl, sl] = createValueSignal(false);
2583
+ const [gl, sl] = createSignal(false);
2536
2584
  scope.getters[loadingTarget] = gl;
2537
2585
  scope.setters[loadingTarget] = sl;
2538
2586
  }
2539
2587
  if (errorTarget) {
2540
- const [ge, se] = createValueSignal(null);
2588
+ const [ge, se] = createSignal(null);
2541
2589
  scope.getters[errorTarget] = ge;
2542
2590
  scope.setters[errorTarget] = se;
2543
2591
  }