@torpor/view 0.0.10 → 0.0.12

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 (173) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{ServerSlotRender-AWF3bD5B.d.cts → ServerSlotRender-t1sOutne.d.cts} +1 -1
  3. package/dist/{ServerSlotRender-AWF3bD5B.d.ts → ServerSlotRender-t1sOutne.d.ts} +1 -1
  4. package/dist/{chunk-GO2L324Q.js → chunk-T6JGCJ5T.js} +5 -2
  5. package/dist/chunk-T6JGCJ5T.js.map +1 -0
  6. package/dist/compile.cjs +39 -32
  7. package/dist/compile.cjs.map +1 -1
  8. package/dist/compile.d.cts +1 -0
  9. package/dist/compile.d.ts +1 -0
  10. package/dist/compile.js +39 -32
  11. package/dist/compile.js.map +1 -1
  12. package/dist/index.cjs +4 -1
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +2 -2
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +1 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/metafile-cjs.json +1 -1
  19. package/dist/metafile-esm.json +1 -1
  20. package/dist/ssr.cjs +4 -1
  21. package/dist/ssr.cjs.map +1 -1
  22. package/dist/ssr.d.cts +2 -2
  23. package/dist/ssr.d.ts +2 -2
  24. package/dist/ssr.js +1 -1
  25. package/dist/ssr.js.map +1 -1
  26. package/package.json +7 -7
  27. package/scripts/buildTestOutput.ts +2 -121
  28. package/src/compile/build/client/buildAddFragment.ts +1 -1
  29. package/src/compile/build/client/buildAwaitNode.ts +1 -1
  30. package/src/compile/build/client/buildComponentNode.ts +1 -1
  31. package/src/compile/build/client/buildControlNode.ts +1 -1
  32. package/src/compile/build/client/buildElementNode.ts +7 -1
  33. package/src/compile/build/client/buildForNode.ts +1 -1
  34. package/src/compile/build/client/buildFragment.ts +1 -1
  35. package/src/compile/build/client/buildFragmentText.ts +7 -1
  36. package/src/compile/build/client/buildHeadNode.ts +1 -1
  37. package/src/compile/build/client/buildHtmlNode.ts +2 -6
  38. package/src/compile/build/client/buildIfNode.ts +1 -1
  39. package/src/compile/build/client/buildMount.ts +1 -1
  40. package/src/compile/build/client/buildNode.ts +1 -1
  41. package/src/compile/build/client/buildReplaceNode.ts +1 -1
  42. package/src/compile/build/client/buildRootNode.ts +1 -1
  43. package/src/compile/build/client/buildRun.ts +1 -1
  44. package/src/compile/build/client/buildScriptNode.ts +1 -1
  45. package/src/compile/build/client/buildSlotNode.ts +1 -1
  46. package/src/compile/build/client/buildSwitchNode.ts +1 -1
  47. package/src/compile/build/client/buildTextNode.ts +1 -1
  48. package/src/compile/build/client/replaceForVarNames.ts +1 -1
  49. package/src/compile/build/server/buildServerAwaitNode.ts +1 -1
  50. package/src/compile/build/server/buildServerComponentNode.ts +1 -1
  51. package/src/compile/build/server/buildServerControlNode.ts +1 -1
  52. package/src/compile/build/server/buildServerElementNode.ts +9 -1
  53. package/src/compile/build/server/buildServerForNode.ts +1 -1
  54. package/src/compile/build/server/buildServerHtmlNode.ts +1 -1
  55. package/src/compile/build/server/buildServerIfNode.ts +1 -1
  56. package/src/compile/build/server/buildServerNode.ts +5 -1
  57. package/src/compile/build/server/buildServerReplaceNode.ts +1 -1
  58. package/src/compile/build/server/buildServerRootNode.ts +5 -1
  59. package/src/compile/build/server/buildServerScriptNode.ts +1 -1
  60. package/src/compile/build/server/buildServerSlotNode.ts +1 -1
  61. package/src/compile/build/server/buildServerSpecialNode.ts +1 -1
  62. package/src/compile/build/server/buildServerSwitchNode.ts +1 -1
  63. package/src/compile/build/server/buildServerTextNode.ts +1 -1
  64. package/src/compile/build/utils/isFullyReactive.ts +1 -1
  65. package/src/compile/build/utils/isReactive.ts +1 -1
  66. package/src/compile/build/utils/isReactiveAttribute.ts +1 -1
  67. package/src/compile/parse/addSpaceElement.ts +4 -1
  68. package/src/compile/parse/parseControl.ts +4 -1
  69. package/src/compile/parse/parseImports.ts +1 -1
  70. package/src/compile/parse/parseMarkup.ts +1 -1
  71. package/src/compile/parse/parseStyles.ts +1 -1
  72. package/src/compile/parse/scopeStyles.ts +13 -21
  73. package/src/compile/parse/slottifyChildNodes.ts +1 -1
  74. package/src/compile/parse/utils/addError.ts +5 -1
  75. package/src/compile/parse/utils/consumeUntil.ts +1 -1
  76. package/src/compile/parse/utils/isAlphaNumeric.ts +1 -1
  77. package/src/compile/parse/utils/isAlphaNumericChar.ts +1 -1
  78. package/src/compile/parse/utils/isSpace.ts +1 -1
  79. package/src/compile/parse/utils/isSpaceChar.ts +1 -1
  80. package/src/compile/types/nodes/TemplateNode.ts +3 -0
  81. package/src/compile/utils/Builder.ts +3 -3
  82. package/src/compile/utils/trimEnd.ts +1 -1
  83. package/src/compile/utils/trimMatched.ts +1 -1
  84. package/src/compile/utils/trimQuotes.ts +1 -1
  85. package/src/compile/utils/trimStart.ts +1 -1
  86. package/src/compile/utils/trimStartAndEnd.ts +1 -1
  87. package/src/compile/utils/voidTags.ts +1 -1
  88. package/src/debug/printHtml.ts +1 -1
  89. package/src/motion/animate.ts +1 -1
  90. package/src/render/$mount.ts +1 -1
  91. package/src/render/$run.ts +1 -1
  92. package/src/render/$serverMount.ts +1 -1
  93. package/src/render/$serverRun.ts +1 -1
  94. package/src/render/$stream.ts +1 -1
  95. package/src/render/addAnimation.ts +1 -1
  96. package/src/render/addEvent.ts +1 -1
  97. package/src/render/addFragment.ts +1 -1
  98. package/src/render/applyProps.ts +1 -1
  99. package/src/render/clearRange.ts +1 -1
  100. package/src/render/createComment.ts +1 -1
  101. package/src/render/createElement.ts +1 -1
  102. package/src/render/createFragment.ts +1 -1
  103. package/src/render/createText.ts +1 -1
  104. package/src/render/flushMountEffects.ts +1 -1
  105. package/src/render/getClasses.ts +4 -1
  106. package/src/render/hydrate.ts +1 -1
  107. package/src/render/hydrateRoot.ts +1 -1
  108. package/src/render/mount.ts +1 -1
  109. package/src/render/moveRange.ts +1 -1
  110. package/src/render/popRange.ts +1 -1
  111. package/src/render/runControl.ts +1 -1
  112. package/src/render/runControlBranch.ts +1 -1
  113. package/src/render/runList.ts +1 -1
  114. package/src/render/runListItems.ts +1 -1
  115. package/src/render/setAttribute.ts +1 -1
  116. package/src/render/setDynamicElement.ts +1 -1
  117. package/src/watch/proxyGet.ts +1 -1
  118. package/src/watch/removeEffect.ts +1 -1
  119. package/src/watch/runEffect.ts +1 -1
  120. package/src/watch/symbols.ts +1 -1
  121. package/src/watch/trackEffect.ts +1 -1
  122. package/src/watch/transferEffects.ts +1 -1
  123. package/src/watch/triggerEffects.ts +1 -1
  124. package/test/bench/components/output/Bench-client.ts +0 -204
  125. package/test/bench/components/output/Bench-server.ts +0 -130
  126. package/test/bench/components/temp/Bench-client-5fee290225ae4771aa847360006123671e8f17f1.ts +208 -0
  127. package/test/bench/components/temp/Bench-server-00cefa588803c01ca4f2741c595e4f045cdd101e.ts +130 -0
  128. package/test/build-server/components/{output/IfNested-client.ts → temp/IfNested-client-979db97eea5b4595550b9b46f297f3fbc31796d2.ts} +11 -0
  129. package/test/buildHtml.ts +1 -1
  130. package/test/buildOutputFiles.ts +47 -12
  131. package/test/class/class.test.ts +29 -6
  132. package/test/class/components/Class.torp +15 -1
  133. package/test/class/components/output/Class-client.ts +10 -6
  134. package/test/class/components/output/Class-server.ts +1 -1
  135. package/test/class/components/temp/{Class-client-600bf865c14f1052d24e1c79242f837aaf5ae5e8.ts → Class-client-8c3f9e0257cc2b687e9bb7106cccbab94a4b5adf.ts} +10 -6
  136. package/test/class/components/temp/Class-server-2218c3284845fdab80d1a41ebace9a9e2ddd6fc1.ts +17 -0
  137. package/test/component/components/temp/Header-client-ac151eea86e3f6b058fab101661e13ae73864968.ts +34 -0
  138. package/test/component/components/temp/Header-server-4f10f2332f3ca7a097517cfb938ab1e6f31d68ac.ts +17 -0
  139. package/test/console/components/temp/{Console-client-254d7d4799471401334d698b1631ab1cb5b70558.ts → Console-client-2f206752ce59e59fba9bb91263b4102fd515951e.ts} +1 -1
  140. package/test/console/components/temp/Console-server-b4b15f7a0d1d2b50d87bad4870e1b8d368707c04.ts +17 -0
  141. package/test/globalSetup.ts +1 -1
  142. package/test/helpers.ts +6 -2
  143. package/test/hydrateComponent.ts +1 -1
  144. package/test/importComponent.ts +12 -40
  145. package/test/mountComponent.ts +5 -1
  146. package/test/party/components/temp/AnswerButton-client-243454cd7bf84c648f244b3587e60d01a0401039.ts +33 -0
  147. package/test/party/components/temp/AnswerButton-server-938e46c1d2510ea37454854ef527e4aa64eb8e52.ts +16 -0
  148. package/test/party/components/temp/FunnyButton-client-2e6bec8259065b5bc9ae16d1ca93dd1bd0c56b7c.ts +40 -0
  149. package/test/party/components/temp/FunnyButton-server-e8ab55e47c735f7e42c55d2b7504dfa4190a1b40.ts +32 -0
  150. package/test/party/components/temp/Time-client-7ba4ca9322af2cb88a873c812fc776760c337c64.ts +47 -0
  151. package/test/party/components/temp/Time-server-08f66c7f3f32b13de06d75fe679cf58b5727c473.ts +31 -0
  152. package/test/party/components/temp/UserProfile-client-938bcef20a2555de22aca939022a32742ac5e729.ts +51 -0
  153. package/test/party/components/temp/UserProfile-server-9df5c59b8797fa67c479bc76450104d45e6076f9.ts +22 -0
  154. package/test/party/components/temp/UserProfileContext-client-93211cdba795b8baf926f60f5b17da90701743b3.ts +44 -0
  155. package/test/party/components/temp/UserProfileContext-server-cf58767df1e2d1dde919f59de73cdd9764bbc006.ts +20 -0
  156. package/test/slots/components/temp/Article-client-741f94eab2e96655f4c9d69ccd7d9c7cc998f4ce.ts +41 -0
  157. package/test/slots/components/temp/Article-server-a6bd47a621cc213db4313eb775a52246541dd203.ts +28 -0
  158. package/test/slots/components/temp/Header-client-e2e1e7d60b48b0841cd0c20224f520330ca96458.ts +38 -0
  159. package/test/slots/components/temp/Header-server-1c195508a91c32822da22a08576c8a30c9070636.ts +22 -0
  160. package/test/slots/components/temp/List-client-0659d999cfb48b865fe5b8aaaf2a4ddac3a8a8b6.ts +76 -0
  161. package/test/slots/components/temp/List-server-4b76485a259d054187edad8aa691d80ac918ad86.ts +25 -0
  162. package/test/special-component/components/temp/BigTitle-client-881a9f84876fb3f6d994736edb253b96e71de926.ts +32 -0
  163. package/test/special-component/components/temp/BigTitle-server-9efc738f5eb131a4b859c4a99a8e255d93834e9a.ts +20 -0
  164. package/test/special-component/components/temp/SmallTitle-client-25b3097b7ae47848dd82967403faf7745fc43388.ts +32 -0
  165. package/test/special-component/components/temp/SmallTitle-server-fc105db9a91b83644d67e049ce583a3d1a61f50c.ts +20 -0
  166. package/tsconfig.json +1 -1
  167. package/tsup.config.ts +7 -2
  168. package/vitest.config.ts +2 -2
  169. package/dist/chunk-GO2L324Q.js.map +0 -1
  170. package/test/bench/components/temp/Bench-client-3efcd3b6c03c7a51368df3b8b1bdf2e7fa722432.ts +0 -126
  171. package/test/build-server/components/IfNested.d.ts +0 -18
  172. package/test/class/components/temp/Class-server-082505b03612c762384ffff329472db3f55b8097.ts +0 -17
  173. /package/test/build-server/components/{output/IfNested-server.ts → temp/IfNested-server-3c4e4b6f2162c0906cef685830219b9ea9ee985c.ts} +0 -0
@@ -0,0 +1,130 @@
1
+ import $watch from "../../../../src/render/$serverWatch";
2
+ import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
3
+ import t_class from "../../../../src/render/getClasses";
4
+ import t_fmt from "../../../../src/render/formatText";
5
+
6
+ export default function Bench(
7
+ // @ts-ignore
8
+ $props?: Record<PropertyKey, any>,
9
+ // @ts-ignore
10
+ $context?: Record<PropertyKey, any>,
11
+ // @ts-ignore
12
+ $slots?: Record<string, ServerSlotRender>
13
+ ) {
14
+ let rowId = 1;
15
+ let $state = $watch({
16
+ data: [],
17
+ selected: null,
18
+ });
19
+
20
+ const adjectives = [
21
+ "pretty",
22
+ "large",
23
+ "big",
24
+ "small",
25
+ "tall",
26
+ "short",
27
+ "long",
28
+ "handsome",
29
+ "plain",
30
+ "quaint",
31
+ "clean",
32
+ "elegant",
33
+ "easy",
34
+ "angry",
35
+ "crazy",
36
+ "helpful",
37
+ "mushy",
38
+ "odd",
39
+ "unsightly",
40
+ "adorable",
41
+ "important",
42
+ "inexpensive",
43
+ "cheap",
44
+ "expensive",
45
+ "fancy",
46
+ ];
47
+ const colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
48
+ const nouns = [
49
+ "table",
50
+ "chair",
51
+ "house",
52
+ "bbq",
53
+ "desk",
54
+ "car",
55
+ "pony",
56
+ "cookie",
57
+ "sandwich",
58
+ "burger",
59
+ "pizza",
60
+ "mouse",
61
+ "keyboard",
62
+ ];
63
+
64
+ function append() {
65
+ $state.data = [...$state.data, ...buildData(1000)];
66
+ }
67
+
68
+ function clear() {
69
+ $state.data = [];
70
+ }
71
+
72
+ function partialUpdate() {
73
+ for (let i = 0; i < $state.data.length; i += 10) {
74
+ const row = $state.data[i];
75
+ row.label = row.label + " !!!";
76
+ }
77
+ }
78
+
79
+ function remove(row) {
80
+ const clone = $state.data.slice();
81
+ clone.splice(clone.indexOf(row), 1);
82
+ $state.data = clone;
83
+ }
84
+
85
+ function create() {
86
+ // TODO: Build this up to 1000:
87
+ $state.data = buildData(10);
88
+ }
89
+
90
+ function createLots() {
91
+ $state.data = buildData(10000);
92
+ }
93
+
94
+ function swapRows() {
95
+ if ($state.data.length > 998) {
96
+ const clone = $state.data.slice();
97
+ const tmp = clone[1];
98
+ clone[1] = clone[998];
99
+ clone[998] = tmp;
100
+ $state.data = clone;
101
+ }
102
+ }
103
+
104
+ function _random(max) {
105
+ return Math.round(Math.random() * 1000) % max;
106
+ }
107
+
108
+ class Item {
109
+ id = rowId++;
110
+ label = `${adjectives[_random(adjectives.length)]} ${colours[_random(colours.length)]} ${nouns[_random(nouns.length)]}`;
111
+ }
112
+
113
+ function buildData(count = 1000) {
114
+ const data = new Array(count);
115
+ for (let i = 0; i < count; i++) {
116
+ data[i] = $watch(new Item());
117
+ }
118
+ return data;
119
+ }
120
+
121
+ /* User interface */
122
+ let $output = "";
123
+ $output += `<div id="main" class="container"> <div class="jumbotron"> <div class="row"> <div class="col-md-6"> <h1>Torpor (keyed)</h1> </div> <div class="col-md-6"> <div class="row"> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="create">Create 1,000 rows</button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="createlots"> Create 10,000 rows </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="append"> Append 1,000 rows </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="update"> Update every 10th row </button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="clear">Clear</button> </div> <div class="col-sm-6 smallpad"> <button type="button" class="btn btn-primary btn-block" id="swaprows">Swap Rows</button> </div> </div> </div> </div> </div> <table class="table table-hover table-striped test-data"> <tbody> <![>`;
124
+ for (let row of $state.data) {
125
+ $output += `<!^> <tr class="${t_class({ danger: $state.selected === row.id })}"> <td class="col-md-1">${t_fmt(row.id)}</td> <td class="col-md-4"> <a> ${t_fmt(row.label)} </a> </td> <td class="col-md-1"> <a> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> </a> </td> <td class="col-md-6"></td> </tr> `;
126
+ }
127
+ $output += `<!]><!> </tbody> </table> <span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true"></span> </div>`;
128
+
129
+ return $output;
130
+ }
@@ -18,11 +18,13 @@ export default function IfNested(
18
18
  // @ts-ignore
19
19
  $slots?: Record<string, SlotRender>
20
20
  ) {
21
+ $props ??= {};
21
22
 
22
23
  /* User interface */
23
24
  const t_fragments: DocumentFragment[] = [];
24
25
 
25
26
  const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> <!> </div>`);
27
+ // @ts-ignore
26
28
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
27
29
  const t_if_anchor_1 = t_anchor(t_next(t_child(t_div_1))) as HTMLElement;
28
30
 
@@ -32,6 +34,7 @@ export default function IfNested(
32
34
  if ($props.counter > 5) {
33
35
  t_run_branch(t_if_range_1, 0, () => {
34
36
  const t_fragment_1 = t_fragment($parent.ownerDocument!, t_fragments, 1, ` <!> `);
37
+ // @ts-ignore
35
38
  const t_root_1 = t_root(t_fragment_1);
36
39
  const t_if_anchor_2 = t_anchor(t_next(t_root_1)) as HTMLElement;
37
40
 
@@ -41,7 +44,9 @@ export default function IfNested(
41
44
  if ($props.counter > 10) {
42
45
  t_run_branch(t_if_range_2, 0, () => {
43
46
  const t_fragment_2 = t_fragment($parent.ownerDocument!, t_fragments, 2, ` <p> It's both true! </p> `);
47
+ // @ts-ignore
44
48
  const t_root_2 = t_root(t_fragment_2);
49
+ // @ts-ignore
45
50
  const t_text_1 = t_next(t_next(t_root_2));
46
51
  t_add_fragment(t_fragment_2, t_fragment_1, t_before);
47
52
  t_next(t_text_1);
@@ -50,7 +55,9 @@ export default function IfNested(
50
55
  else {
51
56
  t_run_branch(t_if_range_2, 1, () => {
52
57
  const t_fragment_3 = t_fragment($parent.ownerDocument!, t_fragments, 3, ` <p> The second is not true! </p> `);
58
+ // @ts-ignore
53
59
  const t_root_3 = t_root(t_fragment_3);
60
+ // @ts-ignore
54
61
  const t_text_2 = t_next(t_next(t_root_3));
55
62
  t_add_fragment(t_fragment_3, t_fragment_1, t_before);
56
63
  t_next(t_text_2);
@@ -58,6 +65,7 @@ export default function IfNested(
58
65
  }
59
66
  });
60
67
 
68
+ // @ts-ignore
61
69
  const t_text_3 = t_next(t_if_anchor_2);
62
70
  t_add_fragment(t_fragment_1, t_div_1, t_before);
63
71
  t_next(t_text_3);
@@ -66,7 +74,9 @@ export default function IfNested(
66
74
  else {
67
75
  t_run_branch(t_if_range_1, 1, () => {
68
76
  const t_fragment_4 = t_fragment($parent.ownerDocument!, t_fragments, 4, ` <p> The first is not true! </p> `);
77
+ // @ts-ignore
69
78
  const t_root_4 = t_root(t_fragment_4);
79
+ // @ts-ignore
70
80
  const t_text_4 = t_next(t_next(t_root_4));
71
81
  t_add_fragment(t_fragment_4, t_div_1, t_before);
72
82
  t_next(t_text_4);
@@ -75,5 +85,6 @@ export default function IfNested(
75
85
  });
76
86
 
77
87
  t_add_fragment(t_fragment_0, $parent, $anchor);
88
+ t_next(t_div_1);
78
89
 
79
90
  }
package/test/buildHtml.ts CHANGED
@@ -8,7 +8,7 @@ import { type BuildResult } from "../src/compile/types/BuildResult";
8
8
 
9
9
  const debugPrint = false;
10
10
 
11
- export default function buildHtml(source: string, state?: any, componentPath?: string) {
11
+ export default function buildHtml(source: string, state?: any, componentPath?: string): string {
12
12
  // HACK: we may be running this from the top level, or from within the view folder
13
13
  if (componentPath && !fs.existsSync(componentPath)) {
14
14
  componentPath = path.join("view", componentPath);
@@ -1,11 +1,11 @@
1
1
  import fg from "fast-glob";
2
- import { existsSync, promises as fs } from "node:fs";
2
+ import crypto from "node:crypto";
3
+ import { existsSync, promises as fs, unlinkSync } from "node:fs";
3
4
  import path from "node:path";
4
- import { buildType } from "../src/compile";
5
5
  import build from "../src/compile/build";
6
6
  import parse from "../src/compile/parse";
7
7
 
8
- export default async function buildOutputFiles(componentPath: string) {
8
+ export default async function buildOutputFiles(componentPath: string): Promise<void> {
9
9
  //console.log("Building test output files", componentPath);
10
10
  const files = await fg("**/*.torp", {
11
11
  absolute: true,
@@ -15,7 +15,7 @@ export default async function buildOutputFiles(componentPath: string) {
15
15
  //console.log("Done\n");
16
16
  }
17
17
 
18
- async function buildFiles(file: string) {
18
+ export async function buildFiles(file: string): Promise<void> {
19
19
  //console.log(`Building files for ${file.substring(path.resolve("./test").length)}`);
20
20
 
21
21
  const source = await fs.readFile(file, "utf8");
@@ -23,22 +23,57 @@ async function buildFiles(file: string) {
23
23
  if (parsed.ok && parsed.template) {
24
24
  let serverCode = formatCode(build(parsed.template, { server: true }).code, "server");
25
25
  let clientCode = formatCode(build(parsed.template).code, "client");
26
+ await maybeWriteFile(file, clientCode, "client");
27
+ await maybeWriteFile(file, serverCode, "server");
28
+ } else {
29
+ // Just log the message and continue with output/testing
30
+ console.log("PARSE FAILED for " + file);
31
+ console.log(parsed.errors.map((e) => e.message).join("\n"));
32
+ }
33
+ }
26
34
 
27
- let typesCode = buildType(parsed.template);
28
- await fs.writeFile(file.replace(".torp", ".d.ts"), typesCode);
35
+ async function maybeWriteFile(file: string, code: string, suffix: string) {
36
+ //const hash = await hashFileContents(code);
37
+ const hash = hashFileCode(code);
38
+
39
+ // If the hashed file doesn't exist, update it and the output file
40
+ let outputFile = file
41
+ .replace("/components/", "/components/temp/")
42
+ .replace(".torp", `-${suffix}-${hash}.ts`);
43
+ if (!existsSync(outputFile)) {
44
+ console.log(`Building files for ${file}`);
45
+
46
+ let outputFolder = path.dirname(outputFile);
47
+ if (!existsSync(outputFolder)) {
48
+ await fs.mkdir(outputFolder);
49
+ }
29
50
 
30
- let outputFile = file.replace("/components/", "/components/output/");
51
+ // Delete old files
52
+ const glob = `${path.basename(file, ".torp")}-${suffix}-*.ts`;
53
+ const oldFiles = await fg(glob, {
54
+ absolute: true,
55
+ cwd: path.resolve(outputFolder),
56
+ });
57
+ oldFiles.forEach((f) => unlinkSync(f));
58
+
59
+ // Create the new hash file
60
+ await fs.writeFile(outputFile, code);
61
+
62
+ // Create the new output file
63
+ outputFile = file
64
+ .replace("/components/", "/components/output/")
65
+ .replace(".torp", `-${suffix}.ts`);
31
66
  if (!existsSync(path.dirname(outputFile))) {
32
67
  await fs.mkdir(path.dirname(outputFile));
33
68
  }
34
- await fs.writeFile(outputFile.replace(".torp", "-server.ts"), serverCode);
35
- await fs.writeFile(outputFile.replace(".torp", "-client.ts"), clientCode);
36
- } else {
37
- // Just log the message and continue with output/testing
38
- console.log("Parse failed for " + file);
69
+ await fs.writeFile(outputFile, code);
39
70
  }
40
71
  }
41
72
 
73
+ function hashFileCode(code: string) {
74
+ return crypto.createHash("sha1").update(code).digest("hex");
75
+ }
76
+
42
77
  function formatCode(code: string, suffix: string): string {
43
78
  // Replace imports from the built @torpor/view to the source code, so that
44
79
  // a) we don't have to build @torpor/view before testing, and
@@ -49,21 +49,44 @@ test("class -- hydrated", async () => {
49
49
  });
50
50
 
51
51
  function check(container: HTMLElement, state: State) {
52
- expect(queryByText(container, "Hello!")).not.toBeNull();
53
- expect(queryByText(container, "Hello!")).toHaveClass("hello red blue", { exact: true });
52
+ expect(queryByText(container, "From string")).not.toBeNull();
53
+ expect(queryByText(container, "From string")).toHaveClass("yo torp-1ljxz83", {
54
+ exact: true,
55
+ });
56
+
57
+ expect(queryByText(container, "From state")).not.toBeNull();
58
+ expect(queryByText(container, "From state")).toHaveClass("hello red blue torp-1ljxz83", {
59
+ exact: true,
60
+ });
61
+
62
+ expect(queryByText(container, "From state with scope")).not.toBeNull();
63
+ expect(queryByText(container, "From state with scope")).toHaveClass(
64
+ "hello red blue torp-1ljxz83",
65
+ {
66
+ exact: true,
67
+ },
68
+ );
54
69
 
55
70
  expect(queryByText(container, "Class object")).not.toBeNull();
56
- expect(queryByText(container, "Class object")).toHaveClass("foo baz", { exact: true });
71
+ expect(queryByText(container, "Class object")).toHaveClass("foo baz torp-1ljxz83", {
72
+ exact: true,
73
+ });
57
74
 
58
75
  expect(queryByText(container, "Class array")).not.toBeNull();
59
- expect(queryByText(container, "Class array")).toHaveClass("foo baz", { exact: true });
76
+ expect(queryByText(container, "Class array")).toHaveClass("foo baz torp-1ljxz83", {
77
+ exact: true,
78
+ });
60
79
 
61
80
  expect(queryByText(container, "Class nested")).not.toBeNull();
62
- expect(queryByText(container, "Class nested")).toHaveClass("foo bar baz qux", { exact: true });
81
+ expect(queryByText(container, "Class nested")).toHaveClass("foo bar baz qux torp-1ljxz83", {
82
+ exact: true,
83
+ });
63
84
 
64
85
  // Change state
65
86
  state.green = true;
66
87
  state.blue = false;
67
88
 
68
- expect(queryByText(container, "Hello!")).toHaveClass("hello red green", { exact: true });
89
+ expect(queryByText(container, "From state")).toHaveClass("hello red green torp-1ljxz83", {
90
+ exact: true,
91
+ });
69
92
  }
@@ -1,8 +1,16 @@
1
1
  export default function Class() {
2
2
  @render {
3
3
  <div>
4
+ <div class="yo">
5
+ From string
6
+ </div>
7
+
8
+ <a :class={{ hello: true, red: $props.red, green: $props.green, blue: $props.blue }}>
9
+ From state
10
+ </a>
11
+
4
12
  <div :class={{ hello: true, red: $props.red, green: $props.green, blue: $props.blue }}>
5
- Hello!
13
+ From state with scope
6
14
  </div>
7
15
 
8
16
  <div :class={{ foo: true, bar: false, baz: 5, qux: null }}>
@@ -18,4 +26,10 @@ export default function Class() {
18
26
  </div>
19
27
  </div>
20
28
  }
29
+
30
+ @style {
31
+ div {
32
+ color: blue;
33
+ }
34
+ }
21
35
  }
@@ -21,24 +21,28 @@ export default function Class(
21
21
  /* User interface */
22
22
  const t_fragments: DocumentFragment[] = [];
23
23
 
24
- const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> <div> Hello! </div> <div> Class object </div> <div> Class array </div> <div> Class nested </div> </div>`);
24
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> <div class="yo torp-1ljxz83"> From string </div> <a> From state </a> <div> From state with scope </div> <div> Class object </div> <div> Class array </div> <div> Class nested </div> </div>`);
25
25
  // @ts-ignore
26
26
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
27
- const t_div_2 = t_next(t_child(t_div_1)) as HTMLDivElement;
27
+ const t_a_1 = t_next(t_next(t_next(t_child(t_div_1)))) as HTMLElement;
28
+ const t_div_2 = t_next(t_next(t_a_1)) as HTMLDivElement;
28
29
  const t_div_3 = t_next(t_next(t_div_2)) as HTMLDivElement;
29
30
  const t_div_4 = t_next(t_next(t_div_3)) as HTMLDivElement;
30
31
  const t_div_5 = t_next(t_next(t_div_4)) as HTMLDivElement;
31
32
  $run(function setClasses() {
32
- t_div_2.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue });
33
+ t_a_1.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
33
34
  });
34
35
  $run(function setClasses() {
35
- t_div_3.className = t_class({ foo: true, bar: false, baz: 5, qux: null });
36
+ t_div_2.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
36
37
  });
37
38
  $run(function setClasses() {
38
- t_div_4.className = t_class([ "foo", false, true && "baz", undefined ]);
39
+ t_div_3.className = t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83");
39
40
  });
40
41
  $run(function setClasses() {
41
- t_div_5.className = t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ]);
42
+ t_div_4.className = t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83");
43
+ });
44
+ $run(function setClasses() {
45
+ t_div_5.className = t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83");
42
46
  });
43
47
  t_add_fragment(t_fragment_0, $parent, $anchor);
44
48
  t_next(t_div_1);
@@ -11,7 +11,7 @@ export default function Class(
11
11
 
12
12
  /* User interface */
13
13
  let $output = "";
14
- $output += `<div> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue })}"> Hello! </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null })}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ])}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ])}"> Class nested </div> </div>`;
14
+ $output += `<div> <div class="yo torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> </div>`;
15
15
 
16
16
  return $output;
17
17
  }
@@ -21,24 +21,28 @@ export default function Class(
21
21
  /* User interface */
22
22
  const t_fragments: DocumentFragment[] = [];
23
23
 
24
- const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> <div> Hello! </div> <div> Class object </div> <div> Class array </div> <div> Class nested </div> </div>`);
24
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> <div class="yo torp-1ljxz83"> From string </div> <a> From state </a> <div> From state with scope </div> <div> Class object </div> <div> Class array </div> <div> Class nested </div> </div>`);
25
25
  // @ts-ignore
26
26
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
27
- const t_div_2 = t_next(t_child(t_div_1)) as HTMLDivElement;
27
+ const t_a_1 = t_next(t_next(t_next(t_child(t_div_1)))) as HTMLElement;
28
+ const t_div_2 = t_next(t_next(t_a_1)) as HTMLDivElement;
28
29
  const t_div_3 = t_next(t_next(t_div_2)) as HTMLDivElement;
29
30
  const t_div_4 = t_next(t_next(t_div_3)) as HTMLDivElement;
30
31
  const t_div_5 = t_next(t_next(t_div_4)) as HTMLDivElement;
31
32
  $run(function setClasses() {
32
- t_div_2.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue });
33
+ t_a_1.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
33
34
  });
34
35
  $run(function setClasses() {
35
- t_div_3.className = t_class({ foo: true, bar: false, baz: 5, qux: null });
36
+ t_div_2.className = t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83");
36
37
  });
37
38
  $run(function setClasses() {
38
- t_div_4.className = t_class([ "foo", false, true && "baz", undefined ]);
39
+ t_div_3.className = t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83");
39
40
  });
40
41
  $run(function setClasses() {
41
- t_div_5.className = t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ]);
42
+ t_div_4.className = t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83");
43
+ });
44
+ $run(function setClasses() {
45
+ t_div_5.className = t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83");
42
46
  });
43
47
  t_add_fragment(t_fragment_0, $parent, $anchor);
44
48
  t_next(t_div_1);
@@ -0,0 +1,17 @@
1
+ import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
2
+ import t_class from "../../../../src/render/getClasses";
3
+
4
+ export default function Class(
5
+ $props: Record<PropertyKey, any>,
6
+ // @ts-ignore
7
+ $context?: Record<PropertyKey, any>,
8
+ // @ts-ignore
9
+ $slots?: Record<string, ServerSlotRender>
10
+ ) {
11
+
12
+ /* User interface */
13
+ let $output = "";
14
+ $output += `<div> <div class="yo torp-1ljxz83"> From string </div> <a class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state </a> <div class="${t_class({ hello: true, red: $props.red, green: $props.green, blue: $props.blue }, "torp-1ljxz83")}"> From state with scope </div> <div class="${t_class({ foo: true, bar: false, baz: 5, qux: null }, "torp-1ljxz83")}"> Class object </div> <div class="${t_class([ "foo", false, true && "baz", undefined ], "torp-1ljxz83")}"> Class array </div> <div class="${t_class([ "foo", 0, { bar: true }, "", [1 && "baz", ["qux"]] ], "torp-1ljxz83")}"> Class nested </div> </div>`;
15
+
16
+ return $output;
17
+ }
@@ -0,0 +1,34 @@
1
+ import $run from "../../../../src/render/$run";
2
+ import { type SlotRender } from "../../../../src/types/SlotRender";
3
+ import t_add_fragment from "../../../../src/render/addFragment";
4
+ import t_child from "../../../../src/render/nodeChild";
5
+ import t_fmt from "../../../../src/render/formatText";
6
+ import t_fragment from "../../../../src/render/getFragment";
7
+ import t_next from "../../../../src/render/nodeNext";
8
+ import t_root from "../../../../src/render/nodeRoot";
9
+
10
+ export default function Header(
11
+ $parent: ParentNode,
12
+ $anchor: Node | null,
13
+ $props: Record<PropertyKey, any>,
14
+ // @ts-ignore
15
+ $context?: Record<PropertyKey, any>,
16
+ // @ts-ignore
17
+ $slots?: Record<string, SlotRender>
18
+ ) {
19
+ $props ??= {};
20
+
21
+ /* User interface */
22
+ const t_fragments: DocumentFragment[] = [];
23
+
24
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<h2>#</h2>`);
25
+ // @ts-ignore
26
+ const t_h2_1 = t_root(t_fragment_0) as HTMLElement;
27
+ const t_text_1 = t_child(t_h2_1);
28
+ $run(function setTextContent() {
29
+ t_text_1.textContent = `Hi, ${t_fmt($props.name)}`;
30
+ });
31
+ t_add_fragment(t_fragment_0, $parent, $anchor);
32
+ t_next(t_h2_1);
33
+
34
+ }
@@ -0,0 +1,17 @@
1
+ import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
2
+ import t_fmt from "../../../../src/render/formatText";
3
+
4
+ export default function Header(
5
+ $props: Record<PropertyKey, any>,
6
+ // @ts-ignore
7
+ $context?: Record<PropertyKey, any>,
8
+ // @ts-ignore
9
+ $slots?: Record<string, ServerSlotRender>
10
+ ) {
11
+
12
+ /* User interface */
13
+ let $output = "";
14
+ $output += `<h2>Hi, ${t_fmt($props.name)}</h2>`;
15
+
16
+ return $output;
17
+ }
@@ -18,7 +18,7 @@ export default function Console(
18
18
  /* User interface */
19
19
  const t_fragments: DocumentFragment[] = [];
20
20
 
21
- const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> </div>`, false);
21
+ const t_fragment_0 = t_fragment($parent.ownerDocument!, t_fragments, 0, `<div> </div>`);
22
22
  // @ts-ignore
23
23
  const t_div_1 = t_root(t_fragment_0) as HTMLDivElement;
24
24
  /* @console */
@@ -0,0 +1,17 @@
1
+ import { type ServerSlotRender } from "../../../../src/types/ServerSlotRender";
2
+
3
+ export default function Console(
4
+ // @ts-ignore
5
+ $props?: Record<PropertyKey, any>,
6
+ // @ts-ignore
7
+ $context?: Record<PropertyKey, any>,
8
+ // @ts-ignore
9
+ $slots?: Record<string, ServerSlotRender>
10
+ ) {
11
+
12
+ /* User interface */
13
+ let $output = "";
14
+ $output += `<div> </div>`;
15
+
16
+ return $output;
17
+ }
@@ -1,6 +1,6 @@
1
1
  //import "../scripts/buildTestOutput";
2
2
 
3
- export async function setup() {
3
+ export async function setup(): Promise<void> {
4
4
  // Build the output files in the above import
5
5
  }
6
6
 
package/test/helpers.ts CHANGED
@@ -28,12 +28,16 @@ export function el(
28
28
  children?: TemplateNode[],
29
29
  selfClosed?: boolean,
30
30
  ): ElementNode {
31
+ let scopeStyles = !!attributes?.find((a) => a.name === "class" && a.value?.startsWith(`"torp-`));
31
32
  return {
32
33
  type: "element",
33
34
  tagName,
34
- attributes: attributes || [],
35
+ attributes: (attributes || []).filter(
36
+ (a) => !(a.name === "class" && a.value?.startsWith(`"torp-`)),
37
+ ),
35
38
  children: children || [],
36
39
  selfClosed,
40
+ scopeStyles: scopeStyles || undefined,
37
41
  closed: true,
38
42
  };
39
43
  }
@@ -116,7 +120,7 @@ function trimElement(el: RootNode | ElementNode | ControlNode) {
116
120
  }
117
121
  }
118
122
 
119
- export function trimCode(code: string) {
123
+ export function trimCode(code: string): string {
120
124
  //return code.split('\n').filter(l => !l.trim().startsWith("import"))
121
125
  return code.replace(/\/\*\*.+\*\/\n/gms, "");
122
126
  }
@@ -7,7 +7,7 @@ export default function hydrateComponent(
7
7
  clientComponent: Component,
8
8
  serverComponent: ServerComponent,
9
9
  state?: any,
10
- ) {
10
+ ): void {
11
11
  const html = serverComponent(state);
12
12
  container.innerHTML = html;
13
13
  container.ownerDocument.body.appendChild(container);