@getforma/core 0.3.1 → 0.8.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.
- package/README.md +279 -20
- package/dist/chunk-3U57L2TY.cjs +38 -0
- package/dist/chunk-3U57L2TY.cjs.map +1 -0
- package/dist/{chunk-5H52PKGF.js → chunk-N522P3G6.js} +37 -19
- package/dist/chunk-N522P3G6.js.map +1 -0
- package/dist/chunk-OZCHIVAZ.js +35 -0
- package/dist/chunk-OZCHIVAZ.js.map +1 -0
- package/dist/{chunk-TSQ7AKFT.cjs → chunk-YMIMKO4W.cjs} +66 -25
- package/dist/chunk-YMIMKO4W.cjs.map +1 -0
- package/dist/forma-runtime-csp.js +1 -1
- package/dist/forma-runtime.js +1 -1
- package/dist/formajs-runtime-hardened.global.js +1 -1
- package/dist/formajs-runtime-hardened.global.js.map +1 -1
- package/dist/formajs-runtime.global.js +1 -1
- package/dist/formajs-runtime.global.js.map +1 -1
- package/dist/formajs.global.js +1 -1
- package/dist/formajs.global.js.map +1 -1
- package/dist/index.cjs +142 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -29
- package/dist/index.d.ts +70 -29
- package/dist/index.js +64 -60
- package/dist/index.js.map +1 -1
- package/dist/runtime-hardened.cjs +166 -39
- package/dist/runtime-hardened.cjs.map +1 -1
- package/dist/runtime-hardened.js +167 -40
- package/dist/runtime-hardened.js.map +1 -1
- package/dist/runtime.cjs +184 -57
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +162 -35
- package/dist/runtime.js.map +1 -1
- package/dist/signal-B4_wQJHs.d.cts +53 -0
- package/dist/signal-B4_wQJHs.d.ts +53 -0
- package/dist/ssr/index.cjs +37 -12
- package/dist/ssr/index.cjs.map +1 -1
- package/dist/ssr/index.js +37 -12
- package/dist/ssr/index.js.map +1 -1
- package/dist/tc39-compat.cjs +4 -12
- package/dist/tc39-compat.cjs.map +1 -1
- package/dist/tc39-compat.d.cts +1 -1
- package/dist/tc39-compat.d.ts +1 -1
- package/dist/tc39-compat.js +3 -11
- package/dist/tc39-compat.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-5H52PKGF.js.map +0 -1
- package/dist/chunk-FPSLC62A.cjs +0 -31
- package/dist/chunk-FPSLC62A.cjs.map +0 -1
- package/dist/chunk-KX5WRZH7.js +0 -27
- package/dist/chunk-KX5WRZH7.js.map +0 -1
- package/dist/chunk-TSQ7AKFT.cjs.map +0 -1
- package/dist/signal-CfLDwMyg.d.cts +0 -29
- package/dist/signal-CfLDwMyg.d.ts +0 -29
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { internalEffect, reconcileList, batch } from './chunk-
|
|
2
|
-
import {
|
|
1
|
+
import { internalEffect, reconcileList, batch } from './chunk-N522P3G6.js';
|
|
2
|
+
import { createSignal, createComputed } from './chunk-OZCHIVAZ.js';
|
|
3
3
|
|
|
4
4
|
// src/dom/reconcile.ts
|
|
5
5
|
function getBindTargets(el) {
|
|
@@ -576,12 +576,11 @@ var RE_TOGGLE = /^(\w+)\s*=\s*!(\w+)$/;
|
|
|
576
576
|
var RE_ASSIGN = /^(\w+)\s*=\s*(.+)$/;
|
|
577
577
|
var RE_COMPOUND = /^(\w+)\s*(\+=|-=|\*=|\/=)\s*(.+)$/;
|
|
578
578
|
var RE_IF_PREFIX = /^if\b/;
|
|
579
|
-
var RE_UNQUOTED_KEYS = /(\w+)\s*:/g;
|
|
580
579
|
var RE_COMPUTED = /^(\w+)\s*=\s*(.+)$/;
|
|
581
580
|
var RE_FETCH = /^(.+?)(?:→|->)\s*(\S+)(.*)$/;
|
|
582
581
|
var RE_FETCH_METHOD = /^(GET|POST|PUT|PATCH|DELETE)\s+(.+)$/i;
|
|
583
582
|
var RE_STRIP_ITEM_BRACES = /^\{item\.?|\}$/g;
|
|
584
|
-
var RE_EVENT_REF = /\bevent\
|
|
583
|
+
var RE_EVENT_REF = /\bevent\s*[.([]|\$event\b/;
|
|
585
584
|
var RE_REFETCH_CALL = /^\$refetch\(\s*['"]([^'"]+)['"]\s*\)$/;
|
|
586
585
|
var TRANSITION_STATE_SYM = /* @__PURE__ */ Symbol.for("forma-transition-state");
|
|
587
586
|
var EXPRESSION_CACHE_MAX = 2048;
|
|
@@ -596,6 +595,14 @@ function cacheExpression(key, factory) {
|
|
|
596
595
|
var scopeExpressionCache = /* @__PURE__ */ new WeakMap();
|
|
597
596
|
var scopeHandlerCache = /* @__PURE__ */ new WeakMap();
|
|
598
597
|
var compiledTemplateCache = /* @__PURE__ */ new Map();
|
|
598
|
+
var COMPILED_TEMPLATE_CACHE_MAX = 2048;
|
|
599
|
+
function cacheCompiledTemplate(key, template) {
|
|
600
|
+
if (compiledTemplateCache.size >= COMPILED_TEMPLATE_CACHE_MAX) {
|
|
601
|
+
const first = compiledTemplateCache.keys().next().value;
|
|
602
|
+
if (first !== void 0) compiledTemplateCache.delete(first);
|
|
603
|
+
}
|
|
604
|
+
compiledTemplateCache.set(key, template);
|
|
605
|
+
}
|
|
599
606
|
var UNSAFE_METHOD_NAMES = /* @__PURE__ */ new Set([
|
|
600
607
|
"constructor",
|
|
601
608
|
"__proto__",
|
|
@@ -604,7 +611,8 @@ var UNSAFE_METHOD_NAMES = /* @__PURE__ */ new Set([
|
|
|
604
611
|
"__defineSetter__",
|
|
605
612
|
"__lookupGetter__",
|
|
606
613
|
"__lookupSetter__",
|
|
607
|
-
"eval"
|
|
614
|
+
"eval",
|
|
615
|
+
"Function"
|
|
608
616
|
]);
|
|
609
617
|
var BLOCKED_METHOD_REGEXES = (() => {
|
|
610
618
|
const result = [];
|
|
@@ -628,8 +636,36 @@ function findBlockedMethod(expr) {
|
|
|
628
636
|
if (dotRe.test(cleaned)) return name;
|
|
629
637
|
if (bracketRe.test(cleaned)) return name;
|
|
630
638
|
}
|
|
639
|
+
if (cleaned.includes("[")) {
|
|
640
|
+
const bracketContents = extractBracketContents(cleaned);
|
|
641
|
+
for (const content of bracketContents) {
|
|
642
|
+
if (!content.includes("+")) continue;
|
|
643
|
+
const fragments = content.match(/['"`]([^'"`]*?)['"`]/g);
|
|
644
|
+
if (!fragments) continue;
|
|
645
|
+
const joined = fragments.map((f) => f.slice(1, -1)).join("");
|
|
646
|
+
if (UNSAFE_METHOD_NAMES.has(joined)) return joined;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
631
649
|
return null;
|
|
632
650
|
}
|
|
651
|
+
function extractBracketContents(expr) {
|
|
652
|
+
const results = [];
|
|
653
|
+
let depth = 0;
|
|
654
|
+
let start = -1;
|
|
655
|
+
for (let i = 0; i < expr.length; i++) {
|
|
656
|
+
if (expr[i] === "[") {
|
|
657
|
+
if (depth === 0) start = i + 1;
|
|
658
|
+
depth++;
|
|
659
|
+
} else if (expr[i] === "]") {
|
|
660
|
+
depth--;
|
|
661
|
+
if (depth === 0 && start >= 0) {
|
|
662
|
+
results.push(expr.slice(start, i));
|
|
663
|
+
start = -1;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return results;
|
|
668
|
+
}
|
|
633
669
|
var TEXT_BINDING_SYM = /* @__PURE__ */ Symbol.for("forma-text-binding-cache");
|
|
634
670
|
function toTextValue(value) {
|
|
635
671
|
if (value == null) return "";
|
|
@@ -965,7 +1001,7 @@ function compileTemplate(text) {
|
|
|
965
1001
|
dynamics,
|
|
966
1002
|
hasItemRef: dynamics.length > 0
|
|
967
1003
|
};
|
|
968
|
-
|
|
1004
|
+
cacheCompiledTemplate(text, result);
|
|
969
1005
|
return result;
|
|
970
1006
|
}
|
|
971
1007
|
var templateTexts = /* @__PURE__ */ new WeakMap();
|
|
@@ -1502,14 +1538,6 @@ function parseExpressionUncached(expr, scope) {
|
|
|
1502
1538
|
return () => left() ?? right();
|
|
1503
1539
|
}
|
|
1504
1540
|
}
|
|
1505
|
-
const andMatch = expr.match(RE_AND);
|
|
1506
|
-
if (andMatch) {
|
|
1507
|
-
const left = parseExpression(andMatch[1].trim(), scope);
|
|
1508
|
-
const right = parseExpression(andMatch[2].trim(), scope);
|
|
1509
|
-
if (left && right) {
|
|
1510
|
-
return () => left() && right();
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
1541
|
const orMatch = expr.match(RE_OR);
|
|
1514
1542
|
if (orMatch) {
|
|
1515
1543
|
const left = parseExpression(orMatch[1].trim(), scope);
|
|
@@ -1518,6 +1546,14 @@ function parseExpressionUncached(expr, scope) {
|
|
|
1518
1546
|
return () => left() || right();
|
|
1519
1547
|
}
|
|
1520
1548
|
}
|
|
1549
|
+
const andMatch = expr.match(RE_AND);
|
|
1550
|
+
if (andMatch) {
|
|
1551
|
+
const left = parseExpression(andMatch[1].trim(), scope);
|
|
1552
|
+
const right = parseExpression(andMatch[2].trim(), scope);
|
|
1553
|
+
if (left && right) {
|
|
1554
|
+
return () => left() && right();
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1521
1557
|
const compMatch = expr.match(RE_COMPARISON);
|
|
1522
1558
|
if (compMatch) {
|
|
1523
1559
|
const left = parseExpression(compMatch[1].trim(), scope);
|
|
@@ -1547,6 +1583,19 @@ function parseExpressionUncached(expr, scope) {
|
|
|
1547
1583
|
};
|
|
1548
1584
|
}
|
|
1549
1585
|
}
|
|
1586
|
+
const addMatch = expr.match(RE_ADD);
|
|
1587
|
+
if (addMatch) {
|
|
1588
|
+
const left = parseExpression(addMatch[1].trim(), scope);
|
|
1589
|
+
const right = parseExpression(addMatch[3].trim(), scope);
|
|
1590
|
+
if (left && right) {
|
|
1591
|
+
const op = addMatch[2];
|
|
1592
|
+
return () => {
|
|
1593
|
+
const l = left(), r = right();
|
|
1594
|
+
if (op === "+") return l + r;
|
|
1595
|
+
return l - r;
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1550
1599
|
const mulMatch = expr.match(RE_MUL);
|
|
1551
1600
|
if (mulMatch) {
|
|
1552
1601
|
const left = parseExpression(mulMatch[1].trim(), scope);
|
|
@@ -1566,19 +1615,6 @@ function parseExpressionUncached(expr, scope) {
|
|
|
1566
1615
|
};
|
|
1567
1616
|
}
|
|
1568
1617
|
}
|
|
1569
|
-
const addMatch = expr.match(RE_ADD);
|
|
1570
|
-
if (addMatch) {
|
|
1571
|
-
const left = parseExpression(addMatch[1].trim(), scope);
|
|
1572
|
-
const right = parseExpression(addMatch[3].trim(), scope);
|
|
1573
|
-
if (left && right) {
|
|
1574
|
-
const op = addMatch[2];
|
|
1575
|
-
return () => {
|
|
1576
|
-
const l = left(), r = right();
|
|
1577
|
-
if (op === "+") return l + r;
|
|
1578
|
-
return l - r;
|
|
1579
|
-
};
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
1618
|
const tmplMatch = expr.match(RE_TEMPLATE_LIT);
|
|
1583
1619
|
if (tmplMatch) {
|
|
1584
1620
|
const raw = tmplMatch[1];
|
|
@@ -1653,6 +1689,7 @@ function buildEvaluator(expr, scope) {
|
|
|
1653
1689
|
return key in scope.getters;
|
|
1654
1690
|
},
|
|
1655
1691
|
get(_, key) {
|
|
1692
|
+
if (UNSAFE_METHOD_NAMES.has(key)) return void 0;
|
|
1656
1693
|
const g = scope.getters[key];
|
|
1657
1694
|
return g ? g() : void 0;
|
|
1658
1695
|
}
|
|
@@ -1808,6 +1845,7 @@ function buildHandler(expr, scope) {
|
|
|
1808
1845
|
return key in scope.getters || key in scope.setters;
|
|
1809
1846
|
},
|
|
1810
1847
|
get(_, key) {
|
|
1848
|
+
if (UNSAFE_METHOD_NAMES.has(key)) return void 0;
|
|
1811
1849
|
const g = scope.getters[key];
|
|
1812
1850
|
return g ? g() : void 0;
|
|
1813
1851
|
},
|
|
@@ -1843,11 +1881,10 @@ function parseState(raw) {
|
|
|
1843
1881
|
try {
|
|
1844
1882
|
parsed = JSON.parse(raw);
|
|
1845
1883
|
} catch {
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
} catch {
|
|
1849
|
-
return {};
|
|
1884
|
+
if (_debug) {
|
|
1885
|
+
dbg("parseState: Invalid JSON in data-forma-state \u2014 use valid JSON with quoted keys. Got:", raw.slice(0, 200));
|
|
1850
1886
|
}
|
|
1887
|
+
return {};
|
|
1851
1888
|
}
|
|
1852
1889
|
for (const key of FORBIDDEN_STATE_KEYS) {
|
|
1853
1890
|
if (key in parsed) delete parsed[key];
|
|
@@ -1867,14 +1904,104 @@ function initScope(stateEl) {
|
|
|
1867
1904
|
const getters = {};
|
|
1868
1905
|
const setters = {};
|
|
1869
1906
|
for (const [key, initial] of Object.entries(state)) {
|
|
1870
|
-
const [get, set] =
|
|
1907
|
+
const [get, set] = createSignal(initial);
|
|
1871
1908
|
getters[key] = get;
|
|
1872
1909
|
setters[key] = set;
|
|
1873
1910
|
}
|
|
1874
1911
|
getters["$refetch"] = () => $refetch;
|
|
1875
1912
|
return { getters, setters };
|
|
1876
1913
|
}
|
|
1914
|
+
var SAFE_EL_PROPS = /* @__PURE__ */ new Set([
|
|
1915
|
+
// Identity & attributes
|
|
1916
|
+
"id",
|
|
1917
|
+
"className",
|
|
1918
|
+
"tagName",
|
|
1919
|
+
"nodeName",
|
|
1920
|
+
"getAttribute",
|
|
1921
|
+
"setAttribute",
|
|
1922
|
+
"removeAttribute",
|
|
1923
|
+
"hasAttribute",
|
|
1924
|
+
"toggleAttribute",
|
|
1925
|
+
"dataset",
|
|
1926
|
+
"classList",
|
|
1927
|
+
// Content
|
|
1928
|
+
"textContent",
|
|
1929
|
+
"innerText",
|
|
1930
|
+
// Form elements
|
|
1931
|
+
"value",
|
|
1932
|
+
"checked",
|
|
1933
|
+
"disabled",
|
|
1934
|
+
"selected",
|
|
1935
|
+
"type",
|
|
1936
|
+
"name",
|
|
1937
|
+
"placeholder",
|
|
1938
|
+
"readOnly",
|
|
1939
|
+
"required",
|
|
1940
|
+
"min",
|
|
1941
|
+
"max",
|
|
1942
|
+
"step",
|
|
1943
|
+
"pattern",
|
|
1944
|
+
// Dimensions & position
|
|
1945
|
+
"getBoundingClientRect",
|
|
1946
|
+
"offsetWidth",
|
|
1947
|
+
"offsetHeight",
|
|
1948
|
+
"offsetTop",
|
|
1949
|
+
"offsetLeft",
|
|
1950
|
+
"clientWidth",
|
|
1951
|
+
"clientHeight",
|
|
1952
|
+
"scrollWidth",
|
|
1953
|
+
"scrollHeight",
|
|
1954
|
+
"scrollTop",
|
|
1955
|
+
"scrollLeft",
|
|
1956
|
+
// Style
|
|
1957
|
+
"style",
|
|
1958
|
+
"hidden",
|
|
1959
|
+
// Focus & interaction
|
|
1960
|
+
"focus",
|
|
1961
|
+
"blur",
|
|
1962
|
+
"click",
|
|
1963
|
+
"scrollIntoView",
|
|
1964
|
+
"scrollTo",
|
|
1965
|
+
// Traversal (safe — returns elements, not window/document)
|
|
1966
|
+
"closest",
|
|
1967
|
+
"matches",
|
|
1968
|
+
"querySelector",
|
|
1969
|
+
"querySelectorAll",
|
|
1970
|
+
"children",
|
|
1971
|
+
"childElementCount",
|
|
1972
|
+
"firstElementChild",
|
|
1973
|
+
"lastElementChild",
|
|
1974
|
+
"nextElementSibling",
|
|
1975
|
+
"previousElementSibling"
|
|
1976
|
+
]);
|
|
1977
|
+
function createSafeElProxy(el) {
|
|
1978
|
+
return new Proxy(el, {
|
|
1979
|
+
get(target, prop) {
|
|
1980
|
+
if (typeof prop === "symbol") return Reflect.get(target, prop);
|
|
1981
|
+
if (!SAFE_EL_PROPS.has(prop)) return void 0;
|
|
1982
|
+
const val = Reflect.get(target, prop);
|
|
1983
|
+
return typeof val === "function" ? val.bind(target) : val;
|
|
1984
|
+
},
|
|
1985
|
+
set(target, prop, value) {
|
|
1986
|
+
if (typeof prop === "symbol") return false;
|
|
1987
|
+
if (!SAFE_EL_PROPS.has(prop)) return false;
|
|
1988
|
+
return Reflect.set(target, prop, value);
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1877
1992
|
function bindElement(el, scope, disposers) {
|
|
1993
|
+
const elMagics = {
|
|
1994
|
+
$el: createSafeElProxy(el),
|
|
1995
|
+
$dispatch: (name, detail) => {
|
|
1996
|
+
el.dispatchEvent(new CustomEvent(name, {
|
|
1997
|
+
bubbles: true,
|
|
1998
|
+
composed: true,
|
|
1999
|
+
// crosses Shadow DOM boundaries (important for <forma-stage>)
|
|
2000
|
+
detail
|
|
2001
|
+
}));
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
scope = createChildScope(scope, elMagics);
|
|
1878
2005
|
const known = getDirectives(el);
|
|
1879
2006
|
const computedAttr = !known || known.has("data-computed") ? el.getAttribute("data-computed") : null;
|
|
1880
2007
|
if (computedAttr) {
|
|
@@ -2254,16 +2381,16 @@ function bindElement(el, scope, disposers) {
|
|
|
2254
2381
|
else if (k === "error") errorTarget = v;
|
|
2255
2382
|
else if (k === "poll") interval = parseInt(v ?? "0", 10);
|
|
2256
2383
|
}
|
|
2257
|
-
const [getTarget, setTarget] =
|
|
2384
|
+
const [getTarget, setTarget] = createSignal(null);
|
|
2258
2385
|
scope.getters[target] = getTarget;
|
|
2259
2386
|
scope.setters[target] = setTarget;
|
|
2260
2387
|
if (loadingTarget) {
|
|
2261
|
-
const [gl, sl] =
|
|
2388
|
+
const [gl, sl] = createSignal(false);
|
|
2262
2389
|
scope.getters[loadingTarget] = gl;
|
|
2263
2390
|
scope.setters[loadingTarget] = sl;
|
|
2264
2391
|
}
|
|
2265
2392
|
if (errorTarget) {
|
|
2266
|
-
const [ge, se] =
|
|
2393
|
+
const [ge, se] = createSignal(null);
|
|
2267
2394
|
scope.getters[errorTarget] = ge;
|
|
2268
2395
|
scope.setters[errorTarget] = se;
|
|
2269
2396
|
}
|