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.
- package/LICENSE +21 -0
- package/dist/Solarite-debug.js +2823 -1856
- package/dist/Solarite.js +2779 -1824
- package/dist/Solarite.min.js +2 -4
- package/package.json +16 -3
- package/readme.md +58 -11
- package/src/Globals.js +54 -72
- package/src/HtmlParser.js +90 -90
- package/src/MultiValueMap.js +57 -105
- package/src/NodeGroup.js +624 -470
- package/src/Path.js +224 -211
- package/src/PathToAttribValue.js +401 -261
- package/src/PathToAttribs.js +113 -80
- package/src/PathToComment.js +7 -7
- package/src/PathToComponent.js +183 -188
- package/src/PathToEvent.js +76 -64
- package/src/PathToKey.js +19 -0
- package/src/PathToNodes.js +1053 -566
- package/src/RootNodeGroup.js +120 -8
- package/src/Shell.js +570 -348
- package/src/Solarite.d.ts +134 -113
- package/src/Solarite.js +243 -286
- package/src/Template.js +195 -274
- package/src/Util.js +353 -351
- package/src/assert.js +10 -10
- package/src/assignAttributes.js +63 -0
- package/src/delve.js +55 -43
- package/src/h.js +220 -138
- package/src/jsx-dev-runtime.d.ts +1 -0
- package/src/jsx-dev-runtime.js +5 -0
- package/src/jsx-runtime.d.ts +21 -0
- package/src/jsx-runtime.js +84 -0
- package/src/jsx.js +194 -0
- package/src/toEl.js +77 -82
- package/dist/udomdiff-license.txt +0 -18
- package/src/getArg.js +0 -137
- package/src/hash.js +0 -89
- package/src/udomdiff.js +0 -176
- package/src/unused/FastLookupArray.js +0 -54
- package/src/unused/Hashes.js +0 -339
- package/src/unused/InUse.test.js +0 -92
- package/src/unused/InUseMap.js +0 -98
- package/src/unused/LinkedList.js +0 -117
- package/src/unused/LinkedList.test.js +0 -115
- package/src/unused/Misc.js +0 -13
- package/src/unused/Perf.js +0 -47
- package/src/unused/TrackedArray.js +0 -54
- package/src/unused/WeakArray.js +0 -33
- package/src/watch.js +0 -543
package/src/Solarite.js
CHANGED
|
@@ -1,286 +1,243 @@
|
|
|
1
|
-
/*
|
|
2
|
-
┏┓ ┓ •
|
|
3
|
-
┗┓┏┓┃┏┓┏┓┓╋▗▖
|
|
4
|
-
┗┛┗┛┗┗┻╹ ╹╹┗
|
|
5
|
-
JavasCript UI library
|
|
6
|
-
@license MIT
|
|
7
|
-
@copyright Vorticode LLC
|
|
8
|
-
https://vorticode.github.io/solarite/ */
|
|
9
|
-
import h from './h.js';
|
|
10
|
-
export default h;
|
|
11
|
-
export {default as delve} from './delve.js';
|
|
12
|
-
export {default as Template} from './Template.js';
|
|
13
|
-
export {default as toEl} from './toEl.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export {default as
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
//--------------
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
i
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
i
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
else if (code[i] === '
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
if (code
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
i++;
|
|
247
|
-
}
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
*/
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Assign fields from `src` to `dest` if they exist in `dest` and their names are not in the `ignore` list.
|
|
256
|
-
* When a value in `src` is a string and the existing value in `dest` is a boolean, number, or Date,
|
|
257
|
-
* it will be converted to that type.
|
|
258
|
-
* This is often used in class constructors that accept an object of arguments.
|
|
259
|
-
* @param {object} dest
|
|
260
|
-
* @param {?object} src
|
|
261
|
-
* @param {string[]} [ignore=[]] */
|
|
262
|
-
export function assignFields(dest, src, ignore=[]) {
|
|
263
|
-
for (let name in src || {}) {
|
|
264
|
-
if (name in dest && !ignore.includes(name)) {
|
|
265
|
-
const descriptor = Object.getOwnPropertyDescriptor(dest, name)
|
|
266
|
-
|| Object.getOwnPropertyDescriptor(Object.getPrototypeOf(dest), name); // Also find (parent?) setters. Is this necssary?
|
|
267
|
-
if (!descriptor || descriptor.writable || descriptor.set) {
|
|
268
|
-
let srcVal = src[name];
|
|
269
|
-
let destVal = dest[name];
|
|
270
|
-
if (typeof src[name] === 'string') {
|
|
271
|
-
if (typeof destVal === 'boolean') // empty string (when an attribute is present with no value) is true
|
|
272
|
-
dest[name] = ![false, 'false', 0, '0'].includes(srcVal);
|
|
273
|
-
else if (typeof destVal === 'number')
|
|
274
|
-
dest[name] = Number(srcVal);
|
|
275
|
-
else if (destVal instanceof Date) {
|
|
276
|
-
dest[name] = new Date(srcVal); // TODO: read it as UTC 0 by default.
|
|
277
|
-
}
|
|
278
|
-
else
|
|
279
|
-
dest[name] = srcVal;
|
|
280
|
-
}
|
|
281
|
-
else
|
|
282
|
-
dest[name] = srcVal;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
┏┓ ┓ •
|
|
3
|
+
┗┓┏┓┃┏┓┏┓┓╋▗▖
|
|
4
|
+
┗┛┗┛┗┗┻╹ ╹╹┗
|
|
5
|
+
JavasCript UI library
|
|
6
|
+
@license MIT
|
|
7
|
+
@copyright Vorticode LLC
|
|
8
|
+
https://vorticode.github.io/solarite/ */
|
|
9
|
+
import h from './h.js';
|
|
10
|
+
export default h;
|
|
11
|
+
export {default as delve} from './delve.js';
|
|
12
|
+
export {default as Template} from './Template.js';
|
|
13
|
+
export {default as toEl} from './toEl.js';
|
|
14
|
+
export {assignAttributes} from './assignAttributes.js';
|
|
15
|
+
export {svg} from './h.js';
|
|
16
|
+
export {getEventBinding} from './PathToAttribValue.js';
|
|
17
|
+
export {Fragment} from './jsx.js';
|
|
18
|
+
|
|
19
|
+
// Experimental:
|
|
20
|
+
//--------------
|
|
21
|
+
export {default as Globals} from './Globals.js';
|
|
22
|
+
export {default as SolariteUtil} from './Util.js';
|
|
23
|
+
|
|
24
|
+
// Deprecated:
|
|
25
|
+
//--------------
|
|
26
|
+
export {default as h} from './h.js'; // Named exports for h() are deprecated.
|
|
27
|
+
|
|
28
|
+
// HtmlParser, NodeGroup, and Shell are internal; tests import them directly from their modules.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
// Solarite Class:
|
|
33
|
+
//--------------
|
|
34
|
+
import Util from "./Util.js";
|
|
35
|
+
import Globals from "./Globals.js";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Intercept the construct call to auto-define the class before the constructor is called. */
|
|
39
|
+
let HTMLElementAutoDefine = new Proxy(HTMLElement, {
|
|
40
|
+
construct(Parent, args, Class) {
|
|
41
|
+
|
|
42
|
+
// 1. Call customElements.define() automatically.
|
|
43
|
+
Util.defineClass(Class);
|
|
44
|
+
|
|
45
|
+
// 2. This line is equivalent the to super() call to HTMLElement:
|
|
46
|
+
return Reflect.construct(Parent, args, Class);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Solarite provides more features if your web component extends Solarite instead of HTMLElement.
|
|
52
|
+
*
|
|
53
|
+
* Reasons to inherit from Solarite instead of HTMLElement.
|
|
54
|
+
* 1. customElements.define() is called automatically when you create the first instance.
|
|
55
|
+
* 2. Calls render() when added to the DOM, if it hasn't been called already.
|
|
56
|
+
* 3. Populates the attribs argument to the constructor when instantiated from regular html outside a template string.
|
|
57
|
+
* It parses JSON from DOM attribute values surrouned with '${...}'
|
|
58
|
+
* 4. Shows an error if render() isn't defined.
|
|
59
|
+
*
|
|
60
|
+
* Advantages to inheriting from HTMLElement
|
|
61
|
+
* 1. We can inherit from things like HTMLTableRowElement directly.
|
|
62
|
+
* 2. There's less magic, since everyone is familiar with defining custom elements.
|
|
63
|
+
* 3. No confusion about how the class name becomes a tag name.
|
|
64
|
+
* @extends {HTMLElement} */
|
|
65
|
+
export class Solarite extends HTMLElementAutoDefine {
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param attribs {?Record<string, any>} */
|
|
69
|
+
constructor(attribs=null) {
|
|
70
|
+
super();
|
|
71
|
+
|
|
72
|
+
if (attribs) {
|
|
73
|
+
if (typeof attribs !== 'object')
|
|
74
|
+
throw new Error('First argument to custom element constructor must be an object.');
|
|
75
|
+
|
|
76
|
+
// 1. Populate attribs if it's an empty object.
|
|
77
|
+
if (attribs && !Object.keys(attribs).length) {
|
|
78
|
+
let attribs2 = Solarite.getAttribs(this);
|
|
79
|
+
for (let name in attribs2) {
|
|
80
|
+
attribs[name] = attribs2[name];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 2. Populate fields from attribs.
|
|
85
|
+
// This does nothing because the fields are overwritten by the child class after this super() constructor executes.
|
|
86
|
+
//for (let name in attribs || {}) {
|
|
87
|
+
// if (name in this) {
|
|
88
|
+
// const descriptor = Object.getOwnPropertyDescriptor(this, name);
|
|
89
|
+
// if (!descriptor || descriptor.writable || descriptor.set)
|
|
90
|
+
// this[name] = attribs[name];
|
|
91
|
+
// }
|
|
92
|
+
//}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 3. Wrap render function so it always provides the attribs argument.
|
|
96
|
+
// Disabled because this gives us strings for attribute values when we call render manually.
|
|
97
|
+
// Instead of values given from ${...} expressions.
|
|
98
|
+
// let originalRender = this.render;
|
|
99
|
+
// this.render = (attribs, changed=true) => {
|
|
100
|
+
// if (!attribs) // If we have to look up the attribs, we don't know if they changed or not.
|
|
101
|
+
// attribs = Solarite.getAttribs(this);
|
|
102
|
+
// originalRender.call(this, attribs, changed);
|
|
103
|
+
// }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
'render'() {
|
|
107
|
+
throw new Error('render() is not defined for ' + this.constructor.name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Call render() only if it hasn't already been called. */
|
|
112
|
+
'renderFirstTime'() {
|
|
113
|
+
if (!Globals.rendered.has(this)) {
|
|
114
|
+
let attribs = Solarite.getAttribs(this);
|
|
115
|
+
this.render(attribs); // calls Globals.rendered.add(this); inside the call to h()'...'.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Called automatically by the browser. */
|
|
121
|
+
'connectedCallback'() { // quoted so terser doesn't remove it.
|
|
122
|
+
this.renderFirstTime();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static 'define'(tagName=null) {
|
|
126
|
+
Util.defineClass(this, tagName);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static 'getAttribs'(el) {
|
|
130
|
+
let result = Util.attribsToObject(el);
|
|
131
|
+
for (let name in result) {
|
|
132
|
+
let val = result[name];
|
|
133
|
+
|
|
134
|
+
// We don't do eval because that seems too dangerous.
|
|
135
|
+
if (val.startsWith('${') && val.endsWith('}'))
|
|
136
|
+
result[name] = JSON.parse(val.slice(2, -1));
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
// TODO: Do we want to use this to get the tag name from the render() function, instead of having the user define it?
|
|
143
|
+
/**
|
|
144
|
+
* Get the tag name for a class, as defined by the tag used in render().
|
|
145
|
+
*
|
|
146
|
+
* This will parse the JavaScript code of the render() function to find the tag name.
|
|
147
|
+
* It will itarage every character, keeping track of quotes and comments so it can
|
|
148
|
+
* skip them until it finds the tag name passed to h(this)`<tagname>` inside the render() function.
|
|
149
|
+
*
|
|
150
|
+
* */
|
|
151
|
+
/*
|
|
152
|
+
static getTagName(Class) {
|
|
153
|
+
let code = Class.prototype.render.toString();
|
|
154
|
+
let i = 0;
|
|
155
|
+
while (i < code.length) {
|
|
156
|
+
let char = code[i];
|
|
157
|
+
let next = code[i + 1];
|
|
158
|
+
|
|
159
|
+
// Skip single line comments
|
|
160
|
+
if (char === '/' && next === '/') {
|
|
161
|
+
i = code.indexOf('\n', i);
|
|
162
|
+
if (i === -1) break;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Skip multi-line comments
|
|
166
|
+
if (char === '/' && next === '*') {
|
|
167
|
+
i = code.indexOf('*'+'/', i + 2);
|
|
168
|
+
if (i === -1) break;
|
|
169
|
+
i += 2;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
// Skip strings and template literals
|
|
173
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
174
|
+
let quote = char;
|
|
175
|
+
i++;
|
|
176
|
+
while (i < code.length) {
|
|
177
|
+
if (code[i] === '\\') i += 2;
|
|
178
|
+
else if (code[i] === quote) { i++; break; }
|
|
179
|
+
else i++;
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
// Skip regex literals (simple heuristic)
|
|
184
|
+
if (char === '/') {
|
|
185
|
+
let prev = code.slice(Math.max(0, i - 10), i).trim();
|
|
186
|
+
// If / is preceded by something that indicates an operator or start of expression
|
|
187
|
+
if (/[=(,;:[!&|?]$|return$|yield$|case$/.test(prev)) {
|
|
188
|
+
i++;
|
|
189
|
+
while (i < code.length) {
|
|
190
|
+
if (code[i] === '\\') i += 2;
|
|
191
|
+
else if (code[i] === '[') { // Skip character classes
|
|
192
|
+
i++;
|
|
193
|
+
while (i < code.length && code[i] !== ']') {
|
|
194
|
+
if (code[i] === '\\') i += 2;
|
|
195
|
+
else i++;
|
|
196
|
+
}
|
|
197
|
+
i++;
|
|
198
|
+
}
|
|
199
|
+
else if (code[i] === '/') { i++; break; }
|
|
200
|
+
else i++;
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Check for h(this)`
|
|
206
|
+
if (char === 'h' && code.slice(i, i + 8) === 'h(this)`') {
|
|
207
|
+
i += 8;
|
|
208
|
+
// We are now inside the template literal.
|
|
209
|
+
// Skip whitespace and HTML comments
|
|
210
|
+
while (i < code.length) {
|
|
211
|
+
// Skip JS template literal end (shouldn't happen before tag, but for safety)
|
|
212
|
+
if (code[i] === '`') return null;
|
|
213
|
+
|
|
214
|
+
// Skip whitespace
|
|
215
|
+
if (/\s/.test(code[i])) { i++; continue; }
|
|
216
|
+
|
|
217
|
+
// Skip HTML comments <!-- ... -->
|
|
218
|
+
if (code.slice(i, i + 4) === '<!--') {
|
|
219
|
+
i = code.indexOf('-->', i + 4);
|
|
220
|
+
if (i === -1) return null;
|
|
221
|
+
i += 3;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Find the first tag
|
|
226
|
+
if (code[i] === '<') {
|
|
227
|
+
let start = ++i;
|
|
228
|
+
while (i < code.length && /[a-zA-Z0-9-]/.test(code[i])) i++;
|
|
229
|
+
return code.slice(start, i);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// If we encounter anything else (like text before a tag),
|
|
233
|
+
// we can keep looking or return null depending on how strict we want to be.
|
|
234
|
+
// For now, let's just skip non-tag characters.
|
|
235
|
+
i++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
i++;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
*/
|
|
243
|
+
}
|