voodoojs 0.7.0 → 0.10.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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-YOZTHZS2.js → chunk-3JV2AYK6.js} +3 -3
  3. package/dist/{chunk-CYN6VLMD.js → chunk-EYNFAYEV.js} +4 -4
  4. package/dist/{chunk-ZIWLQZZL.js → chunk-H3RGM7PR.js} +4 -4
  5. package/dist/{chunk-4T2UIPWX.js → chunk-H64IUSGJ.js} +4 -4
  6. package/dist/{chunk-QO3I7VLJ.js → chunk-HW75QJLQ.js} +5 -5
  7. package/dist/{chunk-WSDB7K4X.js → chunk-IK4MQQTO.js} +6 -6
  8. package/dist/{chunk-JB2YYNK6.js → chunk-OUEXXXTU.js} +310 -64
  9. package/dist/{chunk-MMLUK37L.js → chunk-PXUSD6TT.js} +4 -3
  10. package/dist/{chunk-II3XBOAP.js → chunk-QWQPKMUH.js} +13 -13
  11. package/dist/{chunk-GIWKGFGY.js → chunk-TFDCAZYU.js} +4 -4
  12. package/dist/{chunk-E5T65CEI.js → chunk-WGMUFP5Q.js} +5 -5
  13. package/dist/essential.cjs +305 -58
  14. package/dist/essential.d.cts +2 -2
  15. package/dist/essential.d.ts +2 -2
  16. package/dist/essential.js +10 -10
  17. package/dist/gpu.cjs +1 -1
  18. package/dist/gpu.js +10 -10
  19. package/dist/http.cjs +1 -1
  20. package/dist/http.js +5 -5
  21. package/dist/index.cjs +577 -76
  22. package/dist/index.d.cts +118 -4
  23. package/dist/index.d.ts +118 -4
  24. package/dist/index.js +278 -31
  25. package/dist/{query-CC-_z7v0.d.ts → query-Cf-7iibE.d.ts} +53 -2
  26. package/dist/{query-sEJXe_cO.d.cts → query-DiQAS73Q.d.cts} +53 -2
  27. package/dist/reactivity.cjs +1 -1
  28. package/dist/reactivity.js +2 -2
  29. package/dist/socket.cjs +303 -57
  30. package/dist/socket.js +9 -9
  31. package/dist/style-NW74ROC5.js +5 -0
  32. package/dist/utils.cjs +1 -1
  33. package/dist/utils.js +2 -2
  34. package/dist/voodoo.core.js +312 -58
  35. package/dist/voodoo.core.min.js +18 -18
  36. package/dist/voodoo.full.js +582 -74
  37. package/dist/voodoo.full.min.js +61 -61
  38. package/dist/voodoo.js +312 -58
  39. package/dist/voodoo.min.js +25 -25
  40. package/package.json +127 -127
  41. package/dist/style-SLQ6PHZK.js +0 -5
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Voodoo.js v0.7.0
2
+ * Voodoo.js v0.10.0
3
3
  * JavaScript feels like magic.
4
4
  * (c) 2026 Voodoo.js contributors. MIT License.
5
5
  */
@@ -730,6 +730,7 @@ var Voodoo = (() => {
730
730
  autoDiscover: true,
731
731
  root: null,
732
732
  devtools: false,
733
+ xrayShortcut: "ctrl+shift+f2",
733
734
  baseURL: "",
734
735
  globals: {},
735
736
  locale: typeof navigator !== "undefined" ? navigator.language || "pt-BR" : "pt-BR",
@@ -865,6 +866,7 @@ ${pointer}`);
865
866
  "!==",
866
867
  "**=",
867
868
  "...",
869
+ ">>>",
868
870
  "<<=",
869
871
  ">>=",
870
872
  "&&=",
@@ -887,6 +889,11 @@ ${pointer}`);
887
889
  "*=",
888
890
  "/=",
889
891
  "%=",
892
+ "&=",
893
+ "|=",
894
+ "^=",
895
+ "<<",
896
+ ">>",
890
897
  "+",
891
898
  "-",
892
899
  "*",
@@ -896,6 +903,10 @@ ${pointer}`);
896
903
  "<",
897
904
  ">",
898
905
  "=",
906
+ "&",
907
+ "|",
908
+ "^",
909
+ "~",
899
910
  "(",
900
911
  ")",
901
912
  "[",
@@ -960,6 +971,10 @@ ${pointer}`);
960
971
  raw = "0b";
961
972
  i += 2;
962
973
  while (i < len && /[01_]/.test(source[i])) raw += source[i++];
974
+ } else if (ch === "0" && (source[i + 1] === "o" || source[i + 1] === "O")) {
975
+ raw = "0o";
976
+ i += 2;
977
+ while (i < len && /[0-7_]/.test(source[i])) raw += source[i++];
963
978
  } else {
964
979
  while (i < len && /[0-9_]/.test(source[i])) raw += source[i++];
965
980
  if (source[i] === ".") {
@@ -1116,25 +1131,31 @@ ${pointer}`);
1116
1131
  "??": 1,
1117
1132
  "||": 2,
1118
1133
  "&&": 3,
1119
- "==": 6,
1120
- "!=": 6,
1121
- "===": 6,
1122
- "!==": 6,
1123
- "<": 7,
1124
- ">": 7,
1125
- "<=": 7,
1126
- ">=": 7,
1127
- in: 7,
1128
- instanceof: 7,
1129
- "+": 9,
1130
- "-": 9,
1131
- "*": 10,
1132
- "/": 10,
1133
- "%": 10,
1134
- "**": 11
1134
+ "|": 4,
1135
+ "^": 5,
1136
+ "&": 6,
1137
+ "==": 7,
1138
+ "!=": 7,
1139
+ "===": 7,
1140
+ "!==": 7,
1141
+ "<": 8,
1142
+ ">": 8,
1143
+ "<=": 8,
1144
+ ">=": 8,
1145
+ in: 8,
1146
+ instanceof: 8,
1147
+ "<<": 9,
1148
+ ">>": 9,
1149
+ ">>>": 9,
1150
+ "+": 10,
1151
+ "-": 10,
1152
+ "*": 11,
1153
+ "/": 11,
1154
+ "%": 11,
1155
+ "**": 12
1135
1156
  };
1136
1157
  var ASSIGN_OPS = /* @__PURE__ */ new Set(["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??="]);
1137
- var UNARY_OPS = /* @__PURE__ */ new Set(["!", "-", "+", "typeof", "void"]);
1158
+ var UNARY_OPS = /* @__PURE__ */ new Set(["!", "-", "+", "~", "typeof", "void", "delete"]);
1138
1159
  var LITERALS = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
1139
1160
  true: true,
1140
1161
  false: false,
@@ -1216,6 +1237,13 @@ ${pointer}`);
1216
1237
  * language is an expression.
1217
1238
  */
1218
1239
  parseStatement() {
1240
+ if (this.peek().type === "ident" && this.peek().value === "return") {
1241
+ this.next();
1242
+ if (this.isPunct(";") || this.isPunct(",") || this.isPunct("}") || this.peek().type === "eof") {
1243
+ return { t: "return", a: null };
1244
+ }
1245
+ return { t: "return", a: this.parseExpression() };
1246
+ }
1219
1247
  if (this.peek().type === "ident" && this.peek().value === "if" && this.isPunct("(", 1)) {
1220
1248
  this.next();
1221
1249
  this.expect("(");
@@ -1269,7 +1297,7 @@ ${pointer}`);
1269
1297
  if (this.peek().type === "ident" && this.isPunct("=>", 1)) {
1270
1298
  const param = this.next().value;
1271
1299
  this.next();
1272
- return { t: "arrow", params: [param], body: this.parseArrowBody() };
1300
+ return { t: "arrow", params: [{ kind: "id", name: param }], body: this.parseArrowBody() };
1273
1301
  }
1274
1302
  if (this.isPunct("(")) {
1275
1303
  const arrow = this.tryParseParenArrow();
@@ -1306,19 +1334,108 @@ ${pointer}`);
1306
1334
  const after = this.tokens[i + 1];
1307
1335
  if (!after || after.type !== "punct" || after.value !== "=>") return null;
1308
1336
  this.next();
1337
+ let params;
1338
+ try {
1339
+ params = this.parseParamList();
1340
+ } catch (e) {
1341
+ this.pos = start2;
1342
+ return null;
1343
+ }
1344
+ this.expect("=>");
1345
+ return { t: "arrow", params, body: this.parseArrowBody() };
1346
+ }
1347
+ /** Parameters up to the closing parenthesis, which it consumes. */
1348
+ parseParamList() {
1309
1349
  const params = [];
1310
1350
  while (!this.isPunct(")")) {
1311
- const t2 = this.next();
1312
- if (t2.type !== "ident") {
1313
- this.pos = start2;
1314
- return null;
1315
- }
1316
- params.push(t2.value);
1351
+ params.push(this.parseParam());
1317
1352
  if (this.isPunct(",")) this.next();
1353
+ else break;
1318
1354
  }
1319
1355
  this.expect(")");
1320
- this.expect("=>");
1321
- return { t: "arrow", params, body: this.parseArrowBody() };
1356
+ return params;
1357
+ }
1358
+ /**
1359
+ * One binding: `x`, `x = 1`, `...xs`, `{ a, b: c = 2 }`, `[a, , b]`.
1360
+ *
1361
+ * Recursive, so a pattern nests to any depth the way JavaScript's does.
1362
+ */
1363
+ parseParam() {
1364
+ if (this.isPunct("...")) {
1365
+ this.next();
1366
+ const name = this.next();
1367
+ if (name.type !== "ident") {
1368
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1369
+ }
1370
+ return { kind: "rest", name: name.value };
1371
+ }
1372
+ let param;
1373
+ if (this.isPunct("{")) {
1374
+ this.next();
1375
+ const props = [];
1376
+ let rest;
1377
+ while (!this.isPunct("}")) {
1378
+ if (this.isPunct("...")) {
1379
+ this.next();
1380
+ const name = this.next();
1381
+ if (name.type !== "ident") {
1382
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1383
+ }
1384
+ rest = name.value;
1385
+ } else {
1386
+ const key = this.next();
1387
+ if (key.type !== "ident" && key.type !== "str") {
1388
+ throw new VoodooSyntaxError("Expected a property name", this.source, key.start);
1389
+ }
1390
+ const value = this.isPunct(":") ? (this.next(), this.parseParam()) : { kind: "id", name: key.value };
1391
+ if (this.isPunct("=")) {
1392
+ this.next();
1393
+ value.def = this.parseAssignment();
1394
+ }
1395
+ props.push({ key: String(key.value), value });
1396
+ }
1397
+ if (this.isPunct(",")) this.next();
1398
+ else break;
1399
+ }
1400
+ this.expect("}");
1401
+ param = { kind: "obj", props, rest };
1402
+ } else if (this.isPunct("[")) {
1403
+ this.next();
1404
+ const elements = [];
1405
+ let rest;
1406
+ while (!this.isPunct("]")) {
1407
+ if (this.isPunct(",")) {
1408
+ this.next();
1409
+ elements.push(null);
1410
+ continue;
1411
+ }
1412
+ if (this.isPunct("...")) {
1413
+ this.next();
1414
+ const name = this.next();
1415
+ if (name.type !== "ident") {
1416
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1417
+ }
1418
+ rest = name.value;
1419
+ } else {
1420
+ elements.push(this.parseParam());
1421
+ }
1422
+ if (this.isPunct(",")) this.next();
1423
+ else break;
1424
+ }
1425
+ this.expect("]");
1426
+ param = { kind: "arr", elements, rest };
1427
+ } else {
1428
+ const name = this.next();
1429
+ if (name.type !== "ident") {
1430
+ throw new VoodooSyntaxError("Expected a parameter name", this.source, name.start);
1431
+ }
1432
+ param = { kind: "id", name: name.value };
1433
+ }
1434
+ if (this.isPunct("=")) {
1435
+ this.next();
1436
+ param.def = this.parseAssignment();
1437
+ }
1438
+ return param;
1322
1439
  }
1323
1440
  parseConditional() {
1324
1441
  const test = this.parseBinary(0);
@@ -1378,8 +1495,57 @@ ${pointer}`);
1378
1495
  }
1379
1496
  return expr;
1380
1497
  }
1498
+ /**
1499
+ * `new X`, `new X(a, b)`, and `new a.b.C(x)`.
1500
+ *
1501
+ * `new` did not exist here, in the lexer, or in the interpreter. So
1502
+ * `new Date(0)` lexed as the identifier `new` followed by `Date(0)`, the
1503
+ * parser dropped the dangling identifier, and what ran was `Date(0)`. Called
1504
+ * without `new`, `Date` returns a STRING of the current time, so
1505
+ * `new Date(0)` produced today's date as text, `new Date(0) instanceof Date`
1506
+ * was false, and `new Date(0).getTime()` failed with "getTime is not a
1507
+ * function". Three wrong answers, none of them an error.
1508
+ *
1509
+ * The callee is parsed as a member chain WITHOUT consuming a call, because in
1510
+ * JavaScript the argument list binds to the `new`: `new a.b.C(x)` constructs
1511
+ * `a.b.C` with `x`, and never calls `a.b.C(x)` and constructs the result. The
1512
+ * trailing `(` is then read here, and anything after it, such as
1513
+ * `new Date(0).getTime()`, is left to the ordinary member loop below.
1514
+ */
1515
+ parseNew() {
1516
+ this.next();
1517
+ const callee = this.parseMemberOnly(this.parsePrimary());
1518
+ const args = this.isPunct("(") ? this.parseArguments() : [];
1519
+ return { t: "new", callee, args };
1520
+ }
1521
+ /**
1522
+ * Member access only: `.x`, `?.x` and `[x]`, stopping at a call.
1523
+ *
1524
+ * Used for a `new` callee, where the argument list belongs to the `new`
1525
+ * rather than to the expression it is constructing.
1526
+ */
1527
+ parseMemberOnly(start2) {
1528
+ let expr = start2;
1529
+ for (; ; ) {
1530
+ if (this.isPunct(".")) {
1531
+ this.next();
1532
+ const prop = this.next();
1533
+ if (prop.type !== "ident") {
1534
+ throw new VoodooSyntaxError("Invalid property name", this.source, prop.start);
1535
+ }
1536
+ expr = { t: "member", o: expr, p: { t: "lit", v: prop.value }, computed: false, opt: false };
1537
+ } else if (this.isPunct("[")) {
1538
+ this.next();
1539
+ const p2 = this.parseExpression();
1540
+ this.expect("]");
1541
+ expr = { t: "member", o: expr, p: p2, computed: true, opt: false };
1542
+ } else {
1543
+ return expr;
1544
+ }
1545
+ }
1546
+ }
1381
1547
  parseCallMember() {
1382
- let expr = this.parsePrimary();
1548
+ let expr = this.isIdent("new") ? this.parseNew() : this.parsePrimary();
1383
1549
  for (; ; ) {
1384
1550
  if (this.isPunct(".")) {
1385
1551
  this.next();
@@ -1444,16 +1610,7 @@ ${pointer}`);
1444
1610
  this.next();
1445
1611
  if (this.peek().type === "ident") this.next();
1446
1612
  this.expect("(");
1447
- const params = [];
1448
- while (!this.isPunct(")")) {
1449
- const param = this.next();
1450
- if (param.type !== "ident") {
1451
- throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1452
- }
1453
- params.push(param.value);
1454
- if (this.isPunct(",")) this.next();
1455
- }
1456
- this.expect(")");
1613
+ const params = this.parseParamList();
1457
1614
  return { t: "arrow", params, body: this.parseArrowBody() };
1458
1615
  }
1459
1616
  if (t2.type === "num" || t2.type === "str") {
@@ -1559,16 +1716,7 @@ ${pointer}`);
1559
1716
  props.push({ key, value: this.parseAssignment() });
1560
1717
  } else if (this.isPunct("(")) {
1561
1718
  this.next();
1562
- const params = [];
1563
- while (!this.isPunct(")")) {
1564
- const param = this.next();
1565
- if (param.type !== "ident") {
1566
- throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1567
- }
1568
- params.push(param.value);
1569
- if (this.isPunct(",")) this.next();
1570
- }
1571
- this.expect(")");
1719
+ const params = this.parseParamList();
1572
1720
  props.push({ key, value: { t: "method", params, body: this.parseArrowBody() } });
1573
1721
  } else {
1574
1722
  props.push({ key, value: { t: "id", n: key } });
@@ -1672,6 +1820,14 @@ Expression: ${expression}` : message);
1672
1820
  }
1673
1821
  };
1674
1822
  var SPREAD = /* @__PURE__ */ Symbol("spread");
1823
+ var ReturnSignal = class {
1824
+ constructor(value) {
1825
+ __publicField(this, "value", value);
1826
+ }
1827
+ };
1828
+ function unwrap(value) {
1829
+ return value instanceof ReturnSignal ? value.value : value;
1830
+ }
1675
1831
  var BLOCKED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1676
1832
  function chaveBloqueada(key) {
1677
1833
  return typeof key === "string" && BLOCKED_KEYS.has(key);
@@ -1718,6 +1874,19 @@ Expression: ${expression}` : message);
1718
1874
  );
1719
1875
  return obj[key];
1720
1876
  }
1877
+ case "new": {
1878
+ const target = evaluate(node.callee, scope);
1879
+ if (typeof target !== "function") {
1880
+ throw new VoodooRuntimeError(
1881
+ `Cannot construct ${stringify(target)}: it is not a constructor`
1882
+ );
1883
+ }
1884
+ if (target === Function) {
1885
+ throw new VoodooRuntimeError("Cannot construct Function: expressions never compile code");
1886
+ }
1887
+ const args = evalArgs(node.args, scope);
1888
+ return Reflect.construct(target, args);
1889
+ }
1721
1890
  case "call": {
1722
1891
  let thisArg;
1723
1892
  let fn;
@@ -1765,6 +1934,19 @@ Expression: ${expression}` : message);
1765
1934
  }
1766
1935
  case "unary": {
1767
1936
  if (node.op === "...") return { [SPREAD]: evaluate(node.a, scope) };
1937
+ if (node.op === "delete") {
1938
+ if (node.a.t !== "member") {
1939
+ throw new VoodooRuntimeError(
1940
+ "delete needs a property, as in `delete user.name` or `delete list[0]`"
1941
+ );
1942
+ }
1943
+ const owner = evaluate(node.a.o, scope);
1944
+ if (owner == null) return true;
1945
+ const key = checkKey(
1946
+ node.a.computed ? evaluate(node.a.p, scope) : node.a.p.v
1947
+ );
1948
+ return delete owner[key];
1949
+ }
1768
1950
  if (node.op === "typeof") {
1769
1951
  if (node.a.t === "id") {
1770
1952
  if (chaveBloqueada(node.a.n)) return "undefined";
@@ -1782,6 +1964,8 @@ Expression: ${expression}` : message);
1782
1964
  return -v;
1783
1965
  case "+":
1784
1966
  return +v;
1967
+ case "~":
1968
+ return ~v;
1785
1969
  case "void":
1786
1970
  return void 0;
1787
1971
  }
@@ -1829,6 +2013,23 @@ Expression: ${expression}` : message);
1829
2013
  return l in r2;
1830
2014
  case "instanceof":
1831
2015
  return l instanceof r2;
2016
+ // The bitwise operators coerce through ToInt32, and `>>>` through
2017
+ // ToUint32, which is why the two shifts disagree for negatives:
2018
+ // `-1 >> 0` is -1 and `-1 >>> 0` is 4294967295. Applying the JavaScript
2019
+ // operator directly gets that for free; hand-rolling the coercion is
2020
+ // how an implementation ends up subtly wrong on exactly those cases.
2021
+ case "&":
2022
+ return l & r2;
2023
+ case "|":
2024
+ return l | r2;
2025
+ case "^":
2026
+ return l ^ r2;
2027
+ case "<<":
2028
+ return l << r2;
2029
+ case ">>":
2030
+ return l >> r2;
2031
+ case ">>>":
2032
+ return l >>> r2;
1832
2033
  }
1833
2034
  throw new VoodooRuntimeError(`Unsupported operator: ${node.op}`);
1834
2035
  }
@@ -1886,21 +2087,16 @@ Expression: ${expression}` : message);
1886
2087
  const methodParams = node.params;
1887
2088
  const methodBody = node.body;
1888
2089
  return function(...args) {
1889
- const vars = {};
1890
- for (let i = 0; i < methodParams.length; i++) vars[methodParams[i]] = args[i];
2090
+ const vars = bindParams(methodParams, args, scope);
1891
2091
  const owner = this;
1892
2092
  const base = owner !== null && typeof owner === "object" ? scope.child(owner) : scope;
1893
- return evaluate(methodBody, base.child(vars));
2093
+ return unwrap(evaluate(methodBody, base.child(vars)));
1894
2094
  };
1895
2095
  }
1896
2096
  case "arrow": {
1897
2097
  const params = node.params;
1898
2098
  const body = node.body;
1899
- return (...args) => {
1900
- const vars = {};
1901
- for (let i = 0; i < params.length; i++) vars[params[i]] = args[i];
1902
- return evaluate(body, scope.child(vars));
1903
- };
2099
+ return (...args) => unwrap(evaluate(body, scope.child(bindParams(params, args, scope))));
1904
2100
  }
1905
2101
  case "obj": {
1906
2102
  const out = {};
@@ -1938,14 +2134,65 @@ Expression: ${expression}` : message);
1938
2134
  }
1939
2135
  return out;
1940
2136
  }
2137
+ case "return":
2138
+ return new ReturnSignal(node.a ? evaluate(node.a, scope) : void 0);
1941
2139
  case "seq": {
1942
2140
  let last;
1943
- for (const stmt of node.body) last = evaluate(stmt, scope);
2141
+ for (const stmt of node.body) {
2142
+ last = evaluate(stmt, scope);
2143
+ if (last instanceof ReturnSignal) return last;
2144
+ }
1944
2145
  return last;
1945
2146
  }
1946
2147
  }
1947
2148
  throw new VoodooRuntimeError(`Unknown node: ${node.t}`);
1948
2149
  }
2150
+ function bindParam(param, value, vars, scope) {
2151
+ if (param.kind === "rest") {
2152
+ vars[param.name] = value;
2153
+ return;
2154
+ }
2155
+ if (param.def !== void 0 && value === void 0) {
2156
+ value = evaluate(param.def, scope.child(vars));
2157
+ }
2158
+ if (param.kind === "id") {
2159
+ vars[param.name] = value;
2160
+ return;
2161
+ }
2162
+ if (param.kind === "obj") {
2163
+ if (value == null) {
2164
+ throw new VoodooRuntimeError(
2165
+ `Cannot destructure ${value === null ? "null" : "undefined"}`
2166
+ );
2167
+ }
2168
+ const taken = /* @__PURE__ */ new Set();
2169
+ for (const { key, value: inner } of param.props) {
2170
+ taken.add(key);
2171
+ bindParam(inner, value[checkKey(key)], vars, scope);
2172
+ }
2173
+ if (param.rest) {
2174
+ const rest = {};
2175
+ for (const key of Object.keys(value)) {
2176
+ if (!taken.has(key)) rest[key] = value[key];
2177
+ }
2178
+ vars[param.rest] = rest;
2179
+ }
2180
+ return;
2181
+ }
2182
+ const items = Array.isArray(value) ? value : Array.from(value);
2183
+ param.elements.forEach((element, index) => {
2184
+ if (element) bindParam(element, items[index], vars, scope);
2185
+ });
2186
+ if (param.rest) vars[param.rest] = items.slice(param.elements.length);
2187
+ }
2188
+ function bindParams(params, args, scope) {
2189
+ const vars = {};
2190
+ for (let i = 0; i < params.length; i++) {
2191
+ const param = params[i];
2192
+ bindParam(param, param.kind === "rest" ? args.slice(i) : args[i], vars, scope);
2193
+ }
2194
+ return vars;
2195
+ }
1949
2196
  function evalArgs(args, scope) {
1950
2197
  const out = [];
1951
2198
  for (const arg of args) {
@@ -6621,7 +6868,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
6621
6868
  Object.defineProperties(rootScope.data, Object.getOwnPropertyDescriptors(values));
6622
6869
  return rootScope.data;
6623
6870
  }
6624
- var version2 = "0.7.0";
6871
+ var version2 = "0.10.0";
6625
6872
  var core = {
6626
6873
  // Utilities first: Voodoo's own names can override.
6627
6874
  ...utils_exports,
@@ -8270,7 +8517,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
8270
8517
  el.innerHTML = html != null ? html : fallbackHtml;
8271
8518
  for (const child of Array.from(el.childNodes)) walk(child, scope);
8272
8519
  };
8273
- const render2 = async (record, current2) => {
8520
+ const render3 = async (record, current2) => {
8274
8521
  let html = null;
8275
8522
  if (record == null ? void 0 : record.view) {
8276
8523
  el.classList.add("v-router-loading");
@@ -8291,7 +8538,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
8291
8538
  const matched = route.matched;
8292
8539
  void paramsSignature(route.params);
8293
8540
  const record = findRecord(matched);
8294
- void render2(record, ++token);
8541
+ void render3(record, ++token);
8295
8542
  });
8296
8543
  cleanup(() => {
8297
8544
  token++;
@@ -8507,8 +8754,8 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
8507
8754
  addMessages(locale, source);
8508
8755
  return;
8509
8756
  }
8510
- const pending = loading.get(locale);
8511
- if (pending) return pending;
8757
+ const pending2 = loading.get(locale);
8758
+ if (pending2) return pending2;
8512
8759
  const task = http.get(source, { responseType: "json" }).then((data2) => {
8513
8760
  if (data2 && typeof data2 === "object") addMessages(locale, data2);
8514
8761
  }).catch((err) => {
@@ -11078,7 +11325,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
11078
11325
  close();
11079
11326
  option.el.click();
11080
11327
  };
11081
- const render2 = () => {
11328
+ const render3 = () => {
11082
11329
  var _a2;
11083
11330
  list.replaceChildren();
11084
11331
  if (!visible.length) {
@@ -11110,7 +11357,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
11110
11357
  row.addEventListener("pointermove", () => {
11111
11358
  if (cursor === index) return;
11112
11359
  cursor = index;
11113
- render2();
11360
+ render3();
11114
11361
  });
11115
11362
  list.appendChild(row);
11116
11363
  });
@@ -11124,7 +11371,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
11124
11371
  const term = normalizeSearch(input.value.trim());
11125
11372
  visible = term ? commands.filter((option) => normalizeSearch(`${option.label} ${option.hint}`).includes(term)) : commands;
11126
11373
  cursor = 0;
11127
- render2();
11374
+ render3();
11128
11375
  };
11129
11376
  const onKeyDown = (event) => {
11130
11377
  if (event.key === "Escape") {
@@ -11135,13 +11382,13 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
11135
11382
  if (event.key === "ArrowDown") {
11136
11383
  event.preventDefault();
11137
11384
  cursor = visible.length ? (cursor + 1) % visible.length : 0;
11138
- render2();
11385
+ render3();
11139
11386
  return;
11140
11387
  }
11141
11388
  if (event.key === "ArrowUp") {
11142
11389
  event.preventDefault();
11143
11390
  cursor = visible.length ? (cursor - 1 + visible.length) % visible.length : 0;
11144
- render2();
11391
+ render3();
11145
11392
  return;
11146
11393
  }
11147
11394
  if (event.key === "Enter") {
@@ -11156,7 +11403,7 @@ Suggestion: attribute expressions accept a single value. If the logic spans more
11156
11403
  });
11157
11404
  input.addEventListener("input", filter);
11158
11405
  document.addEventListener("keydown", onKeyDown, true);
11159
- render2();
11406
+ render3();
11160
11407
  input.focus();
11161
11408
  document.addEventListener("focusin", keepFocusTrapped, true);
11162
11409
  }
@@ -13502,8 +13749,8 @@ form.v-loading [type="submit"],form.v-loading button[disabled]{opacity:.6}
13502
13749
  var frameHandle = 0;
13503
13750
  function runFrame(now2) {
13504
13751
  frameHandle = 0;
13505
- const pending = Array.from(frameCallbacks);
13506
- for (const callback of pending) {
13752
+ const pending2 = Array.from(frameCallbacks);
13753
+ for (const callback of pending2) {
13507
13754
  if (frameCallbacks.has(callback)) callback(now2);
13508
13755
  }
13509
13756
  if (frameCallbacks.size > 0) frameHandle = requestAnimationFrame(runFrame);
@@ -20708,12 +20955,39 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
20708
20955
  function isXrayEnabled() {
20709
20956
  return enabled;
20710
20957
  }
20958
+ function parseShortcut(text) {
20959
+ const parts = text.toLowerCase().split("+").map((part) => part.trim()).filter(Boolean);
20960
+ if (!parts.length) return null;
20961
+ const key = parts.pop();
20962
+ const shortcut2 = {
20963
+ ctrl: false,
20964
+ alt: false,
20965
+ shift: false,
20966
+ meta: false,
20967
+ code: /^f\d{1,2}$/.test(key) ? key.toUpperCase() : key.length === 1 && key >= "a" && key <= "z" ? `Key${key.toUpperCase()}` : key.length === 1 && key >= "0" && key <= "9" ? `Digit${key}` : key.charAt(0).toUpperCase() + key.slice(1)
20968
+ };
20969
+ for (const part of parts) {
20970
+ if (part === "ctrl" || part === "control") shortcut2.ctrl = true;
20971
+ else if (part === "alt" || part === "option") shortcut2.alt = true;
20972
+ else if (part === "shift") shortcut2.shift = true;
20973
+ else if (part === "meta" || part === "cmd" || part === "command" || part === "win")
20974
+ shortcut2.meta = true;
20975
+ else return null;
20976
+ }
20977
+ return shortcut2;
20978
+ }
20711
20979
  function enableXrayShortcut() {
20712
20980
  if (shortcutInstalled || typeof document === "undefined") return;
20713
20981
  shortcutInstalled = true;
20714
20982
  document.addEventListener("keydown", (event) => {
20715
- if (!event.altKey || !event.shiftKey || event.ctrlKey || event.metaKey) return;
20716
- if (event.code !== "KeyV" && event.key !== "V" && event.key !== "v") return;
20983
+ const setting = config.xrayShortcut;
20984
+ if (setting === false) return;
20985
+ const wanted = parseShortcut(typeof setting === "string" ? setting : "ctrl+shift+f2");
20986
+ if (!wanted) return;
20987
+ if (event.ctrlKey !== wanted.ctrl || event.altKey !== wanted.alt || event.shiftKey !== wanted.shift || event.metaKey !== wanted.meta)
20988
+ return;
20989
+ if (event.code !== wanted.code && event.key.toUpperCase() !== wanted.code.replace(/^Key/, ""))
20990
+ return;
20717
20991
  event.preventDefault();
20718
20992
  xray();
20719
20993
  });
@@ -20726,6 +21000,230 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
20726
21000
  return enabled;
20727
21001
  }
20728
21002
 
21003
+ // src/jsx/index.ts
21004
+ init_reactivity();
21005
+ init_registry();
21006
+ var OPAQUE = /* @__PURE__ */ new Set([
21007
+ "SCRIPT",
21008
+ "STYLE",
21009
+ "PRE",
21010
+ "CODE",
21011
+ "SAMP",
21012
+ "KBD",
21013
+ "TEXTAREA",
21014
+ "TEMPLATE",
21015
+ "NOSCRIPT"
21016
+ ]);
21017
+ magic("$__jsx", (scope) => scope);
21018
+ var TEMPLATE = /* @__PURE__ */ Symbol("voodoo.jsx.template");
21019
+ function isTemplate(value) {
21020
+ return typeof value === "object" && value !== null && TEMPLATE in value;
21021
+ }
21022
+ function collect(start2, offset) {
21023
+ var _a2;
21024
+ const templates = [];
21025
+ const nodes = [];
21026
+ let source = "";
21027
+ let depth = 0;
21028
+ let quote = null;
21029
+ let escaped = false;
21030
+ let node = start2;
21031
+ let index = offset;
21032
+ let closed = false;
21033
+ let tail = null;
21034
+ while (node) {
21035
+ if (node.nodeType === Node.TEXT_NODE) {
21036
+ const text = (_a2 = node.textContent) != null ? _a2 : "";
21037
+ for (; index < text.length; index++) {
21038
+ const ch = text[index];
21039
+ if (escaped) {
21040
+ escaped = false;
21041
+ source += ch;
21042
+ continue;
21043
+ }
21044
+ if (quote) {
21045
+ if (ch === "\\") escaped = true;
21046
+ else if (ch === quote) quote = null;
21047
+ source += ch;
21048
+ continue;
21049
+ }
21050
+ if (ch === '"' || ch === "'" || ch === "`") {
21051
+ quote = ch;
21052
+ source += ch;
21053
+ continue;
21054
+ }
21055
+ if (ch === "{") {
21056
+ depth++;
21057
+ if (depth > 1) source += ch;
21058
+ continue;
21059
+ }
21060
+ if (ch === "}") {
21061
+ depth--;
21062
+ if (depth === 0) {
21063
+ index++;
21064
+ closed = true;
21065
+ break;
21066
+ }
21067
+ source += ch;
21068
+ continue;
21069
+ }
21070
+ source += ch;
21071
+ }
21072
+ nodes.push(node);
21073
+ if (closed) {
21074
+ tail = { node, offset: index };
21075
+ break;
21076
+ }
21077
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
21078
+ if (depth === 0) return null;
21079
+ source += `$t(${templates.length}, $__jsx)`;
21080
+ templates.push(node);
21081
+ nodes.push(node);
21082
+ } else {
21083
+ nodes.push(node);
21084
+ }
21085
+ index = 0;
21086
+ node = node.nextSibling;
21087
+ }
21088
+ if (!closed) return null;
21089
+ return { source, templates, nodes, tail };
21090
+ }
21091
+ function render2(value, templates, scope, out) {
21092
+ var _a2;
21093
+ if (value == null || value === false || value === true) return;
21094
+ if (Array.isArray(value)) {
21095
+ for (const item of value) render2(item, templates, scope, out);
21096
+ return;
21097
+ }
21098
+ if (isTemplate(value)) {
21099
+ const handle = value;
21100
+ const source = templates[handle.index];
21101
+ const clone2 = source.cloneNode(true);
21102
+ const at = (_a2 = handle.scope) != null ? _a2 : scope;
21103
+ applyRegions(clone2, at);
21104
+ activateJsx();
21105
+ walk(clone2, at);
21106
+ out.push(clone2);
21107
+ return;
21108
+ }
21109
+ out.push(document.createTextNode(String(value)));
21110
+ }
21111
+ function applyRegions(root, parentScope) {
21112
+ var _a2, _b, _c;
21113
+ if (OPAQUE.has(root.tagName)) return;
21114
+ const scope = parentScope != null ? parentScope : findScope(root);
21115
+ let child = root.firstChild;
21116
+ while (child) {
21117
+ const next = child.nextSibling;
21118
+ if (child.nodeType === Node.ELEMENT_NODE) {
21119
+ applyRegions(child, (_a2 = getScope(child)) != null ? _a2 : scope);
21120
+ child = next;
21121
+ continue;
21122
+ }
21123
+ if (child.nodeType !== Node.TEXT_NODE) {
21124
+ child = next;
21125
+ continue;
21126
+ }
21127
+ const text = (_b = child.textContent) != null ? _b : "";
21128
+ const open = text.indexOf("{");
21129
+ if (open < 0) {
21130
+ child = next;
21131
+ continue;
21132
+ }
21133
+ const collected = collect(child, open);
21134
+ if (!collected || collected.templates.length === 0) {
21135
+ child = next;
21136
+ continue;
21137
+ }
21138
+ install(root, collected, scope);
21139
+ child = (_c = collected.nodes[collected.nodes.length - 1]) == null ? void 0 : _c.nextSibling;
21140
+ }
21141
+ }
21142
+ var pending = [];
21143
+ function install(parent, collected, hint) {
21144
+ var _a2;
21145
+ const { source, templates, nodes, tail } = collected;
21146
+ let ast;
21147
+ try {
21148
+ ast = parse(source);
21149
+ } catch (error) {
21150
+ if (config.devtools) {
21151
+ console.warn(`[Voodoo] could not parse the inline expression: ${source}`, error);
21152
+ }
21153
+ return;
21154
+ }
21155
+ if (tail && tail.offset < ((_a2 = tail.node.textContent) != null ? _a2 : "").length) {
21156
+ tail.node.splitText(tail.offset);
21157
+ }
21158
+ const anchor = document.createComment("v-jsx");
21159
+ parent.insertBefore(anchor, nodes[0]);
21160
+ for (const node of nodes) node.remove();
21161
+ let rendered = [];
21162
+ pending.push(() => activateRegion());
21163
+ function activateRegion() {
21164
+ const found = findScope(anchor);
21165
+ const scope = found === rootScope && hint ? hint : found;
21166
+ const local = scope.child({
21167
+ $t: (index, at) => ({ [TEMPLATE]: true, index, scope: at })
21168
+ });
21169
+ const runner = effect(() => {
21170
+ const value = unwrap(evaluate(ast, local));
21171
+ const out = [];
21172
+ render2(value, templates, local, out);
21173
+ for (const node of rendered) node.remove();
21174
+ rendered = out;
21175
+ for (const node of out) parent.insertBefore(node, anchor);
21176
+ });
21177
+ addCleanup(anchor, () => {
21178
+ runner.effect.stop();
21179
+ for (const node of rendered) node.remove();
21180
+ });
21181
+ }
21182
+ }
21183
+ function readDeclarationBlock(root = document.body) {
21184
+ var _a2;
21185
+ for (const node of Array.from(root.childNodes)) {
21186
+ if (node.nodeType !== Node.TEXT_NODE) continue;
21187
+ const text = ((_a2 = node.textContent) != null ? _a2 : "").trim();
21188
+ if (!text.startsWith("{") || !text.endsWith("}")) continue;
21189
+ if (!/\b(const|let|var)\s/.test(text)) continue;
21190
+ const body = text.slice(1, -1).replace(/\b(?:const|let|var)\s+/g, "");
21191
+ const data2 = reactive({});
21192
+ try {
21193
+ evaluate(parse(body), new Scope(data2));
21194
+ } catch (error) {
21195
+ if (config.devtools) {
21196
+ console.warn("[Voodoo] could not read the declaration block", error);
21197
+ }
21198
+ return null;
21199
+ }
21200
+ node.remove();
21201
+ return data2;
21202
+ }
21203
+ return null;
21204
+ }
21205
+ function activateJsx() {
21206
+ const work = pending.splice(0, pending.length);
21207
+ for (const run of work) {
21208
+ try {
21209
+ run();
21210
+ } catch (error) {
21211
+ console.error("[Voodoo] a JSX region failed to render", error);
21212
+ }
21213
+ }
21214
+ }
21215
+ function extractJsx(root = document.body) {
21216
+ const data2 = readDeclarationBlock(root);
21217
+ if (data2) {
21218
+ Object.assign(rootScope.data, data2);
21219
+ }
21220
+ applyRegions(root, findScope(root));
21221
+ }
21222
+ function jsx(root = document.body) {
21223
+ extractJsx(root);
21224
+ activateJsx();
21225
+ }
21226
+
20729
21227
  // src/devtools/launcher.ts
20730
21228
  init_style();
20731
21229
  var POSITION_KEY = "voodoo:devtools:widget-position";
@@ -20906,9 +21404,9 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
20906
21404
  const button = document.createElement("button");
20907
21405
  button.type = "button";
20908
21406
  button.className = "v-devtools-btn";
20909
- button.setAttribute("aria-label", "Open Voodoo devtools (Alt+Shift+V)");
21407
+ button.setAttribute("aria-label", "Open Voodoo devtools (Ctrl+Shift+F2)");
20910
21408
  button.setAttribute("aria-pressed", "false");
20911
- button.title = "Voodoo devtools \u2014 click to inspect, drag to move (Alt+Shift+V)";
21409
+ button.title = "Voodoo devtools \u2014 click to inspect, drag to move (Ctrl+Shift+F2)";
20912
21410
  button.innerHTML = MARK;
20913
21411
  const label = document.createElement("span");
20914
21412
  label.className = "v-devtools-label";
@@ -21096,6 +21594,9 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
21096
21594
  query,
21097
21595
  ready,
21098
21596
  fromHtml,
21597
+ jsx,
21598
+ extractJsx,
21599
+ activateJsx,
21099
21600
  Collection: VoodooCollection,
21100
21601
  // Routes
21101
21602
  router,
@@ -21179,6 +21680,10 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
21179
21680
  const locale = script.getAttribute("data-locale");
21180
21681
  if (locale) config.locale = locale;
21181
21682
  if (readDevtoolsFlag(script)) config.devtools = true;
21683
+ const xrayShortcut = script.getAttribute("data-xray-shortcut");
21684
+ if (xrayShortcut !== null) {
21685
+ config.xrayShortcut = xrayShortcut === "false" || xrayShortcut === "" ? false : xrayShortcut;
21686
+ }
21182
21687
  if (script.hasAttribute("data-no-styles")) config.injectStyles = false;
21183
21688
  if (script.hasAttribute("data-no-observer")) config.autoDiscover = false;
21184
21689
  if (script.hasAttribute("data-keep-attributes")) config.cleanAttributes = false;
@@ -21207,7 +21712,10 @@ textarea.v-dialog-input{min-height:96px;resize:vertical}
21207
21712
  const boot = () => {
21208
21713
  theme.init();
21209
21714
  applySavedPalette();
21715
+ if (typeof V2.extractJsx === "function") V2.extractJsx();
21210
21716
  V2.start();
21717
+ if (typeof V2.activateJsx === "function") V2.activateJsx();
21718
+ if (typeof V2.enableXrayShortcut === "function") V2.enableXrayShortcut();
21211
21719
  if (config.devtools) mountDevtools(V2);
21212
21720
  };
21213
21721
  whenReady(boot);