vasille 4.3.1 → 5.0.1

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 (42) hide show
  1. package/README.md +71 -37
  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/models/set-model.js +1 -0
  13. package/lib/node/app.js +1 -1
  14. package/lib/node/node.js +14 -33
  15. package/lib/runner/web/binding/class.js +2 -15
  16. package/lib/runner/web/runner.js +25 -53
  17. package/lib/value/expression.js +3 -2
  18. package/lib/views/repeat-node.js +4 -1
  19. package/package.json +7 -1
  20. package/types/dev/components.d.ts +20 -0
  21. package/types/dev/core.d.ts +8 -0
  22. package/types/dev/index.d.ts +8 -0
  23. package/types/dev/inspectable.d.ts +244 -0
  24. package/types/dev/models.d.ts +38 -0
  25. package/types/dev/node.d.ts +12 -0
  26. package/types/dev/runner.d.ts +37 -0
  27. package/types/dev/state.d.ts +53 -0
  28. package/types/dev/views.d.ts +22 -0
  29. package/types/index.d.ts +2 -3
  30. package/types/node/app.d.ts +8 -9
  31. package/types/node/node.d.ts +17 -34
  32. package/types/node/runner.d.ts +2 -5
  33. package/types/node/watch.d.ts +5 -6
  34. package/types/runner/web/runner.d.ts +21 -25
  35. package/types/value/expression.d.ts +2 -1
  36. package/types/views/array-view.d.ts +3 -2
  37. package/types/views/base-view.d.ts +4 -4
  38. package/types/views/map-view.d.ts +2 -1
  39. package/types/views/repeat-node.d.ts +7 -6
  40. package/types/views/set-view.d.ts +3 -3
  41. package/lib/value/pointer.js +0 -61
  42. 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";
@@ -46,6 +46,7 @@ export class SetModel extends Set {
46
46
  * @return {boolean} true if a value was deleted, otherwise false
47
47
  */
48
48
  delete(value) {
49
+ /* istanbul ignore else */
49
50
  if (super.has(value)) {
50
51
  this.listener.emitRemoved(value, value);
51
52
  }
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,8 +1,6 @@
1
1
  import { Reactive } from "../core/core.js";
2
2
  import { IValue } from "../core/ivalue.js";
3
3
  import { safe } from "../functional/safety.js";
4
- import { SetModel } from "../models/set-model.js";
5
- import { Reference } from "../value/reference.js";
6
4
  /**
7
5
  * This class is symbolic
8
6
  * @extends Reactive
@@ -18,7 +16,7 @@ export class Root extends Reactive {
18
16
  constructor(runner) {
19
17
  super();
20
18
  this.runner = runner;
21
- this.children = runner.debugUi ? new SetModel() : new Set();
19
+ this.children = new Set();
22
20
  }
23
21
  /**
24
22
  * Pushes a node to children immediately
@@ -51,11 +49,6 @@ export class Root extends Reactive {
51
49
  this.pushNode(node);
52
50
  node.compose();
53
51
  }
54
- debug(text) {
55
- const node = this.runner.debugNode(text);
56
- this.pushNode(node);
57
- node.compose();
58
- }
59
52
  /**
60
53
  * Defines a tag element
61
54
  * @param tagName {String} the tag name
@@ -230,7 +223,6 @@ export class Tag extends INode {
230
223
  this.runner.appendChild(this.node, node);
231
224
  }
232
225
  }
233
- const alwaysTrue = new Reference(true);
234
226
  /**
235
227
  * Defines a node which can switch its children conditionally
236
228
  */
@@ -256,11 +248,11 @@ export class SwitchedNode extends Fragment {
256
248
  constructor(runner, cases, _default) {
257
249
  super(runner);
258
250
  if (_default) {
259
- cases.push({ $case: alwaysTrue, slot: _default });
251
+ cases.push({ $case: 1, slot: _default });
260
252
  }
261
253
  this.cases = cases;
262
254
  this.sync = () => {
263
- 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));
264
256
  if (i === this.index) {
265
257
  return;
266
258
  }
@@ -270,7 +262,7 @@ export class SwitchedNode extends Fragment {
270
262
  this.lastChild = undefined;
271
263
  }
272
264
  if (i !== -1) {
273
- const node = new Fragment(this.runner);
265
+ const node = this.newChild(i);
274
266
  node.parent = this;
275
267
  this.lastChild = node;
276
268
  this.children.add(node);
@@ -282,7 +274,10 @@ export class SwitchedNode extends Fragment {
282
274
  }
283
275
  };
284
276
  cases.forEach(_case => {
285
- _case.$case.on(this.sync);
277
+ const item = _case.$case;
278
+ if (item instanceof IValue) {
279
+ item.on(this.sync);
280
+ }
286
281
  });
287
282
  }
288
283
  compose() {
@@ -290,29 +285,15 @@ export class SwitchedNode extends Fragment {
290
285
  }
291
286
  destroy() {
292
287
  this.cases.forEach(c => {
293
- c.$case.off(this.sync);
288
+ const item = c.$case;
289
+ if (item instanceof IValue) {
290
+ item.off(this.sync);
291
+ }
294
292
  });
295
293
  this.cases.splice(0);
296
294
  super.destroy();
297
295
  }
298
- }
299
- /**
300
- * Represents a debug node
301
- * @class DebugNode
302
- * @extends Fragment
303
- */
304
- export class DebugNode extends Fragment {
305
- handler = null;
306
- data;
307
- constructor(input, runner) {
308
- super(runner);
309
- this.data = input.text;
310
- }
311
- destroy() {
312
- /* istanbul ignore else */
313
- if (this.handler) {
314
- this.data.off(this.handler);
315
- }
316
- super.destroy();
296
+ newChild(_index) {
297
+ return new Fragment(this.runner);
317
298
  }
318
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;