sibujs 4.7.0 → 4.8.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/browser.cjs +45 -4
- package/dist/browser.d.cts +23 -0
- package/dist/browser.d.ts +23 -0
- package/dist/browser.js +6 -5
- package/dist/build.cjs +513 -78
- package/dist/build.d.cts +22 -8
- package/dist/build.d.ts +22 -8
- package/dist/build.js +68 -21
- package/dist/cdn.dev.global.js +15 -13
- package/dist/cdn.full.dev.global.js +15 -13
- package/dist/cdn.full.global.js +14 -12
- package/dist/cdn.global.js +14 -12
- package/dist/chunk-3ACAAQIN.js +224 -0
- package/dist/{chunk-DKXRACVN.js → chunk-44MTL7ED.js} +6 -6
- package/dist/{chunk-3QWBSL5R.js → chunk-4WMSTZ7J.js} +8 -5
- package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
- package/dist/{chunk-BSY63EM6.js → chunk-C5PEWEGH.js} +20 -5
- package/dist/{chunk-BC2SECJD.js → chunk-C7AA2CZX.js} +1 -1
- package/dist/{chunk-SLM3IA34.js → chunk-CZPRSWSS.js} +1 -1
- package/dist/{chunk-FQRUXCEE.js → chunk-DSID757X.js} +1 -1
- package/dist/{chunk-ZVL7TY4K.js → chunk-EGUQLBHE.js} +22 -8
- package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
- package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
- package/dist/{chunk-Z3OHK6QT.js → chunk-GSGNX35Q.js} +5 -5
- package/dist/{chunk-XYV3EDB7.js → chunk-J3YQ457H.js} +37 -20
- package/dist/{chunk-VZSG24LS.js → chunk-JUTFX2RM.js} +18 -10
- package/dist/{chunk-RUSSKG6G.js → chunk-KJ3UKABJ.js} +1 -1
- package/dist/{chunk-UNWRJRKC.js → chunk-LI4W3U6C.js} +1 -1
- package/dist/{chunk-FNJXNGYZ.js → chunk-O6TRVMJI.js} +58 -6
- package/dist/{chunk-7LUJQAOJ.js → chunk-Q5J2LVKH.js} +1 -1
- package/dist/{chunk-4AWA2PVD.js → chunk-QGMSESDD.js} +10 -5
- package/dist/{chunk-XZR4PXRE.js → chunk-RGLPEBDE.js} +13 -10
- package/dist/{chunk-JWKYU5GV.js → chunk-TQQUN4WR.js} +1 -1
- package/dist/{chunk-WOLJZUFQ.js → chunk-UCNP3HVM.js} +12 -8
- package/dist/{chunk-WEQ3DMVL.js → chunk-V3LHZSU5.js} +1 -1
- package/dist/{chunk-UOL2ECCS.js → chunk-VWT3VXPL.js} +18 -12
- package/dist/{chunk-2BPG2XDA.js → chunk-ZVLHNEEL.js} +17 -35
- package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
- package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
- package/dist/data.cjs +9 -2
- package/dist/data.js +6 -6
- package/dist/devtools.cjs +1 -1
- package/dist/devtools.js +5 -5
- package/dist/ecosystem.cjs +400 -37
- package/dist/ecosystem.js +9 -8
- package/dist/extras.cjs +621 -252
- package/dist/extras.d.cts +2 -2
- package/dist/extras.d.ts +2 -2
- package/dist/extras.js +24 -23
- package/dist/index.cjs +464 -70
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +16 -12
- package/dist/motion.cjs +1 -1
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +10 -7
- package/dist/patterns.js +6 -6
- package/dist/performance.cjs +31 -2
- package/dist/performance.d.cts +12 -2
- package/dist/performance.d.ts +12 -2
- package/dist/performance.js +8 -6
- package/dist/plugins.cjs +558 -231
- package/dist/plugins.d.cts +8 -3
- package/dist/plugins.d.ts +8 -3
- package/dist/plugins.js +22 -28
- package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
- package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.cts} +6 -0
- package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.ts} +6 -0
- package/dist/ssr.cjs +457 -131
- package/dist/ssr.d.cts +55 -5
- package/dist/ssr.d.ts +55 -5
- package/dist/ssr.js +11 -9
- package/dist/testing.cjs +3 -3
- package/dist/testing.js +4 -4
- package/dist/ui.cjs +608 -240
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +9 -8
- package/dist/widgets.cjs +1 -1
- package/dist/widgets.js +7 -7
- package/package.json +5 -4
package/dist/build.cjs
CHANGED
|
@@ -791,6 +791,11 @@ function devWarn(message) {
|
|
|
791
791
|
function stripControlChars(value) {
|
|
792
792
|
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
793
793
|
}
|
|
794
|
+
var ASCII_UPPER = /[A-Z]/;
|
|
795
|
+
var ASCII_UPPER_G = /[A-Z]/g;
|
|
796
|
+
function canonicalAttrName(name) {
|
|
797
|
+
return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
|
|
798
|
+
}
|
|
794
799
|
function isEventHandlerAttr(name) {
|
|
795
800
|
if (name.length < 3) return false;
|
|
796
801
|
const lower = name.toLowerCase();
|
|
@@ -802,6 +807,9 @@ function sanitizeUrl(url) {
|
|
|
802
807
|
const probe = stripControlChars(url).trim();
|
|
803
808
|
if (!probe) return "";
|
|
804
809
|
const output2 = url.replace(OUTER_TRIM, "");
|
|
810
|
+
if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
|
|
811
|
+
return "";
|
|
812
|
+
}
|
|
805
813
|
const lower = probe.toLowerCase();
|
|
806
814
|
let schemeEnd = -1;
|
|
807
815
|
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
@@ -818,19 +826,58 @@ function sanitizeUrl(url) {
|
|
|
818
826
|
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
819
827
|
return output2;
|
|
820
828
|
}
|
|
821
|
-
var SRCSET_DESCRIPTOR = /^\
|
|
829
|
+
var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
|
|
830
|
+
function isSrcsetWhitespace(ch) {
|
|
831
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
832
|
+
}
|
|
822
833
|
function sanitizeSrcset(value) {
|
|
823
|
-
const
|
|
834
|
+
const input2 = String(value);
|
|
824
835
|
const out = [];
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
if (
|
|
830
|
-
|
|
831
|
-
|
|
836
|
+
let i2 = 0;
|
|
837
|
+
const n = input2.length;
|
|
838
|
+
while (i2 < n) {
|
|
839
|
+
while (i2 < n && (isSrcsetWhitespace(input2[i2]) || input2[i2] === ",")) i2++;
|
|
840
|
+
if (i2 >= n) break;
|
|
841
|
+
const urlStart = i2;
|
|
842
|
+
while (i2 < n && !isSrcsetWhitespace(input2[i2])) i2++;
|
|
843
|
+
let url = input2.slice(urlStart, i2);
|
|
844
|
+
const descriptors = [];
|
|
845
|
+
if (url.endsWith(",")) {
|
|
846
|
+
url = url.replace(/,+$/, "");
|
|
847
|
+
} else {
|
|
848
|
+
let current = "";
|
|
849
|
+
let inParens = false;
|
|
850
|
+
while (i2 < n) {
|
|
851
|
+
const ch = input2[i2];
|
|
852
|
+
if (inParens) {
|
|
853
|
+
current += ch;
|
|
854
|
+
if (ch === ")") inParens = false;
|
|
855
|
+
i2++;
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (isSrcsetWhitespace(ch)) {
|
|
859
|
+
if (current) descriptors.push(current);
|
|
860
|
+
current = "";
|
|
861
|
+
i2++;
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
if (ch === ",") {
|
|
865
|
+
i2++;
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
if (ch === "(") inParens = true;
|
|
869
|
+
current += ch;
|
|
870
|
+
i2++;
|
|
871
|
+
}
|
|
872
|
+
if (current) descriptors.push(current);
|
|
873
|
+
}
|
|
874
|
+
if (url === "") continue;
|
|
875
|
+
if (descriptors.length > 1) continue;
|
|
876
|
+
if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
|
|
877
|
+
const safe = sanitizeUrl(url);
|
|
832
878
|
if (!safe) continue;
|
|
833
|
-
|
|
879
|
+
if (safe.startsWith(",") || safe.endsWith(",")) continue;
|
|
880
|
+
out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
|
|
834
881
|
}
|
|
835
882
|
return out.join(", ");
|
|
836
883
|
}
|
|
@@ -889,8 +936,16 @@ var BLOCKED_CSS_NEEDLES = [
|
|
|
889
936
|
"behavior:",
|
|
890
937
|
"@import",
|
|
891
938
|
"image-set(",
|
|
892
|
-
"filter:progid"
|
|
939
|
+
"filter:progid",
|
|
940
|
+
// CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
|
|
941
|
+
// plain STRING, so they fetch without ever spelling `url(`. Support is thin
|
|
942
|
+
// today, which is exactly when a blocklist should get ahead of it.
|
|
943
|
+
"image(",
|
|
944
|
+
"src("
|
|
893
945
|
];
|
|
946
|
+
var CSS_REASON_MOZ_BINDING = 4;
|
|
947
|
+
var CSS_REASON_BEHAVIOR = 5;
|
|
948
|
+
var CSS_REASON_PROGID = 8;
|
|
894
949
|
function describeElement(el) {
|
|
895
950
|
if (!el) return "an element";
|
|
896
951
|
let out = el.tagName.toLowerCase();
|
|
@@ -914,7 +969,9 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
914
969
|
"behavior: loads and runs a remote HTC script",
|
|
915
970
|
"@import pulls in a remote stylesheet",
|
|
916
971
|
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
917
|
-
"filter:progid activates legacy scriptable filters"
|
|
972
|
+
"filter:progid activates legacy scriptable filters",
|
|
973
|
+
"image() fetches its string argument as a URL, the same exfiltration channel as url()",
|
|
974
|
+
"src() fetches its string argument as a URL, the same exfiltration channel as url()"
|
|
918
975
|
];
|
|
919
976
|
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
920
977
|
const where = describeElement(ctx?.element);
|
|
@@ -929,27 +986,110 @@ function warnDroppedDeclaration(value, reason, ctx) {
|
|
|
929
986
|
return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
|
|
930
987
|
});
|
|
931
988
|
}
|
|
989
|
+
function normalizeCssForScan(value) {
|
|
990
|
+
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
991
|
+
return normalized.toLowerCase().replace(/\s+/g, "");
|
|
992
|
+
}
|
|
932
993
|
function blockedCssReason(value) {
|
|
933
994
|
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
934
|
-
const
|
|
935
|
-
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
995
|
+
const lower = normalizeCssForScan(value);
|
|
936
996
|
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
937
997
|
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
938
998
|
}
|
|
939
999
|
return -1;
|
|
940
1000
|
}
|
|
941
|
-
function
|
|
942
|
-
const reason =
|
|
1001
|
+
function sanitizeCSSDeclaration(property, value, context2) {
|
|
1002
|
+
const reason = blockedDeclarationReason(property, value);
|
|
943
1003
|
if (reason === -1) return value;
|
|
944
|
-
warnDroppedDeclaration(value, reason, context2);
|
|
1004
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
945
1005
|
return "";
|
|
946
1006
|
}
|
|
1007
|
+
function blockedDeclarationReason(property, value) {
|
|
1008
|
+
const reason = blockedCssReason(value);
|
|
1009
|
+
if (reason !== -1) return reason;
|
|
1010
|
+
const name = canonicalAttrName(property);
|
|
1011
|
+
if (name === "behavior") return CSS_REASON_BEHAVIOR;
|
|
1012
|
+
if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
|
|
1013
|
+
if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
|
|
1014
|
+
return CSS_REASON_PROGID;
|
|
1015
|
+
}
|
|
1016
|
+
return -1;
|
|
1017
|
+
}
|
|
1018
|
+
function parseStyleDeclarations(css) {
|
|
1019
|
+
const chunks = [];
|
|
1020
|
+
let buf = "";
|
|
1021
|
+
let depth = 0;
|
|
1022
|
+
let quote2 = "";
|
|
1023
|
+
for (let i2 = 0; i2 < css.length; i2++) {
|
|
1024
|
+
const ch = css[i2];
|
|
1025
|
+
if (quote2) {
|
|
1026
|
+
buf += ch;
|
|
1027
|
+
if (ch === "\\" && i2 + 1 < css.length) buf += css[++i2];
|
|
1028
|
+
else if (ch === quote2) quote2 = "";
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
if (ch === "\\") {
|
|
1032
|
+
buf += ch;
|
|
1033
|
+
if (i2 + 1 < css.length) buf += css[++i2];
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
if (ch === "/" && css[i2 + 1] === "*") {
|
|
1037
|
+
const end = css.indexOf("*/", i2 + 2);
|
|
1038
|
+
if (end === -1) return null;
|
|
1039
|
+
i2 = end + 1;
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
if (ch === '"' || ch === "'") quote2 = ch;
|
|
1043
|
+
else if (ch === "(" || ch === "[") depth++;
|
|
1044
|
+
else if (ch === ")" || ch === "]") {
|
|
1045
|
+
if (--depth < 0) return null;
|
|
1046
|
+
} else if (ch === "{" || ch === "}") return null;
|
|
1047
|
+
else if (ch === ";" && depth === 0) {
|
|
1048
|
+
chunks.push(buf);
|
|
1049
|
+
buf = "";
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
buf += ch;
|
|
1053
|
+
}
|
|
1054
|
+
if (quote2 || depth !== 0) return null;
|
|
1055
|
+
chunks.push(buf);
|
|
1056
|
+
const out = [];
|
|
1057
|
+
for (const chunk of chunks) {
|
|
1058
|
+
const colon = chunk.indexOf(":");
|
|
1059
|
+
if (colon === -1) continue;
|
|
1060
|
+
const rawName = chunk.slice(0, colon).trim();
|
|
1061
|
+
if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
|
|
1062
|
+
let value = chunk.slice(colon + 1).trim();
|
|
1063
|
+
const bang = /!\s*important\s*$/i.exec(value);
|
|
1064
|
+
if (bang) value = value.slice(0, bang.index).trim();
|
|
1065
|
+
if (value === "") continue;
|
|
1066
|
+
const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
|
|
1067
|
+
out.push([property, value, bang !== null]);
|
|
1068
|
+
}
|
|
1069
|
+
return out;
|
|
1070
|
+
}
|
|
1071
|
+
function sanitizeStyleDeclarationList(cssText, context2) {
|
|
1072
|
+
const input2 = String(cssText);
|
|
1073
|
+
const declarations = parseStyleDeclarations(input2);
|
|
1074
|
+
if (declarations === null) {
|
|
1075
|
+
if (blockedCssReason(input2) !== -1) warnDroppedDeclaration(input2, blockedCssReason(input2), context2);
|
|
1076
|
+
return "";
|
|
1077
|
+
}
|
|
1078
|
+
const kept = [];
|
|
1079
|
+
for (const [property, value, important] of declarations) {
|
|
1080
|
+
const reason = blockedDeclarationReason(property, value);
|
|
1081
|
+
if (reason !== -1) {
|
|
1082
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
kept.push(`${property}: ${value}${important ? " !important" : ""}`);
|
|
1086
|
+
}
|
|
1087
|
+
return kept.join("; ");
|
|
1088
|
+
}
|
|
947
1089
|
function sanitizeStyleAttribute(cssText, context2) {
|
|
948
1090
|
const input2 = String(cssText);
|
|
949
1091
|
if (input2.trim() === "") return "";
|
|
950
|
-
if (typeof document === "undefined")
|
|
951
|
-
return sanitizeCSSValue(input2, context2) === "" ? "" : input2;
|
|
952
|
-
}
|
|
1092
|
+
if (typeof document === "undefined") return sanitizeStyleDeclarationList(input2, context2);
|
|
953
1093
|
const probe = document.createElement("div");
|
|
954
1094
|
try {
|
|
955
1095
|
probe.style.cssText = input2;
|
|
@@ -960,8 +1100,7 @@ function sanitizeStyleAttribute(cssText, context2) {
|
|
|
960
1100
|
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
961
1101
|
const property = probe.style[i2];
|
|
962
1102
|
const value = probe.style.getPropertyValue(property);
|
|
963
|
-
|
|
964
|
-
if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
|
|
1103
|
+
const reason = blockedDeclarationReason(property, value);
|
|
965
1104
|
if (reason !== -1) {
|
|
966
1105
|
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
967
1106
|
continue;
|
|
@@ -996,6 +1135,10 @@ function isHtmlContentAttribute(name) {
|
|
|
996
1135
|
function isUrlAttribute(attr) {
|
|
997
1136
|
return URL_ATTRIBUTES.has(attr.toLowerCase());
|
|
998
1137
|
}
|
|
1138
|
+
function isPolicyAttribute(name) {
|
|
1139
|
+
const lower = name.toLowerCase();
|
|
1140
|
+
return lower === "style" || URL_ATTRIBUTES.has(lower);
|
|
1141
|
+
}
|
|
999
1142
|
function sanitizeAttributeString(attr, value, context2) {
|
|
1000
1143
|
const lower = attr.toLowerCase();
|
|
1001
1144
|
if (lower === "srcset") return sanitizeSrcset(value);
|
|
@@ -1003,6 +1146,11 @@ function sanitizeAttributeString(attr, value, context2) {
|
|
|
1003
1146
|
if (lower === "style") return sanitizeStyleAttribute(value, context2);
|
|
1004
1147
|
return value;
|
|
1005
1148
|
}
|
|
1149
|
+
function resolveAttributeValue(attr, value, context2) {
|
|
1150
|
+
if (!isPolicyAttribute(attr)) return value;
|
|
1151
|
+
const safe = sanitizeAttributeString(attr, value, context2);
|
|
1152
|
+
return safe === "" ? null : safe;
|
|
1153
|
+
}
|
|
1006
1154
|
|
|
1007
1155
|
// src/build/staticAnalysis.ts
|
|
1008
1156
|
var STATIC_TAGS = /* @__PURE__ */ new Set([
|
|
@@ -1456,6 +1604,11 @@ function generateBody(roots, h) {
|
|
|
1456
1604
|
const q2 = jsStringLiteral;
|
|
1457
1605
|
const P = h.prefix;
|
|
1458
1606
|
function genElement(el) {
|
|
1607
|
+
const tag = el.tag.toLowerCase();
|
|
1608
|
+
if (tag === "meta" || tag === "link") return null;
|
|
1609
|
+
for (const attr of el.attrs) {
|
|
1610
|
+
if ((attr.t === 0 || attr.t === 4) && attr.name.toLowerCase() === "srcdoc") return null;
|
|
1611
|
+
}
|
|
1459
1612
|
const v = `e${n++}`;
|
|
1460
1613
|
h.tags.add(el.tag);
|
|
1461
1614
|
if (el.svg) h.svg = true;
|
|
@@ -1547,6 +1700,9 @@ function helperSource(h) {
|
|
|
1547
1700
|
out.push(
|
|
1548
1701
|
`function ${P}on(el, name, handler) {
|
|
1549
1702
|
if (typeof handler === "function") el.addEventListener(name, handler);
|
|
1703
|
+
else if (typeof __SIBU_DEV__ !== "undefined" && __SIBU_DEV__) {
|
|
1704
|
+
console.warn(\`[SibuJS] html: on:\${name} handler is not a function (got \${typeof handler}). Event listener was not attached.\`);
|
|
1705
|
+
}
|
|
1550
1706
|
}`
|
|
1551
1707
|
);
|
|
1552
1708
|
}
|
|
@@ -1554,7 +1710,10 @@ function helperSource(h) {
|
|
|
1554
1710
|
out.push(
|
|
1555
1711
|
`function ${P}child(el, value) {
|
|
1556
1712
|
if (typeof value === "function") {
|
|
1557
|
-
|
|
1713
|
+
const frag = ${P}Fragment([value]);
|
|
1714
|
+
const ph = frag.firstChild;
|
|
1715
|
+
el.appendChild(frag);
|
|
1716
|
+
${P}registerDisposer(el, () => ${P}dispose(ph));
|
|
1558
1717
|
} else if (value instanceof Node) {
|
|
1559
1718
|
el.appendChild(value);
|
|
1560
1719
|
} else if (Array.isArray(value)) {
|
|
@@ -1574,13 +1733,22 @@ function helperSource(h) {
|
|
|
1574
1733
|
function importSource(h) {
|
|
1575
1734
|
const P = h.prefix;
|
|
1576
1735
|
const core = [];
|
|
1577
|
-
if (h.used.has("child")) core.push(`Fragment as ${P}Fragment`);
|
|
1578
|
-
if (h.used.has("attr")) core.push(`registerDisposer as ${P}registerDisposer`);
|
|
1736
|
+
if (h.used.has("child")) core.push(`Fragment as ${P}Fragment`, `dispose as ${P}dispose`);
|
|
1737
|
+
if (h.used.has("attr") || h.used.has("child")) core.push(`registerDisposer as ${P}registerDisposer`);
|
|
1738
|
+
if (h.used.has("run")) core.push(`__renderParsedTemplate as ${P}run`);
|
|
1579
1739
|
const lines = [];
|
|
1580
1740
|
if (core.length > 0) lines.push(`import { ${core.join(", ")} } from "sibujs";`);
|
|
1581
1741
|
if (h.used.has("attr")) lines.push(`import { bindAttrs as ${P}bindAttrs } from "sibujs/ui";`);
|
|
1582
1742
|
return lines.join("\n");
|
|
1583
1743
|
}
|
|
1744
|
+
function collectTags(children, h) {
|
|
1745
|
+
for (const child of children) {
|
|
1746
|
+
if (child.t !== 0) continue;
|
|
1747
|
+
h.tags.add(child.el.tag);
|
|
1748
|
+
if (child.el.svg) h.svg = true;
|
|
1749
|
+
collectTags(child.el.children, h);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1584
1752
|
function planHtmlTemplates(code2) {
|
|
1585
1753
|
const plan = {
|
|
1586
1754
|
edits: [],
|
|
@@ -1608,24 +1776,44 @@ function planHtmlTemplates(code2) {
|
|
|
1608
1776
|
const strings = [];
|
|
1609
1777
|
for (const qs of tmpl.quasis) {
|
|
1610
1778
|
const cooked = cookEscapes(code2.slice(qs.start, qs.end));
|
|
1611
|
-
if (cooked === null)
|
|
1779
|
+
if (cooked === null) {
|
|
1780
|
+
if (tmpl.quasis.length === 1) return null;
|
|
1781
|
+
strings.push("undefined");
|
|
1782
|
+
continue;
|
|
1783
|
+
}
|
|
1612
1784
|
strings.push(cooked);
|
|
1613
1785
|
}
|
|
1786
|
+
const name = `${h.prefix}t${functions.length}`;
|
|
1787
|
+
const params = tmpl.exprs.map((_, i2) => `v${i2}`).join(", ");
|
|
1614
1788
|
let roots;
|
|
1615
1789
|
try {
|
|
1616
1790
|
roots = parseTemplate(strings);
|
|
1617
1791
|
} catch (err) {
|
|
1618
|
-
if (err instanceof RuntimeParseError)
|
|
1792
|
+
if (err instanceof RuntimeParseError) {
|
|
1793
|
+
const message = `html: dynamic \${...} expressions are not allowed inside <${err.message}> (raw-text context). Build the content separately and append it as a Node.`;
|
|
1794
|
+
functions.push(`function ${name}(${params}) {
|
|
1795
|
+
throw new Error(${jsStringLiteral(message)});
|
|
1796
|
+
}`);
|
|
1797
|
+
return name;
|
|
1798
|
+
}
|
|
1619
1799
|
throw err;
|
|
1620
1800
|
}
|
|
1621
1801
|
const scratch = { prefix: h.prefix, used: /* @__PURE__ */ new Set(), tags: /* @__PURE__ */ new Set(), svg: false };
|
|
1622
1802
|
const body2 = generateBody(roots, scratch);
|
|
1623
|
-
if (body2 === null)
|
|
1803
|
+
if (body2 === null) {
|
|
1804
|
+
const tree = JSON.stringify(roots).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1805
|
+
h.used.add("run");
|
|
1806
|
+
collectTags(roots, h);
|
|
1807
|
+
functions.push(
|
|
1808
|
+
`function ${name}(${params}) {
|
|
1809
|
+
return ${h.prefix}run(${name}.tree || (${name}.tree = ${tree}), [${params}]);
|
|
1810
|
+
}`
|
|
1811
|
+
);
|
|
1812
|
+
return name;
|
|
1813
|
+
}
|
|
1624
1814
|
for (const u2 of scratch.used) h.used.add(u2);
|
|
1625
1815
|
for (const t of scratch.tags) h.tags.add(t);
|
|
1626
1816
|
if (scratch.svg) h.svg = true;
|
|
1627
|
-
const name = `${h.prefix}t${functions.length}`;
|
|
1628
|
-
const params = tmpl.exprs.map((_, i2) => `v${i2}`).join(", ");
|
|
1629
1817
|
functions.push(`function ${name}(${params}) {
|
|
1630
1818
|
${body2}
|
|
1631
1819
|
}`);
|
|
@@ -1903,6 +2091,11 @@ function sibuWebpackPlugin(options = {}) {
|
|
|
1903
2091
|
return {
|
|
1904
2092
|
name: "SibuWebpackPlugin",
|
|
1905
2093
|
apply(compiler) {
|
|
2094
|
+
if (options.pureAnnotations === true) {
|
|
2095
|
+
console.warn(
|
|
2096
|
+
'[SibuWebpackPlugin] `pureAnnotations` is not applied by the plugin: webpack needs a loader file. Create sibu-pure-loader.cjs containing `module.exports = require("sibujs/build").createPureAnnotationsLoader();` and add a module rule `{ test: /\\.[cm]?[jt]sx?$/, exclude: /node_modules/, use: "./sibu-pure-loader.cjs" }`.'
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
1906
2099
|
compiler.hooks?.compilation?.tap("SibuWebpackPlugin", (compilation) => {
|
|
1907
2100
|
const comp = compilation;
|
|
1908
2101
|
if (comp.hooks?.optimizeModules) {
|
|
@@ -2079,8 +2272,9 @@ __export(index_exports, {
|
|
|
2079
2272
|
Loading: () => Loading,
|
|
2080
2273
|
MAX_DRAIN_TEARDOWNS: () => MAX_DRAIN_TEARDOWNS,
|
|
2081
2274
|
Portal: () => Portal,
|
|
2082
|
-
SVG_NS: () =>
|
|
2275
|
+
SVG_NS: () => SVG_NS4,
|
|
2083
2276
|
Suspense: () => Suspense,
|
|
2277
|
+
__renderParsedTemplate: () => __renderParsedTemplate,
|
|
2084
2278
|
__resetIdCounter: () => __resetIdCounter,
|
|
2085
2279
|
a: () => a,
|
|
2086
2280
|
abbr: () => abbr,
|
|
@@ -2552,26 +2746,227 @@ function checkLeaks(warnThreshold = 0) {
|
|
|
2552
2746
|
return activeBindingCount;
|
|
2553
2747
|
}
|
|
2554
2748
|
|
|
2555
|
-
// src/utils/
|
|
2749
|
+
// src/utils/metaRefresh.ts
|
|
2750
|
+
function isAsciiWhitespace(ch) {
|
|
2751
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
2752
|
+
}
|
|
2753
|
+
function trimAsciiWhitespace(value) {
|
|
2754
|
+
let start = 0;
|
|
2755
|
+
let end = value.length;
|
|
2756
|
+
while (start < end && isAsciiWhitespace(value[start])) start++;
|
|
2757
|
+
while (end > start && isAsciiWhitespace(value[end - 1])) end--;
|
|
2758
|
+
return value.slice(start, end);
|
|
2759
|
+
}
|
|
2760
|
+
var forbidden = (reason) => ({ kind: "forbidden", reason });
|
|
2761
|
+
function parseMetaRefreshContent(content) {
|
|
2762
|
+
const raw = trimAsciiWhitespace(stripControlChars(content));
|
|
2763
|
+
if (raw === "") return forbidden(DEV ? "empty content" : "");
|
|
2764
|
+
let i2 = 0;
|
|
2765
|
+
while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
|
|
2766
|
+
if (i2 === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
|
|
2767
|
+
const delay = Number.parseInt(raw.slice(0, i2), 10);
|
|
2768
|
+
if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
|
|
2769
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2770
|
+
if (i2 === raw.length) return { kind: "delay-only", delay };
|
|
2771
|
+
if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
|
|
2772
|
+
i2++;
|
|
2773
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2774
|
+
const keyStart = i2;
|
|
2775
|
+
while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
|
|
2776
|
+
const key = raw.slice(keyStart, i2).toLowerCase();
|
|
2777
|
+
if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
|
|
2778
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2779
|
+
if (raw[i2] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
|
|
2780
|
+
i2++;
|
|
2781
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2782
|
+
let destination;
|
|
2783
|
+
const quote2 = raw[i2];
|
|
2784
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
2785
|
+
const close = raw.indexOf(quote2, i2 + 1);
|
|
2786
|
+
if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
|
|
2787
|
+
destination = raw.slice(i2 + 1, close);
|
|
2788
|
+
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
2789
|
+
if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
|
|
2790
|
+
} else {
|
|
2791
|
+
destination = trimAsciiWhitespace(raw.slice(i2));
|
|
2792
|
+
if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
|
|
2793
|
+
}
|
|
2794
|
+
if (destination === "") return forbidden(DEV ? "empty destination" : "");
|
|
2795
|
+
const sanitizedDestination = sanitizeUrl(destination);
|
|
2796
|
+
if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
|
|
2797
|
+
return { kind: "allowed", delay, destination, sanitizedDestination };
|
|
2798
|
+
}
|
|
2799
|
+
function resolveMetaRefreshPolicy(attributes) {
|
|
2800
|
+
let httpEquiv;
|
|
2801
|
+
let content;
|
|
2802
|
+
let duplicateName;
|
|
2803
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2804
|
+
for (const [key, value] of attributes) {
|
|
2805
|
+
const canonical = canonicalAttrName(key);
|
|
2806
|
+
if (seen.has(canonical)) duplicateName = canonical;
|
|
2807
|
+
seen.add(canonical);
|
|
2808
|
+
if (canonical === "http-equiv") httpEquiv = value;
|
|
2809
|
+
else if (canonical === "content") content = value;
|
|
2810
|
+
}
|
|
2811
|
+
if (duplicateName !== void 0) {
|
|
2812
|
+
return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
|
|
2813
|
+
}
|
|
2814
|
+
if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
|
|
2815
|
+
if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
|
|
2816
|
+
return { kind: "not-refresh" };
|
|
2817
|
+
}
|
|
2818
|
+
if (typeof content !== "string") return { kind: "not-refresh" };
|
|
2819
|
+
return parseMetaRefreshContent(content);
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
// src/utils/elementPolicy.ts
|
|
2556
2823
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
2557
2824
|
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
2825
|
+
var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
2826
|
+
function canonicalTagName(tag) {
|
|
2827
|
+
return canonicalAttrName(tag);
|
|
2828
|
+
}
|
|
2829
|
+
function isBlockedElement(tag) {
|
|
2830
|
+
return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
|
|
2831
|
+
}
|
|
2832
|
+
var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
2833
|
+
function isCodeTextElement(tag) {
|
|
2834
|
+
return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
|
|
2835
|
+
}
|
|
2836
|
+
var ContextualRefusal = {
|
|
2837
|
+
None: 0,
|
|
2838
|
+
/** The element would carry a refresh directive the shared policy forbids. */
|
|
2839
|
+
MetaRefreshForbidden: 1,
|
|
2840
|
+
/** A `<meta>` with a reactive binding may not carry any refresh directive. */
|
|
2841
|
+
MetaRefreshReactive: 2,
|
|
2842
|
+
/** A runtime value may not choose which program a `<script>` runs. */
|
|
2843
|
+
ScriptSource: 3,
|
|
2844
|
+
/** An SVG animation may not target a URL, handler or document attribute. */
|
|
2845
|
+
AnimationTarget: 4,
|
|
2846
|
+
/** A runtime-written `href` may not become an applied stylesheet. */
|
|
2847
|
+
StylesheetSource: 5
|
|
2848
|
+
};
|
|
2849
|
+
var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
|
|
2850
|
+
var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
|
|
2851
|
+
var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
|
|
2852
|
+
function isHtmlNamespace(el) {
|
|
2853
|
+
return el.namespaceURI === HTML_NS || el.namespaceURI === null;
|
|
2854
|
+
}
|
|
2855
|
+
function metaSnapshot(el, canonical, value) {
|
|
2856
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
2857
|
+
const attrs = el.attributes;
|
|
2858
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
2859
|
+
const attr = attrs[i2];
|
|
2860
|
+
if (attr.name === canonical) continue;
|
|
2861
|
+
snapshot.set(attr.name, attr.value);
|
|
2862
|
+
}
|
|
2863
|
+
if (canonical !== null && value !== null) snapshot.set(canonical, value);
|
|
2864
|
+
return snapshot;
|
|
2865
|
+
}
|
|
2866
|
+
function claimReactiveMeta(el) {
|
|
2867
|
+
if (reactiveMetaElements.has(el)) return;
|
|
2868
|
+
reactiveMetaElements.add(el);
|
|
2869
|
+
if (el.getAttribute("content") === null) return;
|
|
2870
|
+
if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
|
|
2871
|
+
el.removeAttribute("content");
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
function metaRefusal(el, name, value, origin) {
|
|
2875
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
2876
|
+
const canonical = canonicalAttrName(name);
|
|
2877
|
+
if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
|
|
2878
|
+
if (origin === "reactive") claimReactiveMeta(el);
|
|
2879
|
+
if (value === null) return ContextualRefusal.None;
|
|
2880
|
+
if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
|
|
2881
|
+
const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
|
|
2882
|
+
if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
|
|
2883
|
+
if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
|
|
2884
|
+
return ContextualRefusal.None;
|
|
2885
|
+
}
|
|
2886
|
+
function animationRefusal(name, value) {
|
|
2887
|
+
if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
|
|
2888
|
+
const target = stripControlChars(value);
|
|
2889
|
+
return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
|
|
2890
|
+
}
|
|
2891
|
+
var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
|
|
2892
|
+
function relHasStylesheet(rel) {
|
|
2893
|
+
if (rel === null) return false;
|
|
2894
|
+
const lower = canonicalAttrName(rel);
|
|
2895
|
+
if (!lower.includes("stylesheet")) return false;
|
|
2896
|
+
const tokens = lower.split(/[\t\n\f\r ]+/);
|
|
2897
|
+
for (let i2 = 0; i2 < tokens.length; i2++) if (tokens[i2] === "stylesheet") return true;
|
|
2898
|
+
return false;
|
|
2899
|
+
}
|
|
2900
|
+
function stylesheetRefusal(el, name, value, origin) {
|
|
2901
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
2902
|
+
const canonical = canonicalAttrName(name);
|
|
2903
|
+
if (canonical === "href") {
|
|
2904
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
2905
|
+
if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
|
|
2906
|
+
runtimeHrefLinks.add(el);
|
|
2907
|
+
return ContextualRefusal.None;
|
|
2908
|
+
}
|
|
2909
|
+
if (canonical === "rel") {
|
|
2910
|
+
if (!relHasStylesheet(value)) return ContextualRefusal.None;
|
|
2911
|
+
return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
|
|
2912
|
+
}
|
|
2913
|
+
return ContextualRefusal.None;
|
|
2914
|
+
}
|
|
2915
|
+
function contextualAttributeRefusal(el, name, value, origin) {
|
|
2916
|
+
const local = el.localName;
|
|
2917
|
+
if (local === "meta") return metaRefusal(el, name, value, origin);
|
|
2918
|
+
if (local === "link") return stylesheetRefusal(el, name, value, origin);
|
|
2919
|
+
if (local === "script") {
|
|
2920
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
2921
|
+
return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
|
|
2922
|
+
}
|
|
2923
|
+
if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS2) return animationRefusal(name, value);
|
|
2924
|
+
return ContextualRefusal.None;
|
|
2925
|
+
}
|
|
2926
|
+
function settleAttributeProvenance(el, name, origin) {
|
|
2927
|
+
if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
|
|
2928
|
+
if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
|
|
2929
|
+
else runtimeHrefLinks.delete(el);
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
// src/utils/setSafeAttribute.ts
|
|
2933
|
+
var HTML_NS2 = "http://www.w3.org/1999/xhtml";
|
|
2934
|
+
var SVG_NS3 = "http://www.w3.org/2000/svg";
|
|
2558
2935
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
2559
2936
|
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
2560
2937
|
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
2561
2938
|
function isHtmlElement(el) {
|
|
2562
|
-
return el.namespaceURI === null || el.namespaceURI ===
|
|
2939
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
2940
|
+
}
|
|
2941
|
+
function warnContextualRefusal(label2, name, refusal) {
|
|
2942
|
+
devWarnLazy(() => {
|
|
2943
|
+
const reasons = [
|
|
2944
|
+
"",
|
|
2945
|
+
'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
|
|
2946
|
+
"a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
|
|
2947
|
+
"a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
|
|
2948
|
+
"an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
|
|
2949
|
+
'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
|
|
2950
|
+
];
|
|
2951
|
+
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
2952
|
+
});
|
|
2563
2953
|
}
|
|
2564
2954
|
function setProp(el, key, val) {
|
|
2565
2955
|
el[key] = val;
|
|
2566
2956
|
}
|
|
2567
2957
|
function namespaceFor(el, name) {
|
|
2568
|
-
if (el.namespaceURI !==
|
|
2958
|
+
if (el.namespaceURI !== SVG_NS3) return null;
|
|
2569
2959
|
const lower = name.toLowerCase();
|
|
2570
2960
|
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
2571
2961
|
if (lower.startsWith("xml:")) return XML_NS;
|
|
2572
2962
|
return null;
|
|
2573
2963
|
}
|
|
2574
2964
|
function setSafeAttribute(el, name, value, options = {}) {
|
|
2965
|
+
const written = commitSafeAttribute(el, name, value, options);
|
|
2966
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
2967
|
+
return written;
|
|
2968
|
+
}
|
|
2969
|
+
function commitSafeAttribute(el, name, value, options) {
|
|
2575
2970
|
const ns = namespaceFor(el, name);
|
|
2576
2971
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
2577
2972
|
if (isEventHandlerAttr(name)) {
|
|
@@ -2584,6 +2979,14 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
2584
2979
|
else el.removeAttribute(name);
|
|
2585
2980
|
return false;
|
|
2586
2981
|
}
|
|
2982
|
+
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
2983
|
+
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
2984
|
+
if (refusal !== ContextualRefusal.None) {
|
|
2985
|
+
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
2986
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2987
|
+
else el.removeAttribute(name);
|
|
2988
|
+
return false;
|
|
2989
|
+
}
|
|
2587
2990
|
if (value == null) {
|
|
2588
2991
|
if (ns) el.removeAttributeNS(ns, localName);
|
|
2589
2992
|
else el.removeAttribute(name);
|
|
@@ -2627,13 +3030,32 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
2627
3030
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
2628
3031
|
return true;
|
|
2629
3032
|
}
|
|
2630
|
-
const safe =
|
|
3033
|
+
const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
|
|
3034
|
+
if (safe === null) {
|
|
3035
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
3036
|
+
else el.removeAttribute(name);
|
|
3037
|
+
return true;
|
|
3038
|
+
}
|
|
2631
3039
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
2632
3040
|
if (current === safe) return true;
|
|
2633
3041
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
2634
3042
|
else el.setAttribute(name, safe);
|
|
2635
3043
|
return true;
|
|
2636
3044
|
}
|
|
3045
|
+
function setTrustedAttribute(el, name, value) {
|
|
3046
|
+
if (isHtmlContentAttribute(name)) {
|
|
3047
|
+
if (DEV) devWarn(`html: refusing static attribute "${name}" \u2014 the browser parses it as a nested document.`);
|
|
3048
|
+
return false;
|
|
3049
|
+
}
|
|
3050
|
+
const refusal = contextualAttributeRefusal(el, name, value, "static");
|
|
3051
|
+
if (refusal !== ContextualRefusal.None) {
|
|
3052
|
+
warnContextualRefusal("html (static attribute)", name, refusal);
|
|
3053
|
+
return false;
|
|
3054
|
+
}
|
|
3055
|
+
el.setAttribute(name, value);
|
|
3056
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, "static");
|
|
3057
|
+
return true;
|
|
3058
|
+
}
|
|
2637
3059
|
|
|
2638
3060
|
// src/reactivity/track-core.ts
|
|
2639
3061
|
var POOL_MAX = 4096;
|
|
@@ -3126,7 +3548,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
3126
3548
|
}
|
|
3127
3549
|
|
|
3128
3550
|
// src/reactivity/track.ts
|
|
3129
|
-
var _runtimeVersion = true ? "4.
|
|
3551
|
+
var _runtimeVersion = true ? "4.8.0" : "dev";
|
|
3130
3552
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
3131
3553
|
function resolveReactiveApi() {
|
|
3132
3554
|
const g2 = globalThis;
|
|
@@ -3197,7 +3619,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
3197
3619
|
reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
|
|
3198
3620
|
return;
|
|
3199
3621
|
}
|
|
3200
|
-
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")
|
|
3622
|
+
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
|
|
3201
3623
|
}
|
|
3202
3624
|
return reactiveBinding2(commit, el);
|
|
3203
3625
|
}
|
|
@@ -3222,7 +3644,7 @@ function bindDynamic(el, nameGetter, valueGetter) {
|
|
|
3222
3644
|
el.removeAttribute(prevName);
|
|
3223
3645
|
prevName = null;
|
|
3224
3646
|
}
|
|
3225
|
-
if (!setSafeAttribute(el, name, value, { label: "bindDynamic" })) return;
|
|
3647
|
+
if (!setSafeAttribute(el, name, value, { label: "bindDynamic", reactive: true })) return;
|
|
3226
3648
|
prevName = name;
|
|
3227
3649
|
}
|
|
3228
3650
|
const teardown = reactiveBinding2(commit, el);
|
|
@@ -3403,11 +3825,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
3403
3825
|
}
|
|
3404
3826
|
|
|
3405
3827
|
// src/core/rendering/tagFactory.ts
|
|
3406
|
-
var
|
|
3407
|
-
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
3408
|
-
function isBlockedTag(tag) {
|
|
3409
|
-
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
3410
|
-
}
|
|
3828
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
3411
3829
|
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
3412
3830
|
"config",
|
|
3413
3831
|
"location",
|
|
@@ -3452,11 +3870,12 @@ function applyStyle(el, style2) {
|
|
|
3452
3870
|
}
|
|
3453
3871
|
const next = [];
|
|
3454
3872
|
for (const prop in value) {
|
|
3873
|
+
if (!Object.hasOwn(value, prop)) continue;
|
|
3455
3874
|
const val = value[prop];
|
|
3456
3875
|
if (val == null) continue;
|
|
3457
3876
|
const name = toKebab(prop);
|
|
3458
3877
|
next.push(name);
|
|
3459
|
-
decl.setProperty(name,
|
|
3878
|
+
decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
3460
3879
|
}
|
|
3461
3880
|
for (let i2 = 0; i2 < written.length; i2++) {
|
|
3462
3881
|
if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
|
|
@@ -3472,16 +3891,17 @@ function applyStyle(el, style2) {
|
|
|
3472
3891
|
}
|
|
3473
3892
|
const htmlEl = el;
|
|
3474
3893
|
for (const prop in style2) {
|
|
3894
|
+
if (!Object.hasOwn(style2, prop)) continue;
|
|
3475
3895
|
const val = style2[prop];
|
|
3476
3896
|
const name = toKebab(prop);
|
|
3477
3897
|
if (typeof val === "function") {
|
|
3478
3898
|
const getter = val;
|
|
3479
3899
|
const teardown = reactiveBinding2(() => {
|
|
3480
|
-
htmlEl.style.setProperty(name,
|
|
3900
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
|
|
3481
3901
|
}, el);
|
|
3482
3902
|
registerDisposer(el, teardown);
|
|
3483
3903
|
} else {
|
|
3484
|
-
htmlEl.style.setProperty(name,
|
|
3904
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
3485
3905
|
}
|
|
3486
3906
|
}
|
|
3487
3907
|
}
|
|
@@ -3503,6 +3923,7 @@ function applyClass(el, cls) {
|
|
|
3503
3923
|
let hasReactive = false;
|
|
3504
3924
|
let result = "";
|
|
3505
3925
|
for (const name in obj) {
|
|
3926
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
3506
3927
|
const val = obj[name];
|
|
3507
3928
|
if (typeof val === "function") {
|
|
3508
3929
|
hasReactive = true;
|
|
@@ -3514,6 +3935,7 @@ function applyClass(el, cls) {
|
|
|
3514
3935
|
const update = () => {
|
|
3515
3936
|
let r = "";
|
|
3516
3937
|
for (const name in obj) {
|
|
3938
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
3517
3939
|
const val = obj[name];
|
|
3518
3940
|
const active = typeof val === "function" ? val() : val;
|
|
3519
3941
|
if (active) r = r ? `${r} ${name}` : name;
|
|
@@ -3577,7 +3999,7 @@ function appendChildren(el, nodes) {
|
|
|
3577
3999
|
}
|
|
3578
4000
|
}
|
|
3579
4001
|
function tagFactory(tag, ns) {
|
|
3580
|
-
const blocked =
|
|
4002
|
+
const blocked = isBlockedElement(tag);
|
|
3581
4003
|
return (first, second) => {
|
|
3582
4004
|
if (blocked) {
|
|
3583
4005
|
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
@@ -3640,6 +4062,7 @@ function tagFactory(tag, ns) {
|
|
|
3640
4062
|
const pOn = props.on;
|
|
3641
4063
|
if (pOn) {
|
|
3642
4064
|
for (const ev in pOn) {
|
|
4065
|
+
if (!Object.hasOwn(pOn, ev)) continue;
|
|
3643
4066
|
const handler = pOn[ev];
|
|
3644
4067
|
if (typeof handler === "function") {
|
|
3645
4068
|
el.addEventListener(ev, handler);
|
|
@@ -3666,6 +4089,7 @@ function tagFactory(tag, ns) {
|
|
|
3666
4089
|
continue;
|
|
3667
4090
|
// already handled above / below
|
|
3668
4091
|
default: {
|
|
4092
|
+
if (!Object.hasOwn(props, key)) continue;
|
|
3669
4093
|
const value = props[key];
|
|
3670
4094
|
if (value == null) continue;
|
|
3671
4095
|
if (isEventHandlerAttr(key)) continue;
|
|
@@ -3755,7 +4179,7 @@ var param = tagFactory("param");
|
|
|
3755
4179
|
var picture = tagFactory("picture");
|
|
3756
4180
|
var portal = tagFactory("portal");
|
|
3757
4181
|
var source = tagFactory("source");
|
|
3758
|
-
var svg = tagFactory("svg",
|
|
4182
|
+
var svg = tagFactory("svg", SVG_NS4);
|
|
3759
4183
|
var math = tagFactory("math");
|
|
3760
4184
|
var canvas = tagFactory("canvas");
|
|
3761
4185
|
var noscript = tagFactory("noscript");
|
|
@@ -3796,26 +4220,26 @@ var base = tagFactory("base");
|
|
|
3796
4220
|
var link = tagFactory("link");
|
|
3797
4221
|
var meta = tagFactory("meta");
|
|
3798
4222
|
var style = tagFactory("style");
|
|
3799
|
-
var circle = tagFactory("circle",
|
|
3800
|
-
var ellipse = tagFactory("ellipse",
|
|
3801
|
-
var g = tagFactory("g",
|
|
3802
|
-
var line = tagFactory("line",
|
|
3803
|
-
var path = tagFactory("path",
|
|
3804
|
-
var polygon = tagFactory("polygon",
|
|
3805
|
-
var polyline = tagFactory("polyline",
|
|
3806
|
-
var rect = tagFactory("rect",
|
|
3807
|
-
var text = tagFactory("text",
|
|
3808
|
-
var tspan = tagFactory("tspan",
|
|
3809
|
-
var defs = tagFactory("defs",
|
|
3810
|
-
var clipPath = tagFactory("clipPath",
|
|
3811
|
-
var mask = tagFactory("mask",
|
|
3812
|
-
var pattern = tagFactory("pattern",
|
|
3813
|
-
var linearGradient = tagFactory("linearGradient",
|
|
3814
|
-
var radialGradient = tagFactory("radialGradient",
|
|
3815
|
-
var stop = tagFactory("stop",
|
|
3816
|
-
var use = tagFactory("use",
|
|
3817
|
-
var symbol = tagFactory("symbol",
|
|
3818
|
-
var marker = tagFactory("marker",
|
|
4223
|
+
var circle = tagFactory("circle", SVG_NS4);
|
|
4224
|
+
var ellipse = tagFactory("ellipse", SVG_NS4);
|
|
4225
|
+
var g = tagFactory("g", SVG_NS4);
|
|
4226
|
+
var line = tagFactory("line", SVG_NS4);
|
|
4227
|
+
var path = tagFactory("path", SVG_NS4);
|
|
4228
|
+
var polygon = tagFactory("polygon", SVG_NS4);
|
|
4229
|
+
var polyline = tagFactory("polyline", SVG_NS4);
|
|
4230
|
+
var rect = tagFactory("rect", SVG_NS4);
|
|
4231
|
+
var text = tagFactory("text", SVG_NS4);
|
|
4232
|
+
var tspan = tagFactory("tspan", SVG_NS4);
|
|
4233
|
+
var defs = tagFactory("defs", SVG_NS4);
|
|
4234
|
+
var clipPath = tagFactory("clipPath", SVG_NS4);
|
|
4235
|
+
var mask = tagFactory("mask", SVG_NS4);
|
|
4236
|
+
var pattern = tagFactory("pattern", SVG_NS4);
|
|
4237
|
+
var linearGradient = tagFactory("linearGradient", SVG_NS4);
|
|
4238
|
+
var radialGradient = tagFactory("radialGradient", SVG_NS4);
|
|
4239
|
+
var stop = tagFactory("stop", SVG_NS4);
|
|
4240
|
+
var use = tagFactory("use", SVG_NS4);
|
|
4241
|
+
var symbol = tagFactory("symbol", SVG_NS4);
|
|
4242
|
+
var marker = tagFactory("marker", SVG_NS4);
|
|
3819
4243
|
var center = tagFactory("center");
|
|
3820
4244
|
var font = tagFactory("font");
|
|
3821
4245
|
var marquee = tagFactory("marquee");
|
|
@@ -5629,6 +6053,10 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
|
|
|
5629
6053
|
parent.insertBefore(node, anchor.nextSibling);
|
|
5630
6054
|
return { node, owned };
|
|
5631
6055
|
}
|
|
6056
|
+
function releaseBranchNode(node, owned) {
|
|
6057
|
+
if (owned) dispose(node);
|
|
6058
|
+
node.parentNode?.removeChild(node);
|
|
6059
|
+
}
|
|
5632
6060
|
function when(condition, thenBranch, elseBranch) {
|
|
5633
6061
|
const anchor = document.createComment("when");
|
|
5634
6062
|
let currentNode = null;
|
|
@@ -5646,8 +6074,7 @@ function when(condition, thenBranch, elseBranch) {
|
|
|
5646
6074
|
lastCondition = show2;
|
|
5647
6075
|
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
5648
6076
|
if (currentNode?.parentNode) {
|
|
5649
|
-
|
|
5650
|
-
currentNode.parentNode.removeChild(currentNode);
|
|
6077
|
+
releaseBranchNode(currentNode, currentNodeOwned);
|
|
5651
6078
|
currentNode = null;
|
|
5652
6079
|
}
|
|
5653
6080
|
const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
|
|
@@ -5661,6 +6088,8 @@ function when(condition, thenBranch, elseBranch) {
|
|
|
5661
6088
|
registerDisposer(anchor, () => {
|
|
5662
6089
|
disposed = true;
|
|
5663
6090
|
stopBinding();
|
|
6091
|
+
if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
|
|
6092
|
+
currentNode = null;
|
|
5664
6093
|
});
|
|
5665
6094
|
if (!initialized) {
|
|
5666
6095
|
queueMicrotask(() => {
|
|
@@ -5686,8 +6115,7 @@ function match(value, cases, fallback) {
|
|
|
5686
6115
|
lastKey = key;
|
|
5687
6116
|
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
5688
6117
|
if (currentNode?.parentNode) {
|
|
5689
|
-
|
|
5690
|
-
currentNode.parentNode.removeChild(currentNode);
|
|
6118
|
+
releaseBranchNode(currentNode, currentNodeOwned);
|
|
5691
6119
|
currentNode = null;
|
|
5692
6120
|
}
|
|
5693
6121
|
const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
|
|
@@ -5701,6 +6129,8 @@ function match(value, cases, fallback) {
|
|
|
5701
6129
|
registerDisposer(anchor, () => {
|
|
5702
6130
|
disposed = true;
|
|
5703
6131
|
stopBinding();
|
|
6132
|
+
if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
|
|
6133
|
+
currentNode = null;
|
|
5704
6134
|
});
|
|
5705
6135
|
if (!initialized) {
|
|
5706
6136
|
queueMicrotask(() => {
|
|
@@ -6043,7 +6473,6 @@ function appendChild(frag, child) {
|
|
|
6043
6473
|
}
|
|
6044
6474
|
|
|
6045
6475
|
// src/core/rendering/htm.ts
|
|
6046
|
-
var RAW_TEXT_TAGS2 = /* @__PURE__ */ new Set(["script", "style"]);
|
|
6047
6476
|
var VOID_ELEMENTS3 = /* @__PURE__ */ new Set([
|
|
6048
6477
|
"area",
|
|
6049
6478
|
"base",
|
|
@@ -6266,7 +6695,7 @@ function parseTemplate2(strings) {
|
|
|
6266
6695
|
children.push({ t: 0, el: { tag, svg: SVG_TAGS2.has(tag), attrs, children: [] } });
|
|
6267
6696
|
} else {
|
|
6268
6697
|
const inner = parseChildren();
|
|
6269
|
-
if (
|
|
6698
|
+
if (isCodeTextElement(tag)) {
|
|
6270
6699
|
for (let i2 = 0; i2 < inner.length; i2++) {
|
|
6271
6700
|
if (inner[i2].t === 2) {
|
|
6272
6701
|
throw new Error(
|
|
@@ -6292,12 +6721,12 @@ function parseTemplate2(strings) {
|
|
|
6292
6721
|
return parseChildren();
|
|
6293
6722
|
}
|
|
6294
6723
|
function executeElement(tmpl, values) {
|
|
6295
|
-
const el = tmpl.svg ? document.createElementNS(
|
|
6724
|
+
const el = tmpl.svg ? document.createElementNS(SVG_NS4, tmpl.tag) : document.createElement(tmpl.tag);
|
|
6296
6725
|
for (let i2 = 0; i2 < tmpl.attrs.length; i2++) {
|
|
6297
6726
|
const attr = tmpl.attrs[i2];
|
|
6298
6727
|
switch (attr.t) {
|
|
6299
6728
|
case 0:
|
|
6300
|
-
el
|
|
6729
|
+
setTrustedAttribute(el, attr.name, attr.value);
|
|
6301
6730
|
break;
|
|
6302
6731
|
case 1: {
|
|
6303
6732
|
const name = attr.name;
|
|
@@ -6330,7 +6759,7 @@ function executeElement(tmpl, values) {
|
|
|
6330
6759
|
break;
|
|
6331
6760
|
}
|
|
6332
6761
|
case 4:
|
|
6333
|
-
el
|
|
6762
|
+
setTrustedAttribute(el, attr.name, "");
|
|
6334
6763
|
break;
|
|
6335
6764
|
}
|
|
6336
6765
|
}
|
|
@@ -6375,6 +6804,12 @@ function html2(strings, ...values) {
|
|
|
6375
6804
|
tmpl = parseTemplate2(strings);
|
|
6376
6805
|
cache.set(strings, tmpl);
|
|
6377
6806
|
}
|
|
6807
|
+
return renderTemplate(tmpl, values);
|
|
6808
|
+
}
|
|
6809
|
+
function __renderParsedTemplate(tree, values) {
|
|
6810
|
+
return renderTemplate(tree, values);
|
|
6811
|
+
}
|
|
6812
|
+
function renderTemplate(tmpl, values) {
|
|
6378
6813
|
if (tmpl.length === 1 && tmpl[0].t === 0) {
|
|
6379
6814
|
return executeElement(tmpl[0].el, values);
|
|
6380
6815
|
}
|
|
@@ -7463,7 +7898,7 @@ function enhance(target, setup) {
|
|
|
7463
7898
|
bindNode(el, () => {
|
|
7464
7899
|
const v = value();
|
|
7465
7900
|
const next = v == null ? null : String(v);
|
|
7466
|
-
setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
|
|
7901
|
+
setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()", reactive: true });
|
|
7467
7902
|
})
|
|
7468
7903
|
);
|
|
7469
7904
|
});
|