valyrian.js 7.2.11 → 8.0.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 (165) hide show
  1. package/README.md +6 -6
  2. package/dist/flux-store/index.d.ts +32 -0
  3. package/dist/flux-store/index.d.ts.map +1 -0
  4. package/dist/flux-store/index.js +258 -0
  5. package/dist/flux-store/index.js.map +7 -0
  6. package/dist/flux-store/index.min.js +1 -0
  7. package/dist/flux-store/index.min.js.map +1 -0
  8. package/dist/flux-store/index.mjs +237 -0
  9. package/dist/flux-store/index.mjs.map +7 -0
  10. package/dist/hooks/index.d.ts.map +1 -1
  11. package/dist/hooks/index.js +42 -75
  12. package/dist/hooks/index.js.map +2 -2
  13. package/dist/hooks/index.min.js +1 -0
  14. package/dist/hooks/index.min.js.map +1 -0
  15. package/dist/hooks/index.mjs +43 -76
  16. package/dist/hooks/index.mjs.map +2 -2
  17. package/dist/index.d.ts +52 -54
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +397 -328
  20. package/dist/index.js.map +3 -3
  21. package/dist/index.min.js +1 -1
  22. package/dist/index.min.js.map +1 -1
  23. package/dist/index.mjs +397 -328
  24. package/dist/index.mjs.map +3 -3
  25. package/dist/native-store/index.d.ts +14 -0
  26. package/dist/native-store/index.d.ts.map +1 -0
  27. package/dist/native-store/index.js +103 -0
  28. package/dist/native-store/index.js.map +7 -0
  29. package/dist/native-store/index.min.js +1 -0
  30. package/dist/native-store/index.min.js.map +1 -0
  31. package/dist/native-store/index.mjs +82 -0
  32. package/dist/native-store/index.mjs.map +7 -0
  33. package/dist/node/index.d.ts.map +1 -1
  34. package/dist/node/index.js +223 -86
  35. package/dist/node/index.js.map +4 -4
  36. package/dist/node/index.mjs +223 -86
  37. package/dist/node/index.mjs.map +4 -4
  38. package/dist/node/node.sw.js +152 -0
  39. package/dist/node/utils/inline.d.ts.map +1 -1
  40. package/dist/node/utils/node.sw.js +152 -0
  41. package/dist/node/utils/session-storage.d.ts +22 -0
  42. package/dist/node/utils/session-storage.d.ts.map +1 -0
  43. package/dist/node/utils/sw.d.ts.map +1 -1
  44. package/dist/node/utils/tree-adapter.d.ts +9 -0
  45. package/dist/node/utils/tree-adapter.d.ts.map +1 -1
  46. package/dist/pulse-store/index.d.ts +13 -0
  47. package/dist/pulse-store/index.d.ts.map +1 -0
  48. package/dist/pulse-store/index.js +143 -0
  49. package/dist/pulse-store/index.js.map +7 -0
  50. package/dist/pulse-store/index.min.js +1 -0
  51. package/dist/pulse-store/index.min.js.map +1 -0
  52. package/dist/pulse-store/index.mjs +122 -0
  53. package/dist/pulse-store/index.mjs.map +7 -0
  54. package/dist/request/index.d.ts.map +1 -1
  55. package/dist/request/index.js +68 -89
  56. package/dist/request/index.js.map +2 -2
  57. package/dist/request/index.min.js +1 -0
  58. package/dist/request/index.min.js.map +1 -0
  59. package/dist/request/index.mjs +68 -89
  60. package/dist/request/index.mjs.map +2 -2
  61. package/dist/router/index.d.ts +32 -31
  62. package/dist/router/index.d.ts.map +1 -1
  63. package/dist/router/index.js +256 -104
  64. package/dist/router/index.js.map +3 -3
  65. package/dist/router/index.min.js +1 -0
  66. package/dist/router/index.min.js.map +1 -0
  67. package/dist/router/index.mjs +256 -104
  68. package/dist/router/index.mjs.map +3 -3
  69. package/dist/signals/index.d.ts +6 -0
  70. package/dist/signals/index.d.ts.map +1 -0
  71. package/dist/signals/index.js +92 -0
  72. package/dist/signals/index.js.map +7 -0
  73. package/dist/signals/index.min.js +1 -0
  74. package/dist/signals/index.min.js.map +1 -0
  75. package/dist/signals/index.mjs +71 -0
  76. package/dist/signals/index.mjs.map +7 -0
  77. package/dist/suspense/index.d.ts +6 -0
  78. package/dist/suspense/index.d.ts.map +1 -0
  79. package/dist/suspense/index.js +67 -0
  80. package/dist/suspense/index.js.map +7 -0
  81. package/dist/suspense/index.min.js +1 -0
  82. package/dist/suspense/index.min.js.map +1 -0
  83. package/dist/suspense/index.mjs +46 -0
  84. package/dist/suspense/index.mjs.map +7 -0
  85. package/dist/sw/index.min.js +1 -0
  86. package/dist/sw/index.min.js.map +1 -0
  87. package/dist/translate/index.d.ts +19 -0
  88. package/dist/translate/index.d.ts.map +1 -0
  89. package/dist/translate/index.js +150 -0
  90. package/dist/translate/index.js.map +7 -0
  91. package/dist/translate/index.min.js +1 -0
  92. package/dist/translate/index.min.js.map +1 -0
  93. package/dist/translate/index.mjs +129 -0
  94. package/dist/translate/index.mjs.map +7 -0
  95. package/dist/tsconfig.tsbuildinfo +1 -1
  96. package/dist/utils/deep-freeze.d.ts +3 -0
  97. package/dist/utils/deep-freeze.d.ts.map +1 -0
  98. package/dist/utils/getter-setter.d.ts +3 -0
  99. package/dist/utils/getter-setter.d.ts.map +1 -0
  100. package/dist/utils/has-changed.d.ts +2 -0
  101. package/dist/utils/has-changed.d.ts.map +1 -0
  102. package/dist/utils/index.d.ts +4 -0
  103. package/dist/utils/index.d.ts.map +1 -0
  104. package/dist/utils/index.js +138 -0
  105. package/dist/utils/index.js.map +7 -0
  106. package/dist/utils/index.min.js +1 -0
  107. package/dist/utils/index.min.js.map +1 -0
  108. package/dist/utils/index.mjs +115 -0
  109. package/dist/utils/index.mjs.map +7 -0
  110. package/lib/flux-store/index.ts +301 -0
  111. package/lib/hooks/index.ts +52 -101
  112. package/lib/index.ts +479 -719
  113. package/lib/native-store/index.ts +106 -0
  114. package/lib/node/index.ts +5 -3
  115. package/lib/node/utils/icons.ts +5 -5
  116. package/lib/node/utils/inline.ts +17 -17
  117. package/lib/node/utils/node.sw.js +152 -0
  118. package/lib/node/utils/session-storage.ts +117 -0
  119. package/lib/node/utils/sw.ts +35 -11
  120. package/lib/node/utils/tree-adapter.ts +99 -52
  121. package/lib/pulse-store/index.ts +181 -0
  122. package/lib/request/index.ts +86 -116
  123. package/lib/router/index.ts +358 -170
  124. package/lib/signals/index.ts +98 -0
  125. package/lib/suspense/index.ts +57 -0
  126. package/lib/translate/index.ts +156 -0
  127. package/lib/utils/deep-freeze.ts +54 -0
  128. package/lib/utils/getter-setter.ts +40 -0
  129. package/lib/utils/has-changed.ts +43 -0
  130. package/lib/utils/index.ts +3 -0
  131. package/package.json +38 -50
  132. package/tsconfig.json +1 -1
  133. package/dist/dataset/index.d.ts +0 -24
  134. package/dist/dataset/index.d.ts.map +0 -1
  135. package/dist/dataset/index.js +0 -178
  136. package/dist/dataset/index.js.map +0 -7
  137. package/dist/dataset/index.mjs +0 -157
  138. package/dist/dataset/index.mjs.map +0 -7
  139. package/dist/node/node.sw.tpl +0 -133
  140. package/dist/node/utils/node.sw.tpl +0 -133
  141. package/dist/proxy-signal/index.d.ts +0 -23
  142. package/dist/proxy-signal/index.d.ts.map +0 -1
  143. package/dist/proxy-signal/index.js +0 -138
  144. package/dist/proxy-signal/index.js.map +0 -7
  145. package/dist/proxy-signal/index.mjs +0 -117
  146. package/dist/proxy-signal/index.mjs.map +0 -7
  147. package/dist/signal/index.d.ts +0 -20
  148. package/dist/signal/index.d.ts.map +0 -1
  149. package/dist/signal/index.js +0 -95
  150. package/dist/signal/index.js.map +0 -7
  151. package/dist/signal/index.mjs +0 -74
  152. package/dist/signal/index.mjs.map +0 -7
  153. package/dist/store/index.d.ts +0 -16
  154. package/dist/store/index.d.ts.map +0 -1
  155. package/dist/store/index.js +0 -93
  156. package/dist/store/index.js.map +0 -7
  157. package/dist/store/index.mjs +0 -72
  158. package/dist/store/index.mjs.map +0 -7
  159. package/lib/dataset/index.ts +0 -193
  160. package/lib/index.d.ts +0 -0
  161. package/lib/interfaces.ts.bak +0 -141
  162. package/lib/node/utils/node.sw.tpl +0 -133
  163. package/lib/proxy-signal/index.ts +0 -187
  164. package/lib/signal/index.ts +0 -161
  165. package/lib/store/index.ts +0 -101
@@ -53,6 +53,16 @@ export class Node implements Node {
53
53
  this.parent_node = node;
54
54
  }
55
55
 
56
+ #dataset: Record<string | number, any> = {};
57
+
58
+ get dataset() {
59
+ return this.#dataset;
60
+ }
61
+
62
+ set dataset(value) {
63
+ this.#dataset = value;
64
+ }
65
+
56
66
  constructor() {}
57
67
 
58
68
  appendChild<T extends Node>(node: T): T {
@@ -69,7 +79,7 @@ export class Node implements Node {
69
79
  node.parentNode && node.parentNode.removeChild(node as Node);
70
80
  node.parentNode = this;
71
81
  if (child) {
72
- let idx = this.childNodes.indexOf(child);
82
+ const idx = this.childNodes.indexOf(child);
73
83
  this.childNodes.splice(idx, 0, node);
74
84
  } else {
75
85
  this.childNodes.push(node);
@@ -87,19 +97,24 @@ export class Node implements Node {
87
97
  }
88
98
  removeChild<T extends Node>(child: T): T {
89
99
  if (child && child.parentNode === this) {
90
- let idx = (this.childNodes as unknown as Node[]).indexOf(child);
100
+ const idx = (this.childNodes as unknown as Node[]).indexOf(child);
91
101
  (this.childNodes as unknown as Node[]).splice(idx, 1);
92
102
  child.parentNode = null;
93
103
  }
94
104
  return child;
95
105
  }
106
+
107
+ remove(): Node {
108
+ return this.parentNode ? this.parentNode.removeChild(this) : this;
109
+ }
110
+
96
111
  cloneNode(deep?: boolean | undefined): Node {
97
112
  if (this.nodeType === 3) {
98
113
  return new Text(this.nodeValue);
99
114
  }
100
115
 
101
116
  if (this.nodeType === 1) {
102
- let node = new Element();
117
+ const node = new Element();
103
118
  node.nodeType = this.nodeType;
104
119
  this.nodeName = this.nodeName;
105
120
  if (this.attributes) {
@@ -107,6 +122,11 @@ export class Node implements Node {
107
122
  node.setAttribute(this.attributes[i].nodeName, this.attributes[i].nodeValue);
108
123
  }
109
124
  }
125
+
126
+ for (const key in this.dataset) {
127
+ node.dataset[key] = this.dataset[key];
128
+ }
129
+
110
130
  if (deep) {
111
131
  for (let i = 0, l = this.childNodes.length; i < l; i++) {
112
132
  node.appendChild(this.childNodes[i].cloneNode(deep));
@@ -115,14 +135,14 @@ export class Node implements Node {
115
135
  return node;
116
136
  }
117
137
 
118
- let node = new Node();
138
+ const node = new Node();
119
139
  node.nodeType = this.nodeType;
120
140
  node.nodeName = this.nodeName;
121
141
  return node;
122
142
  }
123
143
 
124
144
  setAttribute(name: string, value: any) {
125
- let attr = {
145
+ const attr = {
126
146
  nodeName: name,
127
147
  nodeValue: value
128
148
  };
@@ -266,8 +286,8 @@ export class Text extends Node {
266
286
 
267
287
  function updateElementStyles(element: Element, state: Record<string, any>) {
268
288
  let str = "";
269
- for (let key in state) {
270
- let value = state[key];
289
+ for (const key in state) {
290
+ const value = state[key];
271
291
  if (typeof value !== "undefined" && value !== null && String(value).length > 0) {
272
292
  str += `${key}: ${state[key]};`;
273
293
  }
@@ -324,11 +344,23 @@ export class Element extends Node {
324
344
  throw new Error("Cannot set style");
325
345
  }
326
346
 
347
+ get className(): string {
348
+ return this.getAttribute("class") || "";
349
+ }
350
+
351
+ set className(value: string | boolean) {
352
+ if (value == null || value === false) {
353
+ this.removeAttribute("class");
354
+ } else {
355
+ this.setAttribute("class", String(value));
356
+ }
357
+ }
358
+
327
359
  classList = {
328
360
  toggle: (item: any, force: any) => {
329
361
  if (item) {
330
- let classes = (this.getAttribute("class") || "").split(" ");
331
- let itemIndex = classes.indexOf(item);
362
+ const classes = (this.className || "").split(" ");
363
+ const itemIndex = classes.indexOf(item);
332
364
  if (force && itemIndex === -1) {
333
365
  classes.push(item);
334
366
  }
@@ -337,16 +369,28 @@ export class Element extends Node {
337
369
  classes.splice(itemIndex, 1);
338
370
  }
339
371
 
340
- let final = classes.join(" ").trim();
372
+ const final = classes.join(" ").trim();
341
373
  if (final.length) {
342
- this.setAttribute("class", classes.join(" ").trim());
374
+ this.className = classes.join(" ").trim();
343
375
  } else {
344
- this.removeAttribute("class");
376
+ this.className = false;
345
377
  }
346
378
  }
347
379
  }
348
380
  };
349
381
 
382
+ get id(): string {
383
+ return this.getAttribute("id") || "";
384
+ }
385
+
386
+ set id(value: string | boolean) {
387
+ if (value == null || value === false) {
388
+ this.removeAttribute("id");
389
+ } else {
390
+ this.setAttribute("id", String(value));
391
+ }
392
+ }
393
+
350
394
  set textContent(text) {
351
395
  this.nodeValue = String(text);
352
396
  this.childNodes = this.nodeValue ? [new Text(this.nodeValue)] : [];
@@ -374,7 +418,7 @@ export class Element extends Node {
374
418
 
375
419
  set innerHTML(html) {
376
420
  this.textContent = "";
377
- let result = htmlToDom(html);
421
+ const result = htmlToDom(html);
378
422
  if (result instanceof DocumentFragment) {
379
423
  for (let i = 0, l = result.childNodes.length; i < l; i++) {
380
424
  this.appendChild(result.childNodes[i]);
@@ -402,20 +446,23 @@ export class Document extends Element {
402
446
  super();
403
447
  this.nodeType = 9;
404
448
  this.nodeName = "#document";
449
+ this.body = this.createElement("body");
405
450
  }
406
451
 
452
+ body: Element;
453
+
407
454
  createDocumentFragment(): DocumentFragment {
408
455
  return new DocumentFragment();
409
456
  }
410
457
 
411
458
  createElement(type: string) {
412
- let element = new Element();
459
+ const element = new Element();
413
460
  element.nodeName = type.toUpperCase();
414
461
  return element;
415
462
  }
416
463
 
417
464
  createElementNS(ns: string, type: string) {
418
- let element = this.createElement(type);
465
+ const element = this.createElement(type);
419
466
  element.baseURI = ns;
420
467
  return element;
421
468
  }
@@ -425,7 +472,7 @@ export class Document extends Element {
425
472
  }
426
473
  }
427
474
 
428
- let selfClosingTags = [
475
+ const selfClosingTags = [
429
476
  "area",
430
477
  "base",
431
478
  "br",
@@ -449,7 +496,7 @@ export function domToHtml(dom: Element): string {
449
496
  }
450
497
 
451
498
  if (dom.nodeType === 1) {
452
- let name = dom.nodeName.toLowerCase();
499
+ const name = dom.nodeName.toLowerCase();
453
500
  let str = "<" + name;
454
501
  for (let i = 0, l = dom.attributes.length; i < l; i++) {
455
502
  str += " " + dom.attributes[i].nodeName + '="' + dom.attributes[i].nodeValue + '"';
@@ -459,7 +506,7 @@ export function domToHtml(dom: Element): string {
459
506
  str += ">";
460
507
  if (dom.childNodes && dom.childNodes.length > 0) {
461
508
  for (let i = 0, l = dom.childNodes.length; i < l; i++) {
462
- let child = domToHtml(dom.childNodes[i] as Element);
509
+ const child = domToHtml(dom.childNodes[i] as Element);
463
510
  if (child) {
464
511
  str += child;
465
512
  }
@@ -492,9 +539,9 @@ export function domToHyperscript(childNodes: ChildNodes, depth = 1) {
492
539
  let str = `\n${spaces}v("${item.nodeName}", `;
493
540
 
494
541
  if (item.attributes) {
495
- let attrs: Record<string, any> = {};
542
+ const attrs: Record<string, any> = {};
496
543
  for (let i = 0, l = item.attributes.length; i < l; i++) {
497
- let attr = item.attributes[i];
544
+ const attr = item.attributes[i];
498
545
  attrs[attr.nodeName] = attr.nodeValue;
499
546
  }
500
547
  str += JSON.stringify(attrs);
@@ -534,21 +581,21 @@ interface ObjectIndexItemWithContent extends ObjectIndexItem {
534
581
  interface ObjectIndexList extends Array<ObjectIndexItem> {}
535
582
 
536
583
  function findTexts(item: ObjectIndexItemWithContent, html: string) {
537
- let newChildren: ObjectIndexItemWithContent[] = [];
584
+ const newChildren: ObjectIndexItemWithContent[] = [];
538
585
 
539
586
  // If the item has children
540
587
  if (item.children.length) {
541
588
  // Search for texts in the children.
542
589
  for (let i = 0; i < item.children.length; i++) {
543
- let child = item.children[i];
544
- let nextChild = item.children[i + 1];
590
+ const child = item.children[i];
591
+ const nextChild = item.children[i + 1];
545
592
 
546
593
  // If is the first child and the child startsAt is greater than the item contentStartsAt then
547
594
  // the content between the item contentStartsAt and the child startsAt is a text child of the item.
548
595
  if (i === 0 && child.startsAt > item.contentStartsAt) {
549
- let childContent = html.substring(item.contentStartsAt, child.startsAt);
596
+ const childContent = html.substring(item.contentStartsAt, child.startsAt);
550
597
 
551
- let childText: ObjectIndexItemWithContent = {
598
+ const childText: ObjectIndexItemWithContent = {
552
599
  tagName: "#text",
553
600
  startsAt: item.contentStartsAt,
554
601
  endsAt: item.contentStartsAt + childContent.length,
@@ -568,9 +615,9 @@ function findTexts(item: ObjectIndexItemWithContent, html: string) {
568
615
  // If there is a next child and the child endsAt is less than the next child startsAt then
569
616
  // the content between the child endsAt and the next child startsAt is a text child of the item.
570
617
  if (nextChild && child.endsAt < nextChild.startsAt) {
571
- let childContent = html.substring(child.endsAt, nextChild.startsAt);
618
+ const childContent = html.substring(child.endsAt, nextChild.startsAt);
572
619
 
573
- let childText: ObjectIndexItemWithContent = {
620
+ const childText: ObjectIndexItemWithContent = {
574
621
  tagName: "#text",
575
622
  startsAt: child.endsAt,
576
623
  endsAt: child.endsAt + childContent.length,
@@ -587,9 +634,9 @@ function findTexts(item: ObjectIndexItemWithContent, html: string) {
587
634
  // If there are no next child and the child endsAt is less than the item contentEndsAt then
588
635
  // the content between the child endsAt and the item contentEndsAt is a text child of the item.
589
636
  if (!nextChild && child.endsAt < item.contentEndsAt) {
590
- let childContent = html.substring(child.endsAt, item.contentEndsAt);
637
+ const childContent = html.substring(child.endsAt, item.contentEndsAt);
591
638
 
592
- let childText: ObjectIndexItemWithContent = {
639
+ const childText: ObjectIndexItemWithContent = {
593
640
  tagName: "#text",
594
641
  startsAt: child.endsAt,
595
642
  endsAt: child.endsAt + childContent.length,
@@ -611,10 +658,10 @@ function findTexts(item: ObjectIndexItemWithContent, html: string) {
611
658
  // If the item has no children then set the contents between the item contentStartsAt and the item contentEndsAt
612
659
  // as a text child of the item.
613
660
  if (!item.children.length) {
614
- let childContent = html.substring(item.contentStartsAt, item.contentEndsAt);
661
+ const childContent = html.substring(item.contentStartsAt, item.contentEndsAt);
615
662
 
616
663
  if (childContent.length) {
617
- let childText: ObjectIndexItemWithContent = {
664
+ const childText: ObjectIndexItemWithContent = {
618
665
  tagName: "#text",
619
666
  startsAt: item.contentStartsAt,
620
667
  endsAt: item.contentEndsAt,
@@ -642,12 +689,12 @@ function convertToDom<T extends Node>(item: ObjectIndexItemWithContent): T {
642
689
  ? document.createDocumentFragment()
643
690
  : document.createElement(item.tagName)) as unknown as T;
644
691
 
645
- for (let key in item.attributes) {
692
+ for (const key in item.attributes) {
646
693
  node.setAttribute(key, item.attributes[key]);
647
694
  }
648
695
 
649
696
  for (let i = 0; i < item.children.length; i++) {
650
- let child = convertToDom(item.children[i]);
697
+ const child = convertToDom(item.children[i]);
651
698
  node.appendChild(child);
652
699
  }
653
700
  }
@@ -658,23 +705,23 @@ function convertToDom<T extends Node>(item: ObjectIndexItemWithContent): T {
658
705
  // eslint-disable-next-line sonarjs/cognitive-complexity
659
706
  function getObjectIndexTree(html: string): DocumentFragment {
660
707
  let item;
661
- let regex = RegExp("<([^>|^!]+)>", "g");
662
- let items: ObjectIndexList = [];
708
+ const regex = RegExp("<([^>|^!]+)>", "g");
709
+ const items: ObjectIndexList = [];
663
710
 
664
711
  // Make the initial list of items.
665
712
  while ((item = regex.exec(html))) {
666
713
  // If is a closing tag
667
714
  if (item[0].startsWith("</")) {
668
- let lastOpenedItem = [...items].reverse().find((item) => item.endsAt === null);
715
+ const lastOpenedItem = [...items].reverse().find((item) => item.endsAt === null);
669
716
  if (lastOpenedItem) {
670
717
  lastOpenedItem.endsAt = item.index + item[0].length;
671
718
  lastOpenedItem.contentEndsAt = item.index;
672
719
 
673
720
  // Find the last opened item again, this will be the parent of the current item.
674
- let parent = [...items].reverse().find((item) => item.endsAt === null);
721
+ const parent = [...items].reverse().find((item) => item.endsAt === null);
675
722
  if (parent) {
676
723
  // Find the index of the current item in the items array.
677
- let index = items.indexOf(lastOpenedItem);
724
+ const index = items.indexOf(lastOpenedItem);
678
725
  // Remove the last opened item from the items array.
679
726
  items.splice(index, 1);
680
727
 
@@ -687,7 +734,7 @@ function getObjectIndexTree(html: string): DocumentFragment {
687
734
  }
688
735
 
689
736
  // If is an opening tag
690
- let element: ObjectIndexItem = {
737
+ const element: ObjectIndexItem = {
691
738
  tagName: item[1].split(" ")[0],
692
739
  startsAt: item.index,
693
740
  endsAt: null,
@@ -700,10 +747,10 @@ function getObjectIndexTree(html: string): DocumentFragment {
700
747
 
701
748
  // Find the attributes of the tag.
702
749
  let string = (item[1] || "").substring(element.tagName.length + 1).replace(/\/$/g, "");
703
- let attributesWithValues = string.match(/\S+="[^"]+"/g);
750
+ const attributesWithValues = string.match(/\S+="[^"]+"/g);
704
751
 
705
752
  if (attributesWithValues) {
706
- for (let attribute of attributesWithValues) {
753
+ for (const attribute of attributesWithValues) {
707
754
  const [name, ...value] = attribute.trim().split("=");
708
755
  string = string.replace(attribute, "");
709
756
  if (value) {
@@ -712,9 +759,9 @@ function getObjectIndexTree(html: string): DocumentFragment {
712
759
  }
713
760
  }
714
761
 
715
- let attributesWithBooleanValues = string.match(/\s\S+=[^"]+/g);
762
+ const attributesWithBooleanValues = string.match(/\s\S+=[^"]+/g);
716
763
  if (attributesWithBooleanValues) {
717
- for (let attribute of attributesWithBooleanValues) {
764
+ for (const attribute of attributesWithBooleanValues) {
718
765
  const [name, ...value] = attribute.trim().split("=");
719
766
  string = string.replace(attribute, "");
720
767
  if (value) {
@@ -723,9 +770,9 @@ function getObjectIndexTree(html: string): DocumentFragment {
723
770
  }
724
771
  }
725
772
 
726
- let attributesWithEmptyValues = string.match(/\s?\S+/g);
773
+ const attributesWithEmptyValues = string.match(/\s?\S+/g);
727
774
  if (attributesWithEmptyValues) {
728
- for (let attribute of attributesWithEmptyValues) {
775
+ for (const attribute of attributesWithEmptyValues) {
729
776
  const name = attribute.trim();
730
777
  element.attributes[name] = true;
731
778
  }
@@ -737,7 +784,7 @@ function getObjectIndexTree(html: string): DocumentFragment {
737
784
  element.contentStartsAt = element.contentEndsAt = element.endsAt;
738
785
 
739
786
  // Find the last opened item, this will be the parent of the current item.
740
- let parent = [...items].reverse().find((item) => item.endsAt === null);
787
+ const parent = [...items].reverse().find((item) => item.endsAt === null);
741
788
  if (parent) {
742
789
  // Add the last opened item as a child of the parent.
743
790
  parent.children.push(element);
@@ -748,7 +795,7 @@ function getObjectIndexTree(html: string): DocumentFragment {
748
795
  items.push(element);
749
796
  }
750
797
 
751
- let fragmentItem: ObjectIndexItemWithContent = {
798
+ const fragmentItem: ObjectIndexItemWithContent = {
752
799
  tagName: "#document-fragment",
753
800
  startsAt: 0,
754
801
  endsAt: html.length,
@@ -777,16 +824,16 @@ export function htmlToDom(html: string): Element | Text | DocumentFragment {
777
824
  // search for the first opening tag.
778
825
  const openingTag = html.match(/<[^>]+>/g);
779
826
 
780
- let document = new Document();
827
+ const document = new Document();
781
828
 
782
829
  // If the opening tag is not found, return a document fragment node with the html string as text content.
783
830
  if (!openingTag) {
784
- let documentFragment = document.createDocumentFragment();
831
+ const documentFragment = document.createDocumentFragment();
785
832
  documentFragment.appendChild(document.createTextNode(html));
786
833
  return documentFragment;
787
834
  }
788
835
 
789
- let fragment = getObjectIndexTree(html);
836
+ const fragment = getObjectIndexTree(html);
790
837
 
791
838
  if (fragment.childNodes.length > 1) {
792
839
  return fragment;
@@ -796,8 +843,8 @@ export function htmlToDom(html: string): Element | Text | DocumentFragment {
796
843
  }
797
844
 
798
845
  export function htmlToHyperscript(html: string) {
799
- let domTree = htmlToDom(html);
800
- let hyperscript = domToHyperscript(domTree instanceof DocumentFragment ? domTree.childNodes : [domTree]);
846
+ const domTree = htmlToDom(html);
847
+ const hyperscript = domToHyperscript(domTree instanceof DocumentFragment ? domTree.childNodes : [domTree]);
801
848
  return `[${hyperscript}\n]`;
802
849
  }
803
850
 
@@ -0,0 +1,181 @@
1
+ /* eslint-disable no-console */
2
+ import { updateVnode, Vnode, VnodeWithDom, current } from "valyrian.js";
3
+ import { deepCloneUnfreeze, deepFreeze, hasChanged } from "valyrian.js/utils";
4
+
5
+ type State = Record<string, any>;
6
+
7
+ // An action or pulse type definition
8
+ // eslint-disable-next-line no-unused-vars
9
+ export type Pulse<StateType> = (state: StateType, ...args: any[]) => void | Promise<void>;
10
+
11
+ // A collection of pulses
12
+ export type Pulses<StateType> = {
13
+ [key: string]: Pulse<StateType>;
14
+ };
15
+
16
+ // A proxy state
17
+ // This is a state that is proxied to automatically subscribe to changes
18
+ // And is used internally to update the vnode when the state changes
19
+ type ProxyState<StateType> = StateType & {
20
+ [key: string]: any;
21
+ };
22
+
23
+ // The effect stack
24
+ const effectStack: Function[] = [];
25
+
26
+ // Creates the store
27
+ // eslint-disable-next-line sonarjs/cognitive-complexity
28
+ function createStore<StateType extends State, PulsesType extends Pulses<StateType>>(
29
+ initialState: StateType | (() => StateType),
30
+ pulses: PulsesType,
31
+ immutable = false
32
+ ): () => [ProxyState<StateType>, PulsesType] {
33
+ const subscribers = new Set<Function>();
34
+ const vnodesToUpdate = new WeakSet<Vnode>();
35
+
36
+ // Initialize the localState for this store
37
+ const localState = (typeof initialState === "function" ? initialState() : initialState) || {};
38
+
39
+ function isMutable() {
40
+ if (immutable) {
41
+ throw new Error("You need to call a pulse to modify the state");
42
+ }
43
+ }
44
+
45
+ // We create a proxy for the state
46
+ const proxyState = new Proxy(localState || {}, {
47
+ get: (state, prop: string) => {
48
+ const currentEffect = effectStack[effectStack.length - 1];
49
+ if (currentEffect && !subscribers.has(currentEffect)) {
50
+ subscribers.add(currentEffect);
51
+ }
52
+
53
+ const currentVnode = current.vnode as VnodeWithDom;
54
+ if (currentVnode && !vnodesToUpdate.has(currentVnode)) {
55
+ const subscription = () => {
56
+ if (!currentVnode.dom) {
57
+ subscribers.delete(subscription);
58
+ vnodesToUpdate.delete(currentVnode);
59
+ return;
60
+ }
61
+
62
+ updateVnode(currentVnode);
63
+ };
64
+
65
+ subscribers.add(subscription);
66
+ vnodesToUpdate.add(currentVnode);
67
+ }
68
+
69
+ return state[prop];
70
+ },
71
+ // If the user tries to set directly it will throw an error
72
+ set: (state, prop: string, value: any) => {
73
+ isMutable();
74
+ Reflect.set(state, prop, value);
75
+ return true;
76
+ },
77
+ // If the user tries to delete directly it will throw an error
78
+ deleteProperty: (state, prop: string) => {
79
+ isMutable();
80
+ Reflect.deleteProperty(state, prop);
81
+ return true;
82
+ }
83
+ });
84
+
85
+ function syncState(newState: StateType) {
86
+ for (const key in newState) {
87
+ localState[key] = immutable ? deepFreeze(newState[key]) : newState[key];
88
+ }
89
+
90
+ for (const key in localState) {
91
+ if (!(key in newState)) {
92
+ Reflect.deleteProperty(localState, key);
93
+ }
94
+ }
95
+ }
96
+
97
+ function setState(newState: StateType) {
98
+ if (!hasChanged(localState, newState)) {
99
+ return;
100
+ }
101
+
102
+ syncState(newState);
103
+
104
+ subscribers.forEach((subscriber) => subscriber());
105
+ }
106
+
107
+ function getPulseMethod(key: string) {
108
+ return (...args: any[]) => {
109
+ const currentState = deepCloneUnfreeze(localState);
110
+ const pulse = pulses[key](currentState, ...args);
111
+
112
+ if (pulse instanceof Promise) {
113
+ return pulse
114
+ .then(() => setState(currentState))
115
+ .catch((error) => {
116
+ console.error("Error in pulse:", error);
117
+ });
118
+ }
119
+
120
+ setState(currentState);
121
+ };
122
+ }
123
+
124
+ const boundPulses: Record<string, Pulse<StateType>> = {};
125
+ for (const key in pulses) {
126
+ if (typeof pulses[key] !== "function") {
127
+ throw new Error(`Pulse '${key}' must be a function`);
128
+ }
129
+ boundPulses[key] = getPulseMethod(key);
130
+ }
131
+
132
+ const pulsesProxy = new Proxy(boundPulses, {
133
+ get: (pulses, prop: string) => {
134
+ if (!(prop in pulses)) {
135
+ throw new Error(`Pulse '${prop}' does not exist`);
136
+ }
137
+ return pulses[prop];
138
+ }
139
+ });
140
+
141
+ function usePulseStore(): [ProxyState<StateType>, PulsesType] {
142
+ return [proxyState, pulsesProxy as PulsesType];
143
+ }
144
+
145
+ syncState(localState);
146
+
147
+ return usePulseStore;
148
+ }
149
+
150
+ // Creates a pulse store with an immutable state by default
151
+ export function createPulseStore<StateType extends State, PulsesType extends Pulses<StateType>>(
152
+ initialState: StateType,
153
+ pulses: PulsesType
154
+ ): () => [ProxyState<StateType>, PulsesType] {
155
+ return createStore(initialState, pulses, true);
156
+ }
157
+
158
+ // Creates a mutable store, useful for performance, but not recommended
159
+ export function createMutableStore<StateType extends State, PulsesType extends Pulses<StateType>>(
160
+ initialState: StateType,
161
+ pulses: PulsesType
162
+ ): () => [ProxyState<StateType>, PulsesType] {
163
+ console.warn(
164
+ "Warning: You are working with a mutable state. This can lead to unpredictable behavior. All state changes made outside of a pulse will not trigger a re-render."
165
+ );
166
+ return createStore(initialState, pulses, false);
167
+ }
168
+
169
+ // Creates an effect
170
+ export function createEffect(effect: Function) {
171
+ const runEffect = () => {
172
+ try {
173
+ effectStack.push(runEffect);
174
+ effect();
175
+ } finally {
176
+ effectStack.pop();
177
+ }
178
+ };
179
+
180
+ runEffect();
181
+ }