vasille 4.3.0 → 5.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 (41) hide show
  1. package/README.md +47 -31
  2. package/lib/dev/components.js +82 -0
  3. package/lib/dev/core.js +15 -0
  4. package/lib/dev/index.js +8 -0
  5. package/lib/dev/inspectable.js +113 -0
  6. package/lib/dev/models.js +147 -0
  7. package/lib/dev/node.js +59 -0
  8. package/lib/dev/runner.js +141 -0
  9. package/lib/dev/state.js +194 -0
  10. package/lib/dev/views.js +62 -0
  11. package/lib/index.js +1 -2
  12. package/lib/node/app.js +1 -1
  13. package/lib/node/node.js +16 -34
  14. package/lib/runner/web/binding/class.js +2 -15
  15. package/lib/runner/web/runner.js +25 -53
  16. package/lib/value/expression.js +3 -2
  17. package/lib/views/repeat-node.js +6 -2
  18. package/package.json +7 -1
  19. package/types/dev/components.d.ts +20 -0
  20. package/types/dev/core.d.ts +8 -0
  21. package/types/dev/index.d.ts +8 -0
  22. package/types/dev/inspectable.d.ts +244 -0
  23. package/types/dev/models.d.ts +38 -0
  24. package/types/dev/node.d.ts +12 -0
  25. package/types/dev/runner.d.ts +37 -0
  26. package/types/dev/state.d.ts +53 -0
  27. package/types/dev/views.d.ts +22 -0
  28. package/types/index.d.ts +2 -3
  29. package/types/node/app.d.ts +8 -9
  30. package/types/node/node.d.ts +17 -34
  31. package/types/node/runner.d.ts +2 -5
  32. package/types/node/watch.d.ts +5 -6
  33. package/types/runner/web/runner.d.ts +21 -25
  34. package/types/value/expression.d.ts +2 -1
  35. package/types/views/array-view.d.ts +3 -2
  36. package/types/views/base-view.d.ts +4 -4
  37. package/types/views/map-view.d.ts +2 -1
  38. package/types/views/repeat-node.d.ts +8 -7
  39. package/types/views/set-view.d.ts +3 -3
  40. package/lib/value/pointer.js +0 -61
  41. package/types/value/pointer.d.ts +0 -46
@@ -0,0 +1,141 @@
1
+ import { IValue } from "../core/ivalue.js";
2
+ import { Runner, Tag, TextNode } from "../runner/web/runner.js";
3
+ import { provideId, toDevId, toDevIdOrValue, toDevObject, toDevValue, } from "./inspectable.js";
4
+ import { DevExpression, DevReference } from "./state.js";
5
+ export class PositionedText {
6
+ text;
7
+ position;
8
+ constructor(text, position) {
9
+ this.text = text;
10
+ this.position = position;
11
+ }
12
+ }
13
+ export function positionedText(text, position) {
14
+ return new PositionedText(text, position);
15
+ }
16
+ export class DevTextNode extends TextNode {
17
+ id;
18
+ constructor(input, runner, usage, inspector) {
19
+ super(input, runner);
20
+ this.id = provideId();
21
+ inspector.createNode({
22
+ id: this.id,
23
+ time: Date.now(),
24
+ text: toDevIdOrValue(input.text),
25
+ position: usage,
26
+ });
27
+ }
28
+ destroy() {
29
+ this.runner.inspector.destroy({ id: this.id, time: Date.now() });
30
+ super.destroy();
31
+ }
32
+ compose() {
33
+ super.compose();
34
+ Object.defineProperty(this.node, "vasille", { value: this.id, configurable: false, enumerable: false });
35
+ }
36
+ }
37
+ export function remapObject(obj, transform) {
38
+ const r = {};
39
+ for (const key in obj) {
40
+ r[key] = transform(obj[key]);
41
+ }
42
+ return r;
43
+ }
44
+ export class DevTag extends Tag {
45
+ id;
46
+ constructor(options, runner, tagName, usage, inspector) {
47
+ super(options, runner, tagName);
48
+ this.id = provideId();
49
+ inspector.createTag({
50
+ id: this.id,
51
+ time: Date.now(),
52
+ tagName: tagName,
53
+ usage: usage,
54
+ callback: options.k && toDevIdOrValue(options.k),
55
+ attr: options.a && toDevObject(options.a),
56
+ class: options.c &&
57
+ options.c.map(item => {
58
+ if (typeof item === "string") {
59
+ return item;
60
+ }
61
+ if (item instanceof DevReference || item instanceof DevExpression) {
62
+ return item.id;
63
+ }
64
+ if (item instanceof IValue) {
65
+ return JSON.stringify(item.V);
66
+ }
67
+ return remapObject(item, toDevIdOrValue);
68
+ }),
69
+ style: options.s &&
70
+ remapObject(options.s, value => {
71
+ return typeof value === "number"
72
+ ? `${value}px`
73
+ : value instanceof Array
74
+ ? value.map(v => `${v}px`).join(" ")
75
+ : typeof value === "string"
76
+ ? value
77
+ : (toDevId(value) ?? "");
78
+ }),
79
+ events: options.e && remapObject(options.e, toDevValue),
80
+ bind: options.b && remapObject(options.b, toDevIdOrValue),
81
+ });
82
+ }
83
+ applyOptions(options) {
84
+ if (options.e) {
85
+ for (const [key, handler] of Object.entries(options.e)) {
86
+ if (handler instanceof Array) {
87
+ const userHandler = handler[0];
88
+ handler[0] = ev => {
89
+ this.runner.inspector.eventTrigger({
90
+ tagId: this.id,
91
+ eventName: key,
92
+ time: Date.now(),
93
+ });
94
+ userHandler(ev);
95
+ };
96
+ }
97
+ else {
98
+ options[key] = ev => {
99
+ this.runner.inspector.eventTrigger({
100
+ tagId: this.id,
101
+ eventName: key,
102
+ time: Date.now(),
103
+ });
104
+ handler(ev);
105
+ };
106
+ }
107
+ }
108
+ }
109
+ super.applyOptions(options);
110
+ }
111
+ getNode() {
112
+ return this.node;
113
+ }
114
+ destroy() {
115
+ this.runner.inspector.destroy({ id: this.id, time: Date.now() });
116
+ super.destroy();
117
+ }
118
+ compose() {
119
+ super.compose();
120
+ Object.defineProperty(this.element, "vasille", { value: this.id, configurable: false, enumerable: false });
121
+ }
122
+ }
123
+ export class DevRunner extends Runner {
124
+ inspector;
125
+ constructor(document, inspector) {
126
+ super(document);
127
+ this.inspector = inspector;
128
+ }
129
+ textNode(text) {
130
+ if (text instanceof PositionedText) {
131
+ return new DevTextNode({ text: text.text }, this, text.position, this.inspector);
132
+ }
133
+ return new TextNode({ text: text }, this);
134
+ }
135
+ tag(tagName, input, cb) {
136
+ if (cb) {
137
+ input.l = cb;
138
+ }
139
+ return new DevTag(input, this, tagName, input.usage, this.inspector);
140
+ }
141
+ }
@@ -0,0 +1,194 @@
1
+ import { IValue } from "../core/ivalue.js";
2
+ import { provideId, toDevValue, } from "./inspectable.js";
3
+ export class DevIValue extends IValue {
4
+ }
5
+ export class BaseDevReference extends DevIValue {
6
+ state;
7
+ onChange;
8
+ constructor(value) {
9
+ super();
10
+ this.state = value;
11
+ this.onChange = new Set();
12
+ }
13
+ get V() {
14
+ return this.state;
15
+ }
16
+ set V(value) {
17
+ this.update(value);
18
+ }
19
+ update(value, position) {
20
+ if (this.state !== value) {
21
+ this.state = value;
22
+ this.shareUpdate(position);
23
+ this.onChange.forEach(handler => {
24
+ try {
25
+ handler(value, position);
26
+ }
27
+ catch (e) {
28
+ this.shareError(e, position);
29
+ reportError(e);
30
+ }
31
+ });
32
+ }
33
+ }
34
+ on(handler) {
35
+ this.onChange.add(handler);
36
+ }
37
+ off(handler) {
38
+ this.onChange.delete(handler);
39
+ }
40
+ shareUpdate(position) {
41
+ void position;
42
+ }
43
+ shareError(error, position) {
44
+ void error;
45
+ void position;
46
+ }
47
+ }
48
+ export class DevReference extends BaseDevReference {
49
+ id;
50
+ inspector;
51
+ constructor(value, declaration, inspector) {
52
+ super(value);
53
+ this.id = provideId();
54
+ this.inspector = inspector;
55
+ inspector?.newReference({
56
+ id: this.id,
57
+ declaration: declaration,
58
+ value: toDevValue(this.state),
59
+ time: Date.now(),
60
+ });
61
+ }
62
+ destroy() {
63
+ this.shareDestroy();
64
+ }
65
+ shareUpdate(position) {
66
+ this.inspector?.updateReference({
67
+ id: this.id,
68
+ time: Date.now(),
69
+ position: position,
70
+ value: toDevValue(this.state),
71
+ });
72
+ }
73
+ shareError(error, position) {
74
+ this.inspector?.reportReferenceError({
75
+ targetId: this.id,
76
+ time: Date.now(),
77
+ error: error instanceof Error ? (error.stack ?? error.message) : `${error}`,
78
+ position: position,
79
+ });
80
+ }
81
+ shareDestroy() {
82
+ this.inspector?.destroy({ id: this.id, time: Date.now() });
83
+ }
84
+ }
85
+ export class ExpressionDevReference extends BaseDevReference {
86
+ id;
87
+ inspector;
88
+ constructor(id, value, inspector) {
89
+ super(value);
90
+ this.id = id;
91
+ this.inspector = inspector;
92
+ }
93
+ shareError(error, position) {
94
+ this.inspector?.reportReferenceError({
95
+ targetId: this.id,
96
+ time: Date.now(),
97
+ error: error instanceof Error ? (error.stack ?? error.message) : `${error}`,
98
+ position: position,
99
+ });
100
+ }
101
+ }
102
+ export class DevExpression extends IValue {
103
+ id;
104
+ declaration;
105
+ inspector;
106
+ values;
107
+ valuesCache;
108
+ linkedFunc = [];
109
+ sync;
110
+ constructor(func, values, ctx, depsCode, declaration, inspector, isWatch) {
111
+ super();
112
+ const id = provideId();
113
+ const handler = (i, value, position) => {
114
+ try {
115
+ this.valuesCache[i] = value;
116
+ const newValue = func.apply(this, this.valuesCache);
117
+ if (this.sync.V !== newValue || isWatch) {
118
+ this.sync.update(newValue, position);
119
+ inspector?.updateExpression({
120
+ id: id,
121
+ time: Date.now(),
122
+ position: position,
123
+ value: newValue,
124
+ deps: this.valuesCache.map(toDevValue),
125
+ });
126
+ }
127
+ }
128
+ catch (e) {
129
+ inspector?.reportExpressionCalculationError({
130
+ targetId: id,
131
+ time: Date.now(),
132
+ error: e instanceof Error ? (e.stack ?? e.message) : `${e}`,
133
+ position: position,
134
+ deps: this.valuesCache.map(toDevValue),
135
+ });
136
+ reportError(e);
137
+ }
138
+ };
139
+ this.valuesCache = values.map(item => item?.V);
140
+ this.sync = new ExpressionDevReference(id, func.apply(this, this.valuesCache), inspector);
141
+ this.id = id;
142
+ this.declaration = declaration;
143
+ this.inspector = inspector;
144
+ let i = 0;
145
+ values.forEach(value => {
146
+ const updater = handler.bind(this, Number(i++));
147
+ this.linkedFunc.push(updater);
148
+ value?.on(updater);
149
+ });
150
+ this.values = values;
151
+ ctx?.bind(this);
152
+ inspector?.newExpression({
153
+ id: this.id,
154
+ declaration: this.declaration,
155
+ isWatch: isWatch,
156
+ value: toDevValue(this.sync.V),
157
+ deps: values.map((dep, index) => {
158
+ if (dep instanceof DevReference || dep instanceof DevExpression) {
159
+ return {
160
+ code: depsCode[index],
161
+ id: dep.id,
162
+ value: toDevValue(dep.V),
163
+ };
164
+ }
165
+ return depsCode[index];
166
+ }),
167
+ time: Date.now(),
168
+ });
169
+ }
170
+ update(value, position) {
171
+ this.sync.update(value, position);
172
+ }
173
+ get V() {
174
+ return this.sync.V;
175
+ }
176
+ set V(v) {
177
+ this.sync.V = v;
178
+ }
179
+ on(handler) {
180
+ this.sync.on(handler);
181
+ }
182
+ off(handler) {
183
+ this.sync.off(handler);
184
+ }
185
+ destroy() {
186
+ this.inspector?.destroy({ id: this.id, time: Date.now() });
187
+ for (let i = 0; i < this.values.length; i++) {
188
+ this.values[i]?.off(this.linkedFunc[i]);
189
+ }
190
+ this.values.splice(0);
191
+ this.valuesCache.splice(0);
192
+ this.linkedFunc.splice(0);
193
+ }
194
+ }
@@ -0,0 +1,62 @@
1
+ import { ArrayView } from "../views/array-view.js";
2
+ import { MapView } from "../views/map-view.js";
3
+ import { SetView } from "../views/set-view.js";
4
+ import { provideId, toDevObject } from "./inspectable.js";
5
+ import { DevFragment } from "./node.js";
6
+ export class DevArrayView extends ArrayView {
7
+ id;
8
+ constructor(input, runner, usage) {
9
+ super(input, runner);
10
+ this.id = provideId();
11
+ runner.inspector.createComponent({
12
+ id: this.id,
13
+ name: "ArrayView",
14
+ props: toDevObject(input),
15
+ usage: usage,
16
+ time: Date.now(),
17
+ });
18
+ }
19
+ newChild(id, item) {
20
+ const frag = new DevFragment(this.runner, null, null, "ArrayViewItem", { item });
21
+ this.runner.inspector?.setElementParent({ parent: this.id, child: frag.id });
22
+ return frag;
23
+ }
24
+ }
25
+ export class DevSetView extends SetView {
26
+ id;
27
+ constructor(input, runner, usage) {
28
+ super(input, runner);
29
+ this.id = provideId();
30
+ runner.inspector.createComponent({
31
+ id: this.id,
32
+ name: "SetView",
33
+ props: toDevObject(input),
34
+ usage: usage,
35
+ time: Date.now(),
36
+ });
37
+ }
38
+ newChild(_id, item) {
39
+ const frag = new DevFragment(this.runner, null, null, "SetViewItem", { item });
40
+ this.runner.inspector.setElementParent({ parent: this.id, child: frag.id });
41
+ return frag;
42
+ }
43
+ }
44
+ export class DevMapView extends MapView {
45
+ id;
46
+ constructor(input, runner, usage) {
47
+ super(input, runner);
48
+ this.id = provideId();
49
+ runner.inspector.createComponent({
50
+ id: this.id,
51
+ name: "MapView",
52
+ props: toDevObject(input),
53
+ usage: usage,
54
+ time: Date.now(),
55
+ });
56
+ }
57
+ newChild(key, value) {
58
+ const frag = new DevFragment(this.runner, null, null, "MapViewItem", { key, value });
59
+ this.runner.inspector.setElementParent({ parent: this.id, child: frag.id });
60
+ return frag;
61
+ }
62
+ }
package/lib/index.js CHANGED
@@ -6,9 +6,8 @@ export { Listener } from "./models/listener.js";
6
6
  export { MapModel } from "./models/map-model.js";
7
7
  export { SetModel } from "./models/set-model.js";
8
8
  export { App, Portal } from "./node/app.js";
9
- export { Fragment, Tag, TextNode, DebugNode, SwitchedNode } from "./node/node.js";
9
+ export { Fragment, Tag, TextNode, SwitchedNode } from "./node/node.js";
10
10
  export { Expression } from "./value/expression.js";
11
- export { Forward, Backward } from "./value/pointer.js";
12
11
  export { Reference } from "./value/reference.js";
13
12
  export { ArrayView } from "./views/array-view.js";
14
13
  export { BaseView } from "./views/base-view.js";
package/lib/node/app.js CHANGED
@@ -9,7 +9,7 @@ export class App extends Root {
9
9
  /**
10
10
  * Constructs an app node
11
11
  * @param node {Element} The root of application
12
- * @param runner {Runner} A adapter which execute DOM manipulation
12
+ * @param runner {IRunner} A adapter which execute DOM manipulation
13
13
  */
14
14
  constructor(node, runner) {
15
15
  super(runner);
package/lib/node/node.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Reactive } from "../core/core.js";
2
2
  import { IValue } from "../core/ivalue.js";
3
- import { SetModel } from "../models/set-model.js";
4
- import { Reference } from "../value/reference.js";
3
+ import { safe } from "../functional/safety.js";
5
4
  /**
6
5
  * This class is symbolic
7
6
  * @extends Reactive
@@ -17,7 +16,7 @@ export class Root extends Reactive {
17
16
  constructor(runner) {
18
17
  super();
19
18
  this.runner = runner;
20
- this.children = runner.debugUi ? new SetModel() : new Set();
19
+ this.children = new Set();
21
20
  }
22
21
  /**
23
22
  * Pushes a node to children immediately
@@ -50,11 +49,6 @@ export class Root extends Reactive {
50
49
  this.pushNode(node);
51
50
  node.compose();
52
51
  }
53
- debug(text) {
54
- const node = this.runner.debugNode(text);
55
- this.pushNode(node);
56
- node.compose();
57
- }
58
52
  /**
59
53
  * Defines a tag element
60
54
  * @param tagName {String} the tag name
@@ -229,7 +223,6 @@ export class Tag extends INode {
229
223
  this.runner.appendChild(this.node, node);
230
224
  }
231
225
  }
232
- const alwaysTrue = new Reference(true);
233
226
  /**
234
227
  * Defines a node which can switch its children conditionally
235
228
  */
@@ -255,11 +248,11 @@ export class SwitchedNode extends Fragment {
255
248
  constructor(runner, cases, _default) {
256
249
  super(runner);
257
250
  if (_default) {
258
- cases.push({ $case: alwaysTrue, slot: _default });
251
+ cases.push({ $case: 1, slot: _default });
259
252
  }
260
253
  this.cases = cases;
261
254
  this.sync = () => {
262
- let i = this.cases.findIndex(item => item.$case.V);
255
+ let i = this.cases.findIndex(item => (item.$case instanceof IValue ? item.$case.V : item.$case));
263
256
  if (i === this.index) {
264
257
  return;
265
258
  }
@@ -269,19 +262,22 @@ export class SwitchedNode extends Fragment {
269
262
  this.lastChild = undefined;
270
263
  }
271
264
  if (i !== -1) {
272
- const node = new Fragment(this.runner);
265
+ const node = this.newChild(i);
273
266
  node.parent = this;
274
267
  this.lastChild = node;
275
268
  this.children.add(node);
276
269
  this.index = i;
277
- this.cases[i].slot(node);
270
+ safe(this.cases[i].slot)(node);
278
271
  }
279
272
  else {
280
273
  this.index = -1;
281
274
  }
282
275
  };
283
276
  cases.forEach(_case => {
284
- _case.$case.on(this.sync);
277
+ const item = _case.$case;
278
+ if (item instanceof IValue) {
279
+ item.on(this.sync);
280
+ }
285
281
  });
286
282
  }
287
283
  compose() {
@@ -289,29 +285,15 @@ export class SwitchedNode extends Fragment {
289
285
  }
290
286
  destroy() {
291
287
  this.cases.forEach(c => {
292
- c.$case.off(this.sync);
288
+ const item = c.$case;
289
+ if (item instanceof IValue) {
290
+ item.off(this.sync);
291
+ }
293
292
  });
294
293
  this.cases.splice(0);
295
294
  super.destroy();
296
295
  }
297
- }
298
- /**
299
- * Represents a debug node
300
- * @class DebugNode
301
- * @extends Fragment
302
- */
303
- export class DebugNode extends Fragment {
304
- handler = null;
305
- data;
306
- constructor(input, runner) {
307
- super(runner);
308
- this.data = input.text;
309
- }
310
- destroy() {
311
- /* istanbul ignore else */
312
- if (this.handler) {
313
- this.data.off(this.handler);
314
- }
315
- super.destroy();
296
+ newChild(_index) {
297
+ return new Fragment(this.runner);
316
298
  }
317
299
  }
@@ -1,22 +1,9 @@
1
1
  import { Binding } from "./binding.js";
2
2
  export function addClass(node, cl) {
3
- if (process.env.VASILLE_TARGET === "es5" && !node.element.classList) {
4
- node.element.className = [...node.element.className.split(" "), cl].filter(item => !!item).join(" ");
5
- }
6
- else {
7
- node.element.classList.add(cl);
8
- }
3
+ node.element.classList.add(cl);
9
4
  }
10
5
  export function removeClass(node, cl) {
11
- if (process.env.VASILLE_TARGET === "es5" && !node.element.classList) {
12
- node.element.className = node.element.className
13
- .split(" ")
14
- .filter(name => name !== cl)
15
- .join(" ");
16
- }
17
- else {
18
- node.element.classList.remove(cl);
19
- }
6
+ node.element.classList.remove(cl);
20
7
  }
21
8
  export class StaticClassBinding extends Binding {
22
9
  current = false;