vasille-jsx 3.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.
- package/README.md +122 -0
- package/lib/components.js +148 -0
- package/lib/compose.js +46 -0
- package/lib/expression.js +52 -0
- package/lib/index.js +4 -0
- package/lib/inline.js +23 -0
- package/lib/internal.js +43 -0
- package/lib/library.js +25 -0
- package/lib/models.js +170 -0
- package/lib/objects.js +78 -0
- package/lib/spec/html.js +1 -0
- package/lib/spec/svg.js +1 -0
- package/lib-node/components.js +162 -0
- package/lib-node/compose.js +51 -0
- package/lib-node/expression.js +56 -0
- package/lib-node/index.js +23 -0
- package/lib-node/inline.js +28 -0
- package/lib-node/internal.js +46 -0
- package/lib-node/library.js +29 -0
- package/lib-node/models.js +176 -0
- package/lib-node/objects.js +86 -0
- package/lib-node/spec/html.js +2 -0
- package/lib-node/spec/svg.js +2 -0
- package/package.json +42 -0
- package/types/components.d.ts +46 -0
- package/types/compose.d.ts +11 -0
- package/types/expression.d.ts +14 -0
- package/types/index.d.ts +6 -0
- package/types/inline.d.ts +4 -0
- package/types/internal.d.ts +31 -0
- package/types/library.d.ts +3 -0
- package/types/models.d.ts +31 -0
- package/types/objects.d.ts +14 -0
- package/types/spec/html.d.ts +974 -0
- package/types/spec/svg.d.ts +314 -0
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Vasille
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
`Vasille Web` is a front-end framework, which is developed to provide the best `developer experience` ever. **Our goal is to keep is as simple as possible.** Developing web applications using Vasille must be *as fast as possible*.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/vasille)
|
|
8
|
+
|
|
9
|
+
## Table of content
|
|
10
|
+
|
|
11
|
+
* [Installation](#installation)
|
|
12
|
+
* [How to use Vasille](#how-to-use-vasille)
|
|
13
|
+
* [How SAFE is Vasille](#how-safe-is-vasille)
|
|
14
|
+
* [How SIMPLE is Vasille](#how-simple-is-vasille)
|
|
15
|
+
* [How POWERFUL is Vasille](#how-powerful-is-vasille)
|
|
16
|
+
* [Road Map](#road-map)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<hr>
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npm install vasille-web --save
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How to use Vasille
|
|
28
|
+
|
|
29
|
+
Create an app from a template
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
$ npx create vasille
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Alternative method to create a TypeScript app.
|
|
36
|
+
```bash
|
|
37
|
+
$ npx degit vasille-js/example-typescript my-project
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Alternative method to create a JavaScript app.
|
|
41
|
+
```bash
|
|
42
|
+
$ npx degit vasille-js/example-javascript my-project
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Full documentation:
|
|
46
|
+
* [Learn `Vasille` in 5 minutes](https://github.com/vasille-js/vasille-js/blob/v3/doc/V3-API.md)
|
|
47
|
+
|
|
48
|
+
### Examples
|
|
49
|
+
* [TypeScript Example](https://github.com/vasille-js/example-typescript)
|
|
50
|
+
* [JavaScript Example](https://github.com/vas[README.md](..%2Ftest%2Fmy-app%2FREADME.md)ille-js/example-javascript)
|
|
51
|
+
|
|
52
|
+
<hr>
|
|
53
|
+
|
|
54
|
+
## How SAFE is Vasille
|
|
55
|
+
|
|
56
|
+
The safe of your application is ensured by
|
|
57
|
+
* `100%` coverage of code by unit tests.
|
|
58
|
+
Each function, each branch is working as designed.
|
|
59
|
+
* OOP, DRY, KISS and SOLID principles are applied.
|
|
60
|
+
* `strong typing` makes your javascript/typescript code safe as C++ code.
|
|
61
|
+
All entities of `vasille` core library are strongly typed, including:
|
|
62
|
+
* data fields & properties.
|
|
63
|
+
* computed properties (function parameters & result).
|
|
64
|
+
* methods.
|
|
65
|
+
* events (defined handlers & event emit).
|
|
66
|
+
* DOM events & DOM operation (attributing, styling, etc.).
|
|
67
|
+
* slots of components.
|
|
68
|
+
* references to children.
|
|
69
|
+
* No asynchronous code, when the line of code is executed, the DOM and reactive things are already synced.
|
|
70
|
+
|
|
71
|
+
## How SIMPLE is Vasille
|
|
72
|
+
|
|
73
|
+
There is the "Hello World":
|
|
74
|
+
```typescript jsx
|
|
75
|
+
import { compose, mount } from "vasille-dx";
|
|
76
|
+
|
|
77
|
+
const App = compose(() => {
|
|
78
|
+
<p>Hello world</p>;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
mount(document.body, App, {});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## How POWERFUL is Vasille
|
|
85
|
+
|
|
86
|
+
All of these are supported:
|
|
87
|
+
* Components.
|
|
88
|
+
* Reactive values (observables).
|
|
89
|
+
* Inline computed values.
|
|
90
|
+
* Multiline computed values.
|
|
91
|
+
* HTML & SVG tags.
|
|
92
|
+
* Component custom slots.
|
|
93
|
+
* 2-way data binding in components.
|
|
94
|
+
* Logic block (if, else).
|
|
95
|
+
* Loops (array, map, set).
|
|
96
|
+
|
|
97
|
+
<hr>
|
|
98
|
+
|
|
99
|
+
## Road map
|
|
100
|
+
|
|
101
|
+
* [x] Update the `Vasille Core` library to version 3.0.
|
|
102
|
+
* [x] `100%` Test Coverage for core Library v3.
|
|
103
|
+
* [x] Develop the `Vasille JSX` library.
|
|
104
|
+
* [x] `100%` Test Coverage for the JSX library.
|
|
105
|
+
* [x] Develop the `Vasille Babel Plugin`.
|
|
106
|
+
* [ ] `100%` Test Coverage fot babel plugin.
|
|
107
|
+
* [ ] Add CSS support (define styles in components).
|
|
108
|
+
* [ ] Add custom `<input/>` components with 2-way value binding.
|
|
109
|
+
* [ ] Add router.
|
|
110
|
+
* [ ] Develop dev-tools extension for debugging.
|
|
111
|
+
* [ ] Develop a lot of libraries for the framework.
|
|
112
|
+
|
|
113
|
+
## Questions
|
|
114
|
+
|
|
115
|
+
If you have questions, feel free to contact the maintainer of the project:
|
|
116
|
+
|
|
117
|
+
* [Author's Email](mailto:vas.lixcode@gmail.com)
|
|
118
|
+
* [Author's Telegram](https://t.me/lixcode)
|
|
119
|
+
|
|
120
|
+
<hr>
|
|
121
|
+
|
|
122
|
+
**Made in Moldova** 🇲🇩
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ArrayModel, ArrayView, Fragment, IValue, MapModel, MapView, SetModel, SetView, userError, Watch as CoreWatch, Tag, } from "vasille";
|
|
2
|
+
export function readValue(v) {
|
|
3
|
+
return v instanceof IValue ? v.$ : v;
|
|
4
|
+
}
|
|
5
|
+
export function Adapter(ctx, { node, slot }) {
|
|
6
|
+
const dNode = readValue(node);
|
|
7
|
+
const dSlot = readValue(slot);
|
|
8
|
+
if (dNode && dSlot) {
|
|
9
|
+
ctx.create(dNode, dSlot);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function Slot(ctx, options) {
|
|
13
|
+
var _a;
|
|
14
|
+
const model = readValue(options.model);
|
|
15
|
+
if (model) {
|
|
16
|
+
if (model.length <= 1) {
|
|
17
|
+
for (const key in options) {
|
|
18
|
+
if (options[key] instanceof IValue) {
|
|
19
|
+
options[key] = options[key].$;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
for (const key in options) {
|
|
25
|
+
if (!(options[key] instanceof IValue)) {
|
|
26
|
+
options[key] = ctx.ref(options[key]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
model(options, ctx);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
(_a = readValue(options.slot)) === null || _a === void 0 ? void 0 : _a(ctx);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function If(ctx, { condition, slot: magicSlot }) {
|
|
37
|
+
const slot = readValue(magicSlot);
|
|
38
|
+
ctx.if(condition instanceof IValue ? condition : ctx.ref(condition), slot !== null && slot !== void 0 ? slot : (() => { }));
|
|
39
|
+
}
|
|
40
|
+
export function ElseIf(ctx, { condition, slot: magicSlot }) {
|
|
41
|
+
const slot = readValue(magicSlot);
|
|
42
|
+
ctx.elif(condition instanceof IValue ? condition : ctx.ref(condition), slot !== null && slot !== void 0 ? slot : (() => { }));
|
|
43
|
+
}
|
|
44
|
+
export function Else(ctx, { slot: magicSlot }) {
|
|
45
|
+
const slot = readValue(magicSlot);
|
|
46
|
+
if (slot) {
|
|
47
|
+
ctx.else(slot);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function For(ctx, { of, slot: magicSlot }) {
|
|
51
|
+
const slot = readValue(magicSlot);
|
|
52
|
+
if (of instanceof IValue) {
|
|
53
|
+
ctx.create(new CoreWatch({
|
|
54
|
+
model: of,
|
|
55
|
+
slot: function (ctx, model) {
|
|
56
|
+
create(model, ctx);
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
else if (of) {
|
|
61
|
+
create(of, ctx);
|
|
62
|
+
}
|
|
63
|
+
function create(model, node) {
|
|
64
|
+
if (!slot) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (model instanceof ArrayModel) {
|
|
68
|
+
node.create(new ArrayView({
|
|
69
|
+
model,
|
|
70
|
+
slot: slot,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
else if (model instanceof MapModel) {
|
|
74
|
+
node.create(new MapView({
|
|
75
|
+
model,
|
|
76
|
+
slot,
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
else if (model instanceof SetModel) {
|
|
80
|
+
node.create(new SetView({
|
|
81
|
+
model,
|
|
82
|
+
slot,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
// fallback if is used external Array/Map/Set
|
|
86
|
+
else {
|
|
87
|
+
console.warn("Vasille <For of/> fallback detected. Please provide reactive data.");
|
|
88
|
+
if (model instanceof Array) {
|
|
89
|
+
model.forEach((value) => {
|
|
90
|
+
slot(node, value, value);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else if (model instanceof Map) {
|
|
94
|
+
for (const [key, value] of model) {
|
|
95
|
+
slot(node, value, key);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (model instanceof Set) {
|
|
99
|
+
for (const value of model) {
|
|
100
|
+
slot(node, value, value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
throw userError("wrong use of `<For of/>` component", "wrong-model");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export function Watch(ctx, { model, slot: magicSlot }) {
|
|
110
|
+
const slot = readValue(magicSlot);
|
|
111
|
+
if (slot && model instanceof IValue) {
|
|
112
|
+
ctx.create(new CoreWatch({ model, slot }));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function Debug(ctx, { model }) {
|
|
116
|
+
const value = model instanceof IValue ? model : ctx.ref(model);
|
|
117
|
+
ctx.debug(value);
|
|
118
|
+
}
|
|
119
|
+
export function Mount(ctx, { bind }) {
|
|
120
|
+
if (!(ctx instanceof Tag)) {
|
|
121
|
+
throw userError("<Mount bind/> can be used only as direct child of html tags", "context-mismatch");
|
|
122
|
+
}
|
|
123
|
+
ctx.bindMount(bind instanceof IValue ? bind : ctx.ref(bind));
|
|
124
|
+
}
|
|
125
|
+
export function Show(ctx, { bind }) {
|
|
126
|
+
if (!(ctx instanceof Tag)) {
|
|
127
|
+
throw userError("<Show bind/> can be used only as direct child of html tags", "context-mismatch");
|
|
128
|
+
}
|
|
129
|
+
ctx.bindShow(bind instanceof IValue ? bind : ctx.ref(bind));
|
|
130
|
+
}
|
|
131
|
+
export function Delay(ctx, { time, slot }) {
|
|
132
|
+
const fragment = new Fragment({}, ":timer");
|
|
133
|
+
const dSlot = readValue(slot);
|
|
134
|
+
let timer;
|
|
135
|
+
ctx.create(fragment, function (node) {
|
|
136
|
+
if (dSlot) {
|
|
137
|
+
timer = setTimeout(() => {
|
|
138
|
+
dSlot(node);
|
|
139
|
+
timer = undefined;
|
|
140
|
+
}, readValue(time));
|
|
141
|
+
}
|
|
142
|
+
node.runOnDestroy(() => {
|
|
143
|
+
if (timer !== undefined) {
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
package/lib/compose.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Extension, Fragment, config, App, reportError, IValue, Reference } from "vasille";
|
|
2
|
+
function proxy(obj) {
|
|
3
|
+
return new Proxy(obj, {
|
|
4
|
+
get(target, p) {
|
|
5
|
+
return p in target && target[p] instanceof IValue ? target[p] : new Reference(target[p]);
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function create(renderer, create, name) {
|
|
10
|
+
return function (node, props, slot) {
|
|
11
|
+
const frag = create(props);
|
|
12
|
+
if (slot) {
|
|
13
|
+
props.slot = slot;
|
|
14
|
+
}
|
|
15
|
+
node.create(frag);
|
|
16
|
+
try {
|
|
17
|
+
const result = renderer(frag, proxy(props));
|
|
18
|
+
if (result !== undefined && props.callback) {
|
|
19
|
+
props.callback(result);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (config.debugUi) {
|
|
24
|
+
console.error(`Vasille: Error found in component ${name}`, e);
|
|
25
|
+
}
|
|
26
|
+
reportError(e);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function compose(renderer, name) {
|
|
31
|
+
return create(renderer, props => {
|
|
32
|
+
return new Fragment(props, name);
|
|
33
|
+
}, name);
|
|
34
|
+
}
|
|
35
|
+
export function extend(renderer, name) {
|
|
36
|
+
return create(renderer, props => {
|
|
37
|
+
return new Extension(props, name);
|
|
38
|
+
}, name);
|
|
39
|
+
}
|
|
40
|
+
export function mount(tag, component, $) {
|
|
41
|
+
const root = new App(tag, {});
|
|
42
|
+
const frag = new Fragment({}, ":app-root");
|
|
43
|
+
root.create(frag, function () {
|
|
44
|
+
component(frag, $);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { IValue, Reference } from "vasille";
|
|
2
|
+
export class PartialExpression extends IValue {
|
|
3
|
+
constructor(func, values) {
|
|
4
|
+
super();
|
|
5
|
+
this.linkedFunc = [];
|
|
6
|
+
const handler = (i) => {
|
|
7
|
+
if (typeof i === "number") {
|
|
8
|
+
const dependency = this.values[i];
|
|
9
|
+
if (dependency instanceof IValue) {
|
|
10
|
+
this.valuesCache[i] = dependency.$;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
this.sync.$ = func.apply(this, this.valuesCache);
|
|
14
|
+
};
|
|
15
|
+
this.valuesCache = values.map(item => (item instanceof IValue ? item.$ : item));
|
|
16
|
+
this.sync = new Reference(func.apply(this, this.valuesCache));
|
|
17
|
+
let i = 0;
|
|
18
|
+
for (const value of values) {
|
|
19
|
+
const index = i++;
|
|
20
|
+
if (value instanceof IValue) {
|
|
21
|
+
value.on((this.linkedFunc[index] = handler.bind(this, index)));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
this.values = values;
|
|
25
|
+
this.func = handler;
|
|
26
|
+
handler();
|
|
27
|
+
}
|
|
28
|
+
get $() {
|
|
29
|
+
return this.sync.$;
|
|
30
|
+
}
|
|
31
|
+
set $(value) {
|
|
32
|
+
this.sync.$ = value;
|
|
33
|
+
}
|
|
34
|
+
on(handler) {
|
|
35
|
+
this.sync.on(handler);
|
|
36
|
+
}
|
|
37
|
+
off(handler) {
|
|
38
|
+
this.sync.off(handler);
|
|
39
|
+
}
|
|
40
|
+
destroy() {
|
|
41
|
+
for (let i = 0; i < this.values.length; i++) {
|
|
42
|
+
const value = this.values[i];
|
|
43
|
+
if (value instanceof IValue) {
|
|
44
|
+
value.off(this.linkedFunc[i]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
this.values.splice(0);
|
|
48
|
+
this.valuesCache.splice(0);
|
|
49
|
+
this.linkedFunc.splice(0);
|
|
50
|
+
super.destroy();
|
|
51
|
+
}
|
|
52
|
+
}
|
package/lib/index.js
ADDED
package/lib/inline.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Fragment, IValue, Pointer, userError } from "vasille";
|
|
2
|
+
export function readValue(v) {
|
|
3
|
+
return v instanceof IValue ? v.$ : v;
|
|
4
|
+
}
|
|
5
|
+
export function setValue(target, value, fallback) {
|
|
6
|
+
if (target instanceof IValue) {
|
|
7
|
+
if (target instanceof Pointer && value instanceof IValue) {
|
|
8
|
+
target.$$ = value;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
target.$ = value instanceof IValue ? value.$ : value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
fallback === null || fallback === void 0 ? void 0 : fallback(value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function asFragment(node) {
|
|
19
|
+
if (!(node instanceof Fragment)) {
|
|
20
|
+
throw userError("missing context", "out-of-context");
|
|
21
|
+
}
|
|
22
|
+
return node;
|
|
23
|
+
}
|
package/lib/internal.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { proxyArrayModel, Expression, Pointer, Reference } from "vasille";
|
|
2
|
+
import { reactiveObject, reactiveObjectProxy } from "./objects";
|
|
3
|
+
import { ContextArray, ContextMap, ContextSet } from "./models";
|
|
4
|
+
export const internal = {
|
|
5
|
+
/** create an expression (without context), use it for OwningPointer */
|
|
6
|
+
ex(func, ...values) {
|
|
7
|
+
return new Expression(func, ...values);
|
|
8
|
+
},
|
|
9
|
+
/** create a forward-only pointer (without context), use it for OwningPointer */
|
|
10
|
+
fo(v) {
|
|
11
|
+
return new Pointer(v);
|
|
12
|
+
},
|
|
13
|
+
/** create a reference (without context), use it for default composing props values */
|
|
14
|
+
r(v) {
|
|
15
|
+
return new Reference(v);
|
|
16
|
+
},
|
|
17
|
+
/** create a reactive object proxy, use it for sending reactive objects to child components */
|
|
18
|
+
rop(o) {
|
|
19
|
+
return reactiveObjectProxy(o);
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* translate `{...}` to `$.ro(this, {...})`
|
|
23
|
+
*/
|
|
24
|
+
ro: reactiveObject,
|
|
25
|
+
/**
|
|
26
|
+
* translate `new Set(#)` to `$.sm(this, #)`
|
|
27
|
+
*/
|
|
28
|
+
sm(node, data) {
|
|
29
|
+
return node.register(new ContextSet(data));
|
|
30
|
+
},
|
|
31
|
+
/**
|
|
32
|
+
* translate `new Map(#)` to `$.mm(this, #)`
|
|
33
|
+
*/
|
|
34
|
+
mm(node, data) {
|
|
35
|
+
return node.register(new ContextMap(data));
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* translate `[...]` to `$.am(this, [...])`
|
|
39
|
+
*/
|
|
40
|
+
am(node, data) {
|
|
41
|
+
return node.register(proxyArrayModel(new ContextArray(data)));
|
|
42
|
+
},
|
|
43
|
+
};
|
package/lib/library.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IValue } from "vasille";
|
|
2
|
+
export function awaited(node, target) {
|
|
3
|
+
const value = node.ref(undefined);
|
|
4
|
+
const err = node.ref(undefined);
|
|
5
|
+
let current = target;
|
|
6
|
+
if (typeof current === "function") {
|
|
7
|
+
try {
|
|
8
|
+
current = current();
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
current = undefined;
|
|
12
|
+
err.$ = e;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (current instanceof Promise) {
|
|
16
|
+
current.then(result => (value.$ = result)).catch(e => (err.$ = e));
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
value.$ = current;
|
|
20
|
+
}
|
|
21
|
+
return [err, value];
|
|
22
|
+
}
|
|
23
|
+
export function ensureIValue(node, value) {
|
|
24
|
+
return value instanceof IValue ? value : node.ref(value);
|
|
25
|
+
}
|
package/lib/models.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _Context_instances, _Context_ctx, _Context_enableObject, _Context_disableObject;
|
|
7
|
+
import { ArrayModel, Destroyable, MapModel, Reactive, SetModel } from "vasille";
|
|
8
|
+
import { ProxyReference, proxyObject } from "./objects";
|
|
9
|
+
const symbol = Symbol("proxy");
|
|
10
|
+
class Context extends Destroyable {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
_Context_instances.add(this);
|
|
14
|
+
_Context_ctx.set(this, new Reactive({}));
|
|
15
|
+
}
|
|
16
|
+
checkEnable(value) {
|
|
17
|
+
if (value && typeof value === "object" && value.constructor === Object) {
|
|
18
|
+
return __classPrivateFieldGet(this, _Context_instances, "m", _Context_enableObject).call(this, value);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
checkDisable(value) {
|
|
23
|
+
if (value && typeof value === "object" && value.constructor === Object) {
|
|
24
|
+
__classPrivateFieldGet(this, _Context_instances, "m", _Context_disableObject).call(this, value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
destroy() {
|
|
28
|
+
__classPrivateFieldGet(this, _Context_ctx, "f").destroy();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
_Context_ctx = new WeakMap(), _Context_instances = new WeakSet(), _Context_enableObject = function _Context_enableObject(o) {
|
|
32
|
+
const ref = new ProxyReference(undefined);
|
|
33
|
+
o[symbol] = ref;
|
|
34
|
+
__classPrivateFieldGet(this, _Context_ctx, "f").register(ref);
|
|
35
|
+
return proxyObject(o, ref);
|
|
36
|
+
}, _Context_disableObject = function _Context_disableObject(o) {
|
|
37
|
+
__classPrivateFieldGet(this, _Context_ctx, "f").release(o[symbol]);
|
|
38
|
+
};
|
|
39
|
+
export class ContextArray extends ArrayModel {
|
|
40
|
+
constructor(data) {
|
|
41
|
+
const ctx = new Context();
|
|
42
|
+
if (data instanceof Array) {
|
|
43
|
+
for (let i = 0; i < data.length; i++) {
|
|
44
|
+
data[i] = ctx.checkEnable(data[i]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
super(data);
|
|
48
|
+
this.ctx = ctx;
|
|
49
|
+
}
|
|
50
|
+
fill(value, start, end) {
|
|
51
|
+
value = this.ctx.checkEnable(value);
|
|
52
|
+
return super.fill(value, start, end);
|
|
53
|
+
}
|
|
54
|
+
pop() {
|
|
55
|
+
const value = super.pop();
|
|
56
|
+
this.ctx.checkDisable(value);
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
push(...items) {
|
|
60
|
+
for (let i = 0; i < items.length; i++) {
|
|
61
|
+
items[i] = this.ctx.checkEnable(items[i]);
|
|
62
|
+
}
|
|
63
|
+
return super.push(...items);
|
|
64
|
+
}
|
|
65
|
+
shift() {
|
|
66
|
+
const value = super.shift();
|
|
67
|
+
this.ctx.checkDisable(value);
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
splice(start, deleteCount, ...items) {
|
|
71
|
+
for (let i = 0; i < items.length; i++) {
|
|
72
|
+
items[i] = this.ctx.checkEnable(items[i]);
|
|
73
|
+
}
|
|
74
|
+
const removed = super.splice(start, deleteCount, ...items);
|
|
75
|
+
for (const item of removed) {
|
|
76
|
+
this.ctx.checkDisable(removed);
|
|
77
|
+
}
|
|
78
|
+
return removed;
|
|
79
|
+
}
|
|
80
|
+
unshift(...items) {
|
|
81
|
+
for (let i = 0; i < items.length; i++) {
|
|
82
|
+
items[i] = this.ctx.checkEnable(items[i]);
|
|
83
|
+
}
|
|
84
|
+
return super.unshift(...items);
|
|
85
|
+
}
|
|
86
|
+
replace(at, with_) {
|
|
87
|
+
this.ctx.checkDisable(this[at]);
|
|
88
|
+
with_ = this.ctx.checkEnable(with_);
|
|
89
|
+
return super.replace(at, with_);
|
|
90
|
+
}
|
|
91
|
+
destroy() {
|
|
92
|
+
super.destroy();
|
|
93
|
+
this.ctx.destroy();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export class ContextMap extends MapModel {
|
|
97
|
+
constructor(map) {
|
|
98
|
+
const ctx = new Context();
|
|
99
|
+
if (map) {
|
|
100
|
+
for (const item of map) {
|
|
101
|
+
item[1] = ctx.checkEnable(item[1]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
super(map);
|
|
105
|
+
this.ctx = ctx;
|
|
106
|
+
}
|
|
107
|
+
clear() {
|
|
108
|
+
for (const value of this.values()) {
|
|
109
|
+
this.ctx.checkDisable(value);
|
|
110
|
+
}
|
|
111
|
+
super.clear();
|
|
112
|
+
}
|
|
113
|
+
delete(key) {
|
|
114
|
+
this.ctx.checkDisable(this.get(key));
|
|
115
|
+
return super.delete(key);
|
|
116
|
+
}
|
|
117
|
+
set(key, value) {
|
|
118
|
+
this.ctx.checkDisable(this.get(key));
|
|
119
|
+
value = this.ctx.checkEnable(value);
|
|
120
|
+
return super.set(key, value);
|
|
121
|
+
}
|
|
122
|
+
destroy() {
|
|
123
|
+
super.destroy();
|
|
124
|
+
this.ctx.destroy();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export class ContextSet extends SetModel {
|
|
128
|
+
constructor(set) {
|
|
129
|
+
const ctx = new Context();
|
|
130
|
+
const real = new Map();
|
|
131
|
+
if (set) {
|
|
132
|
+
for (let i = 0; i < set.length; i++) {
|
|
133
|
+
real.set(set[i], (set[i] = ctx.checkEnable(set[i])));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
super(set);
|
|
137
|
+
this.ctx = ctx;
|
|
138
|
+
this.real = real;
|
|
139
|
+
}
|
|
140
|
+
add(value) {
|
|
141
|
+
if (!this.real.has(value)) {
|
|
142
|
+
this.real.set(value, (value = this.ctx.checkEnable(value)));
|
|
143
|
+
return super.add(value);
|
|
144
|
+
}
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
has(value) {
|
|
148
|
+
return this.real.has(value);
|
|
149
|
+
}
|
|
150
|
+
clear() {
|
|
151
|
+
for (const item of this) {
|
|
152
|
+
this.ctx.checkDisable(item);
|
|
153
|
+
}
|
|
154
|
+
super.clear();
|
|
155
|
+
this.real.clear();
|
|
156
|
+
}
|
|
157
|
+
delete(value) {
|
|
158
|
+
const real = this.real.get(value);
|
|
159
|
+
if (real !== undefined) {
|
|
160
|
+
this.ctx.checkDisable(value);
|
|
161
|
+
this.real.delete(value);
|
|
162
|
+
return super.delete(real);
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
destroy() {
|
|
167
|
+
super.destroy();
|
|
168
|
+
this.ctx.destroy();
|
|
169
|
+
}
|
|
170
|
+
}
|