solarite 0.1.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 (63) hide show
  1. package/build/build.bat +3 -0
  2. package/build/build.js +139 -0
  3. package/build/lib/rollup.min.js +11 -0
  4. package/build/lib/source-map.min.js +1 -0
  5. package/build/lib/terser.min.js +1 -0
  6. package/dist/Solarite-debug.js +4143 -0
  7. package/dist/Solarite.js +3740 -0
  8. package/dist/Solarite.min.js +4 -0
  9. package/docs/index.md +423 -0
  10. package/docs/js/Playground.js +184 -0
  11. package/docs/js/codemirror/codemirror6.js +32036 -0
  12. package/docs/js/codemirror/themeSolarIce.js +312 -0
  13. package/docs/js/documentation.js +32 -0
  14. package/docs/js/ui/CodeEditor.js +840 -0
  15. package/docs/js/ui/DarkToggle.js +52 -0
  16. package/docs/js/ui/FlexResizer.js +142 -0
  17. package/docs/js/util/Draggable2.js +151 -0
  18. package/docs/js/util/Errors.js +9 -0
  19. package/docs/js/util/Html.js +147 -0
  20. package/docs/js/util/Icons.js +623 -0
  21. package/docs/js/util/Input.js +253 -0
  22. package/docs/js/util/Util.js +88 -0
  23. package/docs/js/util/delve.js +43 -0
  24. package/docs/media/FiraCode400.woff2 +0 -0
  25. package/docs/media/cabin-latin-700.woff2 +0 -0
  26. package/docs/media/documentation.css +93 -0
  27. package/docs/media/eternium.css +1123 -0
  28. package/docs/media/solarite-machine.webp +0 -0
  29. package/index.html +325 -0
  30. package/package.json +33 -0
  31. package/readme.md +3 -0
  32. package/src/solarite/ExprPath.js +554 -0
  33. package/src/solarite/MultiValueMap.js +65 -0
  34. package/src/solarite/NodeGroup.js +706 -0
  35. package/src/solarite/NodeGroupManager.js +582 -0
  36. package/src/solarite/Shell.js +307 -0
  37. package/src/solarite/Solarite.js +19 -0
  38. package/src/solarite/Template.js +85 -0
  39. package/src/solarite/Util.js +264 -0
  40. package/src/solarite/createSolarite.js +267 -0
  41. package/src/solarite/getArg.js +99 -0
  42. package/src/solarite/hash.js +101 -0
  43. package/src/solarite/r.js +143 -0
  44. package/src/solarite/udomdiff.js +233 -0
  45. package/src/solarite/watch.js +302 -0
  46. package/src/solarite/watch2.js +439 -0
  47. package/src/unused/FastLookupArray.js +54 -0
  48. package/src/unused/Hashes.js +339 -0
  49. package/src/unused/InUse.test.js +92 -0
  50. package/src/unused/InUseMap.js +98 -0
  51. package/src/unused/LinkedList.js +117 -0
  52. package/src/unused/LinkedList.test.js +115 -0
  53. package/src/unused/Perf.js +47 -0
  54. package/src/unused/Template.js +108 -0
  55. package/src/util/Errors.js +9 -0
  56. package/src/util/Util.js +88 -0
  57. package/src/util/delve.js +43 -0
  58. package/tests/Benchmark.test.js +319 -0
  59. package/tests/NodeGroup.test.js +115 -0
  60. package/tests/Shell.test.js +75 -0
  61. package/tests/Solarite.test.js +2896 -0
  62. package/tests/Testimony.js +602 -0
  63. package/tests/index.html +75 -0
@@ -0,0 +1,319 @@
1
+ import {
2
+ getObjectId2,
3
+ hashObject,
4
+ hashObject64,
5
+ memoize,
6
+ memoize2,
7
+ memoize3,
8
+ memoize4
9
+ } from "../src/unused/Hashes.js";
10
+ import {getObjectHash} from '../src/solarite/hash.js'
11
+ import Testimony from "./Testimony.js";
12
+
13
+ //import {r, Solarite} from "../src/Solarite.js";
14
+ import {r, Solarite} from "../dist/Solarite.min.js";
15
+
16
+
17
+ window.verify = false;
18
+
19
+ let rowCount = 10000
20
+
21
+
22
+ // Benchmarks are based on:
23
+ // https://github.com/krausest/js-framework-benchmark
24
+ // https://krausest.github.io/js-framework-benchmark/current.html
25
+
26
+
27
+ const rowTemplate = document.createElement("div");
28
+ rowTemplate.setAttribute('style', 'display: flex')
29
+ rowTemplate.innerHTML = `<div class="col-md-1"></div><div class="col-md-4"><a class="lbl"></a></div><div class="col-md-1"><a class="remove"><span class="remove glyphicon glyphicon-remove" aria-hidden="true"></span></a></div><div class="col-md-6"></div>`;
30
+
31
+
32
+
33
+ function buildData(count = rowCount) {
34
+ function _random(max) {
35
+ return Math.round(Math.random()*1000)%max;
36
+ }
37
+
38
+ var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
39
+ var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
40
+ var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
41
+ var data = [];
42
+ for (let i=0; i<count; i++)
43
+ data.push({id: i, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] });
44
+ return data;
45
+ }
46
+
47
+
48
+
49
+
50
+ Testimony.test('Benchmark.vanilla._createRows', `Create ${rowCount} rows`, () => {
51
+
52
+ // Setup performance monitoring
53
+ let startTime;
54
+ let lcpObserver = new PerformanceObserver((entryList) => {
55
+ const lastEntry = entryList.getEntries().pop();
56
+ if (startTime) // [below] duration is always 0?
57
+ console.log(`Largest Contentful Paint: ${lastEntry.startTime+lastEntry.duration - startTime}`);
58
+ });
59
+ lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
60
+
61
+
62
+ // Build table and data
63
+ let table = document.createElement(`table`);
64
+ let tbody = document.createElement('tbody');
65
+ table.append(tbody)
66
+ document.body.append(table);
67
+
68
+ let data = buildData()
69
+
70
+ function createRows() {
71
+ for (let rowData of data) {
72
+ let tr = rowTemplate.cloneNode(true);
73
+ tr.firstChild.textContent = rowData.id
74
+ tr.children[1].firstChild.textContent = rowData.label;
75
+ tbody.append(tr);
76
+ }
77
+ }
78
+
79
+ setTimeout(() => {
80
+ startTime = performance.now();
81
+ createRows();
82
+ }, 100)
83
+ });
84
+
85
+
86
+ Testimony.test('Benchmark.solarite._createRows', `Create ${rowCount.toLocaleString()} rows`, () => {
87
+
88
+ // Setup performance monitoring
89
+ let startTime;
90
+ let lcpObserver = new PerformanceObserver((entryList) => {
91
+ const lastEntry = entryList.getEntries().pop();
92
+ if (startTime) // [below] duration is always 0?
93
+ console.log(`Largest Contentful Paint: ${lastEntry.startTime+lastEntry.duration - startTime}`);
94
+ });
95
+ lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
96
+
97
+
98
+
99
+ class A extends Solarite {
100
+ data = []
101
+ render() {
102
+ r(this)`<div>
103
+ <div style="display: flex: flex-direction: column">
104
+ ${this.data.map(row=>r`
105
+ <div style="dispay: flex">
106
+ <td class="col-md-1">${row.id}</td>
107
+ <td class="col-md-4"><a class="lbl">${row.label}</a></td>
108
+ <td class="col-md-1"><a class="remove"><span class="remove glyphicon glyphicon-remove" aria-hidden="true"></span></a></td>
109
+ <td class="col-md-6"></td>
110
+ </div>
111
+ `)}
112
+ </div>
113
+ </div>`
114
+ }
115
+ }
116
+ customElements.define('a-800', A);
117
+ let a = new A();
118
+ document.body.append(a);
119
+
120
+ let data = buildData()
121
+
122
+
123
+ function createRows() {
124
+ a.data = data
125
+ a.render();
126
+ }
127
+
128
+ setTimeout(() => {
129
+ startTime = performance.now();
130
+ createRows();
131
+ }, 100)
132
+
133
+ });
134
+
135
+
136
+
137
+
138
+ Testimony.test('Benchmark.vanilla._partialUpdate', 'Add text to every 10th row', () => {
139
+
140
+ // Build table and data
141
+ let table = document.createElement(`div`);
142
+ table.setAttribute('style', 'display: flex; flex-direction: row')
143
+ let tbody = document.createElement('div');
144
+ table.append(tbody)
145
+ document.body.append(table);
146
+
147
+ let data = buildData()
148
+
149
+ function createRows() {
150
+ for (let rowData of data) {
151
+ let tr = rowTemplate.cloneNode(true);
152
+ tr.firstChild.textContent = rowData.id
153
+ tr.children[1].firstChild.textContent = rowData.label;
154
+ tbody.append(tr);
155
+ }
156
+ }
157
+
158
+ createRows();
159
+
160
+ function updateRows() {
161
+ let i = 0;
162
+ let children = [...tbody.children]
163
+ for (let tr of children) {
164
+ if (i % 10 === 0) {
165
+ let a = tr.children[1].firstChild;
166
+
167
+ a.textContent = a.textContent.slice(0, -4) + ' ' + Math.round(Math.random()*1000)
168
+
169
+ // Alternate. Seems to be about the same speed.
170
+ // let b = document.createTextNode(a.textContent + '!!!');
171
+ // a.parentNode.insertBefore(b, a);
172
+ // a.remove();
173
+ }
174
+ i++;
175
+ }
176
+ }
177
+
178
+ setTimeout(() => {
179
+ let start = performance.now()
180
+ updateRows()
181
+ console.log(performance.now() - start)
182
+ }, 1200)
183
+
184
+ });
185
+
186
+
187
+ Testimony.test('Benchmark.solarite._partialUpdate', `Update ${rowCount.toLocaleString()} rows`, () => {
188
+
189
+ class R810 extends Solarite {
190
+ data = []
191
+
192
+ // Removing spaces before and after the inner loop speeds up this benchmark by 25%.
193
+ // But that makes performance measurements inconsistent across git revisions.
194
+ render() {
195
+ let options = {scripts: false, styles: false, ids: false}
196
+ r(this, options)`
197
+ <div>
198
+ <div style="display: flex: flex-direction: column">
199
+ ${this.data.map((row, i) => r`
200
+ <div style="display: flex">
201
+ <div class='col-md-1'>${row.id}</div>
202
+ <div class='col-md-4'><a class='lbl'>${row.label}</a></div>
203
+ <div class='col-md-1'><a class='remove'><span class='remove glyphicon glyphicon-remove' aria-hidden='true'></span></a></div>
204
+ <div class='col-md-6'></div>
205
+ </div>
206
+ `)}
207
+ </div>
208
+ </div>`
209
+ }
210
+ }
211
+ let a = new R810();
212
+ document.body.append(a);
213
+
214
+ let data = buildData()
215
+
216
+
217
+ function createRows() {
218
+ a.data = data
219
+ a.render();
220
+ }
221
+
222
+ createRows();
223
+
224
+ function updateRows() {
225
+ let i = 0;
226
+ for (let row of a.data) {
227
+ if (i % 10 === 0)
228
+ row.label = row.label.slice(0, -4) + ' ' + Math.round(Math.random()*1000)
229
+ i++;
230
+ }
231
+ }
232
+
233
+ setTimeout(async () => {
234
+ let testCount = 10;
235
+ let times = [];
236
+ for (let i=0; i<testCount; i++) {
237
+ let start = performance.now()
238
+ updateRows();
239
+ a.render();
240
+ times.push(performance.now() - start)
241
+ }
242
+
243
+ let min = Math.min(...times);
244
+ const avg = times.reduce((a, b) => a + b, 0) / times.length;
245
+ console.log(`partialUpdate: ${min.toLocaleString()}ms best, ${avg.toLocaleString()}ms avg`)
246
+ }, 1300)
247
+
248
+ });
249
+
250
+
251
+
252
+ Testimony.test('Benchmark._memoize', () => {
253
+ let data = buildData(100_000)
254
+ let start = performance.now();
255
+ JSON.stringify(memoize(data));
256
+
257
+ console.log(performance.now() - start)
258
+
259
+ });
260
+
261
+
262
+
263
+ Testimony.test('Benchmark._hashObject', () => {
264
+ let data = buildData(100_000)
265
+ let start = performance.now();
266
+ let result = hashObject(data);
267
+ console.log(performance.now() - start)
268
+
269
+ console.log(result.toLocaleString())
270
+ });
271
+
272
+
273
+
274
+
275
+ Testimony.test('Benchmark._hashObject64', () => {
276
+ let data = buildData(100_000)
277
+ let start = performance.now();
278
+ let result = hashObject64(data);
279
+ console.log('hashObject64:' + (performance.now() - start))
280
+
281
+ console.log(result.toLocaleString())
282
+ });
283
+
284
+
285
+ Testimony.test('Benchmark._memoize2', () => {
286
+ let data = buildData(100_000)
287
+ let start = performance.now();
288
+ memoize2(data);
289
+ console.log('memoize2: ' + (performance.now() - start))
290
+ //console.log(data)
291
+ });
292
+
293
+
294
+ Testimony.test('Benchmark._memoize4', () => {
295
+ let data = buildData(100_000)
296
+ let start = performance.now();
297
+ memoize4(data);
298
+ console.log('memoize4: ' + (performance.now() - start))
299
+ //console.log(data)
300
+ });
301
+
302
+
303
+
304
+ Testimony.test('Benchmark._JSONstringify', () => {
305
+ let data = buildData(100_000)
306
+ let start = performance.now();
307
+ JSON.stringify(data)
308
+ console.log('JSONstringify: ' + (performance.now() - start))
309
+ //console.log(data)
310
+ });
311
+
312
+
313
+ Testimony.test('Benchmark._getObjectHash', () => {
314
+ let data = buildData(100_000)
315
+ let start = performance.now();
316
+ getObjectHash(data)
317
+ console.log('getObjectHash: ' + (performance.now() - start))
318
+ //console.log(data)
319
+ });
@@ -0,0 +1,115 @@
1
+ /**
2
+ * These tests make it easier to debug individual functions of NodeGroup.
3
+ */
4
+ import NodeGroupManager from "../src/solarite/NodeGroupManager.js";
5
+ import {r} from "../src/solarite/Solarite.js";
6
+ import NodeGroup from "../src/solarite/NodeGroup.js";
7
+ import Shell from "../src/solarite/Shell.js";
8
+ import Template from "../src/solarite/Template.js";
9
+ import Testimony, {assert} from "./Testimony.js";
10
+
11
+
12
+
13
+
14
+ Testimony.test('NodeGroup.empty', () => {
15
+ let ngm = new NodeGroupManager(document.body);
16
+
17
+ let ng = new NodeGroup(new Template([``], []), ngm)
18
+ assert.eq(getHtml(ng), '')
19
+
20
+ ng.applyExprs([])
21
+ assert.eq(getHtml(ng), '')
22
+ });
23
+
24
+
25
+ Testimony.test('NodeGroup.oneExpr', () => {
26
+ let ngm = new NodeGroupManager(document.body);
27
+
28
+ let ng = new NodeGroup(new Template([``, ``], ['1']), ngm)
29
+ assert.eq(getHtml(ng), '1')
30
+
31
+ ng.applyExprs([2])
32
+ assert.eq(getHtml(ng), '2')
33
+
34
+ ng.applyExprs([[3, 4, 5]])
35
+ assert.eq(getHtml(ng), '3|4|5')
36
+ });
37
+
38
+ Testimony.test('NodeGroup.emptyAdjacent', () => {
39
+ let ngm = new NodeGroupManager(document.body);
40
+ let ng = new NodeGroup(new Template([``, ``, ``], ['1', '2']), ngm)
41
+ ng.verify();
42
+
43
+ assert.eq(getHtml(ng), '1|2')
44
+
45
+ ng.applyExprs([3, 4])
46
+ assert.eq(getHtml(ng), '3|4')
47
+
48
+ ng.applyExprs([[1, 2, 3], [4, 5, 6]])
49
+ assert.eq(getHtml(ng), '1|2|3|4|5|6')
50
+ });
51
+
52
+
53
+ Testimony.test('NodeGroup.paragraph', () => {
54
+ let ngm = new NodeGroupManager(document.body);
55
+ let ng = new NodeGroup(new Template(['<p>', '</p>'], ['1']), ngm)
56
+ assert.eq(getHtml(ng), '<p>1</p>')
57
+
58
+ ng.applyExprs([2])
59
+ assert.eq(getHtml(ng), '<p>2</p>')
60
+
61
+ ng.applyExprs([[3, 4, 5]])
62
+ assert.eq(getHtml(ng), '<p>345</p>')
63
+ });
64
+
65
+ Testimony.test('NodeGroup.node', () => {
66
+ let ngm = new NodeGroupManager(document.body);
67
+ let a = r('<p>a</p>')
68
+ let b = r('<p>b</p>')
69
+ let ng = new NodeGroup(new Template(['<div>', '</div>'], [a]), ngm)
70
+
71
+ assert.eq(getHtml(ng), '<div><p>a</p></div>')
72
+
73
+ ng.applyExprs([b]);
74
+ assert.eq(getHtml(ng), '<div><p>b</p></div>')
75
+
76
+ ng.applyExprs([1]);
77
+ assert.eq(getHtml(ng), '<div>1</div>')
78
+
79
+ ng.applyExprs([a]);
80
+ assert.eq(getHtml(ng), '<div><p>a</p></div>')
81
+ });
82
+
83
+
84
+ /**
85
+ * This fails because
86
+ */
87
+ Testimony.test('NodeGroup._nodeSwap', () => {
88
+ let ngm = new NodeGroupManager(document.body);
89
+ let a = r('<p>a</p>')
90
+ let b = r('<p>b</p>')
91
+ let ng = new NodeGroup(new Template(['<div>', '', '</div>'], [a, b]), ngm)
92
+ document.body.append(ng.startNode)
93
+
94
+ assert.eq(getHtml(ng), '<div><p>a</p><p>b</p></div>')
95
+
96
+
97
+ ng.applyExprs([b, a]);
98
+ assert.eq(getHtml(ng), '<div><p>b</p><p>a</p></div>')
99
+
100
+ });
101
+
102
+
103
+ Testimony.test('NodeGroup.arrayReverse', () => {
104
+ let ngm = new NodeGroupManager(document.body);
105
+ let list = [r('a'), r('b')];
106
+
107
+ let ng = new NodeGroup(new Template(['<div>', '</div>'], [list]), ngm)
108
+ ng.verify();
109
+ assert(getHtml(ng), '<div>ab</div')
110
+
111
+ list.reverse();
112
+ ng.applyExprs([list])
113
+ assert(getHtml(ng), '<div>ba</div')
114
+ });
115
+
@@ -0,0 +1,75 @@
1
+
2
+
3
+
4
+
5
+
6
+ import Testimony, {assert} from "./Testimony.js";
7
+ import Shell from "../src/solarite/Shell.js";
8
+
9
+ Testimony.test('Shell.empty', () => {
10
+ let shell = new Shell(['', ''])
11
+ assert.eq(getHtml(shell, true), '<!--PathStart:0-->|<!--PathEnd:0-->')
12
+ });
13
+
14
+ Testimony.test('Shell.paragraph', () => {
15
+ let shell = new Shell(['<p>', '</p>'])
16
+ assert.eq(getHtml(shell, true), '<p><!--PathStart:0--><!--PathEnd:0--></p>')
17
+ });
18
+
19
+ Testimony.test('Shell.nodeBefore', () => {
20
+ let shell = new Shell(['a', ''])
21
+ assert.eq(getHtml(shell, true), 'a|<!--PathEnd:0-->')
22
+ });
23
+
24
+ Testimony.test('Shell.nodeAfter', () => {
25
+ let shell = new Shell(['', 'b'])
26
+ assert.eq(getHtml(shell, true), '<!--PathStart:0-->|b')
27
+ });
28
+
29
+ Testimony.test('Shell.nodeBeforeAfter', () => {
30
+ let shell = new Shell(['a', 'b'])
31
+ assert.eq(getHtml(shell, true), 'a|b')
32
+ });
33
+
34
+ Testimony.test('Shell.emptyTwoPaths', () => {
35
+ let shell = new Shell(['', '', ''])
36
+ assert.eq(getHtml(shell, true), '<!--PathStart:0-->|<!--PathEnd:0-->|<!--PathEnd:1-->')
37
+ });
38
+
39
+ Testimony.test('Shell.nodeBetweenPaths', () => {
40
+ let shell = new Shell(['', 'a', ''])
41
+ assert.eq(getHtml(shell, true), '<!--PathStart:0-->|a|<!--PathEnd:1-->')
42
+ });
43
+
44
+ Testimony.test('Shell.nodesAroundPaths', () => {
45
+ let shell = new Shell(['a', 'b', 'c'])
46
+ assert.eq(getHtml(shell, true), 'a|b|c')
47
+ });
48
+
49
+ Testimony.test('Shell.emptyTwoPathsNested', () => {
50
+ let shell = new Shell(['<p>', '', '</p>'])
51
+ assert.eq(getHtml(shell, true), '<p><!--PathStart:0--><!--PathEnd:0--><!--PathEnd:1--></p>')
52
+ });
53
+
54
+ Testimony.test('Shell.nodesAroundPathsNested', () => {
55
+ let shell = new Shell(['<p>a', 'b', 'c</p>'])
56
+ assert.eq(getHtml(shell, true), '<p>abc</p>')
57
+ });
58
+
59
+
60
+ /*
61
+ `<button value=${button}
62
+ ${product[option.field] == button && 'class="primary"'}
63
+ onclick=${e => this.select(product, option.field, e.target.value ? '' : e.target.value)}
64
+
65
+ >${button}</button>`
66
+ */
67
+
68
+
69
+
70
+ // Testimony.test('Shell.emptySpacer', () => {
71
+ // let expr = 1;
72
+ // let shell = new Shell(['<input ', '', 'onclick=','>'])
73
+ // console.log(getHtml(shell, true))
74
+ // });
75
+