-
Notifications
You must be signed in to change notification settings - Fork 96
/
van-0.11.10.nomodule.debug.js
207 lines (205 loc) · 8.02 KB
/
van-0.11.10.nomodule.debug.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
(() => {
// van.js
var Obj = Object;
var _undefined;
var protoOf = Object.getPrototypeOf;
var addAndScheduleOnFirst = (set, s, func, waitMs) => (set ?? (setTimeout(func, waitMs), /* @__PURE__ */ new Set())).add(s);
var changedStates;
var stateProto = {
get "val"() {
return this._val;
},
set "val"(v) {
let s = this, curV = s._val;
if (v !== curV) {
if (s.oldVal === curV)
changedStates = addAndScheduleOnFirst(changedStates, s, updateDoms);
else if (v === s.oldVal)
changedStates.delete(s);
s._val = v;
s.listeners.forEach((l) => l(v, curV));
}
},
"onnew"(l) {
this.listeners.push(l);
}
};
var objProto = protoOf(stateProto);
var state = (initVal) => ({
__proto__: stateProto,
_val: initVal,
oldVal: initVal,
bindings: [],
listeners: []
});
var toDom = (v) => v.nodeType ? v : new Text(v);
var add = (dom, ...children) => (children.flat(Infinity).forEach((child) => dom.appendChild(
protoOf(child) === stateProto ? bind(child, (v) => v) : toDom(child)
)), dom);
var tags = new Proxy((name, ...args) => {
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args];
let dom = document.createElement(name);
Obj.entries(props).forEach(([k, v]) => {
let setter = dom[k] !== _undefined ? (v2) => dom[k] = v2 : (v2) => dom.setAttribute(k, v2);
if (protoOf(v) === stateProto)
bind(v, (v2) => (setter(v2), dom));
else if (protoOf(v) === objProto)
bind(...v["deps"], (...deps) => (setter(v["f"](...deps)), dom));
else
setter(v);
});
return add(dom, ...children);
}, { get: (tag, name) => tag.bind(_undefined, name) });
var filterBindings = (s) => s.bindings = s.bindings.filter((b) => b.dom?.isConnected);
var updateDoms = () => {
let changedStatesArray = [...changedStates];
changedStates = _undefined;
new Set(changedStatesArray.flatMap(filterBindings)).forEach((b) => {
let { _deps, dom, func } = b;
let newDom = func(..._deps.map((d) => d._val), dom, ..._deps.map((d) => d.oldVal));
if (newDom !== dom)
if (newDom != _undefined)
dom.replaceWith(b.dom = toDom(newDom));
else
dom.remove(), b.dom = _undefined;
});
changedStatesArray.forEach((s) => s.oldVal = s._val);
};
var bindingGcCycleInMs = 1e3;
var statesToGc;
var bind = (...deps) => {
let [func] = deps.splice(-1, 1);
let result = func(...deps.map((d) => d._val));
if (result == _undefined)
return [];
let binding = { _deps: deps, dom: toDom(result), func };
deps.forEach((s) => {
statesToGc = addAndScheduleOnFirst(
statesToGc,
s,
() => (statesToGc.forEach(filterBindings), statesToGc = _undefined),
bindingGcCycleInMs
);
s.bindings.push(binding);
});
return binding.dom;
};
var van_default = { add, tags, state, bind };
// van.debug.js
var capturedErrors;
var startCapturingErrors = () => capturedErrors = [];
var stopCapturingErrors = () => capturedErrors = null;
var expect = (cond, msg) => {
if (!cond) {
if (capturedErrors)
capturedErrors.push(msg);
else
throw new Error(msg);
return false;
}
return true;
};
var protoOf2 = Object.getPrototypeOf;
var stateProto2 = protoOf2(van_default.state());
var checkStateValValid = (v) => {
expect(!(v instanceof Node), "DOM Node is not valid value for state");
expect(protoOf2(v ?? 0) !== stateProto2, "State couldn't have value to other state");
return v;
};
var state2 = (initVal) => new Proxy(van_default.state(Object.freeze(checkStateValValid(initVal))), {
set: (s, prop, val) => {
if (prop === "val")
Object.freeze(checkStateValValid(val));
return Reflect.set(s, prop, val);
},
get: (s, prop) => {
if (prop === "onnew")
return (l) => {
expect(typeof l === "function", "You should pass-in functions to register `onnew` handlers");
s.onnew(l);
};
return Reflect.get(s, prop);
}
});
var isValidPrimitive = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "bigint";
var isDomOrPrimitive = (v) => v instanceof Node || isValidPrimitive(v);
var checkChildValid = (child) => {
expect(
isDomOrPrimitive(child) || protoOf2(child ?? 0) === stateProto2 && isValidPrimitive(child.val),
"Only DOM Node, string, number, boolean, bigint, and state of string, number, boolean or bigint are valid child of a DOM Node"
);
expect(!child.isConnected, "You can't add a DOM Node that is already connected to document");
};
var add2 = (dom, ...children) => {
expect(dom instanceof Node, "1st argument of `add` function must be a DOM Node object");
children.flat(Infinity).forEach((child) => checkChildValid(child));
return van_default.add(dom, ...children);
};
var tags2 = new Proxy(van_default.tags, {
get: (vanTags, name) => {
const vanTag = vanTags[name];
return (...args) => {
const [props, ...children] = protoOf2(args[0] ?? 0) === Object.prototype ? args : [{}, ...args];
const debugProps = {};
for (const [k, v] of Object.entries(props)) {
const validatePropValue = k.startsWith("on") ? (v2) => (expect(
typeof v2 === "function",
`Invalid property value for ${k}: Only functions are allowed for on... handler`
), v2) : (v2) => (expect(
isValidPrimitive(v2),
`Invalid property value for ${k}: Only string, number, boolean, bigint are valid prop value types`
), v2);
if (protoOf2(v ?? 0) === stateProto2) {
debugProps[k] = { deps: [v], f: (v2) => validatePropValue(v2) };
} else if (protoOf2(v ?? 0) === Object.prototype) {
expect(
Array.isArray(v.deps) && v.deps.every((d) => protoOf2(d) === stateProto2),
"For state-derived properties, you want specify an Array of states in `deps` field"
);
expect(
typeof v.f === "function",
"For state-derived properties, you want specify the generation function in `f` field"
);
debugProps[k] = { deps: v.deps, f: (...deps) => validatePropValue(v.f(...deps)) };
} else
debugProps[k] = validatePropValue(v);
}
children.flat(Infinity).forEach((child) => checkChildValid(child));
return vanTag(debugProps, ...children);
};
}
});
var bind2 = (...deps) => {
let [func] = deps.splice(-1, 1);
expect(deps.length > 0, "`bind` must be called with 1 or more states as dependencies");
deps.forEach((d) => expect(protoOf2(d) === stateProto2, "Dependencies in `bind` must be states"));
expect(typeof func === "function", "The last argument of `bind` must be the generation function");
return van_default.bind(...deps, (...depArgs) => {
const result = func(...depArgs);
if (!expect(
result === null || result === void 0 || isDomOrPrimitive(result),
"The result of `bind` generation function must be DOM node, primitive, null or undefined"
))
return null;
if (depArgs.length > deps.length) {
const prevResult = depArgs[deps.length];
if (!expect(
prevResult instanceof Node && prevResult.isConnected,
"The previous result of the `bind` generation function must be a DOM node connected to document"
))
return null;
if (result !== prevResult && result instanceof Node)
expect(
!result.isConnected,
"If the result of `bind` generation fucntion is not the same as previous one, it shouldn't be already connected to document"
);
}
return result;
});
};
var van_debug_default = { add: add2, tags: tags2, state: state2, bind: bind2, startCapturingErrors, stopCapturingErrors, get capturedErrors() {
return capturedErrors;
} };
// van.forbundle.debug.js
window.van = van_debug_default;
})();