vasille-jsx 4.3.4 → 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.
package/README.md CHANGED
@@ -1,19 +1,32 @@
1
- # Vasille
1
+ # Steel Frame
2
2
 
3
- ![Vasille.js logo](https://raw.githubusercontent.com/vasille-js/vasille-js/refs/heads/v4/doc/img/logo.png)
3
+ ![Vasille.js logo](https://raw.githubusercontent.com/vasille-js/vasille-js/refs/heads/v5/doc/img/logo.png)
4
4
 
5
- `Vasille Web` is a front-end framework, which is developed to provide bulletproof frontends.
5
+ `SteelFrameKit` is a front-end development kit, which is developed to provide fault tolerant web applications.
6
6
 
7
- [![npm](https://img.shields.io/npm/v/vasille?style=flat-square)](https://www.npmjs.com/package/vasille)
7
+ [![npm](https://img.shields.io/npm/v/steel-frame?style=flat-square)](https://www.npmjs.com/package/steel-frame)
8
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/vasille-js/steel-frame)
9
+ [![Coverage Status](https://coveralls.io/repos/github/vasille-js/steel-frame/badge.svg?branch=v5)](https://coveralls.io/github/vasille-js/steel-frame?branch=v5)
8
10
 
9
11
  ## Table of content
10
12
 
11
- * [Installation](#installation)
12
- * [How to use Vasille](#how-to-use-vasille)
13
- * [How SAFE is Vasille](#how-safe-is-vasille)
14
- * [How INTUITIVE is Vasille](#how-intuitive-is-vasille)
15
- * [How POWERFUL is Vasille](#how-powerful-is-vasille)
16
- * [Road Map](#road-map)
13
+ - [Steel Frame](#steel-frame)
14
+ - [Table of content](#table-of-content)
15
+ - [Installation](#installation)
16
+ - [How to use SteelFramekit](#how-to-use-steelframekit)
17
+ - [Full documentation:](#full-documentation)
18
+ - [Examples](#examples)
19
+ - [How SAFE is SteelFrameKit](#how-safe-is-steelframekit)
20
+ - [How INTUITIVE is SteelFrameKit](#how-intuitive-is-steelframekit)
21
+ - [How POWERFUL is SteelFrameKit](#how-powerful-is-steelframekit)
22
+ - [Road map](#road-map)
23
+ - [Change log](#change-log)
24
+ - [5.0](#50)
25
+ - [4.0 - 4.3](#40---43)
26
+ - [3.0 - 3.2](#30---32)
27
+ - [2.0 - 2.3](#20---23)
28
+ - [1.0 - 1.2](#10---12)
29
+ - [Questions](#questions)
17
30
 
18
31
 
19
32
  <hr>
@@ -21,21 +34,22 @@
21
34
  ## Installation
22
35
 
23
36
  ```
24
- npm install vasille-web --save
37
+ npm install steel-frame --save
25
38
  ```
26
39
 
27
- ## How to use Vasille
40
+ ## How to use SteelFramekit
28
41
 
29
42
  Create an app from a template
30
43
 
31
44
  ```bash
32
- $ npm create vasille
45
+ $ npm create steel-frame
33
46
  ```
34
47
 
35
48
  ### Full documentation:
36
- * [Learn `Vasille` in 5 minutes](https://github.com/vasille-js/vasille-js/blob/v4/doc/V4-API.md)
37
- * [Vasille Router Documentation](https://github.com/vasille-js/vasille-js/blob/v4/doc/Router-API.md)
38
- * [Vasille Compostion function](https://github.com/vasille-js/vasille-js/blob/v4/doc/Compositions.md)
49
+ * [Learn `SteelFrameKit` in 5 minutes](https://github.com/vasille-js/vasille-js/blob/v5/doc/V4-API.md)
50
+ * [Router Documentation](https://github.com/vasille-js/vasille-js/blob/v5/doc/Router-API.md)
51
+ * [Compostion functions](https://github.com/vasille-js/vasille-js/blob/v5/doc/Compositions.md)
52
+ * [Dependency injection](https://github.com/vasille-js/vasille-js/blob/v5/doc/Context.md)
39
53
 
40
54
  ### Examples
41
55
  * [TypeScript Example](https://github.com/vasille-js/example-typescript)
@@ -43,14 +57,14 @@ $ npm create vasille
43
57
 
44
58
  <hr>
45
59
 
46
- ## How SAFE is Vasille
60
+ ## How SAFE is SteelFrameKit
47
61
 
48
62
  The safe of your application is ensured by
49
63
  * `100%` coverage of code by unit tests.
50
64
  Each function, each branch is working as designed.
51
65
  * OOP, DRY, KISS and SOLID principles are applied.
52
66
  * `strong typing` makes your javascript/typescript code safe as C++ code.
53
- All entities of `vasille` core library are strongly typed, including:
67
+ All entities of `SteelFrameKit` core library are strongly typed, including:
54
68
  * data fields & properties.
55
69
  * computed properties (function parameters and result).
56
70
  * methods.
@@ -60,11 +74,11 @@ All entities of `vasille` core library are strongly typed, including:
60
74
  * references to children.
61
75
  * No asynchronous code, when the line of code is executed, the DOM and reactive things are already synced.
62
76
 
63
- ## How INTUITIVE is Vasille
77
+ ## How INTUITIVE is SteelFrameKit
64
78
 
65
79
  There is the "Hello World":
66
80
  ```typescript jsx
67
- import { compose, mount } from "vasille-dx";
81
+ import { compose, mount } from "steel-frame";
68
82
 
69
83
  const App = compose(() => {
70
84
  <p>Hello world</p>;
@@ -73,60 +87,76 @@ const App = compose(() => {
73
87
  mount(document.body, App, {});
74
88
  ```
75
89
 
76
- ## How POWERFUL is Vasille
90
+ ## How POWERFUL is SteelFrameKit
77
91
 
78
92
  All of these are supported:
79
93
  * Components.
80
94
  * Reactive values (observables).
81
95
  * Inline computed values.
82
96
  * Multiline computed values.
83
- * HTML & SVG tags.
97
+ * HTML tags.
84
98
  * Component custom slots.
85
99
  * 2-way data binding in components.
86
100
  * Logic block (if, else).
87
101
  * Loops (array, map, set).
102
+ * Dependency injection.
88
103
 
89
104
  <hr>
90
105
 
91
106
  ## Road map
92
107
 
93
- * [x] Update the `Vasille Core` library to version 3.0.
94
108
  * [x] `100%` Test Coverage for core Library v3.
95
- * [x] Develop the `Vasille JSX` library.
109
+ * [x] Develop the `JSX` library.
96
110
  * [x] `100%` Test Coverage for the JSX library.
97
- * [x] Develop the `Vasille Babel Plugin`.
111
+ * [x] Develop the `Babel Plugin`.
98
112
  * [x] `100%` Test Coverage fot babel plugin.
99
113
  * [x] Add CSS support (define styles in components).
100
114
  * [x] Add router.
101
115
  * [x] Add SSG (static site generation).
116
+ * [ ] Develop tools extension for debugging (WIP).
102
117
  * [ ] Add SSR (server side rendering).
103
- * [ ] Develop tools extension for debugging.
104
118
 
105
119
  ## Change log
106
120
 
107
- ### 4.3.0
121
+ We respect semantic versioning:
122
+ - Major version is increased when we make incompatible API changes.
123
+ - Minor version is increased when we add functionality.
124
+ - Patch version is increased when we fix bugs.
108
125
 
109
- Add new function `safe` which make functions safe, errors are reported automatically.
126
+ ### 5.0
110
127
 
111
- ### 4.2.0
128
+ - Add support for context and dependencies injection.
129
+ - New developement direction: `fault tolerant`.
130
+ - Renamed to `steel-frame`. **[API change]**
131
+ - Removed `forward` and `backward` functions. **[API change]**
132
+ - Removed `Debug` component. **[API change]**
112
133
 
113
- Add support for inlined conditions in JSX, binary `&&` and ternary `?:` operator.
134
+ ### 4.0 - 4.3
114
135
 
115
- ### 4.1.0
136
+ - Initial version of the framework with file based routing and building scripts (`web dev` and `web build spa`).
137
+ - Reactive values naming switched to `$` prefix. **[API change]**
138
+ - `4.1` Added SSG (static site generation) as build option `web build static`.
139
+ - `4.2` Add support for inlined conditions in JSX, binary `&&` and ternary `?:` operator.
140
+ - `4.3` Add new function `safe` which make functions safe, errors are reported automatically.
116
141
 
117
- Added SSG (static site generation) as build option `vasille-web build static`.
142
+ ### 3.0 - 3.2
118
143
 
119
- ### 4.0.0
144
+ - Switch to a babel plugin to compile components code. **[API change]**
145
+ - 100% of code has been covered with unit tests.
146
+ - New developement direction: `keep it simple`.
120
147
 
121
- Initial version of the framework with file based routing and building scripts (`vasille-web dev` and `vasille-web build spa`).
148
+ ### 2.0 - 2.3
149
+
150
+ - Introduces components compilation via a typescript plugin. **[API change]**
151
+ - New developement direction: `write less, do more`.
152
+
153
+ ### 1.0 - 1.2
154
+
155
+ - Initial version of core library.
156
+ - Developemnt direction: `performance-first`.
122
157
 
123
158
  ## Questions
124
159
 
125
160
  If you have questions, feel free to contact the maintainer of the project:
126
161
 
127
162
  * [Author's Email](mailto:vas.lixcode@gmail.com)
128
- * [Author's Telegram](https://t.me/lixcode)
129
-
130
- <hr>
131
-
132
- **Made in Moldova** 🇲🇩
package/lib/components.js CHANGED
@@ -72,9 +72,6 @@ export function Watch({ $model, slot: _slot }, ctx, defaultSlot) {
72
72
  ctx.create(new CoreWatch({ model: $model, slot: safe(slot) }, ctx.runner));
73
73
  }
74
74
  }
75
- export function Debug({ $model }, ctx) {
76
- ctx.debug($model);
77
- }
78
75
  export function Delay({ time, slot: _slot }, ctx, defaultSlot) {
79
76
  const fragment = new Fragment(ctx.runner);
80
77
  const slot = _slot ?? defaultSlot;
package/lib/compose.js CHANGED
@@ -25,14 +25,10 @@ export function store(fn) {
25
25
  return fn(new Reactive());
26
26
  }
27
27
  export function model(fn) {
28
- return o => {
28
+ return (o, parent) => {
29
29
  const ctx = new Reactive();
30
- return {
31
- ...fn(ctx, o),
32
- destroy() {
33
- ctx.destroy();
34
- },
35
- };
30
+ parent?.bind(ctx);
31
+ return fn(ctx, o);
36
32
  };
37
33
  }
38
34
  export function mount(tag, view, runner, $) {
@@ -0,0 +1,103 @@
1
+ import { reportError, safe, userError } from "vasille";
2
+ import { DevArrayModel, DevArrayView, DevFragment, DevMapModel, DevMapView, DevSetModel, DevSetView, DevSwitchedNode, DevWatch as DevCoreWatch, } from "vasille/dev";
3
+ export function DevSlot({ model, slot, ...options }, ctx, defaultSlot, usage) {
4
+ try {
5
+ if (model) {
6
+ model(options, ctx);
7
+ }
8
+ else if (slot) {
9
+ slot({}, ctx);
10
+ }
11
+ else if (defaultSlot) {
12
+ defaultSlot(ctx);
13
+ }
14
+ }
15
+ catch (e) {
16
+ ctx.runner.inspector.reportComponentSlotError({
17
+ targetId: "id" in ctx && typeof ctx.id === "number" ? ctx.id : 0,
18
+ error: e,
19
+ usage: usage,
20
+ time: Date.now(),
21
+ });
22
+ reportError(e);
23
+ }
24
+ }
25
+ export function DevSwitch(options, ctx, _slot, usage) {
26
+ ctx.create(new DevSwitchedNode(usage, ctx.runner, options.cases, options.default));
27
+ }
28
+ export function DevFor({ of: model, slot: _slot }, ctx, defaultSlot, usage) {
29
+ const slot = _slot ?? defaultSlot;
30
+ if (!slot) {
31
+ return;
32
+ }
33
+ if (model instanceof DevArrayModel) {
34
+ ctx.create(new DevArrayView({
35
+ model,
36
+ slot: slot,
37
+ }, ctx.runner, usage));
38
+ }
39
+ else if (model instanceof DevMapModel) {
40
+ ctx.create(new DevMapView({
41
+ model,
42
+ slot,
43
+ }, ctx.runner, usage));
44
+ }
45
+ else if (model instanceof DevSetModel) {
46
+ ctx.create(new DevSetView({
47
+ model,
48
+ slot: slot,
49
+ }, ctx.runner, usage));
50
+ }
51
+ // fallback if is used external Array/Map/Set
52
+ else {
53
+ const safeSlot = safe(slot);
54
+ console.warn("Vasille <For of/> fallback detected. Please provide reactive data.");
55
+ if (model instanceof Array) {
56
+ model.forEach((value) => {
57
+ safeSlot(ctx, value, value);
58
+ });
59
+ }
60
+ else if (model instanceof Map) {
61
+ model.forEach((value, key) => {
62
+ safeSlot(ctx, value, key);
63
+ });
64
+ }
65
+ else if (model instanceof Set) {
66
+ model.forEach(value => {
67
+ safeSlot(ctx, value, value);
68
+ });
69
+ }
70
+ else {
71
+ throw userError("wrong use of `<For of/>` component", "wrong-model");
72
+ }
73
+ }
74
+ }
75
+ export function DevWatch({ $model, slot: _slot }, ctx, defaultSlot, usage) {
76
+ const slot = _slot ?? defaultSlot;
77
+ /* istanbul ignore else */
78
+ if (slot) {
79
+ ctx.create(new DevCoreWatch({ model: $model, slot: safe(slot) }, ctx.runner, usage));
80
+ }
81
+ }
82
+ export function DevDelay({ time, slot: _slot }, ctx, defaultSlot, usage) {
83
+ const fragment = new DevFragment(ctx.runner, null, usage, "Delay", {
84
+ time,
85
+ slot: _slot,
86
+ });
87
+ const slot = _slot ?? defaultSlot;
88
+ let timer;
89
+ ctx.create(fragment, function (node) {
90
+ /* istanbul ignore else */
91
+ if (slot) {
92
+ timer = setTimeout(() => {
93
+ safe(slot)(node);
94
+ timer = undefined;
95
+ }, time);
96
+ }
97
+ node.runOnDestroy(() => {
98
+ if (timer !== undefined) {
99
+ clearTimeout(timer);
100
+ }
101
+ });
102
+ });
103
+ }
@@ -0,0 +1,72 @@
1
+ import { DevReactive, remapObject, toDevIdOrValue } from "vasille/dev";
2
+ import { DevApp, DevFragment, ModelId } from "vasille/dev";
3
+ import { earlyInspector } from "./early-inspector.js";
4
+ export function devView(renderer, declaration, name) {
5
+ return function (props, node, slot, usage) {
6
+ const { callback } = props;
7
+ if (!node) {
8
+ throw new Error("Vasille: Component context is missing");
9
+ }
10
+ const frag = new DevFragment(node.runner, declaration, usage ?? null, name, props);
11
+ if (slot) {
12
+ props.slot = slot;
13
+ }
14
+ node.create(frag);
15
+ try {
16
+ const result = renderer(frag, props);
17
+ if (result !== undefined && result !== null && callback) {
18
+ callback(result);
19
+ }
20
+ }
21
+ catch (e) {
22
+ node.runner.inspector.reportComponentError({
23
+ targetId: frag.id,
24
+ error: e,
25
+ time: Date.now(),
26
+ });
27
+ reportError(e);
28
+ }
29
+ finally {
30
+ node.runner.inspector.composeTime({
31
+ id: frag.id,
32
+ time: Date.now(),
33
+ });
34
+ }
35
+ };
36
+ }
37
+ export function devStore(fn, declaration, name) {
38
+ const reactive = new DevReactive({ inspector: earlyInspector });
39
+ earlyInspector.createStore({ id: reactive.id, declaration, name, time: Date.now() });
40
+ return fn(reactive);
41
+ }
42
+ export function devModel(fn, declaration, name) {
43
+ return (o, parent, usage) => {
44
+ const ctx = new DevReactive({ inspector: earlyInspector });
45
+ const id = ctx.id;
46
+ earlyInspector.createCustomModel({
47
+ id,
48
+ declaration,
49
+ usage,
50
+ name,
51
+ time: Date.now(),
52
+ props: remapObject(o, toDevIdOrValue),
53
+ });
54
+ if (parent) {
55
+ parent.runOnDestroy(() => ctx.destroy());
56
+ }
57
+ return {
58
+ ...fn(ctx, o),
59
+ [ModelId]: id,
60
+ };
61
+ };
62
+ }
63
+ export function devMount(tag, view, runner, $, inspector) {
64
+ const root = new DevApp(tag, runner);
65
+ const frag = new DevFragment(runner, null, null, "Root", {});
66
+ // share information about created stores
67
+ earlyInspector.connect(inspector);
68
+ root.create(frag, function () {
69
+ view($, frag);
70
+ });
71
+ return root;
72
+ }
@@ -0,0 +1,111 @@
1
+ export class AbstractInspector {
2
+ addContextState(state) {
3
+ this.send(this.addContextState.name, state);
4
+ }
5
+ composeTime(time) {
6
+ this.send(this.composeTime.name, time);
7
+ }
8
+ createComponent(comp) {
9
+ this.send(this.createComponent.name, comp);
10
+ }
11
+ createCustomModel(model) {
12
+ this.send(this.createCustomModel.name, model);
13
+ }
14
+ createModel(model) {
15
+ this.send(this.createModel.name, model);
16
+ }
17
+ createNode(node) {
18
+ this.send(this.createNode.name, node);
19
+ }
20
+ createStore(store) {
21
+ this.send(this.createStore.name, store);
22
+ }
23
+ createTag(tag) {
24
+ this.send(this.createTag.name, tag);
25
+ }
26
+ destroy(data) {
27
+ this.send(this.destroy.name, data);
28
+ }
29
+ eventTrigger(call) {
30
+ this.send(this.eventTrigger.name, call);
31
+ }
32
+ functionCall(call) {
33
+ this.send(this.functionCall.name, call);
34
+ }
35
+ functionReturn(result) {
36
+ this.send(this.functionReturn.name, result);
37
+ }
38
+ functionThrows(error) {
39
+ this.send(this.functionThrows.name, error);
40
+ }
41
+ newExpression(expr) {
42
+ this.send(this.newExpression.name, expr);
43
+ }
44
+ newReference(ref) {
45
+ this.send(this.newReference.name, ref);
46
+ }
47
+ registerExecutionPosition(pos) {
48
+ this.send(this.registerExecutionPosition.name, pos);
49
+ }
50
+ registeredRoutes(routes) {
51
+ this.send(this.registeredRoutes.name, routes);
52
+ }
53
+ reportComponentError(error) {
54
+ this.send(this.reportComponentError.name, error);
55
+ }
56
+ reportComponentSlotError(error) {
57
+ this.send(this.reportComponentSlotError.name, error);
58
+ }
59
+ reportError(err) {
60
+ this.send(this.reportError.name, err);
61
+ }
62
+ reportExpressionCalculationError(error) {
63
+ this.send(this.reportExpressionCalculationError.name, error);
64
+ }
65
+ reportReferenceError(error) {
66
+ this.send(this.reportReferenceError.name, error);
67
+ }
68
+ routerActionCall(call) {
69
+ this.send(this.routerActionCall.name, call);
70
+ }
71
+ routerStateChange(change) {
72
+ this.send(this.routerStateChange.name, change);
73
+ }
74
+ routerTargetResult(data) {
75
+ this.send(this.routerTargetResult.name, data);
76
+ }
77
+ setElementParent(parent) {
78
+ this.send(this.setElementParent.name, parent);
79
+ }
80
+ updateExpression(update) {
81
+ this.send(this.updateExpression.name, update);
82
+ }
83
+ updateModel(update) {
84
+ this.send(this.updateModel.name, update);
85
+ }
86
+ updateReference(update) {
87
+ this.send(this.updateReference.name, update);
88
+ }
89
+ }
90
+ export class EarlyInspector extends AbstractInspector {
91
+ constructor() {
92
+ super(...arguments);
93
+ this.queue = [];
94
+ }
95
+ connect(inspector) {
96
+ this.inspector = inspector;
97
+ for (const item of this.queue) {
98
+ inspector[item[0]](item[1]);
99
+ }
100
+ this.queue = [];
101
+ }
102
+ send(name, data) {
103
+ if (this.inspector) {
104
+ this.inspector[name](data);
105
+ }
106
+ else {
107
+ this.queue.push([name, data]);
108
+ }
109
+ }
110
+ }
111
+ export const earlyInspector = new EarlyInspector();
@@ -0,0 +1,21 @@
1
+ import { setErrorHandler as coreSetErrorHandler } from "vasille";
2
+ import { earlyInspector } from "./early-inspector.js";
3
+ export { DevDelay, DevWatch, DevFor, DevSwitch, DevSlot } from "./components.js";
4
+ export { devStore, devModel, devMount, devView } from "./compose.js";
5
+ export { devArrayModel, devMapModel, devEnsure, devExpr, devMatch, devSetModel, devRef, devSet } from "./internal.js";
6
+ export { devAwaited } from "./library.js";
7
+ export { AbstractInspector, EarlyInspector, earlyInspector } from "./early-inspector.js";
8
+ function devErrorHandler(e) {
9
+ earlyInspector.reportError({
10
+ targetId: 0,
11
+ error: e instanceof Error ? (e.stack ?? e.message) : `${e}`,
12
+ time: Date.now(),
13
+ });
14
+ }
15
+ coreSetErrorHandler(devErrorHandler);
16
+ export function setErrorHandler(fn) {
17
+ coreSetErrorHandler(e => {
18
+ devErrorHandler(e);
19
+ fn(e);
20
+ });
21
+ }
@@ -0,0 +1,33 @@
1
+ import { DevArrayModel, DevExpression, DevIValue, DevMapModel, DevReference, DevSetModel, } from "vasille/dev";
2
+ import { match, set } from "../internal.js";
3
+ export function devExpr(ctx, func, values, depsCode, declaration, inspector) {
4
+ return new DevExpression(func, values, ctx, depsCode, declaration, inspector, false);
5
+ }
6
+ export function devRef(v, declaration, inspector) {
7
+ return new DevReference(v, declaration, inspector);
8
+ }
9
+ export function devSetModel(inspector, usage, ctx, data) {
10
+ return new DevSetModel(inspector, usage, data, ctx);
11
+ }
12
+ export function devMapModel(inspector, usage, ctx, data) {
13
+ return new DevMapModel(inspector, usage, data, ctx);
14
+ }
15
+ export function devArrayModel(inspector, usage, ctx, data) {
16
+ return new DevArrayModel(inspector, usage, data, ctx);
17
+ }
18
+ export function devEnsure(obj, key, declaration, inspector) {
19
+ if (!obj) {
20
+ return undefined;
21
+ }
22
+ return key in obj ? obj[key] : (obj[key] = devRef(undefined, declaration, inspector));
23
+ }
24
+ export function devMatch(name, data, declaration, inspector) {
25
+ return match(name, data, v => devRef(v, declaration, inspector));
26
+ }
27
+ export function devSet(o, key, value, declaration, inspector, executionPosition) {
28
+ if (o[key] instanceof DevIValue) {
29
+ o[key].update(value, executionPosition);
30
+ return value;
31
+ }
32
+ return set(o, key, value, v => devRef(v, declaration, inspector));
33
+ }
@@ -0,0 +1,8 @@
1
+ import { awaited } from "../library.js";
2
+ import { devRef } from "./internal.js";
3
+ export function devAwaited(target, callback, declaration, inspector) {
4
+ let i = 0;
5
+ const result = awaited(target, v => devRef(v, declaration[i++], inspector));
6
+ callback(result[0], result[1]);
7
+ return result;
8
+ }
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { Debug, Delay, For, Slot, Watch, Switch } from "./components.js";
1
+ export { Delay, For, Slot, Watch, Switch } from "./components.js";
2
2
  export { view, mount, model, store } from "./compose.js";
3
3
  export { awaited } from "./library.js";
4
- export { ref, arrayModel, backward, mapModel, expr, setModel, forward, set, ensure, match, extract, } from "./internal.js";
4
+ export { ref, arrayModel, mapModel, expr, setModel, set, ensure, match } from "./internal.js";
5
5
  export { setErrorHandler } from "vasille";
package/lib/internal.js CHANGED
@@ -1,13 +1,7 @@
1
- import { IValue, Expression, Reference, Forward, Backward, SetModel, MapModel, ArrayModel, } from "vasille";
1
+ import { IValue, Expression, Reference, SetModel, MapModel, ArrayModel } from "vasille";
2
2
  export function expr(ctx, func, values) {
3
3
  return new Expression(func, values, ctx);
4
4
  }
5
- export function forward(ctx, v) {
6
- return new Forward(v, ctx);
7
- }
8
- export function backward(v) {
9
- return new Backward(v);
10
- }
11
5
  /**
12
6
  * It transforms a non-reactive value to a reactive one.
13
7
  * 1. `let a = 0` to `const a = ref(0)`
@@ -40,19 +34,19 @@ export function arrayModel(ctx, data) {
40
34
  * Use when a value must be IValue but can be undefined
41
35
  * 1. `let a = obj.$key` to `const a = ensure(obj.$key)`
42
36
  */
43
- export function ensure(data) {
44
- return data instanceof IValue ? data : new Reference(data);
37
+ export function ensure(obj, key) {
38
+ return !obj ? ref(undefined) : key in obj ? obj[key] : (obj[key] = ref(undefined));
45
39
  }
46
40
  /**
47
41
  * Used for destruction with computed values
48
42
  * 1. `{[a]: a1} = {x: 2}` to `{[a]: a1 = match("a1")} = {x: 2}`
49
43
  * 1. `{[a]: a1 = 3} = {x: 2}` to `{[a]: a1 = match("a1", 3)} = {x: 2}`
50
44
  */
51
- export function match(name, data) {
45
+ export function match(name, data, createRef = ref) {
52
46
  const iValueRequired = typeof name === "string" && name.startsWith("$");
53
47
  const isIValue = data instanceof IValue;
54
48
  if (iValueRequired && !isIValue) {
55
- return new Reference(data);
49
+ return createRef(data);
56
50
  }
57
51
  if (!iValueRequired && isIValue) {
58
52
  return data.V;
@@ -64,7 +58,7 @@ export function match(name, data) {
64
58
  * 1. `obj.$key = 23` to `set(obj, "$key", 23)`
65
59
  * 2. `arr[0] = 23` to `set(arr, 0, 23)`
66
60
  */
67
- export function set(o, key, value) {
61
+ export function set(o, key, value, createRef = ref) {
68
62
  if (o[key] instanceof IValue) {
69
63
  o[key].V = value;
70
64
  }
@@ -72,13 +66,10 @@ export function set(o, key, value) {
72
66
  o.replace(key, value);
73
67
  }
74
68
  else if (typeof key === "string" && key.charAt(0) === "$") {
75
- o[key] = new Reference(value);
69
+ o[key] = createRef(value);
76
70
  }
77
71
  else {
78
72
  o[key] = value;
79
73
  }
80
74
  return value;
81
75
  }
82
- export function extract(value) {
83
- return value instanceof IValue ? value.V : value;
84
- }
package/lib/library.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ref } from "./internal.js";
2
- export function awaited(target) {
3
- const value = ref(undefined);
4
- const err = ref(undefined);
2
+ export function awaited(target, createRef = ref) {
3
+ const err = createRef(undefined);
4
+ const value = createRef(undefined);
5
5
  let running = false;
6
6
  function run() {
7
7
  if (running) {
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "vasille-jsx",
3
- "version": "4.3.4",
3
+ "version": "5.0.1",
4
4
  "description": "The same framework which is designed to build bulletproof frontends (JSX components)",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
7
- "types": "./types/index.d.ts",
8
- "import": "./lib/index.js",
9
- "browser": "./lib/index.js"
7
+ ".": {
8
+ "types": "./types/index.d.ts",
9
+ "import": "./lib/index.js",
10
+ "browser": "./lib/index.js"
11
+ },
12
+ "./dev": {
13
+ "types": "./types/dev/index.d.ts",
14
+ "import": "./lib/dev/index.js",
15
+ "browser": "./lib/dev/index.js"
16
+ }
10
17
  },
11
18
  "types": "./types/index.d.ts",
12
19
  "scripts": {
@@ -43,9 +50,6 @@
43
50
  "firefox 21",
44
51
  "opera 15"
45
52
  ],
46
- "dependencies": {
47
- "vasille": "^4.3.0"
48
- },
49
53
  "devDependencies": {
50
54
  "@types/jest": "^30.0.0",
51
55
  "@types/jsdom": "^21.1.7",
@@ -53,11 +57,14 @@
53
57
  "cross-env": "^10.0.0",
54
58
  "eslint": "^9.33.0",
55
59
  "eslint-plugin-compat": "^6.0.2",
56
- "jest": "^30.2.0",
60
+ "jest": "^30.0.5",
57
61
  "jsdom": "^26.1.0",
58
62
  "prettier": "^3.6.2",
59
63
  "ts-jest": "^29.4.0",
60
64
  "typescript": "^5.8.3",
61
65
  "typescript-eslint": "^8.39.1"
66
+ },
67
+ "dependencies": {
68
+ "vasille": "^5.0.0"
62
69
  }
63
70
  }
@@ -23,10 +23,6 @@ interface WatchOptions<Node, Element, TagOptions extends object, T> {
23
23
  slot?: (ctx: Fragment<Node, Element, TagOptions>, value: T) => void;
24
24
  }
25
25
  export declare function Watch<Node, Element, TagOptions extends object, T>({ $model, slot: _slot }: WatchOptions<Node, Element, TagOptions, T>, ctx: Fragment<Node, Element, TagOptions>, defaultSlot?: (ctx: Fragment<Node, Element, TagOptions>) => void): void;
26
- interface DebugOptions {
27
- $model: IValue<unknown>;
28
- }
29
- export declare function Debug<Node, Element, TagOptions extends object>({ $model }: DebugOptions, ctx: Fragment<Node, Element, TagOptions>): void;
30
26
  interface DelayOptions<Node, Element, TagOptions extends object> {
31
27
  time?: number;
32
28
  slot?: (ctx: Fragment<Node, Element, TagOptions>) => unknown;
@@ -1,5 +1,5 @@
1
- import { Fragment, App, Runner, Reactive, Destroyable } from "vasille";
2
- interface CompositionProps {
1
+ import { Fragment, App, Runner, Reactive } from "vasille";
2
+ export interface CompositionProps {
3
3
  slot?: (...args: any[]) => void;
4
4
  }
5
5
  export type Composed<Node, Element, TagOptions extends object, In extends CompositionProps, Out> = ($: In & {
@@ -7,6 +7,5 @@ export type Composed<Node, Element, TagOptions extends object, In extends Compos
7
7
  }, node?: Fragment<Node, Element, TagOptions>, slot?: In["slot"]) => void;
8
8
  export declare function view<Node, Element, TagOptions extends object, In extends CompositionProps, Out>(renderer: (node: Fragment<Node, Element, TagOptions>, input: In) => Out): Composed<Node, Element, TagOptions, In, Out>;
9
9
  export declare function store<Out extends object>(fn: (ctx: Reactive) => Out): Out;
10
- export declare function model<In extends object, Out extends object>(fn: (ctx: Reactive, o: In) => Out): (o: In) => Out & Destroyable;
10
+ export declare function model<In extends object, Out extends object>(fn: (ctx: Reactive, o: In) => Out): (o: In, parent?: Reactive) => Out;
11
11
  export declare function mount<Node, Element, TagOptions extends object, T>(tag: Element, view: ($: T, node: Fragment<Node, Element, TagOptions>) => unknown, runner: Runner<Node, Element, TagOptions>, $: T): App<Node, Element, TagOptions>;
12
- export {};
@@ -0,0 +1,33 @@
1
+ import { Fragment } from "vasille";
2
+ import { DevIValue, StaticPosition } from "vasille/dev";
3
+ import { IDevRunner } from "vasille/dev";
4
+ interface DevSlotOptions<Node, Element, TagOptions extends object, T extends object> {
5
+ model?: (input: T, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void;
6
+ slot?: (input: object, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void;
7
+ }
8
+ export declare function DevSlot<Node, Element, TagOptions extends object, T extends object = {}>({ model, slot, ...options }: DevSlotOptions<Node, Element, TagOptions, T> & T, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, defaultSlot: ((ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void) | undefined, usage: StaticPosition): void;
9
+ interface DevSwitchOptions<Node, Element, TagOptions extends object> {
10
+ cases: {
11
+ $case: DevIValue<unknown>;
12
+ slot: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void;
13
+ }[];
14
+ default?: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void;
15
+ slot?: never;
16
+ }
17
+ export declare function DevSwitch<Node, Element, TagOptions extends object>(options: DevSwitchOptions<Node, Element, TagOptions>, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, _slot: undefined, usage: StaticPosition): void;
18
+ interface DevForOptions<Node, Element, TagOptions extends object, T, K, V> {
19
+ of: T;
20
+ slot?: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, value: T, index: K) => void;
21
+ }
22
+ export declare function DevFor<Node, Element, TagOptions extends object, T extends Set<unknown> | Map<unknown, unknown> | unknown[], K = T extends unknown[] ? number : T extends Set<infer R> ? R : T extends Map<infer R, unknown> ? R : never, V = T extends (infer R)[] ? R : T extends Set<infer R> ? R : T extends Map<unknown, infer R> ? R : never>({ of: model, slot: _slot }: DevForOptions<Node, Element, TagOptions, T, K, V>, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, defaultSlot: ((ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void) | undefined, usage: StaticPosition): void;
23
+ interface DevWatchOptions<Node, Element, TagOptions extends object, T> {
24
+ $model: DevIValue<T>;
25
+ slot?: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, value: T) => void;
26
+ }
27
+ export declare function DevWatch<Node, Element, TagOptions extends object, T>({ $model, slot: _slot }: DevWatchOptions<Node, Element, TagOptions, T>, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, defaultSlot: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void | undefined, usage: StaticPosition): void;
28
+ interface DevDelayOptions<Node, Element, TagOptions extends object> {
29
+ time?: number;
30
+ slot?: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => unknown;
31
+ }
32
+ export declare function DevDelay<Node, Element, TagOptions extends object>({ time, slot: _slot }: DevDelayOptions<Node, Element, TagOptions>, ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, defaultSlot: (ctx: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>) => void | undefined, usage: StaticPosition): void;
33
+ export {};
@@ -0,0 +1,12 @@
1
+ import { App, Fragment, Reactive } from "vasille";
2
+ import { DevReactive, StaticPosition } from "vasille/dev";
3
+ import { IDevRunner } from "vasille/dev";
4
+ import { CompositionProps } from "../compose.js";
5
+ import { DevRunner, DevTagOptions, Inspector } from "vasille/dev";
6
+ export type DevComposed<Node, Element, TagOptions extends object, In extends CompositionProps, Out> = ($: In & {
7
+ callback?(data: Out | undefined): void;
8
+ }, node?: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, slot?: In["slot"], usage?: StaticPosition) => void;
9
+ export declare function devView<Node, Element, TagOptions extends object, In extends CompositionProps, Out>(renderer: (node: Fragment<Node, Element, TagOptions, IDevRunner<Node, Element, TagOptions>>, input: In) => Out, declaration: StaticPosition, name: string): DevComposed<Node, Element, TagOptions, In, Out>;
10
+ export declare function devStore<Out extends object>(fn: (ctx: Reactive) => Out, declaration: StaticPosition, name: string): Out;
11
+ export declare function devModel<In extends object, Out extends object>(fn: (ctx: DevReactive<IDevRunner<unknown, unknown, object>>, o: In) => Out, declaration: StaticPosition, name: string): (o: In, parent: Reactive | undefined, usage: StaticPosition) => Out;
12
+ export declare function devMount<T>(tag: Element, view: ($: T, node: Fragment<Node, Element, DevTagOptions, IDevRunner<Node, Element, DevTagOptions>>) => unknown, runner: DevRunner, $: T, inspector: Inspector): App<Node, Element, DevTagOptions>;
@@ -0,0 +1,40 @@
1
+ import { Inspector, ProtocolComponent, ProtocolCustomModel, ProtocolExecutionPosition, ProtocolExpression, ProtocolExpressionError, ProtocolExpressionUpdate, ProtocolModel, ProtocolModelUpdate, ProtocolNode, ProtocolParent, ProtocolReference, ProtocolReferenceError, ProtocolReferenceUpdate, ProtocolState, ProtocolStore, ProtocolTag, ProtocolRouterActionCall, ProtocolRouterStateChange, ProtocolRouterTargetResult, ProtocolRoutes, ProtocolSlotError, ProtocolFunctionCall, ProtocolFunctionResult, ProtocolFunctionError, ProtocolEventTrigger, ProtocolComposeTime, ProtocolError, DestroyData } from "vasille/dev";
2
+ export declare abstract class AbstractInspector implements Inspector {
3
+ addContextState(state: ProtocolState): void;
4
+ composeTime(time: ProtocolComposeTime): void;
5
+ createComponent(comp: ProtocolComponent): void;
6
+ createCustomModel(model: ProtocolCustomModel): void;
7
+ createModel(model: ProtocolModel): void;
8
+ createNode(node: ProtocolNode): void;
9
+ createStore(store: ProtocolStore): void;
10
+ createTag(tag: ProtocolTag): void;
11
+ destroy(data: DestroyData): void;
12
+ eventTrigger(call: ProtocolEventTrigger): void;
13
+ functionCall(call: ProtocolFunctionCall): void;
14
+ functionReturn(result: ProtocolFunctionResult): void;
15
+ functionThrows(error: ProtocolFunctionError): void;
16
+ newExpression(expr: ProtocolExpression): void;
17
+ newReference(ref: ProtocolReference): void;
18
+ registerExecutionPosition(pos: ProtocolExecutionPosition): void;
19
+ registeredRoutes(routes: ProtocolRoutes): void;
20
+ reportComponentError(error: ProtocolError): void;
21
+ reportComponentSlotError(error: ProtocolSlotError): void;
22
+ reportError(err: ProtocolError): void;
23
+ reportExpressionCalculationError(error: ProtocolExpressionError): void;
24
+ reportReferenceError(error: ProtocolReferenceError): void;
25
+ routerActionCall(call: ProtocolRouterActionCall): void;
26
+ routerStateChange(change: ProtocolRouterStateChange): void;
27
+ routerTargetResult(data: ProtocolRouterTargetResult): void;
28
+ setElementParent(parent: ProtocolParent): void;
29
+ updateExpression(update: ProtocolExpressionUpdate): void;
30
+ updateModel(update: ProtocolModelUpdate): void;
31
+ updateReference(update: ProtocolReferenceUpdate): void;
32
+ protected abstract send(name: string, data: object): void;
33
+ }
34
+ export declare class EarlyInspector extends AbstractInspector {
35
+ protected inspector: Inspector | undefined;
36
+ protected queue: [string, object][];
37
+ connect(inspector: Inspector): void;
38
+ protected send(name: string, data: object): void;
39
+ }
40
+ export declare const earlyInspector: EarlyInspector;
@@ -0,0 +1,6 @@
1
+ export { DevDelay, DevWatch, DevFor, DevSwitch, DevSlot } from "./components.js";
2
+ export { devStore, type DevComposed, devModel, devMount, devView } from "./compose.js";
3
+ export { devArrayModel, devMapModel, devEnsure, devExpr, devMatch, devSetModel, devRef, devSet } from "./internal.js";
4
+ export { devAwaited } from "./library.js";
5
+ export { AbstractInspector, EarlyInspector, earlyInspector } from "./early-inspector.js";
6
+ export declare function setErrorHandler(fn: (e: unknown) => void): void;
@@ -0,0 +1,10 @@
1
+ import { Reactive } from "vasille";
2
+ import { DevArrayModel, DevExpression, DevIValue, DevMapModel, DevSetModel, ExecutionPosition, Inspector, KindOfDevIValue, StaticPosition } from "vasille/dev";
3
+ export declare function devExpr<T, Args extends unknown[]>(ctx: Reactive | undefined, func: (...args: Args) => T, values: KindOfDevIValue<Args>, depsCode: string[], declaration: StaticPosition, inspector: Inspector): DevExpression<T, Args>;
4
+ export declare function devRef<T>(v: T, declaration: StaticPosition, inspector?: Inspector): DevIValue<T>;
5
+ export declare function devSetModel(inspector: Inspector | undefined, usage: StaticPosition, ctx: Reactive | undefined, data?: unknown[]): DevSetModel<unknown>;
6
+ export declare function devMapModel(inspector: Inspector | undefined, usage: StaticPosition, ctx: Reactive | undefined, data?: [unknown, unknown][]): DevMapModel<unknown, unknown>;
7
+ export declare function devArrayModel(inspector: Inspector | undefined, usage: StaticPosition, ctx: Reactive | undefined, data?: unknown[] | number): DevArrayModel<unknown>;
8
+ export declare function devEnsure<T extends object>(obj: T | null | undefined, key: keyof T, declaration: StaticPosition, inspector: Inspector | undefined): T[keyof T] | undefined;
9
+ export declare function devMatch(name: string | number | symbol, data: unknown, declaration: StaticPosition, inspector: Inspector | undefined): any;
10
+ export declare function devSet(o: object, key: string | symbol | number, value: unknown, declaration: StaticPosition, inspector: Inspector | undefined, executionPosition: ExecutionPosition): unknown;
@@ -0,0 +1,3 @@
1
+ import { Inspector, StaticPosition } from "vasille/dev";
2
+ import { IValue } from "vasille";
3
+ export declare function devAwaited<T>(target: () => Promise<T>, callback: (error: IValue<unknown>, data: IValue<unknown>) => void, declaration: [StaticPosition, StaticPosition], inspector?: Inspector): [IValue<unknown>, IValue<unknown>, () => void];
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { Debug, Delay, For, Slot, Watch, Switch } from "./components.js";
1
+ export { Delay, For, Slot, Watch, Switch } from "./components.js";
2
2
  export { view, mount, model, store, type Composed } from "./compose.js";
3
3
  export { awaited } from "./library.js";
4
- export { ref, arrayModel, backward, mapModel, expr, setModel, forward, set, ensure, match, extract, } from "./internal.js";
4
+ export { ref, arrayModel, mapModel, expr, setModel, set, ensure, match } from "./internal.js";
5
5
  export { setErrorHandler } from "vasille";
@@ -1,7 +1,5 @@
1
1
  import { IValue, Reactive, KindOfIValue, Expression, SetModel, MapModel, ArrayModel } from "vasille";
2
2
  export declare function expr<T, Args extends unknown[]>(ctx: Reactive | undefined, func: (...args: Args) => T, values: KindOfIValue<Args>): Expression<T, Args>;
3
- export declare function forward<T>(ctx: Reactive | undefined, v: IValue<T>): IValue<T>;
4
- export declare function backward<T>(v: IValue<T>): IValue<T>;
5
3
  /**
6
4
  * It transforms a non-reactive value to a reactive one.
7
5
  * 1. `let a = 0` to `const a = ref(0)`
@@ -26,17 +24,16 @@ export declare function arrayModel(ctx: Reactive | undefined, data?: unknown[] |
26
24
  * Use when a value must be IValue but can be undefined
27
25
  * 1. `let a = obj.$key` to `const a = ensure(obj.$key)`
28
26
  */
29
- export declare function ensure(data: unknown): IValue<any>;
27
+ export declare function ensure<T extends object>(obj: T | null | undefined, key: keyof T): IValue<undefined> | T[keyof T];
30
28
  /**
31
29
  * Used for destruction with computed values
32
30
  * 1. `{[a]: a1} = {x: 2}` to `{[a]: a1 = match("a1")} = {x: 2}`
33
31
  * 1. `{[a]: a1 = 3} = {x: 2}` to `{[a]: a1 = match("a1", 3)} = {x: 2}`
34
32
  */
35
- export declare function match(name: string | number | symbol, data?: unknown): any;
33
+ export declare function match(name: string | number | symbol, data?: unknown, createRef?: typeof ref): any;
36
34
  /**
37
35
  * Set a value of a field (alternative to proxies)
38
36
  * 1. `obj.$key = 23` to `set(obj, "$key", 23)`
39
37
  * 2. `arr[0] = 23` to `set(arr, 0, 23)`
40
38
  */
41
- export declare function set(o: object, key: string | symbol | number, value: unknown): unknown;
42
- export declare function extract<T>(value: IValue<T> | T): T;
39
+ export declare function set(o: object, key: string | symbol | number, value: unknown, createRef?: typeof ref): unknown;
@@ -1,2 +1,3 @@
1
1
  import { IValue } from "vasille";
2
- export declare function awaited<T>(target: () => Promise<T>): [IValue<unknown>, IValue<unknown>, () => void];
2
+ import { ref } from "./internal.js";
3
+ export declare function awaited<T>(target: () => Promise<T>, createRef?: typeof ref): [IValue<unknown>, IValue<unknown>, () => void];