Skip to content

Commit ed37cef

Browse files
committed
VanX 0.5.0: Better console debugging for reactive objects
1 parent 4005578 commit ed37cef

16 files changed

+407
-174
lines changed

x/dist/van-x.nomodule.js

+56-57
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
{
22
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.
33
// Global variables - aliasing some builtin symbols to reduce the bundle size.
4-
let {fromEntries, entries, keys} = Object
4+
let {fromEntries, entries, keys, hasOwn, getPrototypeOf} = Object
55
let {get: refGet, set: refSet, deleteProperty: refDelete, ownKeys: refOwnKeys} = Reflect
66
let {state, derive, add} = van
7-
let itemsToGc, gcCycleInMs = 1000, _undefined, replacing
8-
let objSym = Symbol(), statesSym = Symbol(), isCalcFunc = Symbol(), bindingsSym = Symbol()
9-
let keysGenSym = Symbol(), keyToChildSym = Symbol()
7+
let statesToGc, gcCycleInMs = 1000, _undefined, replacing
8+
let statesSym = Symbol(), isCalcFunc = Symbol(), bindingsSym = Symbol(), keysGenSym = Symbol(), keyToChildSym = Symbol()
109
let calc = f => (f[isCalcFunc] = 1, f)
1110
let toState = v => {
1211
if (v?.[isCalcFunc]) {
@@ -19,87 +18,87 @@
1918
return s
2019
} else return state(reactive(v))
2120
}
21+
let buildStates = srcObj => {
22+
let states = Array.isArray(srcObj) ? [] : {__proto__: getPrototypeOf(srcObj)}
23+
for (let [k, v] of entries(srcObj)) states[k] = toState(v)
24+
states[bindingsSym] = []
25+
states[keysGenSym] = state(1)
26+
return states
27+
}
2228
let reactive = srcObj => !(srcObj instanceof Object) || srcObj[statesSym] ? srcObj :
23-
new Proxy(
24-
(srcObj[objSym] = srcObj,
25-
srcObj[statesSym] = fromEntries(entries(srcObj).map(([k, v]) => [k, toState(v)])),
26-
srcObj[bindingsSym] = [],
27-
srcObj[keysGenSym] = state(1),
28-
srcObj),
29-
{
30-
get: (obj, name, proxy) => obj[statesSym].hasOwnProperty(name) ? obj[statesSym][name].val : (
31-
name === "length" && obj[keysGenSym].val,
32-
refGet(obj, name, proxy)
33-
),
34-
set(obj, name, v, proxy) {
35-
let states = obj[statesSym]
36-
if (states.hasOwnProperty(name)) return states[name].val = reactive(v), 1
37-
let existingKey = name in obj
38-
let setNewLength = existingKey && name === "length" && v !== obj.length
39-
if (!refSet(obj, name, v)) return
40-
existingKey ?
41-
setNewLength && ++obj[keysGenSym].val :
42-
refSet(states, name, toState(v)) && (++obj[keysGenSym].val, onAdd(proxy, name, states[name]))
43-
return 1
44-
},
45-
deleteProperty: (obj, name) => (
46-
refDelete(obj[statesSym], name) && onDelete(obj, name),
47-
refDelete(obj, name) && ++obj[keysGenSym].val
48-
),
49-
ownKeys: obj => (obj[keysGenSym].val, refOwnKeys(obj)),
50-
}
51-
)
29+
new Proxy(buildStates(srcObj), {
30+
get: (states, name, proxy) =>
31+
name === statesSym ? states :
32+
hasOwn(states, name) ?
33+
Array.isArray(states) && name === "length" ?
34+
(states[keysGenSym].val, states.length) :
35+
states[name].val :
36+
refGet(states, name, proxy),
37+
set: (states, name, v, proxy) =>
38+
hasOwn(states, name) ?
39+
Array.isArray(states) && name === "length" && v !== states.length ?
40+
(states.length = v, ++states[keysGenSym].val) :
41+
(states[name].val = reactive(v), 1) :
42+
name in states ? refSet(states, name, v, proxy) :
43+
refSet(states, name, toState(v)) && (
44+
++states[keysGenSym].val,
45+
filterBindings(states).forEach(
46+
addToContainer.bind(_undefined, proxy, name, states[name], replacing)),
47+
1
48+
),
49+
deleteProperty: (states, name) =>
50+
(refDelete(states, name) && onDelete(states, name), ++states[keysGenSym].val),
51+
ownKeys: states => (states[keysGenSym].val, refOwnKeys(states)),
52+
})
5253
let stateFields = obj => obj[statesSym]
5354
let raw = obj => obj[statesSym] ?
5455
new Proxy(obj[statesSym], {get: (obj, name) => raw(obj[name].rawVal)}) : obj
55-
let filterBindings = items =>
56-
items[bindingsSym] = items[bindingsSym].filter(b => b._containerDom.isConnected)
56+
let filterBindings = states =>
57+
states[bindingsSym] = states[bindingsSym].filter(b => b._containerDom.isConnected)
5758
let addToContainer = (items, k, v, skipReorder, {_containerDom, f}) => {
58-
let isArray = Array.isArray(items)
59+
let isArray = Array.isArray(items), typedK = isArray ? Number(k) : k
5960
add(_containerDom, () =>
60-
_containerDom[keyToChildSym][k] = f(v, () => delete items[k], isArray ? Number(k) : k))
61-
if (isArray && !skipReorder && k != items.length - 1) {
62-
let kNumber = Number(k)
61+
_containerDom[keyToChildSym][k] = f(v, () => delete items[k], typedK))
62+
isArray && !skipReorder && typedK !== items.length - 1 &&
6363
_containerDom.insertBefore(_containerDom.lastChild,
64-
_containerDom[keyToChildSym][keys(items).find(key => Number(key) > kNumber)])
65-
}
64+
_containerDom[keyToChildSym][keys(items).find(key => Number(key) > typedK)])
6665
}
67-
let onAdd = (items, k, v) => filterBindings(items).forEach(
68-
addToContainer.bind(_undefined, items, k, v, replacing))
69-
let onDelete = (items, k) => {
70-
for (let b of filterBindings(items)) {
66+
let onDelete = (states, k) => {
67+
for (let b of filterBindings(states)) {
7168
let keyToChild = b._containerDom[keyToChildSym]
7269
keyToChild[k]?.remove()
7370
delete keyToChild[k]
7471
}
7572
}
76-
let addItemsToGc = items => (itemsToGc ?? (itemsToGc = (
73+
let addStatesToGc = states => (statesToGc ?? (statesToGc = (
7774
setTimeout(
78-
() => (itemsToGc.forEach(filterBindings), itemsToGc = _undefined), gcCycleInMs),
79-
new Set))).add(items)
75+
() => (statesToGc.forEach(filterBindings), statesToGc = _undefined), gcCycleInMs),
76+
new Set))).add(states)
8077
let list = (container, items, itemFunc) => {
8178
let binding = {_containerDom: container instanceof Function ? container() : container, f: itemFunc}
79+
let states = items[statesSym]
8280
binding._containerDom[keyToChildSym] = {}
83-
items[bindingsSym].push(binding)
84-
addItemsToGc(items)
85-
for (let [k, v] of entries(items[statesSym])) addToContainer(items, k, v, 1, binding)
81+
states[bindingsSym].push(binding)
82+
addStatesToGc(states)
83+
for (let [k, v] of entries(states)) addToContainer(items, k, v, 1, binding)
8684
return binding._containerDom
8785
}
8886
let replaceInternal = (obj, replacement) => {
8987
for (let [k, v] of entries(replacement)) {
9088
let existingV = obj[k]
9189
existingV instanceof Object && v instanceof Object ? replaceInternal(existingV, v) : obj[k] = v
9290
}
93-
for (let k in obj) replacement.hasOwnProperty(k) || delete obj[k]
91+
for (let k in obj) hasOwn(replacement, k) || delete obj[k]
9492
let newKeys = keys(replacement), isArray = Array.isArray(obj)
9593
if (isArray || keys(obj).some((k, i) => k !== newKeys[i])) {
94+
let states = obj[statesSym]
9695
if (isArray) obj.length = replacement.length; else {
97-
++obj[keysGenSym].val
98-
let rawObj = obj[objSym], objCopy = {...rawObj}
99-
for (let k of newKeys) delete rawObj[k]
100-
for (let k of newKeys) rawObj[k] = objCopy[k]
96+
++states[keysGenSym].val
97+
let statesCopy = {...states}
98+
for (let k of newKeys) delete states[k]
99+
for (let k of newKeys) states[k] = statesCopy[k]
101100
}
102-
for (let {_containerDom} of filterBindings(obj)) {
101+
for (let {_containerDom} of filterBindings(states)) {
103102
let {firstChild: dom, [keyToChildSym]: keyToChild} = _containerDom
104103
for (let k of newKeys) dom === keyToChild[k] ?
105104
dom = dom.nextSibling : _containerDom.insertBefore(keyToChild[k], dom)

x/dist/van-x.nomodule.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/examples/list-advanced/package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/examples/list-advanced/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"dependencies": {
1515
"terser": "^5.21.0",
1616
"vanjs-core": "^1.5.0",
17-
"vanjs-ext": "^0.4.0"
17+
"vanjs-ext": "^0.5.0"
1818
}
1919
}

x/examples/list-basic/package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/examples/list-basic/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"dependencies": {
1515
"terser": "^5.21.0",
1616
"vanjs-core": "^1.5.0",
17-
"vanjs-ext": "^0.4.0"
17+
"vanjs-ext": "^0.5.0"
1818
}
1919
}

x/examples/reactive/package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/examples/reactive/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"dependencies": {
1515
"terser": "^5.21.0",
1616
"vanjs-core": "^1.5.0",
17-
"vanjs-ext": "^0.4.0"
17+
"vanjs-ext": "^0.5.0"
1818
}
1919
}

x/examples/todo-app/package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/examples/todo-app/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"dependencies": {
1515
"terser": "^5.21.0",
1616
"vanjs-core": "^1.5.0",
17-
"vanjs-ext": "^0.4.0"
17+
"vanjs-ext": "^0.5.0"
1818
}
1919
}

x/package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vanjs-ext",
3-
"version": "0.4.0",
3+
"version": "0.5.0",
44
"description": "The official extension library for VanJS",
55
"files": [
66
"src/van-x.js",

0 commit comments

Comments
 (0)