Skip to content

Commit

Permalink
VanX 0.1.2: Properly handle the case where fields of reactive object …
Browse files Browse the repository at this point in the history
…is `null` or `undefined`
  • Loading branch information
Tao-VanJS committed Oct 23, 2023
1 parent 557d821 commit 0bb8665
Show file tree
Hide file tree
Showing 16 changed files with 103 additions and 42 deletions.
19 changes: 12 additions & 7 deletions x/dist/van-x.nomodule.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
{
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.
// Global variables - aliasing some builtin symbols to reduce the bundle size.
let {fromEntries, entries, keys} = Object, {get: refGet, set: refSet, deleteProperty: refDelete, ownKeys: refOwnKeys} = Reflect, Sym = Symbol, {state, derive, add, tags} = van, itemsToGc, gcCycleInMs = 1000, _undefined
let statesSym = Sym(), objSym = Sym(), isCalcFunc = Sym(), bindingsSym = Sym(), keysGenSym = Sym(), keySym = Sym()
let {fromEntries, entries, keys, getPrototypeOf} = Object
let {get: refGet, set: refSet, deleteProperty: refDelete, ownKeys: refOwnKeys} = Reflect
let Sym = Symbol, {state, derive, add, tags} = van, stateProto = getPrototypeOf(state())
let itemsToGc, gcCycleInMs = 1000, _undefined
let statesSym = Sym(), objSym = Sym(), isCalcFunc = Sym(), bindingsSym = Sym(), keysGenSym = Sym()
let keySym = Sym()
let calc = f => (f[isCalcFunc] = 1, f)
let toState = v => v[isCalcFunc] ? derive(() => reactive(v())) : state(reactive(v))
let toState = v => v?.[isCalcFunc] ? derive(() => reactive(v())) : state(reactive(v))
let reactive = srcObj => {
if (!(srcObj instanceof Object) || srcObj[statesSym]) return srcObj
let proxy = new Proxy(
Expand All @@ -14,10 +18,11 @@
srcObj[keysGenSym] = state(1),
srcObj),
{
get: (obj, name) => obj[statesSym][name]?.val ?? (
name === "length" && obj[keysGenSym].val,
refGet(obj, name, proxy)
),
get: (obj, name) =>
getPrototypeOf(obj[statesSym][name] ?? 0) === stateProto ? obj[statesSym][name].val : (
name === "length" && obj[keysGenSym].val,
refGet(obj, name, proxy)
),
set(obj, name, v) {
let states = obj[statesSym]
if (name in states) return states[name].val = reactive(v), 1
Expand Down
2 changes: 1 addition & 1 deletion x/dist/van-x.nomodule.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions x/examples/list-advanced/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/examples/list-advanced/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"dependencies": {
"terser": "^5.21.0",
"vanjs-core": "^1.2.4",
"vanjs-ext": "^0.1.1"
"vanjs-ext": "^0.1.2"
}
}
10 changes: 5 additions & 5 deletions x/examples/list-basic/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/examples/list-basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"dependencies": {
"terser": "^5.21.0",
"vanjs-core": "^1.2.4",
"vanjs-ext": "^0.1.1"
"vanjs-ext": "^0.1.2"
}
}
10 changes: 5 additions & 5 deletions x/examples/reactive/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/examples/reactive/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"dependencies": {
"terser": "^5.21.0",
"vanjs-core": "^1.2.4",
"vanjs-ext": "^0.1.1"
"vanjs-ext": "^0.1.2"
}
}
10 changes: 5 additions & 5 deletions x/examples/todo-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/examples/todo-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"dependencies": {
"terser": "^5.21.0",
"vanjs-core": "^1.2.4",
"vanjs-ext": "^0.1.1"
"vanjs-ext": "^0.1.2"
}
}
4 changes: 2 additions & 2 deletions x/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion x/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vanjs-ext",
"version": "0.1.1",
"version": "0.1.2",
"description": "The official extension library for VanJS",
"files": [
"src/van-x.js",
Expand Down
19 changes: 12 additions & 7 deletions x/src/van-x.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import van from "vanjs-core"
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size.

// Global variables - aliasing some builtin symbols to reduce the bundle size.
let {fromEntries, entries, keys} = Object, {get: refGet, set: refSet, deleteProperty: refDelete, ownKeys: refOwnKeys} = Reflect, Sym = Symbol, {state, derive, add, tags} = van, itemsToGc, gcCycleInMs = 1000, _undefined
let statesSym = Sym(), objSym = Sym(), isCalcFunc = Sym(), bindingsSym = Sym(), keysGenSym = Sym(), keySym = Sym()
let {fromEntries, entries, keys, getPrototypeOf} = Object
let {get: refGet, set: refSet, deleteProperty: refDelete, ownKeys: refOwnKeys} = Reflect
let Sym = Symbol, {state, derive, add, tags} = van, stateProto = getPrototypeOf(state())
let itemsToGc, gcCycleInMs = 1000, _undefined
let statesSym = Sym(), objSym = Sym(), isCalcFunc = Sym(), bindingsSym = Sym(), keysGenSym = Sym()
let keySym = Sym()

let calc = f => (f[isCalcFunc] = 1, f)

let toState = v => v[isCalcFunc] ? derive(() => reactive(v())) : state(reactive(v))
let toState = v => v?.[isCalcFunc] ? derive(() => reactive(v())) : state(reactive(v))

let reactive = srcObj => {
if (!(srcObj instanceof Object) || srcObj[statesSym]) return srcObj
Expand All @@ -19,10 +23,11 @@ let reactive = srcObj => {
srcObj[keysGenSym] = state(1),
srcObj),
{
get: (obj, name) => obj[statesSym][name]?.val ?? (
name === "length" && obj[keysGenSym].val,
refGet(obj, name, proxy)
),
get: (obj, name) =>
getPrototypeOf(obj[statesSym][name] ?? 0) === stateProto ? obj[statesSym][name].val : (
name === "length" && obj[keysGenSym].val,
refGet(obj, name, proxy)
),
set(obj, name, v) {
let states = obj[statesSym]
if (name in states) return states[name].val = reactive(v), 1
Expand Down
14 changes: 14 additions & 0 deletions x/test/van-x.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,20 @@ window.runTests = async (van, vanX, file) => {
assertEq(json.val, '{"a":3,"c":4}');
vanX.replace(data, _ => [["a", 1], ["b", 2], ["c", 3], ["d", 4]]);
},
reactive_nullOrUndefinedFields: withHiddenDom(async (hiddenDom) => {
const data = vanX.reactive({
a: null,
b: undefined,
c: 1,
d: 2,
});
van.add(hiddenDom, div("a: ", () => String(data.a)), div("b: ", () => String(data.b)), div("c: ", () => String(data.c)), div("d: ", () => String(data.d)));
assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: 1</div><div>d: 2</div>');
data.c = null;
data.d = undefined;
await sleep(waitMsOnDomUpdates);
assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: null</div><div>d: undefined</div>');
}),
list_arraySetItem: withHiddenDom(async (hiddenDom) => {
const items = vanX.reactive([1, 2, 3]);
van.add(hiddenDom, vanX.list(ul, items, v => li(v)));
Expand Down
14 changes: 14 additions & 0 deletions x/test/van-x.test.nomodule.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,20 @@ window.runTests = async (van, vanX, file) => {
assertEq(json.val, '{"a":3,"c":4}');
vanX.replace(data, _ => [["a", 1], ["b", 2], ["c", 3], ["d", 4]]);
},
reactive_nullOrUndefinedFields: withHiddenDom(async (hiddenDom) => {
const data = vanX.reactive({
a: null,
b: undefined,
c: 1,
d: 2,
});
van.add(hiddenDom, div("a: ", () => String(data.a)), div("b: ", () => String(data.b)), div("c: ", () => String(data.c)), div("d: ", () => String(data.d)));
assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: 1</div><div>d: 2</div>');
data.c = null;
data.d = undefined;
await sleep(waitMsOnDomUpdates);
assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: null</div><div>d: undefined</div>');
}),
list_arraySetItem: withHiddenDom(async (hiddenDom) => {
const items = vanX.reactive([1, 2, 3]);
van.add(hiddenDom, vanX.list(ul, items, v => li(v)));
Expand Down
23 changes: 23 additions & 0 deletions x/test/van-x.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,29 @@ window.runTests = async (van: Van, vanX: typeof vanXObj, file: string) => {
vanX.replace(data, _ => [["a", 1], ["b", 2], ["c", 3], ["d", 4]])
},

reactive_nullOrUndefinedFields: withHiddenDom(async hiddenDom => {
const data = vanX.reactive({
a: null,
b: undefined,
c: <number | null>1,
d: <number | undefined>2,
})

van.add(hiddenDom,
div("a: ", () => String(data.a)),
div("b: ", () => String(data.b)),
div("c: ", () => String(data.c)),
div("d: ", () => String(data.d)),
)

assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: 1</div><div>d: 2</div>')

data.c = null
data.d = undefined
await sleep(waitMsOnDomUpdates)
assertEq(hiddenDom.innerHTML, '<div>a: null</div><div>b: undefined</div><div>c: null</div><div>d: undefined</div>')
}),

list_arraySetItem: withHiddenDom(async hiddenDom => {
const items = vanX.reactive([1, 2, 3])
van.add(hiddenDom, vanX.list(ul, items, v => li(v)))
Expand Down

0 comments on commit 0bb8665

Please sign in to comment.