valyrian.js 7.1.2 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +71 -48
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +71 -48
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/proxy-signal/index.d.ts +23 -0
- package/dist/proxy-signal/index.d.ts.map +1 -0
- package/dist/proxy-signal/index.js +136 -0
- package/dist/proxy-signal/index.mjs +116 -0
- package/dist/signal/index.d.ts +1 -22
- package/dist/signal/index.d.ts.map +1 -1
- package/dist/signal/index.js +45 -104
- package/dist/signal/index.mjs +46 -105
- package/lib/index.ts +133 -81
- package/lib/interfaces.ts +1 -0
- package/lib/proxy-signal/index.ts +187 -0
- package/lib/signal/index.ts +88 -168
- package/package.json +3 -4
package/lib/signal/index.ts
CHANGED
|
@@ -1,182 +1,102 @@
|
|
|
1
|
-
import { update } from "valyrian.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { VnodeWithDom, current, update, updateVnode, v } from "valyrian.js";
|
|
2
|
+
|
|
3
|
+
export function Signal(initialValue) {
|
|
4
|
+
// Create a copy of the current context object
|
|
5
|
+
const context = { ...current };
|
|
6
|
+
|
|
7
|
+
// Check if the context object has a vnode property
|
|
8
|
+
if (context.vnode) {
|
|
9
|
+
// Is first call
|
|
10
|
+
if (!context.vnode.signals) {
|
|
11
|
+
// Set the signals property to the signals property of the oldVnode object, or an empty array if that doesn't exist
|
|
12
|
+
context.vnode.signals = context.oldVnode?.signals || [];
|
|
13
|
+
// Set the calls property to -1
|
|
14
|
+
context.vnode.calls = -1;
|
|
15
|
+
// Set the subscribers property to the subscribers property of the oldVnode object, or an empty array if that doesn't exist
|
|
16
|
+
context.vnode.subscribers = context.oldVnode?.subscribers || [];
|
|
17
|
+
|
|
18
|
+
// Set the initialChildren property of the vnode object to a copy of the children array of the vnode object
|
|
19
|
+
context.vnode.initialChildren = [...context.vnode.children];
|
|
20
|
+
}
|
|
12
21
|
|
|
13
|
-
|
|
22
|
+
// Assign the signal variable to the signal stored at the index of the vnode object's calls property in the vnode's signals array
|
|
23
|
+
let signal = context.vnode.signals[++context.vnode.calls];
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
25
|
+
// If a signal has already been assigned to the signal variable, return it
|
|
26
|
+
if (signal) {
|
|
27
|
+
return signal;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
19
30
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
31
|
+
// Declare a variable to store the current value of the Signal
|
|
32
|
+
let value = initialValue;
|
|
23
33
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
(): Signal["value"];
|
|
27
|
-
// Works as a subscription to the value
|
|
28
|
-
// eslint-disable-next-line no-unused-vars
|
|
29
|
-
(value: Subscription): Signal;
|
|
30
|
-
// Works as a setter with a path and a handler
|
|
31
|
-
// eslint-disable-next-line no-unused-vars
|
|
32
|
-
(path: string, handler: (valueAtPathPosition: any) => any): Signal["value"];
|
|
33
|
-
// Works as a setter with a path and a value
|
|
34
|
-
// eslint-disable-next-line no-unused-vars
|
|
35
|
-
(path: string, value: any): Signal["value"];
|
|
36
|
-
// Works as a setter with a value
|
|
37
|
-
// eslint-disable-next-line no-unused-vars
|
|
38
|
-
(value: any): Signal["value"];
|
|
39
|
-
// Gets the current value of the signal.
|
|
40
|
-
value: any;
|
|
41
|
-
// Cleanup function to be called to remove all subscriptions.
|
|
42
|
-
cleanup: () => void;
|
|
43
|
-
// Creates a getter on the signal.
|
|
44
|
-
// eslint-disable-next-line no-unused-vars
|
|
45
|
-
getter: (name: string, handler: Getter) => any;
|
|
46
|
-
// To access the getters on the signal.
|
|
47
|
-
[key: string | number | symbol]: any;
|
|
48
|
-
}
|
|
34
|
+
// Create an array to store functions that have subscribed to changes to the Signal's value
|
|
35
|
+
const subscribers = [];
|
|
49
36
|
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
computed?.cleanup();
|
|
37
|
+
// Define a function that allows other parts of the code to subscribe to changes to the Signal's value
|
|
38
|
+
const subscribe = (callback) => {
|
|
39
|
+
// Add the callback function to the subscribers array
|
|
40
|
+
if (subscribers.indexOf(callback) === -1) {
|
|
41
|
+
subscribers.push(callback);
|
|
42
|
+
}
|
|
57
43
|
};
|
|
58
|
-
}
|
|
59
44
|
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let computed = Signal(() => handler(signal.value));
|
|
64
|
-
let cleanup = computed(); // Execute to register itself
|
|
65
|
-
makeUnsubscribe(subscriptions, computed, handler, cleanup);
|
|
66
|
-
subscriptions.set(handler, computed);
|
|
45
|
+
// Define a function that returns the current value of the Signal
|
|
46
|
+
function get() {
|
|
47
|
+
return value;
|
|
67
48
|
}
|
|
49
|
+
// Add value, toJSON, valueOf, and toString properties to the get function
|
|
50
|
+
get.value = value;
|
|
51
|
+
get.toJSON = get.valueOf = get;
|
|
52
|
+
get.toString = () => `${value}`;
|
|
53
|
+
|
|
54
|
+
// Define a function that allows the value of the Signal to be updated and notifies any subscribed functions of the change
|
|
55
|
+
const set = (newValue) => {
|
|
56
|
+
// Update the value of the Signal
|
|
57
|
+
value = newValue;
|
|
58
|
+
// Update the value property of the get function
|
|
59
|
+
get.value = value;
|
|
60
|
+
// Call each subscribed function with the new value of the Signal as an argument
|
|
61
|
+
for (let i = 0, l = subscribers.length; i < l; i++) {
|
|
62
|
+
subscribers[i](value);
|
|
63
|
+
}
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
// Check if the context object has a vnode property
|
|
66
|
+
if (context.vnode) {
|
|
67
|
+
// If it does, create a new vnode object based on the original vnode, its children, and its DOM and SVG properties
|
|
68
|
+
let newVnode = v(context.vnode.tag, context.vnode.props, ...context.vnode.initialChildren) as VnodeWithDom;
|
|
69
|
+
newVnode.dom = context.vnode.dom;
|
|
70
|
+
newVnode.isSVG = context.vnode.isSVG;
|
|
71
|
+
|
|
72
|
+
// Clear the subscribers array by setting the length property to 0
|
|
73
|
+
context.vnode.subscribers.forEach(
|
|
74
|
+
(subscribers) =>
|
|
75
|
+
// Setting the length property to 0 is faster than clearing the array with a loop
|
|
76
|
+
(subscribers.length = 0)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Clear the subscribers array by setting it to an empty array
|
|
80
|
+
context.vnode.subscribers = [];
|
|
81
|
+
|
|
82
|
+
// Return the result of updating the original vnode with the new vnode
|
|
83
|
+
return updateVnode(newVnode, context.vnode);
|
|
84
|
+
}
|
|
71
85
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
updateTimeout = setTimeout(update);
|
|
76
|
-
}
|
|
86
|
+
// If the context object doesn't have a vnode property, return the result of calling the update function
|
|
87
|
+
return update();
|
|
88
|
+
};
|
|
77
89
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
function (valOrPath?: any | Subscription, handler?: (valueAtPathPosition: any) => any) {
|
|
88
|
-
// Works as a getter
|
|
89
|
-
if (typeof valOrPath === "undefined") {
|
|
90
|
-
return signal.value;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Works as a subscription
|
|
94
|
-
if (typeof valOrPath === "function") {
|
|
95
|
-
return createSubscription(signal, subscriptions, valOrPath);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Works as a setter with a path
|
|
99
|
-
if (typeof valOrPath === "string" && typeof handler !== "undefined") {
|
|
100
|
-
let parsed = valOrPath.split(".");
|
|
101
|
-
let result = signal.value;
|
|
102
|
-
let next;
|
|
103
|
-
while (parsed.length) {
|
|
104
|
-
next = parsed.shift() as string;
|
|
105
|
-
if (parsed.length > 0) {
|
|
106
|
-
if (typeof result[next] !== "object") {
|
|
107
|
-
result[next] = {};
|
|
108
|
-
}
|
|
109
|
-
result = result[next];
|
|
110
|
-
} else {
|
|
111
|
-
result[next] = typeof handler === "function" ? handler(result[next]) : handler;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
forceUpdate = true;
|
|
115
|
-
signal.value = signal.value;
|
|
116
|
-
return signal.value;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Works as a setter with a value
|
|
120
|
-
signal.value = valOrPath;
|
|
121
|
-
return signal.value;
|
|
122
|
-
} as Signal,
|
|
123
|
-
{
|
|
124
|
-
set(state, prop, val) {
|
|
125
|
-
if (prop === "value" || prop === "unsubscribe" || prop === "cleanup") {
|
|
126
|
-
let old = state[prop];
|
|
127
|
-
state[prop] = val;
|
|
128
|
-
if (prop === "value" && (forceUpdate || val !== old)) {
|
|
129
|
-
forceUpdate = false;
|
|
130
|
-
for (let [handler, computed] of subscriptions) {
|
|
131
|
-
computed.cleanup();
|
|
132
|
-
let cleanup = handler(val);
|
|
133
|
-
makeUnsubscribe(subscriptions, computed, handler, cleanup);
|
|
134
|
-
}
|
|
135
|
-
delayedUpdate();
|
|
136
|
-
}
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
return false;
|
|
140
|
-
},
|
|
141
|
-
get(state, prop) {
|
|
142
|
-
if (prop === "value") {
|
|
143
|
-
return typeof state.value === "function" ? state.value() : state.value;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (prop === "cleanup" || prop === "unsubscribe" || prop === "getter") {
|
|
147
|
-
return state[prop];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (prop in getters) {
|
|
151
|
-
return getters[prop](state.value);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
Object.defineProperties(signal, {
|
|
158
|
-
value: { value, writable: true, enumerable: true },
|
|
159
|
-
cleanup: {
|
|
160
|
-
value() {
|
|
161
|
-
// eslint-disable-next-line no-unused-vars
|
|
162
|
-
for (let [handler, computed] of subscriptions) {
|
|
163
|
-
computed.unsubscribe();
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
writable: true,
|
|
167
|
-
enumerable: true
|
|
168
|
-
},
|
|
169
|
-
getter: {
|
|
170
|
-
value(name: string, handler: Getter) {
|
|
171
|
-
if (name in getters) {
|
|
172
|
-
throw new Error("Named computed already exists.");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
getters[name] = handler;
|
|
176
|
-
},
|
|
177
|
-
enumerable: true
|
|
178
|
-
}
|
|
179
|
-
});
|
|
90
|
+
// Assign the signal variable an array containing the get, set, and subscribe functions
|
|
91
|
+
let signal = [get, set, subscribe];
|
|
92
|
+
|
|
93
|
+
// If the context object has a vnode property, add the signal to the vnode's signals array
|
|
94
|
+
// and add the subscribers array to the vnode's subscribers array
|
|
95
|
+
if (context.vnode) {
|
|
96
|
+
context.vnode.signals.push(signal);
|
|
97
|
+
context.vnode.subscribers.push(subscribers);
|
|
98
|
+
}
|
|
180
99
|
|
|
100
|
+
// Return the signal
|
|
181
101
|
return signal;
|
|
182
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "valyrian.js",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.2.0",
|
|
4
4
|
"description": "Lightweight steel to forge PWAs. (Minimal Frontend Framework with server side rendering and other capabilities)",
|
|
5
5
|
"repository": "git@github.com:Masquerade-Circus/valyrian.js.git",
|
|
6
6
|
"author": "Masquerade <christian@masquerade-circus.net>",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"typescript": "^4.8.3"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@release-it/conventional-changelog": "^5.1.
|
|
86
|
+
"@release-it/conventional-changelog": "^5.1.1",
|
|
87
87
|
"@types/clean-css": "^4.2.5",
|
|
88
88
|
"@types/node": "^18.7.16",
|
|
89
89
|
"@types/node-fetch": "^2.6.2",
|
|
@@ -91,7 +91,6 @@
|
|
|
91
91
|
"@types/source-map": "^0.5.7",
|
|
92
92
|
"@typescript-eslint/eslint-plugin": "^5.36.2",
|
|
93
93
|
"@typescript-eslint/parser": "^5.36.2",
|
|
94
|
-
"browser-sync": "^2.27.10",
|
|
95
94
|
"buffalo-test": "^2.0.0",
|
|
96
95
|
"compression": "^1.7.4",
|
|
97
96
|
"cross-env": "^7.0.3",
|
|
@@ -100,7 +99,7 @@
|
|
|
100
99
|
"eslint": "^8.23.1",
|
|
101
100
|
"eslint-plugin-sonarjs": "^0.15.0",
|
|
102
101
|
"expect": "^29.0.3",
|
|
103
|
-
"fastify": "^4.
|
|
102
|
+
"fastify": "^4.10.2",
|
|
104
103
|
"gzip-size": "^7.0.0",
|
|
105
104
|
"mocha": "^10.0.0",
|
|
106
105
|
"nodemon": "^2.0.19",
|