kiru 1.4.0 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/hooks/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAUnD,MAAM,WAAW,KAAK,CAAC,KAAK,SAAS,EAAE;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,CAAC,KAC/D,MAAM,CAAC,CAAC,CAAC,CAAA;IACd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAA;CACrE;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,KAAK,SAAS,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAkBtD"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/hooks/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAanD,MAAM,WAAW,KAAK,CAAC,KAAK,SAAS,EAAE;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,CAAC,KAC/D,MAAM,CAAC,CAAC,CAAC,CAAA;IACd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAE3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAA;CACrE;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,KAAK,SAAS,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,CAkBtD"}
@@ -1,9 +1,11 @@
1
1
  import { signal, Signal } from "../signals/base.js";
2
- import { createVNodeId } from "../utils/vdom.js";
2
+ import { createVNodeId, isVNodeDeleted } from "../utils/vdom.js";
3
3
  import { __DEV__ } from "../env.js";
4
4
  import { node, setups } from "../globals.js";
5
5
  import { tracking, } from "../signals/tracking.js";
6
6
  import { registerVNodeCleanup } from "../utils/index.js";
7
+ let currentAccessedPaths = null;
8
+ const OWN_KEYS = `__KEYS__`;
7
9
  /**
8
10
  * Creates a per‑VNode setup context that can be used during
9
11
  * component setup to derive props into signals.
@@ -29,6 +31,7 @@ export function setup() {
29
31
  }
30
32
  function createSetup(vNode) {
31
33
  let id;
34
+ let propsProxy;
32
35
  const propSyncs = (vNode.propSyncs = []);
33
36
  let prevIndex = -1;
34
37
  // Always points at latest props (updated in propSync) so selector and subs see current props
@@ -39,8 +42,8 @@ function createSetup(vNode) {
39
42
  const old = currentProps.current;
40
43
  const skip = new Set();
41
44
  for (const entry of deriveEntries) {
42
- if (entry.accessedPaths.size > 0 &&
43
- propsUnchangedAtPaths(old, p, entry.accessedPaths)) {
45
+ if (entry.paths.size > 0 &&
46
+ propsUnchangedAtPaths(old, p, entry.paths)) {
44
47
  skip.add(entry);
45
48
  }
46
49
  }
@@ -62,10 +65,12 @@ function createSetup(vNode) {
62
65
  const accessedPaths = new Set();
63
66
  function sync() {
64
67
  accessedPaths.clear();
65
- const propsProxy = createPropsProxy(currentProps.current, accessedPaths);
68
+ const propsProxy = createProxy(currentProps.current);
66
69
  const observations = new Map();
67
70
  tracking.stack.push(observations);
71
+ currentAccessedPaths = accessedPaths;
68
72
  const value = selector(propsProxy);
73
+ currentAccessedPaths = null;
69
74
  tracking.stack.pop();
70
75
  // Always assign and notify so the component re-renders when the derived value changes
71
76
  // (e.g. when parent passes a different signal ref like toggle switching count/double).
@@ -88,7 +93,7 @@ function createSetup(vNode) {
88
93
  }
89
94
  }
90
95
  sync();
91
- const entry = { run: sync, accessedPaths };
96
+ const entry = { run: sync, paths: accessedPaths };
92
97
  deriveEntries.push(entry);
93
98
  deriveCleanups.push(() => {
94
99
  unsubs.forEach((u) => u());
@@ -102,6 +107,13 @@ function createSetup(vNode) {
102
107
  get id() {
103
108
  if (!id) {
104
109
  id = signal(createVNodeId(vNode));
110
+ if (isVNodeDeleted(vNode)) {
111
+ return id;
112
+ }
113
+ if (node.current !== vNode) {
114
+ // @ts-expect-error
115
+ registerVNodeCleanup(vNode, id.$id, Signal.dispose.bind(null, id));
116
+ }
105
117
  prevIndex = vNode.index;
106
118
  propSyncs.push(() => {
107
119
  if (prevIndex !== vNode.index) {
@@ -113,49 +125,99 @@ function createSetup(vNode) {
113
125
  return id;
114
126
  },
115
127
  get props() {
116
- return currentProps.current;
128
+ return (propsProxy ?? (propsProxy = new Proxy({}, {
129
+ get(_, key) {
130
+ if (typeof key === "symbol")
131
+ return Reflect.get(currentProps.current, key);
132
+ const v = currentProps.current[key];
133
+ if (v !== null && typeof v === "object" && !Signal.isSignal(v)) {
134
+ return createProxy(v);
135
+ }
136
+ return v;
137
+ },
138
+ })));
117
139
  },
118
140
  };
119
141
  return setupResult;
120
142
  }
121
- function propsUnchangedAtPaths(oldProps, newProps, paths) {
122
- for (const path of paths) {
123
- if (!Object.is(getAtPath(oldProps, path), getAtPath(newProps, path))) {
124
- return false;
143
+ function propsUnchangedAtPaths(oldProps, newProps, accessedPaths) {
144
+ outer: for (const path of accessedPaths) {
145
+ let a = oldProps;
146
+ let b = newProps;
147
+ for (let i = 0; i < path.length; i++) {
148
+ const key = path[i];
149
+ // Sentinel: caller iterated keys of the object at this path —
150
+ // re-run if the key sets differ
151
+ if (key === OWN_KEYS) {
152
+ if (a === b)
153
+ continue outer;
154
+ if (a == null ||
155
+ b == null ||
156
+ typeof a !== "object" ||
157
+ typeof b !== "object") {
158
+ return false;
159
+ }
160
+ const aKeys = Object.keys(a);
161
+ const bKeys = Object.keys(b);
162
+ if (aKeys.length !== bKeys.length)
163
+ return false;
164
+ for (const k of aKeys) {
165
+ if (!(k in b))
166
+ return false;
167
+ }
168
+ continue outer;
169
+ }
170
+ if (a === b)
171
+ continue outer;
172
+ if (a == null ||
173
+ b == null ||
174
+ typeof a !== "object" ||
175
+ typeof b !== "object") {
176
+ if (!Object.is(a, b))
177
+ return false;
178
+ continue outer;
179
+ }
180
+ a = a[key];
181
+ b = b[key];
125
182
  }
183
+ if (!Object.is(a, b))
184
+ return false;
126
185
  }
127
186
  return true;
128
187
  }
129
- function getAtPath(obj, path) {
130
- let cur = obj;
131
- for (const key of path.split(".")) {
132
- if (cur == null || typeof cur !== "object")
133
- return undefined;
134
- cur = cur[key];
135
- }
136
- return cur;
137
- }
188
+ const proxyCache = new WeakMap();
138
189
  /**
139
- * Proxy that records paths and wraps signals. We only add to accessedPaths when
140
- * we hit a signal (the leaf we subscribe to), so propSync skip only compares
141
- * signal refs. Container objects (e.g. "data") are new every render and would
142
- * always fail the skip.
190
+ * Proxy that records accessed paths and primitives into the current
191
+ * tracking context (currentAccessedPaths).
143
192
  */
144
- function createPropsProxy(props, accessedPaths, pathPrefix) {
145
- return new Proxy(props, {
146
- get(holder, key) {
147
- const path = pathPrefix ? `${pathPrefix}.${key}` : key;
148
- const v = holder[key];
149
- if (Signal.isSignal(v)) {
150
- accessedPaths.add(path); // only record path for signal leaves
193
+ function createProxy(source, path = []) {
194
+ let cached = proxyCache.get(source);
195
+ if (!cached) {
196
+ cached = new Proxy(source, {
197
+ get(holder, key) {
198
+ if (typeof key === "symbol")
199
+ return Reflect.get(holder, key);
200
+ const keyPath = [...path, key];
201
+ const v = holder[key];
202
+ if (v !== null && typeof v === "object" && !Signal.isSignal(v)) {
203
+ return createProxy(v, keyPath);
204
+ }
205
+ currentAccessedPaths?.add(keyPath);
151
206
  return v;
152
- }
153
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
154
- return createPropsProxy(v, accessedPaths, path);
155
- }
156
- accessedPaths.add(path); // primitive leaf
157
- return v;
158
- },
159
- });
207
+ },
208
+ has(holder, key) {
209
+ if (typeof key === "symbol")
210
+ return Reflect.has(holder, key);
211
+ currentAccessedPaths?.add([...path, key]);
212
+ return key in holder;
213
+ },
214
+ ownKeys(holder) {
215
+ currentAccessedPaths?.add([...path, OWN_KEYS]);
216
+ return Reflect.ownKeys(holder);
217
+ },
218
+ });
219
+ proxyCache.set(source, cached);
220
+ }
221
+ return cached;
160
222
  }
161
223
  //# sourceMappingURL=setup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/hooks/setup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/hooks/setup.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiru",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "A batteries-included, easy-to-use rendering library with a tiny footprint",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  import { signal, Signal } from "../signals/base.js"
2
- import { createVNodeId } from "../utils/vdom.js"
2
+ import { createVNodeId, isVNodeDeleted } from "../utils/vdom.js"
3
3
  import { __DEV__ } from "../env.js"
4
4
  import { node, setups } from "../globals.js"
5
5
  import {
@@ -8,11 +8,15 @@ import {
8
8
  } from "../signals/tracking.js"
9
9
  import { registerVNodeCleanup } from "../utils/index.js"
10
10
 
11
+ let currentAccessedPaths: Set<string[]> | null = null
12
+ const OWN_KEYS = `__KEYS__`
13
+
11
14
  export interface Setup<Props extends {}> {
12
15
  readonly derive: <T>(
13
16
  selector: (props: Props extends Kiru.FC<infer P> ? P : Props) => T
14
17
  ) => Signal<T>
15
18
  readonly id: Signal<string>
19
+ // Not reactive — for use in render functions only
16
20
  readonly props: Readonly<Props extends Kiru.FC<infer P> ? P : Props>
17
21
  }
18
22
 
@@ -41,8 +45,10 @@ export function setup<Props extends {}>(): Setup<Props> {
41
45
  setups.set(vNode, setup)
42
46
  return setup
43
47
  }
48
+
44
49
  function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
45
50
  let id: Signal<string>
51
+ let propsProxy: InferredProps
46
52
 
47
53
  type InferredProps = Props extends Kiru.FC<infer R> ? R : Props
48
54
  const propSyncs = (vNode.propSyncs = []) as ((props: InferredProps) => void)[]
@@ -53,7 +59,7 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
53
59
  const currentProps = { current: { ...vNode.props } as InferredProps }
54
60
  const deriveCleanups: Array<() => void> = []
55
61
 
56
- type DeriveEntry = { run: () => void; accessedPaths: Set<string> }
62
+ type DeriveEntry = { run: () => void; paths: Set<string[]> }
57
63
  const deriveEntries: DeriveEntry[] = []
58
64
 
59
65
  propSyncs.push((p) => {
@@ -61,12 +67,8 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
61
67
  const skip = new Set<DeriveEntry>()
62
68
  for (const entry of deriveEntries) {
63
69
  if (
64
- entry.accessedPaths.size > 0 &&
65
- propsUnchangedAtPaths(
66
- old,
67
- p as Record<string, unknown>,
68
- entry.accessedPaths
69
- )
70
+ entry.paths.size > 0 &&
71
+ propsUnchangedAtPaths(old, p as Record<string, unknown>, entry.paths)
70
72
  ) {
71
73
  skip.add(entry)
72
74
  }
@@ -88,17 +90,18 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
88
90
  ) {
89
91
  const resultSig = signal(undefined!) as Signal<T>
90
92
  const unsubs = new Map<string, () => void>()
91
- const accessedPaths = new Set<string>()
93
+ const accessedPaths = new Set<string[]>()
92
94
 
93
95
  function sync() {
94
96
  accessedPaths.clear()
95
- const propsProxy = createPropsProxy(
96
- currentProps.current as Record<string, unknown>,
97
- accessedPaths
97
+ const propsProxy = createProxy(
98
+ currentProps.current as Record<string, unknown>
98
99
  ) as InferredProps
99
100
  const observations: TrackingStackObservations = new Map()
100
101
  tracking.stack.push(observations)
102
+ currentAccessedPaths = accessedPaths
101
103
  const value = selector(propsProxy)
104
+ currentAccessedPaths = null
102
105
  tracking.stack.pop()
103
106
  // Always assign and notify so the component re-renders when the derived value changes
104
107
  // (e.g. when parent passes a different signal ref like toggle switching count/double).
@@ -122,7 +125,7 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
122
125
  }
123
126
 
124
127
  sync()
125
- const entry: DeriveEntry = { run: sync, accessedPaths }
128
+ const entry: DeriveEntry = { run: sync, paths: accessedPaths }
126
129
  deriveEntries.push(entry)
127
130
  deriveCleanups.push(() => {
128
131
  unsubs.forEach((u) => u())
@@ -136,6 +139,13 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
136
139
  get id() {
137
140
  if (!id) {
138
141
  id = signal(createVNodeId(vNode))
142
+ if (isVNodeDeleted(vNode)) {
143
+ return id
144
+ }
145
+ if (node.current !== vNode) {
146
+ // @ts-expect-error
147
+ registerVNodeCleanup(vNode, id.$id, Signal.dispose.bind(null, id))
148
+ }
139
149
  prevIndex = vNode.index
140
150
  propSyncs.push(() => {
141
151
  if (prevIndex !== vNode.index) {
@@ -148,61 +158,118 @@ function createSetup<Props extends {}>(vNode: Kiru.VNode): Setup<Props> {
148
158
  return id
149
159
  },
150
160
  get props() {
151
- return currentProps.current
161
+ return (propsProxy ??= new Proxy(
162
+ {},
163
+ {
164
+ get(_, key) {
165
+ if (typeof key === "symbol")
166
+ return Reflect.get(currentProps.current as any, key)
167
+ const v = (currentProps.current as any)[key]
168
+ if (v !== null && typeof v === "object" && !Signal.isSignal(v)) {
169
+ return createProxy(v)
170
+ }
171
+ return v
172
+ },
173
+ }
174
+ ) as InferredProps)
152
175
  },
153
176
  }
154
177
  return setupResult
155
178
  }
179
+
156
180
  function propsUnchangedAtPaths(
157
181
  oldProps: Record<string, unknown>,
158
182
  newProps: Record<string, unknown>,
159
- paths: Set<string>
183
+ accessedPaths: Set<string[]>
160
184
  ): boolean {
161
- for (const path of paths) {
162
- if (!Object.is(getAtPath(oldProps, path), getAtPath(newProps, path))) {
163
- return false
185
+ outer: for (const path of accessedPaths) {
186
+ let a: unknown = oldProps
187
+ let b: unknown = newProps
188
+
189
+ for (let i = 0; i < path.length; i++) {
190
+ const key = path[i]
191
+
192
+ // Sentinel: caller iterated keys of the object at this path —
193
+ // re-run if the key sets differ
194
+ if (key === OWN_KEYS) {
195
+ if (a === b) continue outer
196
+ if (
197
+ a == null ||
198
+ b == null ||
199
+ typeof a !== "object" ||
200
+ typeof b !== "object"
201
+ ) {
202
+ return false
203
+ }
204
+ const aKeys = Object.keys(a)
205
+ const bKeys = Object.keys(b)
206
+ if (aKeys.length !== bKeys.length) return false
207
+ for (const k of aKeys) {
208
+ if (!(k in (b as object))) return false
209
+ }
210
+ continue outer
211
+ }
212
+
213
+ if (a === b) continue outer
214
+ if (
215
+ a == null ||
216
+ b == null ||
217
+ typeof a !== "object" ||
218
+ typeof b !== "object"
219
+ ) {
220
+ if (!Object.is(a, b)) return false
221
+ continue outer
222
+ }
223
+ a = (a as Record<string, unknown>)[key]
224
+ b = (b as Record<string, unknown>)[key]
164
225
  }
226
+
227
+ if (!Object.is(a, b)) return false
165
228
  }
229
+
166
230
  return true
167
231
  }
168
232
 
169
- function getAtPath(obj: Record<string, unknown>, path: string): unknown {
170
- let cur: unknown = obj
171
- for (const key of path.split(".")) {
172
- if (cur == null || typeof cur !== "object") return undefined
173
- cur = (cur as Record<string, unknown>)[key]
174
- }
175
- return cur
176
- }
233
+ const proxyCache = new WeakMap<object, any>()
177
234
 
178
235
  /**
179
- * Proxy that records paths and wraps signals. We only add to accessedPaths when
180
- * we hit a signal (the leaf we subscribe to), so propSync skip only compares
181
- * signal refs. Container objects (e.g. "data") are new every render and would
182
- * always fail the skip.
236
+ * Proxy that records accessed paths and primitives into the current
237
+ * tracking context (currentAccessedPaths).
183
238
  */
184
- function createPropsProxy<P extends Record<string, unknown>>(
185
- props: P,
186
- accessedPaths: Set<string>,
187
- pathPrefix?: string
239
+ function createProxy<P extends Record<string, unknown>>(
240
+ source: P,
241
+ path: string[] = []
188
242
  ): P {
189
- return new Proxy(props, {
190
- get(holder, key: string) {
191
- const path = pathPrefix ? `${pathPrefix}.${key}` : key
192
- const v = holder[key]
193
- if (Signal.isSignal(v)) {
194
- accessedPaths.add(path) // only record path for signal leaves
243
+ let cached = proxyCache.get(source)
244
+
245
+ if (!cached) {
246
+ cached = new Proxy(source, {
247
+ get(holder, key: string | symbol) {
248
+ if (typeof key === "symbol") return Reflect.get(holder, key)
249
+
250
+ const keyPath = [...path, key as string]
251
+ const v = holder[key as string]
252
+
253
+ if (v !== null && typeof v === "object" && !Signal.isSignal(v)) {
254
+ return createProxy(v as Record<string, unknown>, keyPath)
255
+ }
256
+
257
+ currentAccessedPaths?.add(keyPath)
195
258
  return v
196
- }
197
- if (v !== null && typeof v === "object" && !Array.isArray(v)) {
198
- return createPropsProxy(
199
- v as Record<string, unknown>,
200
- accessedPaths,
201
- path
202
- ) as P[keyof P]
203
- }
204
- accessedPaths.add(path) // primitive leaf
205
- return v
206
- },
207
- }) as P
259
+ },
260
+ has(holder, key: string | symbol) {
261
+ if (typeof key === "symbol") return Reflect.has(holder, key)
262
+ currentAccessedPaths?.add([...path, key as string])
263
+ return key in holder
264
+ },
265
+ ownKeys(holder) {
266
+ currentAccessedPaths?.add([...path, OWN_KEYS])
267
+ return Reflect.ownKeys(holder)
268
+ },
269
+ })
270
+
271
+ proxyCache.set(source, cached)
272
+ }
273
+
274
+ return cached
208
275
  }