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
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  /**
6
- * Voodoo.js v0.7.0
6
+ * Voodoo.js v0.10.0
7
7
  * JavaScript feels like magic.
8
8
  * (c) 2026 Voodoo.js contributors. MIT License.
9
9
  */
@@ -715,6 +715,7 @@ var init_registry = __esm({
715
715
  autoDiscover: true,
716
716
  root: null,
717
717
  devtools: false,
718
+ xrayShortcut: "ctrl+shift+f2",
718
719
  baseURL: "",
719
720
  globals: {},
720
721
  locale: typeof navigator !== "undefined" ? navigator.language || "pt-BR" : "pt-BR",
@@ -843,6 +844,7 @@ var PUNCTUATORS = [
843
844
  "!==",
844
845
  "**=",
845
846
  "...",
847
+ ">>>",
846
848
  "<<=",
847
849
  ">>=",
848
850
  "&&=",
@@ -865,6 +867,11 @@ var PUNCTUATORS = [
865
867
  "*=",
866
868
  "/=",
867
869
  "%=",
870
+ "&=",
871
+ "|=",
872
+ "^=",
873
+ "<<",
874
+ ">>",
868
875
  "+",
869
876
  "-",
870
877
  "*",
@@ -874,6 +881,10 @@ var PUNCTUATORS = [
874
881
  "<",
875
882
  ">",
876
883
  "=",
884
+ "&",
885
+ "|",
886
+ "^",
887
+ "~",
877
888
  "(",
878
889
  ")",
879
890
  "[",
@@ -937,6 +948,10 @@ function tokenize(source) {
937
948
  raw = "0b";
938
949
  i += 2;
939
950
  while (i < len && /[01_]/.test(source[i])) raw += source[i++];
951
+ } else if (ch === "0" && (source[i + 1] === "o" || source[i + 1] === "O")) {
952
+ raw = "0o";
953
+ i += 2;
954
+ while (i < len && /[0-7_]/.test(source[i])) raw += source[i++];
940
955
  } else {
941
956
  while (i < len && /[0-9_]/.test(source[i])) raw += source[i++];
942
957
  if (source[i] === ".") {
@@ -1093,25 +1108,31 @@ var BINARY_PRECEDENCE = {
1093
1108
  "??": 1,
1094
1109
  "||": 2,
1095
1110
  "&&": 3,
1096
- "==": 6,
1097
- "!=": 6,
1098
- "===": 6,
1099
- "!==": 6,
1100
- "<": 7,
1101
- ">": 7,
1102
- "<=": 7,
1103
- ">=": 7,
1104
- in: 7,
1105
- instanceof: 7,
1106
- "+": 9,
1107
- "-": 9,
1108
- "*": 10,
1109
- "/": 10,
1110
- "%": 10,
1111
- "**": 11
1111
+ "|": 4,
1112
+ "^": 5,
1113
+ "&": 6,
1114
+ "==": 7,
1115
+ "!=": 7,
1116
+ "===": 7,
1117
+ "!==": 7,
1118
+ "<": 8,
1119
+ ">": 8,
1120
+ "<=": 8,
1121
+ ">=": 8,
1122
+ in: 8,
1123
+ instanceof: 8,
1124
+ "<<": 9,
1125
+ ">>": 9,
1126
+ ">>>": 9,
1127
+ "+": 10,
1128
+ "-": 10,
1129
+ "*": 11,
1130
+ "/": 11,
1131
+ "%": 11,
1132
+ "**": 12
1112
1133
  };
1113
1134
  var ASSIGN_OPS = /* @__PURE__ */ new Set(["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??="]);
1114
- var UNARY_OPS = /* @__PURE__ */ new Set(["!", "-", "+", "typeof", "void"]);
1135
+ var UNARY_OPS = /* @__PURE__ */ new Set(["!", "-", "+", "~", "typeof", "void", "delete"]);
1115
1136
  var LITERALS = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
1116
1137
  true: true,
1117
1138
  false: false,
@@ -1193,6 +1214,13 @@ var Parser = class {
1193
1214
  * language is an expression.
1194
1215
  */
1195
1216
  parseStatement() {
1217
+ if (this.peek().type === "ident" && this.peek().value === "return") {
1218
+ this.next();
1219
+ if (this.isPunct(";") || this.isPunct(",") || this.isPunct("}") || this.peek().type === "eof") {
1220
+ return { t: "return", a: null };
1221
+ }
1222
+ return { t: "return", a: this.parseExpression() };
1223
+ }
1196
1224
  if (this.peek().type === "ident" && this.peek().value === "if" && this.isPunct("(", 1)) {
1197
1225
  this.next();
1198
1226
  this.expect("(");
@@ -1246,7 +1274,7 @@ var Parser = class {
1246
1274
  if (this.peek().type === "ident" && this.isPunct("=>", 1)) {
1247
1275
  const param = this.next().value;
1248
1276
  this.next();
1249
- return { t: "arrow", params: [param], body: this.parseArrowBody() };
1277
+ return { t: "arrow", params: [{ kind: "id", name: param }], body: this.parseArrowBody() };
1250
1278
  }
1251
1279
  if (this.isPunct("(")) {
1252
1280
  const arrow = this.tryParseParenArrow();
@@ -1283,19 +1311,108 @@ var Parser = class {
1283
1311
  const after = this.tokens[i + 1];
1284
1312
  if (!after || after.type !== "punct" || after.value !== "=>") return null;
1285
1313
  this.next();
1314
+ let params;
1315
+ try {
1316
+ params = this.parseParamList();
1317
+ } catch {
1318
+ this.pos = start2;
1319
+ return null;
1320
+ }
1321
+ this.expect("=>");
1322
+ return { t: "arrow", params, body: this.parseArrowBody() };
1323
+ }
1324
+ /** Parameters up to the closing parenthesis, which it consumes. */
1325
+ parseParamList() {
1286
1326
  const params = [];
1287
1327
  while (!this.isPunct(")")) {
1288
- const t2 = this.next();
1289
- if (t2.type !== "ident") {
1290
- this.pos = start2;
1291
- return null;
1292
- }
1293
- params.push(t2.value);
1328
+ params.push(this.parseParam());
1294
1329
  if (this.isPunct(",")) this.next();
1330
+ else break;
1295
1331
  }
1296
1332
  this.expect(")");
1297
- this.expect("=>");
1298
- return { t: "arrow", params, body: this.parseArrowBody() };
1333
+ return params;
1334
+ }
1335
+ /**
1336
+ * One binding: `x`, `x = 1`, `...xs`, `{ a, b: c = 2 }`, `[a, , b]`.
1337
+ *
1338
+ * Recursive, so a pattern nests to any depth the way JavaScript's does.
1339
+ */
1340
+ parseParam() {
1341
+ if (this.isPunct("...")) {
1342
+ this.next();
1343
+ const name = this.next();
1344
+ if (name.type !== "ident") {
1345
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1346
+ }
1347
+ return { kind: "rest", name: name.value };
1348
+ }
1349
+ let param;
1350
+ if (this.isPunct("{")) {
1351
+ this.next();
1352
+ const props = [];
1353
+ let rest;
1354
+ while (!this.isPunct("}")) {
1355
+ if (this.isPunct("...")) {
1356
+ this.next();
1357
+ const name = this.next();
1358
+ if (name.type !== "ident") {
1359
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1360
+ }
1361
+ rest = name.value;
1362
+ } else {
1363
+ const key = this.next();
1364
+ if (key.type !== "ident" && key.type !== "str") {
1365
+ throw new VoodooSyntaxError("Expected a property name", this.source, key.start);
1366
+ }
1367
+ const value = this.isPunct(":") ? (this.next(), this.parseParam()) : { kind: "id", name: key.value };
1368
+ if (this.isPunct("=")) {
1369
+ this.next();
1370
+ value.def = this.parseAssignment();
1371
+ }
1372
+ props.push({ key: String(key.value), value });
1373
+ }
1374
+ if (this.isPunct(",")) this.next();
1375
+ else break;
1376
+ }
1377
+ this.expect("}");
1378
+ param = { kind: "obj", props, rest };
1379
+ } else if (this.isPunct("[")) {
1380
+ this.next();
1381
+ const elements = [];
1382
+ let rest;
1383
+ while (!this.isPunct("]")) {
1384
+ if (this.isPunct(",")) {
1385
+ this.next();
1386
+ elements.push(null);
1387
+ continue;
1388
+ }
1389
+ if (this.isPunct("...")) {
1390
+ this.next();
1391
+ const name = this.next();
1392
+ if (name.type !== "ident") {
1393
+ throw new VoodooSyntaxError("Expected a name after ...", this.source, name.start);
1394
+ }
1395
+ rest = name.value;
1396
+ } else {
1397
+ elements.push(this.parseParam());
1398
+ }
1399
+ if (this.isPunct(",")) this.next();
1400
+ else break;
1401
+ }
1402
+ this.expect("]");
1403
+ param = { kind: "arr", elements, rest };
1404
+ } else {
1405
+ const name = this.next();
1406
+ if (name.type !== "ident") {
1407
+ throw new VoodooSyntaxError("Expected a parameter name", this.source, name.start);
1408
+ }
1409
+ param = { kind: "id", name: name.value };
1410
+ }
1411
+ if (this.isPunct("=")) {
1412
+ this.next();
1413
+ param.def = this.parseAssignment();
1414
+ }
1415
+ return param;
1299
1416
  }
1300
1417
  parseConditional() {
1301
1418
  const test = this.parseBinary(0);
@@ -1355,8 +1472,57 @@ var Parser = class {
1355
1472
  }
1356
1473
  return expr;
1357
1474
  }
1475
+ /**
1476
+ * `new X`, `new X(a, b)`, and `new a.b.C(x)`.
1477
+ *
1478
+ * `new` did not exist here, in the lexer, or in the interpreter. So
1479
+ * `new Date(0)` lexed as the identifier `new` followed by `Date(0)`, the
1480
+ * parser dropped the dangling identifier, and what ran was `Date(0)`. Called
1481
+ * without `new`, `Date` returns a STRING of the current time, so
1482
+ * `new Date(0)` produced today's date as text, `new Date(0) instanceof Date`
1483
+ * was false, and `new Date(0).getTime()` failed with "getTime is not a
1484
+ * function". Three wrong answers, none of them an error.
1485
+ *
1486
+ * The callee is parsed as a member chain WITHOUT consuming a call, because in
1487
+ * JavaScript the argument list binds to the `new`: `new a.b.C(x)` constructs
1488
+ * `a.b.C` with `x`, and never calls `a.b.C(x)` and constructs the result. The
1489
+ * trailing `(` is then read here, and anything after it, such as
1490
+ * `new Date(0).getTime()`, is left to the ordinary member loop below.
1491
+ */
1492
+ parseNew() {
1493
+ this.next();
1494
+ const callee = this.parseMemberOnly(this.parsePrimary());
1495
+ const args = this.isPunct("(") ? this.parseArguments() : [];
1496
+ return { t: "new", callee, args };
1497
+ }
1498
+ /**
1499
+ * Member access only: `.x`, `?.x` and `[x]`, stopping at a call.
1500
+ *
1501
+ * Used for a `new` callee, where the argument list belongs to the `new`
1502
+ * rather than to the expression it is constructing.
1503
+ */
1504
+ parseMemberOnly(start2) {
1505
+ let expr = start2;
1506
+ for (; ; ) {
1507
+ if (this.isPunct(".")) {
1508
+ this.next();
1509
+ const prop = this.next();
1510
+ if (prop.type !== "ident") {
1511
+ throw new VoodooSyntaxError("Invalid property name", this.source, prop.start);
1512
+ }
1513
+ expr = { t: "member", o: expr, p: { t: "lit", v: prop.value }, computed: false, opt: false };
1514
+ } else if (this.isPunct("[")) {
1515
+ this.next();
1516
+ const p2 = this.parseExpression();
1517
+ this.expect("]");
1518
+ expr = { t: "member", o: expr, p: p2, computed: true, opt: false };
1519
+ } else {
1520
+ return expr;
1521
+ }
1522
+ }
1523
+ }
1358
1524
  parseCallMember() {
1359
- let expr = this.parsePrimary();
1525
+ let expr = this.isIdent("new") ? this.parseNew() : this.parsePrimary();
1360
1526
  for (; ; ) {
1361
1527
  if (this.isPunct(".")) {
1362
1528
  this.next();
@@ -1421,16 +1587,7 @@ var Parser = class {
1421
1587
  this.next();
1422
1588
  if (this.peek().type === "ident") this.next();
1423
1589
  this.expect("(");
1424
- const params = [];
1425
- while (!this.isPunct(")")) {
1426
- const param = this.next();
1427
- if (param.type !== "ident") {
1428
- throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1429
- }
1430
- params.push(param.value);
1431
- if (this.isPunct(",")) this.next();
1432
- }
1433
- this.expect(")");
1590
+ const params = this.parseParamList();
1434
1591
  return { t: "arrow", params, body: this.parseArrowBody() };
1435
1592
  }
1436
1593
  if (t2.type === "num" || t2.type === "str") {
@@ -1535,16 +1692,7 @@ var Parser = class {
1535
1692
  props.push({ key, value: this.parseAssignment() });
1536
1693
  } else if (this.isPunct("(")) {
1537
1694
  this.next();
1538
- const params = [];
1539
- while (!this.isPunct(")")) {
1540
- const param = this.next();
1541
- if (param.type !== "ident") {
1542
- throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1543
- }
1544
- params.push(param.value);
1545
- if (this.isPunct(",")) this.next();
1546
- }
1547
- this.expect(")");
1695
+ const params = this.parseParamList();
1548
1696
  props.push({ key, value: { t: "method", params, body: this.parseArrowBody() } });
1549
1697
  } else {
1550
1698
  props.push({ key, value: { t: "id", n: key } });
@@ -1647,6 +1795,14 @@ Expression: ${expression}` : message);
1647
1795
  }
1648
1796
  };
1649
1797
  var SPREAD = /* @__PURE__ */ Symbol("spread");
1798
+ var ReturnSignal = class {
1799
+ constructor(value) {
1800
+ __publicField(this, "value", value);
1801
+ }
1802
+ };
1803
+ function unwrap(value) {
1804
+ return value instanceof ReturnSignal ? value.value : value;
1805
+ }
1650
1806
  var BLOCKED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1651
1807
  function chaveBloqueada(key) {
1652
1808
  return typeof key === "string" && BLOCKED_KEYS.has(key);
@@ -1692,6 +1848,19 @@ function evaluate(node, scope) {
1692
1848
  );
1693
1849
  return obj[key];
1694
1850
  }
1851
+ case "new": {
1852
+ const target2 = evaluate(node.callee, scope);
1853
+ if (typeof target2 !== "function") {
1854
+ throw new VoodooRuntimeError(
1855
+ `Cannot construct ${stringify(target2)}: it is not a constructor`
1856
+ );
1857
+ }
1858
+ if (target2 === Function) {
1859
+ throw new VoodooRuntimeError("Cannot construct Function: expressions never compile code");
1860
+ }
1861
+ const args = evalArgs(node.args, scope);
1862
+ return Reflect.construct(target2, args);
1863
+ }
1695
1864
  case "call": {
1696
1865
  let thisArg;
1697
1866
  let fn;
@@ -1739,6 +1908,19 @@ function evaluate(node, scope) {
1739
1908
  }
1740
1909
  case "unary": {
1741
1910
  if (node.op === "...") return { [SPREAD]: evaluate(node.a, scope) };
1911
+ if (node.op === "delete") {
1912
+ if (node.a.t !== "member") {
1913
+ throw new VoodooRuntimeError(
1914
+ "delete needs a property, as in `delete user.name` or `delete list[0]`"
1915
+ );
1916
+ }
1917
+ const owner = evaluate(node.a.o, scope);
1918
+ if (owner == null) return true;
1919
+ const key = checkKey(
1920
+ node.a.computed ? evaluate(node.a.p, scope) : node.a.p.v
1921
+ );
1922
+ return delete owner[key];
1923
+ }
1742
1924
  if (node.op === "typeof") {
1743
1925
  if (node.a.t === "id") {
1744
1926
  if (chaveBloqueada(node.a.n)) return "undefined";
@@ -1756,6 +1938,8 @@ function evaluate(node, scope) {
1756
1938
  return -v;
1757
1939
  case "+":
1758
1940
  return +v;
1941
+ case "~":
1942
+ return ~v;
1759
1943
  case "void":
1760
1944
  return void 0;
1761
1945
  }
@@ -1803,6 +1987,23 @@ function evaluate(node, scope) {
1803
1987
  return l in r2;
1804
1988
  case "instanceof":
1805
1989
  return l instanceof r2;
1990
+ // The bitwise operators coerce through ToInt32, and `>>>` through
1991
+ // ToUint32, which is why the two shifts disagree for negatives:
1992
+ // `-1 >> 0` is -1 and `-1 >>> 0` is 4294967295. Applying the JavaScript
1993
+ // operator directly gets that for free; hand-rolling the coercion is
1994
+ // how an implementation ends up subtly wrong on exactly those cases.
1995
+ case "&":
1996
+ return l & r2;
1997
+ case "|":
1998
+ return l | r2;
1999
+ case "^":
2000
+ return l ^ r2;
2001
+ case "<<":
2002
+ return l << r2;
2003
+ case ">>":
2004
+ return l >> r2;
2005
+ case ">>>":
2006
+ return l >>> r2;
1806
2007
  }
1807
2008
  throw new VoodooRuntimeError(`Unsupported operator: ${node.op}`);
1808
2009
  }
@@ -1860,21 +2061,16 @@ function evaluate(node, scope) {
1860
2061
  const methodParams = node.params;
1861
2062
  const methodBody = node.body;
1862
2063
  return function(...args) {
1863
- const vars = {};
1864
- for (let i = 0; i < methodParams.length; i++) vars[methodParams[i]] = args[i];
2064
+ const vars = bindParams(methodParams, args, scope);
1865
2065
  const owner = this;
1866
2066
  const base = owner !== null && typeof owner === "object" ? scope.child(owner) : scope;
1867
- return evaluate(methodBody, base.child(vars));
2067
+ return unwrap(evaluate(methodBody, base.child(vars)));
1868
2068
  };
1869
2069
  }
1870
2070
  case "arrow": {
1871
2071
  const params = node.params;
1872
2072
  const body = node.body;
1873
- return (...args) => {
1874
- const vars = {};
1875
- for (let i = 0; i < params.length; i++) vars[params[i]] = args[i];
1876
- return evaluate(body, scope.child(vars));
1877
- };
2073
+ return (...args) => unwrap(evaluate(body, scope.child(bindParams(params, args, scope))));
1878
2074
  }
1879
2075
  case "obj": {
1880
2076
  const out = {};
@@ -1912,14 +2108,65 @@ function evaluate(node, scope) {
1912
2108
  }
1913
2109
  return out;
1914
2110
  }
2111
+ case "return":
2112
+ return new ReturnSignal(node.a ? evaluate(node.a, scope) : void 0);
1915
2113
  case "seq": {
1916
2114
  let last;
1917
- for (const stmt of node.body) last = evaluate(stmt, scope);
2115
+ for (const stmt of node.body) {
2116
+ last = evaluate(stmt, scope);
2117
+ if (last instanceof ReturnSignal) return last;
2118
+ }
1918
2119
  return last;
1919
2120
  }
1920
2121
  }
1921
2122
  throw new VoodooRuntimeError(`Unknown node: ${node.t}`);
1922
2123
  }
2124
+ function bindParam(param, value, vars, scope) {
2125
+ if (param.kind === "rest") {
2126
+ vars[param.name] = value;
2127
+ return;
2128
+ }
2129
+ if (param.def !== void 0 && value === void 0) {
2130
+ value = evaluate(param.def, scope.child(vars));
2131
+ }
2132
+ if (param.kind === "id") {
2133
+ vars[param.name] = value;
2134
+ return;
2135
+ }
2136
+ if (param.kind === "obj") {
2137
+ if (value == null) {
2138
+ throw new VoodooRuntimeError(
2139
+ `Cannot destructure ${value === null ? "null" : "undefined"}`
2140
+ );
2141
+ }
2142
+ const taken = /* @__PURE__ */ new Set();
2143
+ for (const { key, value: inner } of param.props) {
2144
+ taken.add(key);
2145
+ bindParam(inner, value[checkKey(key)], vars, scope);
2146
+ }
2147
+ if (param.rest) {
2148
+ const rest = {};
2149
+ for (const key of Object.keys(value)) {
2150
+ if (!taken.has(key)) rest[key] = value[key];
2151
+ }
2152
+ vars[param.rest] = rest;
2153
+ }
2154
+ return;
2155
+ }
2156
+ const items = Array.isArray(value) ? value : Array.from(value);
2157
+ param.elements.forEach((element, index) => {
2158
+ if (element) bindParam(element, items[index], vars, scope);
2159
+ });
2160
+ if (param.rest) vars[param.rest] = items.slice(param.elements.length);
2161
+ }
2162
+ function bindParams(params, args, scope) {
2163
+ const vars = {};
2164
+ for (let i = 0; i < params.length; i++) {
2165
+ const param = params[i];
2166
+ bindParam(param, param.kind === "rest" ? args.slice(i) : args[i], vars, scope);
2167
+ }
2168
+ return vars;
2169
+ }
1923
2170
  function evalArgs(args, scope) {
1924
2171
  const out = [];
1925
2172
  for (const arg of args) {
@@ -6516,7 +6763,7 @@ function data(values) {
6516
6763
  Object.defineProperties(rootScope.data, Object.getOwnPropertyDescriptors(values));
6517
6764
  return rootScope.data;
6518
6765
  }
6519
- var version2 = "0.7.0";
6766
+ var version2 = "0.10.0";
6520
6767
  var core = {
6521
6768
  // Utilities first: Voodoo's own names can override.
6522
6769
  ...utils_exports,
@@ -8140,7 +8387,7 @@ defineDirective(
8140
8387
  el.innerHTML = html ?? fallbackHtml;
8141
8388
  for (const child of Array.from(el.childNodes)) walk(child, scope);
8142
8389
  };
8143
- const render2 = async (record, current2) => {
8390
+ const render3 = async (record, current2) => {
8144
8391
  let html = null;
8145
8392
  if (record?.view) {
8146
8393
  el.classList.add("v-router-loading");
@@ -8161,7 +8408,7 @@ defineDirective(
8161
8408
  const matched = route.matched;
8162
8409
  void paramsSignature(route.params);
8163
8410
  const record = findRecord(matched);
8164
- void render2(record, ++token);
8411
+ void render3(record, ++token);
8165
8412
  });
8166
8413
  cleanup(() => {
8167
8414
  token++;
@@ -8371,8 +8618,8 @@ async function loadMessages(locale, source) {
8371
8618
  addMessages(locale, source);
8372
8619
  return;
8373
8620
  }
8374
- const pending = loading.get(locale);
8375
- if (pending) return pending;
8621
+ const pending2 = loading.get(locale);
8622
+ if (pending2) return pending2;
8376
8623
  const task = http.get(source, { responseType: "json" }).then((data2) => {
8377
8624
  if (data2 && typeof data2 === "object") addMessages(locale, data2);
8378
8625
  }).catch((err) => {
@@ -10903,7 +11150,7 @@ function commandPalette() {
10903
11150
  close();
10904
11151
  option.el.click();
10905
11152
  };
10906
- const render2 = () => {
11153
+ const render3 = () => {
10907
11154
  list.replaceChildren();
10908
11155
  if (!visible.length) {
10909
11156
  const empty = document.createElement("li");
@@ -10934,7 +11181,7 @@ function commandPalette() {
10934
11181
  row.addEventListener("pointermove", () => {
10935
11182
  if (cursor === index) return;
10936
11183
  cursor = index;
10937
- render2();
11184
+ render3();
10938
11185
  });
10939
11186
  list.appendChild(row);
10940
11187
  });
@@ -10948,7 +11195,7 @@ function commandPalette() {
10948
11195
  const term = normalizeSearch(input.value.trim());
10949
11196
  visible = term ? commands.filter((option) => normalizeSearch(`${option.label} ${option.hint}`).includes(term)) : commands;
10950
11197
  cursor = 0;
10951
- render2();
11198
+ render3();
10952
11199
  };
10953
11200
  const onKeyDown = (event) => {
10954
11201
  if (event.key === "Escape") {
@@ -10959,13 +11206,13 @@ function commandPalette() {
10959
11206
  if (event.key === "ArrowDown") {
10960
11207
  event.preventDefault();
10961
11208
  cursor = visible.length ? (cursor + 1) % visible.length : 0;
10962
- render2();
11209
+ render3();
10963
11210
  return;
10964
11211
  }
10965
11212
  if (event.key === "ArrowUp") {
10966
11213
  event.preventDefault();
10967
11214
  cursor = visible.length ? (cursor - 1 + visible.length) % visible.length : 0;
10968
- render2();
11215
+ render3();
10969
11216
  return;
10970
11217
  }
10971
11218
  if (event.key === "Enter") {
@@ -10980,7 +11227,7 @@ function commandPalette() {
10980
11227
  });
10981
11228
  input.addEventListener("input", filter);
10982
11229
  document.addEventListener("keydown", onKeyDown, true);
10983
- render2();
11230
+ render3();
10984
11231
  input.focus();
10985
11232
  document.addEventListener("focusin", keepFocusTrapped, true);
10986
11233
  }
@@ -13285,8 +13532,8 @@ var frameCallbacks = /* @__PURE__ */ new Set();
13285
13532
  var frameHandle = 0;
13286
13533
  function runFrame(now2) {
13287
13534
  frameHandle = 0;
13288
- const pending = Array.from(frameCallbacks);
13289
- for (const callback of pending) {
13535
+ const pending2 = Array.from(frameCallbacks);
13536
+ for (const callback of pending2) {
13290
13537
  if (frameCallbacks.has(callback)) callback(now2);
13291
13538
  }
13292
13539
  if (frameCallbacks.size > 0) frameHandle = requestAnimationFrame(runFrame);
@@ -20393,12 +20640,39 @@ function disableXray() {
20393
20640
  function isXrayEnabled() {
20394
20641
  return enabled;
20395
20642
  }
20643
+ function parseShortcut(text) {
20644
+ const parts = text.toLowerCase().split("+").map((part) => part.trim()).filter(Boolean);
20645
+ if (!parts.length) return null;
20646
+ const key = parts.pop();
20647
+ const shortcut2 = {
20648
+ ctrl: false,
20649
+ alt: false,
20650
+ shift: false,
20651
+ meta: false,
20652
+ 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)
20653
+ };
20654
+ for (const part of parts) {
20655
+ if (part === "ctrl" || part === "control") shortcut2.ctrl = true;
20656
+ else if (part === "alt" || part === "option") shortcut2.alt = true;
20657
+ else if (part === "shift") shortcut2.shift = true;
20658
+ else if (part === "meta" || part === "cmd" || part === "command" || part === "win")
20659
+ shortcut2.meta = true;
20660
+ else return null;
20661
+ }
20662
+ return shortcut2;
20663
+ }
20396
20664
  function enableXrayShortcut() {
20397
20665
  if (shortcutInstalled || typeof document === "undefined") return;
20398
20666
  shortcutInstalled = true;
20399
20667
  document.addEventListener("keydown", (event) => {
20400
- if (!event.altKey || !event.shiftKey || event.ctrlKey || event.metaKey) return;
20401
- if (event.code !== "KeyV" && event.key !== "V" && event.key !== "v") return;
20668
+ const setting = exports.config.xrayShortcut;
20669
+ if (setting === false) return;
20670
+ const wanted = parseShortcut(typeof setting === "string" ? setting : "ctrl+shift+f2");
20671
+ if (!wanted) return;
20672
+ if (event.ctrlKey !== wanted.ctrl || event.altKey !== wanted.alt || event.shiftKey !== wanted.shift || event.metaKey !== wanted.meta)
20673
+ return;
20674
+ if (event.code !== wanted.code && event.key.toUpperCase() !== wanted.code.replace(/^Key/, ""))
20675
+ return;
20402
20676
  event.preventDefault();
20403
20677
  xray();
20404
20678
  });
@@ -20411,6 +20685,225 @@ function xray(force) {
20411
20685
  return enabled;
20412
20686
  }
20413
20687
 
20688
+ // src/jsx/index.ts
20689
+ init_reactivity();
20690
+ init_registry();
20691
+ var OPAQUE = /* @__PURE__ */ new Set([
20692
+ "SCRIPT",
20693
+ "STYLE",
20694
+ "PRE",
20695
+ "CODE",
20696
+ "SAMP",
20697
+ "KBD",
20698
+ "TEXTAREA",
20699
+ "TEMPLATE",
20700
+ "NOSCRIPT"
20701
+ ]);
20702
+ magic("$__jsx", (scope) => scope);
20703
+ var TEMPLATE = /* @__PURE__ */ Symbol("voodoo.jsx.template");
20704
+ function isTemplate(value) {
20705
+ return typeof value === "object" && value !== null && TEMPLATE in value;
20706
+ }
20707
+ function collect(start2, offset) {
20708
+ const templates = [];
20709
+ const nodes = [];
20710
+ let source = "";
20711
+ let depth = 0;
20712
+ let quote = null;
20713
+ let escaped = false;
20714
+ let node = start2;
20715
+ let index = offset;
20716
+ let closed = false;
20717
+ let tail = null;
20718
+ while (node) {
20719
+ if (node.nodeType === Node.TEXT_NODE) {
20720
+ const text = node.textContent ?? "";
20721
+ for (; index < text.length; index++) {
20722
+ const ch = text[index];
20723
+ if (escaped) {
20724
+ escaped = false;
20725
+ source += ch;
20726
+ continue;
20727
+ }
20728
+ if (quote) {
20729
+ if (ch === "\\") escaped = true;
20730
+ else if (ch === quote) quote = null;
20731
+ source += ch;
20732
+ continue;
20733
+ }
20734
+ if (ch === '"' || ch === "'" || ch === "`") {
20735
+ quote = ch;
20736
+ source += ch;
20737
+ continue;
20738
+ }
20739
+ if (ch === "{") {
20740
+ depth++;
20741
+ if (depth > 1) source += ch;
20742
+ continue;
20743
+ }
20744
+ if (ch === "}") {
20745
+ depth--;
20746
+ if (depth === 0) {
20747
+ index++;
20748
+ closed = true;
20749
+ break;
20750
+ }
20751
+ source += ch;
20752
+ continue;
20753
+ }
20754
+ source += ch;
20755
+ }
20756
+ nodes.push(node);
20757
+ if (closed) {
20758
+ tail = { node, offset: index };
20759
+ break;
20760
+ }
20761
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
20762
+ if (depth === 0) return null;
20763
+ source += `$t(${templates.length}, $__jsx)`;
20764
+ templates.push(node);
20765
+ nodes.push(node);
20766
+ } else {
20767
+ nodes.push(node);
20768
+ }
20769
+ index = 0;
20770
+ node = node.nextSibling;
20771
+ }
20772
+ if (!closed) return null;
20773
+ return { source, templates, nodes, tail };
20774
+ }
20775
+ function render2(value, templates, scope, out) {
20776
+ if (value == null || value === false || value === true) return;
20777
+ if (Array.isArray(value)) {
20778
+ for (const item of value) render2(item, templates, scope, out);
20779
+ return;
20780
+ }
20781
+ if (isTemplate(value)) {
20782
+ const handle = value;
20783
+ const source = templates[handle.index];
20784
+ const clone2 = source.cloneNode(true);
20785
+ const at = handle.scope ?? scope;
20786
+ applyRegions(clone2, at);
20787
+ activateJsx();
20788
+ walk(clone2, at);
20789
+ out.push(clone2);
20790
+ return;
20791
+ }
20792
+ out.push(document.createTextNode(String(value)));
20793
+ }
20794
+ function applyRegions(root, parentScope) {
20795
+ if (OPAQUE.has(root.tagName)) return;
20796
+ const scope = parentScope ?? findScope(root);
20797
+ let child = root.firstChild;
20798
+ while (child) {
20799
+ const next = child.nextSibling;
20800
+ if (child.nodeType === Node.ELEMENT_NODE) {
20801
+ applyRegions(child, getScope(child) ?? scope);
20802
+ child = next;
20803
+ continue;
20804
+ }
20805
+ if (child.nodeType !== Node.TEXT_NODE) {
20806
+ child = next;
20807
+ continue;
20808
+ }
20809
+ const text = child.textContent ?? "";
20810
+ const open = text.indexOf("{");
20811
+ if (open < 0) {
20812
+ child = next;
20813
+ continue;
20814
+ }
20815
+ const collected = collect(child, open);
20816
+ if (!collected || collected.templates.length === 0) {
20817
+ child = next;
20818
+ continue;
20819
+ }
20820
+ install(root, collected, scope);
20821
+ child = collected.nodes[collected.nodes.length - 1]?.nextSibling;
20822
+ }
20823
+ }
20824
+ var pending = [];
20825
+ function install(parent, collected, hint) {
20826
+ const { source, templates, nodes, tail } = collected;
20827
+ let ast;
20828
+ try {
20829
+ ast = parse(source);
20830
+ } catch (error) {
20831
+ if (exports.config.devtools) {
20832
+ console.warn(`[Voodoo] could not parse the inline expression: ${source}`, error);
20833
+ }
20834
+ return;
20835
+ }
20836
+ if (tail && tail.offset < (tail.node.textContent ?? "").length) {
20837
+ tail.node.splitText(tail.offset);
20838
+ }
20839
+ const anchor = document.createComment("v-jsx");
20840
+ parent.insertBefore(anchor, nodes[0]);
20841
+ for (const node of nodes) node.remove();
20842
+ let rendered = [];
20843
+ pending.push(() => activateRegion());
20844
+ function activateRegion() {
20845
+ const found = findScope(anchor);
20846
+ const scope = found === rootScope && hint ? hint : found;
20847
+ const local = scope.child({
20848
+ $t: (index, at) => ({ [TEMPLATE]: true, index, scope: at })
20849
+ });
20850
+ const runner = effect(() => {
20851
+ const value = unwrap(evaluate(ast, local));
20852
+ const out = [];
20853
+ render2(value, templates, local, out);
20854
+ for (const node of rendered) node.remove();
20855
+ rendered = out;
20856
+ for (const node of out) parent.insertBefore(node, anchor);
20857
+ });
20858
+ addCleanup(anchor, () => {
20859
+ runner.effect.stop();
20860
+ for (const node of rendered) node.remove();
20861
+ });
20862
+ }
20863
+ }
20864
+ function readDeclarationBlock(root = document.body) {
20865
+ for (const node of Array.from(root.childNodes)) {
20866
+ if (node.nodeType !== Node.TEXT_NODE) continue;
20867
+ const text = (node.textContent ?? "").trim();
20868
+ if (!text.startsWith("{") || !text.endsWith("}")) continue;
20869
+ if (!/\b(const|let|var)\s/.test(text)) continue;
20870
+ const body = text.slice(1, -1).replace(/\b(?:const|let|var)\s+/g, "");
20871
+ const data2 = reactive({});
20872
+ try {
20873
+ evaluate(parse(body), new Scope(data2));
20874
+ } catch (error) {
20875
+ if (exports.config.devtools) {
20876
+ console.warn("[Voodoo] could not read the declaration block", error);
20877
+ }
20878
+ return null;
20879
+ }
20880
+ node.remove();
20881
+ return data2;
20882
+ }
20883
+ return null;
20884
+ }
20885
+ function activateJsx() {
20886
+ const work = pending.splice(0, pending.length);
20887
+ for (const run of work) {
20888
+ try {
20889
+ run();
20890
+ } catch (error) {
20891
+ console.error("[Voodoo] a JSX region failed to render", error);
20892
+ }
20893
+ }
20894
+ }
20895
+ function extractJsx(root = document.body) {
20896
+ const data2 = readDeclarationBlock(root);
20897
+ if (data2) {
20898
+ Object.assign(rootScope.data, data2);
20899
+ }
20900
+ applyRegions(root, findScope(root));
20901
+ }
20902
+ function jsx(root = document.body) {
20903
+ extractJsx(root);
20904
+ activateJsx();
20905
+ }
20906
+
20414
20907
  // src/devtools/launcher.ts
20415
20908
  init_style();
20416
20909
  var POSITION_KEY = "voodoo:devtools:widget-position";
@@ -20591,9 +21084,9 @@ function build() {
20591
21084
  const button = document.createElement("button");
20592
21085
  button.type = "button";
20593
21086
  button.className = "v-devtools-btn";
20594
- button.setAttribute("aria-label", "Open Voodoo devtools (Alt+Shift+V)");
21087
+ button.setAttribute("aria-label", "Open Voodoo devtools (Ctrl+Shift+F2)");
20595
21088
  button.setAttribute("aria-pressed", "false");
20596
- button.title = "Voodoo devtools \u2014 click to inspect, drag to move (Alt+Shift+V)";
21089
+ button.title = "Voodoo devtools \u2014 click to inspect, drag to move (Ctrl+Shift+F2)";
20597
21090
  button.innerHTML = MARK;
20598
21091
  const label = document.createElement("span");
20599
21092
  label.className = "v-devtools-label";
@@ -21111,9 +21604,9 @@ function createSocket(url2, options = {}) {
21111
21604
  }
21112
21605
  function drainQueue() {
21113
21606
  if (!queue3.length) return;
21114
- const pending = queue3.splice(0, queue3.length);
21607
+ const pending2 = queue3.splice(0, queue3.length);
21115
21608
  state2.queued = 0;
21116
- for (const text of pending) sendText(text);
21609
+ for (const text of pending2) sendText(text);
21117
21610
  }
21118
21611
  function sendText(text) {
21119
21612
  if (ws && ws.readyState === 1 && (!socketIo || state2.connected)) {
@@ -22870,6 +23363,9 @@ Object.assign(V, core, {
22870
23363
  query,
22871
23364
  ready: ready2,
22872
23365
  fromHtml,
23366
+ jsx,
23367
+ extractJsx,
23368
+ activateJsx,
22873
23369
  Collection: VoodooCollection,
22874
23370
  // Routes
22875
23371
  router,
@@ -22935,12 +23431,14 @@ exports.V = V;
22935
23431
  exports.VoodooCollection = VoodooCollection;
22936
23432
  exports.VoodooRuntimeError = VoodooRuntimeError;
22937
23433
  exports.VoodooSyntaxError = VoodooSyntaxError;
23434
+ exports.activateJsx = activateJsx;
22938
23435
  exports.addCleanup = addCleanup;
22939
23436
  exports.alert = alert;
22940
23437
  exports.allStores = allStores;
22941
23438
  exports.allowedGlobals = allowedGlobals;
22942
23439
  exports.animate = animate;
22943
23440
  exports.applyMask = applyMask;
23441
+ exports.applyRegions = applyRegions;
22944
23442
  exports.cache = cache2;
22945
23443
  exports.capitalize = capitalize;
22946
23444
  exports.charts = charts;
@@ -22974,6 +23472,7 @@ exports.ensureTokens = ensureTokens;
22974
23472
  exports.enter = enter;
22975
23473
  exports.escapeHtml = escapeHtml;
22976
23474
  exports.evaluate = evaluate;
23475
+ exports.extractJsx = extractJsx;
22977
23476
  exports.fadeIn = fadeIn;
22978
23477
  exports.fadeOut = fadeOut;
22979
23478
  exports.findScope = findScope;
@@ -22999,6 +23498,7 @@ exports.isBrowser = isBrowser;
22999
23498
  exports.isDevtoolsWidgetMounted = isDevtoolsWidgetMounted;
23000
23499
  exports.isReactive = isReactive;
23001
23500
  exports.isXrayEnabled = isXrayEnabled;
23501
+ exports.jsx = jsx;
23002
23502
  exports.leave = leave;
23003
23503
  exports.magic = magic;
23004
23504
  exports.magics = magics;
@@ -23023,6 +23523,7 @@ exports.prompt = prompt;
23023
23523
  exports.query = query;
23024
23524
  exports.random = random;
23025
23525
  exports.reactive = reactive;
23526
+ exports.readDeclarationBlock = readDeclarationBlock;
23026
23527
  exports.ready = ready2;
23027
23528
  exports.ref = ref;
23028
23529
  exports.reflectWgsl = reflectWgsl;