solarite 0.5.2 → 0.7.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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/dist/Solarite-debug.js +2823 -1856
  3. package/dist/Solarite.js +2779 -1824
  4. package/dist/Solarite.min.js +2 -4
  5. package/package.json +16 -3
  6. package/readme.md +58 -11
  7. package/src/Globals.js +54 -72
  8. package/src/HtmlParser.js +90 -90
  9. package/src/MultiValueMap.js +57 -105
  10. package/src/NodeGroup.js +624 -470
  11. package/src/Path.js +224 -211
  12. package/src/PathToAttribValue.js +401 -261
  13. package/src/PathToAttribs.js +113 -80
  14. package/src/PathToComment.js +7 -7
  15. package/src/PathToComponent.js +183 -188
  16. package/src/PathToEvent.js +76 -64
  17. package/src/PathToKey.js +19 -0
  18. package/src/PathToNodes.js +1053 -566
  19. package/src/RootNodeGroup.js +120 -8
  20. package/src/Shell.js +570 -348
  21. package/src/Solarite.d.ts +134 -113
  22. package/src/Solarite.js +243 -286
  23. package/src/Template.js +195 -274
  24. package/src/Util.js +353 -351
  25. package/src/assert.js +10 -10
  26. package/src/assignAttributes.js +63 -0
  27. package/src/delve.js +55 -43
  28. package/src/h.js +220 -138
  29. package/src/jsx-dev-runtime.d.ts +1 -0
  30. package/src/jsx-dev-runtime.js +5 -0
  31. package/src/jsx-runtime.d.ts +21 -0
  32. package/src/jsx-runtime.js +84 -0
  33. package/src/jsx.js +194 -0
  34. package/src/toEl.js +77 -82
  35. package/dist/udomdiff-license.txt +0 -18
  36. package/src/getArg.js +0 -137
  37. package/src/hash.js +0 -89
  38. package/src/udomdiff.js +0 -176
  39. package/src/unused/FastLookupArray.js +0 -54
  40. package/src/unused/Hashes.js +0 -339
  41. package/src/unused/InUse.test.js +0 -92
  42. package/src/unused/InUseMap.js +0 -98
  43. package/src/unused/LinkedList.js +0 -117
  44. package/src/unused/LinkedList.test.js +0 -115
  45. package/src/unused/Misc.js +0 -13
  46. package/src/unused/Perf.js +0 -47
  47. package/src/unused/TrackedArray.js +0 -54
  48. package/src/unused/WeakArray.js +0 -33
  49. package/src/watch.js +0 -543
package/src/Path.js CHANGED
@@ -1,212 +1,225 @@
1
- import assert from "./assert.js";
2
-
3
- /**
4
- * Path to where an expression should be evaluated within a Shell or NodeGroup. */
5
- export default class Path {
6
-
7
- // Used for attributes:
8
-
9
- /**
10
- * @type {Node} Node that occurs before this Path's first Node.
11
- * This is necessary because udomdiff() can steal nodes from another Path.
12
- * If we had a pointer to our own startNode then that node could be moved somewhere else w/o us knowing it.
13
- * Used only for type='content'
14
- * Will be null if Path has no Nodes. */
15
- nodeBefore;
16
-
17
- /**
18
- * If type is AttribType.Multiple or AttribType.Value, points to the node having the attribute.
19
- * If type is 'content', points to a node that never changes that this NodeGroup should always insert its nodes before.
20
- * An empty text node will be created to insertBefore if there's no other NodeMarker and this isn't at the last position.
21
- * @type {Node|HTMLElement} */
22
- nodeMarker;
23
-
24
-
25
- // These are set after an expression is assigned:
26
-
27
- /** @type {NodeGroup} */
28
- parentNg;
29
-
30
- /** @type {NodeGroup[]} */
31
- nodeGroups = [];
32
-
33
- // Caches to make things faster
34
-
35
- /**
36
- * @private
37
- * @type {Node[]} Cached result of getNodes() */
38
- nodesCache;
39
-
40
- /**
41
- * @type {int} Index of nodeBefore among its parentNode's children. */
42
- nodeBeforeIndex;
43
-
44
- /**
45
- * @type {int[]} Path to the node marker, in reverse for performance reasons. */
46
- nodeMarkerPath;
47
-
48
- /** @type {?function} A function called by renderWatched() to update the value of this expression. */
49
- watchFunction
50
-
51
-
52
- /**
53
- * @param nodeBefore {Node}
54
- * @param nodeMarker {?Node}*/
55
- constructor(nodeBefore, nodeMarker) {
56
- this.nodeBefore = nodeBefore;
57
- this.nodeMarker = nodeMarker;
58
- /*#IFDEV*/this.verify();/*#ENDIF*/
59
- }
60
-
61
- /**
62
- * Apply expressions to a path.
63
- * This is called by NodeGroup.applyExprs() when it's time to put the expression values into the DOM.
64
- *
65
- * @param exprs {Expr[]}
66
- * Suppose we have the following tagged template:
67
- * `<div title=${expr1} class="big ${expr2} muted ${expr3}">
68
- * ${expr4}
69
- * <my-component></my-component>
70
- * <my-component user=${expr5} roles="${expr6},${expr7}"></my-component>
71
- * </div>`
72
- * The exprs arrays will look like this, with each being passed to a path.
73
- * [expr1] // title attribute value.
74
- * [expr2, expr3] // class attribute values.
75
- * [expr4] // children of div.
76
- * [] // arguments to first my-component constructor.
77
- * [[expr5], [expr6, expr7]] // arguments to second my-component constructor.
78
- * [expr5] // user attribute value.
79
- * [expr6, expr7] // role attribute value.
80
- * @param freeNodeGroups {boolean} Used only by watch. */
81
- apply(exprs, freeNodeGroups=true) {}
82
-
83
- getExpressionCount() { return 1 }
84
-
85
-
86
- /**
87
- * Resolve nodeMarkerPath to new root.
88
- * TODO: Make clone() use this.*/
89
- getNewNodeMarker(newRoot, pathOffset) {
90
- let root = newRoot;
91
- let path = this.nodeMarkerPath;
92
- let pathLength = path.length - pathOffset;
93
- for (let i=pathLength-1; i>0; i--) { // Resolve the path.
94
- //#IFDEV
95
- assert(root.childNodes[path[i]]);
96
- //#ENDIF
97
- root = root.childNodes[path[i]];
98
- }
99
- let childNodes = root.childNodes;
100
-
101
- return pathLength
102
- ? childNodes[path[0]]
103
- : newRoot;
104
- }
105
-
106
-
107
- /**
108
- * @param newRoot {HTMLElement}
109
- * @param pathOffset {int}
110
- * @return {Path} */
111
- clone(newRoot, pathOffset=0) {
112
- /*#IFDEV*/this.verify();/*#ENDIF*/
113
-
114
- // Resolve node paths.
115
- let nodeMarker, nodeBefore;
116
- let root = newRoot;
117
- let path = this.nodeMarkerPath;
118
- let pathLength = path.length - pathOffset;
119
- for (let i=pathLength-1; i>0; i--) { // Resolve the path.
120
- //#IFDEV
121
- assert(root.childNodes[path[i]]);
122
- //#ENDIF
123
- root = root.childNodes[path[i]];
124
- }
125
- let childNodes = root.childNodes;
126
-
127
- nodeMarker = pathLength
128
- ? childNodes[path[0]]
129
- : newRoot;
130
- if (this.nodeBefore) {
131
- //#IFDEV
132
- assert(childNodes[this.nodeBeforeIndex]);
133
- //#ENDIF
134
- nodeBefore = childNodes[this.nodeBeforeIndex];
135
-
136
- }
137
-
138
- let result = new this.constructor(nodeBefore, nodeMarker, this.attrName, this.attrValue);
139
-
140
- result.isComponentAttrib = this.isComponentAttrib;
141
-
142
- // TODO: Put this in PathToAttribValue.clone().
143
- result.isHtmlProperty = this.isHtmlProperty;
144
-
145
- //#IFDEV
146
- result.verify();
147
- //#ENDIF
148
-
149
- return result;
150
- }
151
-
152
- // Only used for watch.js
153
- getNodes() {
154
- return [this.nodeMarker];
155
- }
156
-
157
- /** @return {int[]} Returns indices in reverse order, because doing it that way is faster. */
158
- static get(node) {
159
- let result = [];
160
- while(true) {
161
- let parent = node.parentNode
162
- if (!parent)
163
- break;
164
- result.push(Array.prototype.indexOf.call(node.parentNode.childNodes, node))
165
- node = parent;
166
- }
167
- return result;
168
- }
169
-
170
- /**
171
- * Note that the path is backward, with the outermost element at the end.
172
- * @param root {HTMLElement|Document|DocumentFragment|ParentNode}
173
- * @param path {int[]}
174
- * @returns {Node|HTMLElement|HTMLStyleElement} */
175
- static resolve(root, path) {
176
- for (let i=path.length-1; i>=0; i--)
177
- root = root.childNodes[path[i]];
178
- return root;
179
- }
180
-
181
- //#IFDEV
182
-
183
- /** @return {HTMLElement|ParentNode} */
184
- getParentNode() {
185
- return this.nodeMarker.parentNode
186
- }
187
-
188
- verify() {
189
- if (!window.verify)
190
- return;
191
-
192
- // Need either nodeMarker or parentNode
193
- assert(this.nodeMarker)
194
-
195
- // nodeMarker must be attached.
196
- assert(!this.nodeMarker || this.nodeMarker.parentNode)
197
-
198
- assert(this.nodeBefore !== this.nodeMarker)
199
-
200
- // Detect cyclic parent and grandparent references.
201
- assert(this.parentNg?.parentPath !== this)
202
- assert(this.parentNg?.parentPath?.parentNg?.parentPath !== this)
203
- assert(this.parentNg?.parentPath?.parentNg?.parentPath?.parentNg?.parentPath !== this)
204
-
205
- for (let ng of this.nodeGroups)
206
- ng.verify();
207
-
208
- // Make sure the nodesCache matches the nodes.
209
- //this.checkNodesCache();
210
- }
211
- //#ENDIF
1
+ import assert from "./assert.js";
2
+
3
+ /**
4
+ * Path to where an expression should be evaluated within a Shell or NodeGroup. */
5
+ export default class Path {
6
+
7
+ // Used for attributes:
8
+
9
+ /**
10
+ * @type {Node} Node that occurs before this Path's first Node.
11
+ * This is necessary because reconcileNodes() can steal nodes from another Path.
12
+ * If we had a pointer to our own startNode then that node could be moved somewhere else w/o us knowing it.
13
+ * Used only for type='content'
14
+ * Will be null if Path has no Nodes. */
15
+ nodeBefore;
16
+
17
+ /**
18
+ * If type is AttribType.Multiple or AttribType.Value, points to the node having the attribute.
19
+ * If type is 'content', points to a node that never changes that this NodeGroup should always insert its nodes before.
20
+ * An empty text node will be created to insertBefore if there's no other NodeMarker and this isn't at the last position.
21
+ * @type {Node|HTMLElement} */
22
+ nodeMarker;
23
+
24
+ /**
25
+ * @type {boolean} True if the expression is the only child of its parent element.
26
+ * Then nodeMarker is that parent element, nodeBefore is null, and no marker comments exist. */
27
+ wholeParent = false;
28
+
29
+
30
+ // These are set after an expression is assigned:
31
+
32
+ /** @type {NodeGroup} */
33
+ parentNg;
34
+
35
+ // Caches to make things faster
36
+
37
+ /**
38
+ * @private
39
+ * @type {Node[]} Cached result of getNodes() */
40
+ nodesCache;
41
+
42
+ // Set only on Shell paths, never on cloned instances, so they're not declared as
43
+ // class fields; that would cost a store per field on every clone:
44
+ // nodeBeforeIndex {int} Index of nodeBefore among its parentNode's children.
45
+ // nodeMarkerPath {int[]} Path to the node marker, in reverse for performance reasons.
46
+ // markerSlot/beforeSlot {int} Slot indexes into the Shell's resolve program.
47
+
48
+
49
+ /**
50
+ * @param nodeBefore {Node}
51
+ * @param nodeMarker {?Node}*/
52
+ constructor(nodeBefore, nodeMarker) {
53
+ this.nodeBefore = nodeBefore;
54
+ this.nodeMarker = nodeMarker;
55
+ /*#IFDEV*/this.verify();/*#ENDIF*/
56
+ }
57
+
58
+ /**
59
+ * Apply expressions to a path.
60
+ * This is called by NodeGroup.applyExprs() when it's time to put the expression values into the DOM.
61
+ *
62
+ * @param exprs {Expr[]}
63
+ * Suppose we have the following tagged template:
64
+ * `<div title=${expr1} class="big ${expr2} muted ${expr3}">
65
+ * ${expr4}
66
+ * <my-component></my-component>
67
+ * <my-component user=${expr5} roles="${expr6},${expr7}"></my-component>
68
+ * </div>`
69
+ * The exprs arrays will look like this, with each being passed to a path.
70
+ * [expr1] // title attribute value.
71
+ * [expr2, expr3] // class attribute values.
72
+ * [expr4] // children of div.
73
+ * [] // arguments to first my-component constructor.
74
+ * [[expr5], [expr6, expr7]] // arguments to second my-component constructor.
75
+ * [expr5] // user attribute value.
76
+ * [expr6, expr7] // role attribute value. */
77
+ apply(exprs) {}
78
+
79
+ /**
80
+ * Fast path used by NodeGroup.applyExprs() when every path consumes exactly one expression.
81
+ * Avoids allocating per-path expression arrays.
82
+ * @param expr {Expr} */
83
+ applySingle(expr) {}
84
+
85
+ getExpressionCount() { return 1 }
86
+
87
+
88
+ /**
89
+ * Resolve nodeMarkerPath to new root.
90
+ * TODO: Make clone() use this.*/
91
+ getNewNodeMarker(newRoot, pathOffset) {
92
+ let root = newRoot;
93
+ let path = this.nodeMarkerPath;
94
+ let pathLength = path.length - pathOffset;
95
+ for (let i=pathLength-1; i>0; i--) { // Resolve the path.
96
+ //#IFDEV
97
+ assert(root.childNodes[path[i]]);
98
+ //#ENDIF
99
+ root = root.childNodes[path[i]];
100
+ }
101
+ let childNodes = root.childNodes;
102
+
103
+ return pathLength
104
+ ? childNodes[path[0]]
105
+ : newRoot;
106
+ }
107
+
108
+
109
+ /**
110
+ * Copy this path, pointing it at already-resolved nodes.
111
+ * Used by the Shell resolve-program fast path in NodeGroup.setPathsFromFragment().
112
+ * @param nodeBefore {?Node}
113
+ * @param nodeMarker {Node}
114
+ * @return {Path} */
115
+ cloneWithNodes(nodeBefore, nodeMarker) {
116
+ let result = new this.constructor(nodeBefore, nodeMarker, this.attrName, this.attrValue);
117
+ result.isComponentAttrib = this.isComponentAttrib;
118
+ result.wholeParent = this.wholeParent;
119
+ result.isHtmlProperty = this.isHtmlProperty;
120
+ return result;
121
+ }
122
+
123
+ /**
124
+ * @param newRoot {HTMLElement}
125
+ * @param pathOffset {int}
126
+ * @return {Path} */
127
+ clone(newRoot, pathOffset=0) {
128
+ /*#IFDEV*/this.verify();/*#ENDIF*/
129
+
130
+ // Resolve node paths.
131
+ let nodeMarker, nodeBefore;
132
+ let root = newRoot;
133
+ let path = this.nodeMarkerPath;
134
+ let pathLength = path.length - pathOffset;
135
+ for (let i=pathLength-1; i>0; i--) { // Resolve the path.
136
+ //#IFDEV
137
+ assert(root.childNodes[path[i]]);
138
+ //#ENDIF
139
+ root = root.childNodes[path[i]];
140
+ }
141
+ let childNodes = root.childNodes;
142
+
143
+ nodeMarker = pathLength
144
+ ? childNodes[path[0]]
145
+ : newRoot;
146
+ if (this.nodeBefore) {
147
+ //#IFDEV
148
+ assert(childNodes[this.nodeBeforeIndex]);
149
+ //#ENDIF
150
+ nodeBefore = childNodes[this.nodeBeforeIndex];
151
+
152
+ }
153
+
154
+ let result = new this.constructor(nodeBefore, nodeMarker, this.attrName, this.attrValue);
155
+
156
+ result.isComponentAttrib = this.isComponentAttrib;
157
+ result.wholeParent = this.wholeParent;
158
+
159
+ // TODO: Put this in PathToAttribValue.clone().
160
+ result.isHtmlProperty = this.isHtmlProperty;
161
+
162
+ //#IFDEV
163
+ result.verify();
164
+ //#ENDIF
165
+
166
+ return result;
167
+ }
168
+
169
+ /** @return {int[]} Returns indices in reverse order, because doing it that way is faster. */
170
+ static get(node) {
171
+ let result = [];
172
+ while(true) {
173
+ let parent = node.parentNode
174
+ if (!parent)
175
+ break;
176
+ result.push(Array.prototype.indexOf.call(node.parentNode.childNodes, node))
177
+ node = parent;
178
+ }
179
+ return result;
180
+ }
181
+
182
+ /**
183
+ * Note that the path is backward, with the outermost element at the end.
184
+ * @param root {HTMLElement|Document|DocumentFragment|ParentNode}
185
+ * @param path {int[]}
186
+ * @returns {Node|HTMLElement|HTMLStyleElement} */
187
+ static resolve(root, path) {
188
+ for (let i=path.length-1; i>=0; i--)
189
+ root = root.childNodes[path[i]];
190
+ return root;
191
+ }
192
+
193
+ //#IFDEV
194
+
195
+ /** @return {HTMLElement|ParentNode} */
196
+ getParentNode() {
197
+ return this.nodeMarker.parentNode
198
+ }
199
+
200
+ verify() {
201
+ if (!window.verify)
202
+ return;
203
+
204
+ // Need either nodeMarker or parentNode
205
+ assert(this.nodeMarker)
206
+
207
+ // nodeMarker must be attached, unless it's an element that is itself the top of a
208
+ // singleRoot shell clone (no fragment wrapper exists above it).
209
+ assert(!this.nodeMarker || this.nodeMarker.parentNode || this.wholeParent || this.nodeMarker.nodeType === 1)
210
+
211
+ assert(this.nodeBefore !== this.nodeMarker)
212
+
213
+ // Detect cyclic parent and grandparent references.
214
+ assert(this.parentNg?.parentPath !== this)
215
+ assert(this.parentNg?.parentPath?.parentNg?.parentPath !== this)
216
+ assert(this.parentNg?.parentPath?.parentNg?.parentPath?.parentNg?.parentPath !== this)
217
+
218
+ for (let ng of this.nodeGroups || [])
219
+ ng.verify();
220
+
221
+ // Make sure the nodesCache matches the nodes.
222
+ //this.checkNodesCache();
223
+ }
224
+ //#ENDIF
212
225
  }