@assistant-ui/tap 0.5.12 → 0.5.14
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/core/ResourceFiber.d.ts.map +1 -1
- package/dist/core/helpers/commit.d.ts.map +1 -1
- package/dist/core/helpers/execution-context.d.ts.map +1 -1
- package/dist/core/helpers/root.d.ts.map +1 -1
- package/dist/core/helpers/root.js.map +1 -1
- package/dist/core/resource.d.ts.map +1 -1
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/withKey.d.ts.map +1 -1
- package/dist/hooks/tap-callback.js.map +1 -1
- package/dist/hooks/tap-const.d.ts.map +1 -1
- package/dist/hooks/tap-effect-event.d.ts.map +1 -1
- package/dist/hooks/tap-reducer.d.ts.map +1 -1
- package/dist/hooks/tap-ref.d.ts.map +1 -1
- package/dist/hooks/tap-resource.d.ts.map +1 -1
- package/dist/hooks/tap-resource.js.map +1 -1
- package/dist/hooks/tap-resources.d.ts.map +1 -1
- package/dist/hooks/tap-resources.js.map +1 -1
- package/dist/hooks/tap-state.d.ts.map +1 -1
- package/dist/react/use-resource.d.ts.map +1 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/tapResourceRoot.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/basic/tapEffect.basic.test.ts +4 -3
- package/src/__tests__/errors/errors.effect-errors.test.ts +3 -4
- package/src/__tests__/lifecycle/lifecycle.dependencies.test.ts +1 -1
- package/src/__tests__/lifecycle/lifecycle.mount-unmount.test.ts +0 -3
- package/src/__tests__/strictmode/react-strictmode-behavior.test.tsx +1 -3
- package/src/__tests__/strictmode/react-strictmode-rerender-sources.test.tsx +17 -5
- package/src/__tests__/strictmode/tap-strictmode-rerender-sources.test.ts +1 -3
- package/src/__tests__/test-utils.ts +0 -1
- package/src/core/helpers/root.ts +0 -1
- package/src/hooks/tap-callback.ts +1 -1
- package/src/hooks/tap-resource.ts +2 -2
- package/src/hooks/tap-resources.ts +1 -1
- package/src/react/use-resource.ts +2 -2
- package/src/tapResourceRoot.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceFiber.d.ts","names":[],"sources":["../../src/core/ResourceFiber.ts"],"mappings":";;;iBAcgB,mBAAA,
|
|
1
|
+
{"version":3,"file":"ResourceFiber.d.ts","names":[],"sources":["../../src/core/ResourceFiber.ts"],"mappings":";;;iBAcgB,mBAAA,OACd,IAAA,EAAM,QAAA,CAAS,CAAA,EAAG,CAAA,GAClB,IAAA,EAAM,iBAAA,EACN,SAAA,6BACA,UAAA,6BACC,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAeJ,oBAAA,OAA2B,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA;AAAA,iBAQnD,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,KAAA,EAAO,CAAA,GACN,YAAA;AAAA,iBAmBa,mBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,MAAA,EAAQ,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.d.ts","names":[],"sources":["../../../src/core/helpers/commit.ts"],"mappings":";;;iBAEgB,gBAAA,CAAiB,YAA0B,EAAZ,YAAY;AAAA,iBAuB3C,iBAAA,
|
|
1
|
+
{"version":3,"file":"commit.d.ts","names":[],"sources":["../../../src/core/helpers/commit.ts"],"mappings":";;;iBAEgB,gBAAA,CAAiB,YAA0B,EAAZ,YAAY;AAAA,iBAuB3C,iBAAA,OAAwB,gBAAA,EAAkB,aAAA,CAAc,CAAA,EAAG,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-context.d.ts","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"mappings":";;;iBAKgB,iBAAA,
|
|
1
|
+
{"version":3,"file":"execution-context.d.ts","names":[],"sources":["../../../src/core/helpers/execution-context.ts"],"mappings":";;;iBAKgB,iBAAA,OACd,KAAA,EAAO,aAAA,CAAc,CAAA,EAAG,CAAA,GACxB,EAAA;AAAA,iBAsBc,uBAAA,IAA2B,aAAa;AAAA,iBAOxC,gBAAA,CAAiB,MAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.d.ts","names":[],"sources":["../../../src/core/helpers/root.ts"],"mappings":";;;cAEa,uBAAA,GACX,cAAA,GAAiB,EAAA,6BAChB,iBAQF;AAAA,cAEY,UAAA,GAAc,IAAuB,EAAjB,iBAAiB;AAAA,cAWrC,cAAA,GACX,IAAA,EAAM,iBAAiB,EACvB,OAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"root.d.ts","names":[],"sources":["../../../src/core/helpers/root.ts"],"mappings":";;;cAEa,uBAAA,GACX,cAAA,GAAiB,EAAA,6BAChB,iBAQF;AAAA,cAEY,UAAA,GAAc,IAAuB,EAAjB,iBAAiB;AAAA,cAWrC,cAAA,GACX,IAAA,EAAM,iBAAiB,EACvB,OAAA;AAAA,cA8BW,aAAA,GACX,KAAA,EAAO,aAAA,YACP,IAAA,EAAM,IAAI;EAAK,IAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.js","names":[],"sources":["../../../src/core/helpers/root.ts"],"sourcesContent":["import type { Cell, ResourceFiber, ResourceFiberRoot } from \"../types\";\n\nexport const createResourceFiberRoot = (\n dispatchUpdate: (cb: () => boolean) => void,\n): ResourceFiberRoot => {\n return {\n version: 0,\n committedVersion: 0,\n dispatchUpdate,\n changelog: [],\n dirtyCells: [],\n };\n};\n\nexport const commitRoot = (root: ResourceFiberRoot): void => {\n for (const cell of root.dirtyCells) {\n cell.dirty = false;\n cell.queue.clear();\n cell.current = cell.workInProgress;\n }\n root.committedVersion = root.version;\n root.changelog.length = 0;\n root.dirtyCells.length = 0;\n};\n\nexport const setRootVersion = (\n root: ResourceFiberRoot,\n version: number,\n): void => {\n const rollback = root.version > version;\n root.version = version;\n if (rollback) {\n for (const cell of root.dirtyCells) {\n cell.dirty = false;\n cell.queue.clear();\n cell.workInProgress = cell.current;\n }\n root.dirtyCells.length = 0;\n\n if (version === root.committedVersion) {\n root.changelog.length = 0;\n } else {\n // commit happened without a useEffect update (offscreen API)\n\n if (root.committedVersion > version)\n throw new Error(\"Version is less than committed version\");\n\n while (root.committedVersion + root.changelog.length > version) {\n root.changelog.pop();\n }\n\n
|
|
1
|
+
{"version":3,"file":"root.js","names":[],"sources":["../../../src/core/helpers/root.ts"],"sourcesContent":["import type { Cell, ResourceFiber, ResourceFiberRoot } from \"../types\";\n\nexport const createResourceFiberRoot = (\n dispatchUpdate: (cb: () => boolean) => void,\n): ResourceFiberRoot => {\n return {\n version: 0,\n committedVersion: 0,\n dispatchUpdate,\n changelog: [],\n dirtyCells: [],\n };\n};\n\nexport const commitRoot = (root: ResourceFiberRoot): void => {\n for (const cell of root.dirtyCells) {\n cell.dirty = false;\n cell.queue.clear();\n cell.current = cell.workInProgress;\n }\n root.committedVersion = root.version;\n root.changelog.length = 0;\n root.dirtyCells.length = 0;\n};\n\nexport const setRootVersion = (\n root: ResourceFiberRoot,\n version: number,\n): void => {\n const rollback = root.version > version;\n root.version = version;\n if (rollback) {\n for (const cell of root.dirtyCells) {\n cell.dirty = false;\n cell.queue.clear();\n cell.workInProgress = cell.current;\n }\n root.dirtyCells.length = 0;\n\n if (version === root.committedVersion) {\n root.changelog.length = 0;\n } else {\n // commit happened without a useEffect update (offscreen API)\n\n if (root.committedVersion > version)\n throw new Error(\"Version is less than committed version\");\n\n while (root.committedVersion + root.changelog.length > version) {\n root.changelog.pop();\n }\n\n root.changelog.forEach((apply) => apply());\n commitRoot(root);\n }\n }\n};\n\nexport const markCellDirty = (\n fiber: ResourceFiber<any, any>,\n cell: Cell & { type: \"reducer\" },\n): void => {\n if (!cell.dirty) {\n cell.dirty = true;\n fiber.markDirty?.();\n fiber.root.dirtyCells.push(cell);\n }\n};\n"],"mappings":";AAEA,MAAa,2BACX,mBACsB;CACtB,OAAO;EACL,SAAS;EACT,kBAAkB;EAClB;EACA,WAAW,CAAC;EACZ,YAAY,CAAC;CACf;AACF;AAEA,MAAa,cAAc,SAAkC;CAC3D,KAAK,MAAM,QAAQ,KAAK,YAAY;EAClC,KAAK,QAAQ;EACb,KAAK,MAAM,MAAM;EACjB,KAAK,UAAU,KAAK;CACtB;CACA,KAAK,mBAAmB,KAAK;CAC7B,KAAK,UAAU,SAAS;CACxB,KAAK,WAAW,SAAS;AAC3B;AAEA,MAAa,kBACX,MACA,YACS;CACT,MAAM,WAAW,KAAK,UAAU;CAChC,KAAK,UAAU;CACf,IAAI,UAAU;EACZ,KAAK,MAAM,QAAQ,KAAK,YAAY;GAClC,KAAK,QAAQ;GACb,KAAK,MAAM,MAAM;GACjB,KAAK,iBAAiB,KAAK;EAC7B;EACA,KAAK,WAAW,SAAS;EAEzB,IAAI,YAAY,KAAK,kBACnB,KAAK,UAAU,SAAS;OACnB;GAGL,IAAI,KAAK,mBAAmB,SAC1B,MAAM,IAAI,MAAM,wCAAwC;GAE1D,OAAO,KAAK,mBAAmB,KAAK,UAAU,SAAS,SACrD,KAAK,UAAU,IAAI;GAGrB,KAAK,UAAU,SAAS,UAAU,MAAM,CAAC;GACzC,WAAW,IAAI;EACjB;CACF;AACF;AAEA,MAAa,iBACX,OACA,SACS;CACT,IAAI,CAAC,KAAK,OAAO;EACf,KAAK,QAAQ;EACb,MAAM,YAAY;EAClB,MAAM,KAAK,WAAW,KAAK,IAAI;CACjC;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","names":[],"sources":["../../src/core/resource.ts"],"mappings":";;;iBAGgB,QAAA,
|
|
1
|
+
{"version":3,"file":"resource.d.ts","names":[],"sources":["../../src/core/resource.ts"],"mappings":";;;iBAGgB,QAAA,IAAY,EAAA,QAAU,CAAA,SAAU,eAAA,CAAgB,CAAA;AAAA,iBAChD,QAAA,OACd,EAAA,GAAK,KAAA,EAAO,CAAA,KAAM,CAAA,IAChB,KAAA,EAAO,CAAA,KAAM,eAAA,CAAgB,CAAA,EAAG,CAAA;AAAA,iBACpB,QAAA,OACd,EAAA,GAAK,KAAA,GAAQ,CAAA,KAAM,CAAA,IACjB,KAAA,GAAQ,CAAA,KAAM,eAAA,CAAgB,CAAA,EAAG,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","names":[],"sources":["../../src/core/scheduler.ts"],"mappings":";KAAK,IAAA;AAAA,cAaQ,eAAA;EAAA,iBAGkB,KAAA;EAAA,QAFrB,QAAA;cAEqB,KAAA,EAAO,IAAI;EAAA,IAEpC,OAAA
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","names":[],"sources":["../../src/core/scheduler.ts"],"mappings":";KAAK,IAAA;AAAA,cAaQ,eAAA;EAAA,iBAGkB,KAAA;EAAA,QAFrB,QAAA;cAEqB,KAAA,EAAO,IAAI;EAAA,IAEpC,OAAA;EAIJ,SAAA;EAOA,OAAA;AAAA;AAAA,cAiEW,kBAAA,MAAyB,QAAA,QAAgB,CAAA,KAAI,CAezD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withKey.d.ts","names":[],"sources":["../../src/core/withKey.ts"],"mappings":";;;iBAEgB,OAAA,WAAkB,eAAA,
|
|
1
|
+
{"version":3,"file":"withKey.d.ts","names":[],"sources":["../../src/core/withKey.ts"],"mappings":";;;iBAEgB,OAAA,WAAkB,eAAA,YAChC,GAAA,mBACA,OAAA,EAAS,CAAA,GACR,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-callback.js","names":[],"sources":["../../src/hooks/tap-callback.ts"],"sourcesContent":["import { tapMemo } from \"./tap-memo\";\n\nexport const tapCallback = <T extends (...args: any[]) => any>(\n fn: T,\n deps: readonly unknown[],\n): T => {\n //
|
|
1
|
+
{"version":3,"file":"tap-callback.js","names":[],"sources":["../../src/hooks/tap-callback.ts"],"sourcesContent":["import { tapMemo } from \"./tap-memo\";\n\nexport const tapCallback = <T extends (...args: any[]) => any>(\n fn: T,\n deps: readonly unknown[],\n): T => {\n // oxlint-disable-next-line tap-hooks/exhaustive-deps -- user-provided dep array forwarded verbatim\n return tapMemo(() => fn, deps);\n};\n"],"mappings":";;AAEA,MAAa,eACX,IACA,SACM;CAEN,OAAO,cAAc,IAAI,IAAI;AAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-const.d.ts","names":[],"sources":["../../src/hooks/tap-const.ts"],"mappings":";iBAEgB,QAAA,
|
|
1
|
+
{"version":3,"file":"tap-const.d.ts","names":[],"sources":["../../src/hooks/tap-const.ts"],"mappings":";iBAEgB,QAAA,IAAY,QAAA,QAAgB,CAAA,EAAG,KAAA,qBAA0B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-effect-event.d.ts","names":[],"sources":["../../src/hooks/tap-effect-event.ts"],"mappings":";;AAqBA;;;;;;;;;;AAEI;;;;iBAFY,cAAA,eAA6B,IAAA,
|
|
1
|
+
{"version":3,"file":"tap-effect-event.d.ts","names":[],"sources":["../../src/hooks/tap-effect-event.ts"],"mappings":";;AAqBA;;;;;;;;;;AAEI;;;;iBAFY,cAAA,eAA6B,IAAA,iBAC3C,QAAA,EAAU,CAAA,GACT,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-reducer.d.ts","names":[],"sources":["../../src/hooks/tap-reducer.ts"],"mappings":";KAMK,QAAA,OAAe,MAAA,EAAQ,CAAC;AAAA,iBAqGb,UAAA,
|
|
1
|
+
{"version":3,"file":"tap-reducer.d.ts","names":[],"sources":["../../src/hooks/tap-reducer.ts"],"mappings":";KAMK,QAAA,OAAe,MAAA,EAAQ,CAAC;AAAA,iBAqGb,UAAA,OACd,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,YAAA,EAAc,CAAA,IACZ,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBACA,UAAA,UACd,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,UAAA,EAAY,CAAA,EACZ,IAAA,GAAO,GAAA,EAAK,CAAA,KAAM,CAAA,IAChB,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBAcA,0BAAA,iBAA2C,CAAA,EACzD,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,eAAA,GAAkB,KAAA,EAAO,CAAA,KAAM,CAAA,EAC/B,YAAA,EAAc,CAAA,IACZ,CAAA,EAAG,QAAA,CAAS,CAAA;AAAA,iBACA,0BAAA,oBAA8C,CAAA,EAC5D,OAAA,GAAU,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,CAAA,EAClC,eAAA,GAAkB,KAAA,EAAO,CAAA,KAAM,CAAA,EAC/B,UAAA,EAAY,CAAA,EACZ,IAAA,GAAO,GAAA,EAAK,CAAA,KAAM,CAAA,IAChB,CAAA,EAAG,QAAA,CAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-ref.d.ts","names":[],"sources":["../../src/hooks/tap-ref.ts"],"mappings":";kBAEiB,MAAA;EAAA,UACE,SAAA;IACf,OAAA,EAAS,CAAC;EAAA;AAAA;AAAA,iBAIE,MAAA,
|
|
1
|
+
{"version":3,"file":"tap-ref.d.ts","names":[],"sources":["../../src/hooks/tap-ref.ts"],"mappings":";kBAEiB,MAAA;EAAA,UACE,SAAA;IACf,OAAA,EAAS,CAAC;EAAA;AAAA;AAAA,iBAIE,MAAA,IAAU,YAAA,EAAc,CAAA,GAAI,MAAA,CAAO,SAAA,CAAU,CAAA;AAAA,iBAC7C,MAAA,mBAAyB,MAAA,CAAO,SAAS,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-resource.d.ts","names":[],"sources":["../../src/hooks/tap-resource.ts"],"mappings":";;;iBAYgB,WAAA,WAAsB,eAAA,
|
|
1
|
+
{"version":3,"file":"tap-resource.d.ts","names":[],"sources":["../../src/hooks/tap-resource.ts"],"mappings":";;;iBAYgB,WAAA,WAAsB,eAAA,YACpC,OAAA,EAAS,CAAA,GACR,yBAAA,CAA0B,CAAA;AAAA,iBACb,WAAA,WAAsB,eAAA,YACpC,OAAA,EAAS,CAAA,EACT,SAAA,uBACC,yBAAA,CAA0B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-resource.js","names":[],"sources":["../../src/hooks/tap-resource.ts"],"sourcesContent":["import type { ExtractResourceReturnType, ResourceElement } from \"../core/types\";\nimport { tapEffect } from \"./tap-effect\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { tapMemo } from \"./tap-memo\";\nimport { tapRef } from \"./tap-ref\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\n\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n): ExtractResourceReturnType<E>;\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n propsDeps: readonly unknown[],\n): ExtractResourceReturnType<E>;\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n propsDeps?: readonly unknown[],\n): ExtractResourceReturnType<E> {\n const parentFiber = getCurrentResourceFiber();\n const versionRef = tapRef(0);\n const fiber = tapMemo(() => {\n void element.key;\n return createResourceFiber(element.type, parentFiber.root, () => {\n versionRef.current++;\n parentFiber.markDirty?.();\n });\n }, [element.type, element.key, parentFiber]);\n\n const result = propsDeps\n ?
|
|
1
|
+
{"version":3,"file":"tap-resource.js","names":[],"sources":["../../src/hooks/tap-resource.ts"],"sourcesContent":["import type { ExtractResourceReturnType, ResourceElement } from \"../core/types\";\nimport { tapEffect } from \"./tap-effect\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { tapMemo } from \"./tap-memo\";\nimport { tapRef } from \"./tap-ref\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\n\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n): ExtractResourceReturnType<E>;\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n propsDeps: readonly unknown[],\n): ExtractResourceReturnType<E>;\nexport function tapResource<E extends ResourceElement<any, any>>(\n element: E,\n propsDeps?: readonly unknown[],\n): ExtractResourceReturnType<E> {\n const parentFiber = getCurrentResourceFiber();\n const versionRef = tapRef(0);\n const fiber = tapMemo(() => {\n void element.key;\n return createResourceFiber(element.type, parentFiber.root, () => {\n versionRef.current++;\n parentFiber.markDirty?.();\n });\n }, [element.type, element.key, parentFiber]);\n\n const result = propsDeps\n ? tapMemo(\n () => renderResourceFiber(fiber, element.props),\n // oxlint-disable-next-line tap-hooks/exhaustive-deps -- props identity replaced by user-provided deps\n [fiber, ...propsDeps, versionRef.current],\n )\n : renderResourceFiber(fiber, element.props);\n\n tapEffect(() => () => unmountResourceFiber(fiber), [fiber]);\n tapEffect(() => {\n commitResourceFiber(fiber, result);\n }, [fiber, result]);\n\n return result.output;\n}\n"],"mappings":";;;;;;AAmBA,SAAgB,YACd,SACA,WAC8B;CAC9B,MAAM,cAAc,wBAAwB;CAC5C,MAAM,aAAa,OAAO,CAAC;CAC3B,MAAM,QAAQ,cAAc;EAC1B,QAAa;EACb,OAAO,oBAAoB,QAAQ,MAAM,YAAY,YAAY;GAC/D,WAAW;GACX,YAAY,YAAY;EAC1B,CAAC;CACH,GAAG;EAAC,QAAQ;EAAM,QAAQ;EAAK;CAAW,CAAC;CAE3C,MAAM,SAAS,YACX,cACQ,oBAAoB,OAAO,QAAQ,KAAK,GAE9C;EAAC;EAAO,GAAG;EAAW,WAAW;CAAO,CAC1C,IACA,oBAAoB,OAAO,QAAQ,KAAK;CAE5C,sBAAsB,qBAAqB,KAAK,GAAG,CAAC,KAAK,CAAC;CAC1D,gBAAgB;EACd,oBAAoB,OAAO,MAAM;CACnC,GAAG,CAAC,OAAO,MAAM,CAAC;CAElB,OAAO,OAAO;AAChB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-resources.d.ts","names":[],"sources":["../../src/hooks/tap-resources.ts"],"mappings":";;;iBA2BgB,YAAA,WAAuB,eAAA,
|
|
1
|
+
{"version":3,"file":"tap-resources.d.ts","names":[],"sources":["../../src/hooks/tap-resources.ts"],"mappings":";;;iBA2BgB,YAAA,WAAuB,eAAA,YACrC,WAAA,iBAA4B,CAAA,IAC5B,eAAA,wBACC,yBAAA,CAA0B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-resources.js","names":[],"sources":["../../src/hooks/tap-resources.ts"],"sourcesContent":["import type {\n ExtractResourceReturnType,\n RenderResult,\n ResourceElement,\n ResourceFiber,\n} from \"../core/types\";\nimport { tapEffect } from \"./tap-effect\";\nimport { tapMemo } from \"./tap-memo\";\nimport { tapCallback } from \"./tap-callback\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { tapConst } from \"./tap-const\";\nimport { tapRef } from \"./tap-ref\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\n\ntype FiberState = {\n fiber: ResourceFiber<unknown, unknown>;\n next:\n | RenderResult\n | [ResourceFiber<unknown, unknown>, RenderResult]\n | \"delete\";\n};\n\nexport function tapResources<E extends ResourceElement<any, any>>(\n getElements: () => readonly E[],\n getElementsDeps?: readonly unknown[],\n): ExtractResourceReturnType<E>[] {\n const versionRef = tapRef(0);\n const version = versionRef.current;\n\n const parentFiber = tapConst(getCurrentResourceFiber, []);\n const markDirty = tapConst(\n () => () => {\n versionRef.current++;\n parentFiber.markDirty?.();\n },\n [],\n );\n const fibers = tapConst(() => new Map<string | number, FiberState>(), []);\n\n const getElementsMemo = getElementsDeps\n ? //
|
|
1
|
+
{"version":3,"file":"tap-resources.js","names":[],"sources":["../../src/hooks/tap-resources.ts"],"sourcesContent":["import type {\n ExtractResourceReturnType,\n RenderResult,\n ResourceElement,\n ResourceFiber,\n} from \"../core/types\";\nimport { tapEffect } from \"./tap-effect\";\nimport { tapMemo } from \"./tap-memo\";\nimport { tapCallback } from \"./tap-callback\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { tapConst } from \"./tap-const\";\nimport { tapRef } from \"./tap-ref\";\nimport { getCurrentResourceFiber } from \"../core/helpers/execution-context\";\n\ntype FiberState = {\n fiber: ResourceFiber<unknown, unknown>;\n next:\n | RenderResult\n | [ResourceFiber<unknown, unknown>, RenderResult]\n | \"delete\";\n};\n\nexport function tapResources<E extends ResourceElement<any, any>>(\n getElements: () => readonly E[],\n getElementsDeps?: readonly unknown[],\n): ExtractResourceReturnType<E>[] {\n const versionRef = tapRef(0);\n const version = versionRef.current;\n\n const parentFiber = tapConst(getCurrentResourceFiber, []);\n const markDirty = tapConst(\n () => () => {\n versionRef.current++;\n parentFiber.markDirty?.();\n },\n [],\n );\n const fibers = tapConst(() => new Map<string | number, FiberState>(), []);\n\n const getElementsMemo = getElementsDeps\n ? // oxlint-disable-next-line tap-hooks/exhaustive-deps -- deps forwarded by caller\n tapCallback(getElements, getElementsDeps)\n : getElements;\n\n // Process each element\n\n const res = tapMemo(() => {\n void version;\n\n const elementsArray = getElementsMemo();\n const seenKeys = new Set<string | number>();\n const results: any[] = [];\n let newCount = 0;\n\n // Create/update fibers and render\n for (let i = 0; i < elementsArray.length; i++) {\n const element = elementsArray[i]!;\n\n const elementKey = element.key;\n if (elementKey === undefined) {\n throw new Error(\n `tapResources did not provide a key for array at index ${i}`,\n );\n }\n\n if (seenKeys.has(elementKey))\n throw new Error(`Duplicate key ${elementKey} in tapResources`);\n seenKeys.add(elementKey);\n\n let state = fibers.get(elementKey);\n if (!state) {\n const fiber = createResourceFiber(\n element.type,\n parentFiber.root,\n markDirty,\n );\n const result = renderResourceFiber(fiber, element.props);\n state = {\n fiber,\n next: result,\n };\n newCount++;\n fibers.set(elementKey, state);\n results.push(result.output);\n } else if (state.fiber.type !== element.type) {\n const fiber = createResourceFiber(\n element.type,\n parentFiber.root,\n markDirty,\n );\n const result = renderResourceFiber(fiber, element.props);\n state.next = [fiber, result];\n results.push(result.output);\n } else {\n state.next = renderResourceFiber(state.fiber, element.props);\n results.push(state.next.output);\n }\n }\n\n // Clean up removed fibers (only if there might be stale ones)\n if (fibers.size > results.length - newCount) {\n for (const key of fibers.keys()) {\n if (!seenKeys.has(key)) {\n fibers.get(key)!.next = \"delete\";\n }\n }\n }\n\n return results;\n }, [getElementsMemo, version]);\n\n // Cleanup on unmount\n tapEffect(() => {\n return () => {\n for (const key of fibers.keys()) {\n const fiber = fibers.get(key)!.fiber;\n unmountResourceFiber(fiber);\n }\n };\n }, []);\n\n tapEffect(() => {\n res; // as a performance optimization, we only run if the results have changed\n\n for (const [key, state] of fibers.entries()) {\n if (state.next === \"delete\") {\n if (state.fiber.isMounted) {\n unmountResourceFiber(state.fiber);\n }\n\n fibers.delete(key);\n } else if (Array.isArray(state.next)) {\n unmountResourceFiber(state.fiber);\n state.fiber = state.next[0];\n commitResourceFiber(state.fiber, state.next[1]);\n } else {\n commitResourceFiber(state.fiber, state.next);\n }\n }\n }, [res]);\n\n return res;\n}\n"],"mappings":";;;;;;;;AA2BA,SAAgB,aACd,aACA,iBACgC;CAChC,MAAM,aAAa,OAAO,CAAC;CAC3B,MAAM,UAAU,WAAW;CAE3B,MAAM,cAAc,SAAS,yBAAyB,CAAC,CAAC;CACxD,MAAM,YAAY,qBACJ;EACV,WAAW;EACX,YAAY,YAAY;CAC1B,GACA,CAAC,CACH;CACA,MAAM,SAAS,+BAAe,IAAI,IAAiC,GAAG,CAAC,CAAC;CAExE,MAAM,kBAAkB,kBAEpB,YAAY,aAAa,eAAe,IACxC;CAIJ,MAAM,MAAM,cAAc;EAGxB,MAAM,gBAAgB,gBAAgB;EACtC,MAAM,2BAAW,IAAI,IAAqB;EAC1C,MAAM,UAAiB,CAAC;EACxB,IAAI,WAAW;EAGf,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;GAC7C,MAAM,UAAU,cAAc;GAE9B,MAAM,aAAa,QAAQ;GAC3B,IAAI,eAAe,KAAA,GACjB,MAAM,IAAI,MACR,yDAAyD,GAC3D;GAGF,IAAI,SAAS,IAAI,UAAU,GACzB,MAAM,IAAI,MAAM,iBAAiB,WAAW,iBAAiB;GAC/D,SAAS,IAAI,UAAU;GAEvB,IAAI,QAAQ,OAAO,IAAI,UAAU;GACjC,IAAI,CAAC,OAAO;IACV,MAAM,QAAQ,oBACZ,QAAQ,MACR,YAAY,MACZ,SACF;IACA,MAAM,SAAS,oBAAoB,OAAO,QAAQ,KAAK;IACvD,QAAQ;KACN;KACA,MAAM;IACR;IACA;IACA,OAAO,IAAI,YAAY,KAAK;IAC5B,QAAQ,KAAK,OAAO,MAAM;GAC5B,OAAO,IAAI,MAAM,MAAM,SAAS,QAAQ,MAAM;IAC5C,MAAM,QAAQ,oBACZ,QAAQ,MACR,YAAY,MACZ,SACF;IACA,MAAM,SAAS,oBAAoB,OAAO,QAAQ,KAAK;IACvD,MAAM,OAAO,CAAC,OAAO,MAAM;IAC3B,QAAQ,KAAK,OAAO,MAAM;GAC5B,OAAO;IACL,MAAM,OAAO,oBAAoB,MAAM,OAAO,QAAQ,KAAK;IAC3D,QAAQ,KAAK,MAAM,KAAK,MAAM;GAChC;EACF;EAGA,IAAI,OAAO,OAAO,QAAQ,SAAS;QAC5B,MAAM,OAAO,OAAO,KAAK,GAC5B,IAAI,CAAC,SAAS,IAAI,GAAG,GACnB,OAAO,IAAI,GAAG,EAAG,OAAO;EAAA;EAK9B,OAAO;CACT,GAAG,CAAC,iBAAiB,OAAO,CAAC;CAG7B,gBAAgB;EACd,aAAa;GACX,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG;IAC/B,MAAM,QAAQ,OAAO,IAAI,GAAG,EAAG;IAC/B,qBAAqB,KAAK;GAC5B;EACF;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB;EAGd,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GACxC,IAAI,MAAM,SAAS,UAAU;GAC3B,IAAI,MAAM,MAAM,WACd,qBAAqB,MAAM,KAAK;GAGlC,OAAO,OAAO,GAAG;EACnB,OAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,GAAG;GACpC,qBAAqB,MAAM,KAAK;GAChC,MAAM,QAAQ,MAAM,KAAK;GACzB,oBAAoB,MAAM,OAAO,MAAM,KAAK,EAAE;EAChD,OACE,oBAAoB,MAAM,OAAO,MAAM,IAAI;CAGjD,GAAG,CAAC,GAAG,CAAC;CAER,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tap-state.d.ts","names":[],"sources":["../../src/hooks/tap-state.ts"],"mappings":";kBAEiB,QAAA;EAAA,KACH,YAAA,MAAkB,CAAA,KAAM,IAAA,EAAM,CAAA,KAAM,CAAA;AAAA;AAAA,iBAclC,QAAA,
|
|
1
|
+
{"version":3,"file":"tap-state.d.ts","names":[],"sources":["../../src/hooks/tap-state.ts"],"mappings":";kBAEiB,QAAA;EAAA,KACH,YAAA,MAAkB,CAAA,KAAM,IAAA,EAAM,CAAA,KAAM,CAAA;AAAA;AAAA,iBAclC,QAAA,oBACd,CAAA,eACC,OAAA,EAAS,QAAA,CAAS,YAAA,CAAa,CAAA;AAAA,iBAElB,QAAA,IACd,OAAA,EAAS,CAAA,UAAW,CAAA,KAClB,CAAA,GAAI,OAAA,EAAS,QAAA,CAAS,YAAA,CAAa,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-resource.d.ts","names":[],"sources":["../../src/react/use-resource.ts"],"mappings":";;;iBA+BgB,WAAA,WAAsB,eAAA,
|
|
1
|
+
{"version":3,"file":"use-resource.d.ts","names":[],"sources":["../../src/react/use-resource.ts"],"mappings":";;;iBA+BgB,WAAA,WAAsB,eAAA,YACpC,OAAA,EAAS,CAAA,GACR,yBAAA,CAA0B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport type {\n ResourceFiberRoot,\n ExtractResourceReturnType,\n ResourceElement,\n} from \"../core/types\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { isDevelopment } from \"../core/helpers/env\";\nimport {\n commitRoot,\n createResourceFiberRoot,\n setRootVersion,\n} from \"../core/helpers/root\";\n\nconst useDevStrictMode = () => {\n if (!isDevelopment) return null;\n\n //
|
|
1
|
+
{"version":3,"file":"use-resource.js","names":[],"sources":["../../src/react/use-resource.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useReducer, useRef, useState } from \"react\";\nimport type {\n ResourceFiberRoot,\n ExtractResourceReturnType,\n ResourceElement,\n} from \"../core/types\";\nimport {\n createResourceFiber,\n unmountResourceFiber,\n renderResourceFiber,\n commitResourceFiber,\n} from \"../core/ResourceFiber\";\nimport { isDevelopment } from \"../core/helpers/env\";\nimport {\n commitRoot,\n createResourceFiberRoot,\n setRootVersion,\n} from \"../core/helpers/root\";\n\nconst useDevStrictMode = () => {\n if (!isDevelopment) return null;\n\n // oxlint-disable-next-line react-hooks/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build\n const count = useRef(0);\n const isFirstRender = count.current === 0;\n // oxlint-disable-next-line react-hooks/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build\n useState(() => count.current++);\n if (count.current !== 2) return null;\n return isFirstRender ? (\"child\" as const) : (\"root\" as const);\n};\n\nexport function useResource<E extends ResourceElement<any, any>>(\n element: E,\n): ExtractResourceReturnType<E> {\n const root = useMemo<ResourceFiberRoot>(() => {\n return createResourceFiberRoot((cb) => dispatch(cb));\n }, []);\n\n const [version, dispatch] = useReducer((v: number, cb: () => boolean) => {\n setRootVersion(root, v);\n return v + (cb() ? 1 : 0);\n }, 0);\n setRootVersion(root, version);\n\n const devStrictMode = useDevStrictMode();\n const fiber = useMemo(() => {\n void element.key;\n return createResourceFiber(element.type, root, undefined, devStrictMode);\n }, [element.type, element.key, root, devStrictMode]);\n\n const result = renderResourceFiber(fiber, element.props);\n useLayoutEffect(() => {\n return () => unmountResourceFiber(fiber);\n }, [fiber]);\n useLayoutEffect(() => {\n commitRoot(root);\n commitResourceFiber(fiber, result);\n });\n\n return result.output;\n}\n"],"mappings":";;;;;AAmBA,MAAM,yBAAyB;CAC7B,IAAI,CAAC,eAAe,OAAO;CAG3B,MAAM,QAAQ,OAAO,CAAC;CACtB,MAAM,gBAAgB,MAAM,YAAY;CAExC,eAAe,MAAM,SAAS;CAC9B,IAAI,MAAM,YAAY,GAAG,OAAO;CAChC,OAAO,gBAAiB,UAAqB;AAC/C;AAEA,SAAgB,YACd,SAC8B;CAC9B,MAAM,OAAO,cAAiC;EAC5C,OAAO,yBAAyB,OAAO,SAAS,EAAE,CAAC;CACrD,GAAG,CAAC,CAAC;CAEL,MAAM,CAAC,SAAS,YAAY,YAAY,GAAW,OAAsB;EACvE,eAAe,MAAM,CAAC;EACtB,OAAO,KAAK,GAAG,IAAI,IAAI;CACzB,GAAG,CAAC;CACJ,eAAe,MAAM,OAAO;CAE5B,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,QAAQ,cAAc;EAC1B,QAAa;EACb,OAAO,oBAAoB,QAAQ,MAAM,MAAM,KAAA,GAAW,aAAa;CACzE,GAAG;EAAC,QAAQ;EAAM,QAAQ;EAAK;EAAM;CAAa,CAAC;CAEnD,MAAM,SAAS,oBAAoB,OAAO,QAAQ,KAAK;CACvD,sBAAsB;EACpB,aAAa,qBAAqB,KAAK;CACzC,GAAG,CAAC,KAAK,CAAC;CACV,sBAAsB;EACpB,WAAW,IAAI;EACf,oBAAoB,OAAO,MAAM;CACnC,CAAC;CAED,OAAO,OAAO;AAChB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tapResourceRoot.js","names":[],"sources":["../src/tapResourceRoot.ts"],"sourcesContent":["import {\n commitResourceFiber,\n createResourceFiber,\n renderResourceFiber,\n unmountResourceFiber,\n} from \"./core/ResourceFiber\";\nimport { UpdateScheduler } from \"./core/scheduler\";\nimport { tapConst } from \"./hooks/tap-const\";\nimport { tapMemo } from \"./hooks/tap-memo\";\nimport { tapEffect } from \"./hooks/tap-effect\";\nimport { tapEffectEvent } from \"./hooks/tap-effect-event\";\nimport { tapRef } from \"./hooks/tap-ref\";\nimport type { RenderResult, ResourceElement } from \"./core/types\";\nimport { isDevelopment } from \"./core/helpers/env\";\nimport {\n commitRoot,\n createResourceFiberRoot,\n setRootVersion,\n} from \"./core/helpers/root\";\n\nexport namespace tapResourceRoot {\n export type Unsubscribe = () => void;\n\n export interface SubscribableResource<TState> {\n /**\n * Get the current state of the store.\n */\n getValue(): TState;\n\n /**\n * Subscribe to the store.\n */\n subscribe(listener: () => void): Unsubscribe;\n }\n}\n\n// currently we never reset the root, because rollbakcs are not supported in tapResourceRoot\n\nexport const tapResourceRoot = <TState>(\n element: ResourceElement<TState>,\n): tapResourceRoot.SubscribableResource<TState> => {\n const scheduler = tapConst(\n () => new UpdateScheduler(() => handleUpdate(null)),\n [],\n );\n const queue = tapConst(() => [] as (() => void)[], []);\n\n const fiber = tapMemo(() => {\n void element.key;\n\n return createResourceFiber(\n element.type,\n createResourceFiberRoot((callback) => {\n if (!scheduler.isDirty && !callback()) return;\n queue.push(callback);\n scheduler.markDirty();\n }),\n );\n }, [element.type, element.key]);\n\n setRootVersion(fiber.root, fiber.root.committedVersion);\n const render = renderResourceFiber(fiber, element.props);\n\n const isMountedRef = tapRef(false);\n const committedPropsRef = tapRef(element.props);\n const valueRef = tapRef<TState>(render.output);\n const subscribers = tapConst(() => new Set<() => void>(), []);\n const handleUpdate = tapEffectEvent((render: RenderResult | null) => {\n if (render === null) {\n setRootVersion(fiber.root, 2);\n setRootVersion(fiber.root, 1);\n\n queue.forEach((callback) => {\n if (isDevelopment && fiber.devStrictMode) {\n callback();\n }\n\n callback();\n });\n\n if (isDevelopment && fiber.devStrictMode) {\n void renderResourceFiber(fiber, committedPropsRef.current);\n }\n\n render = renderResourceFiber(fiber, committedPropsRef.current);\n }\n\n if (scheduler.isDirty)\n throw new Error(\"Scheduler is dirty, this should never happen\");\n\n commitRoot(fiber.root);\n queue.length = 0;\n\n if (isMountedRef.current) {\n commitResourceFiber(fiber, render);\n }\n\n if (scheduler.isDirty || valueRef.current === render.output) return;\n valueRef.current = render.output;\n
|
|
1
|
+
{"version":3,"file":"tapResourceRoot.js","names":[],"sources":["../src/tapResourceRoot.ts"],"sourcesContent":["import {\n commitResourceFiber,\n createResourceFiber,\n renderResourceFiber,\n unmountResourceFiber,\n} from \"./core/ResourceFiber\";\nimport { UpdateScheduler } from \"./core/scheduler\";\nimport { tapConst } from \"./hooks/tap-const\";\nimport { tapMemo } from \"./hooks/tap-memo\";\nimport { tapEffect } from \"./hooks/tap-effect\";\nimport { tapEffectEvent } from \"./hooks/tap-effect-event\";\nimport { tapRef } from \"./hooks/tap-ref\";\nimport type { RenderResult, ResourceElement } from \"./core/types\";\nimport { isDevelopment } from \"./core/helpers/env\";\nimport {\n commitRoot,\n createResourceFiberRoot,\n setRootVersion,\n} from \"./core/helpers/root\";\n\nexport namespace tapResourceRoot {\n export type Unsubscribe = () => void;\n\n export interface SubscribableResource<TState> {\n /**\n * Get the current state of the store.\n */\n getValue(): TState;\n\n /**\n * Subscribe to the store.\n */\n subscribe(listener: () => void): Unsubscribe;\n }\n}\n\n// currently we never reset the root, because rollbakcs are not supported in tapResourceRoot\n\nexport const tapResourceRoot = <TState>(\n element: ResourceElement<TState>,\n): tapResourceRoot.SubscribableResource<TState> => {\n const scheduler = tapConst(\n () => new UpdateScheduler(() => handleUpdate(null)),\n [],\n );\n const queue = tapConst(() => [] as (() => void)[], []);\n\n const fiber = tapMemo(() => {\n void element.key;\n\n return createResourceFiber(\n element.type,\n createResourceFiberRoot((callback) => {\n if (!scheduler.isDirty && !callback()) return;\n queue.push(callback);\n scheduler.markDirty();\n }),\n );\n }, [element.type, element.key]);\n\n setRootVersion(fiber.root, fiber.root.committedVersion);\n const render = renderResourceFiber(fiber, element.props);\n\n const isMountedRef = tapRef(false);\n const committedPropsRef = tapRef(element.props);\n const valueRef = tapRef<TState>(render.output);\n const subscribers = tapConst(() => new Set<() => void>(), []);\n const handleUpdate = tapEffectEvent((render: RenderResult | null) => {\n if (render === null) {\n setRootVersion(fiber.root, 2);\n setRootVersion(fiber.root, 1);\n\n queue.forEach((callback) => {\n if (isDevelopment && fiber.devStrictMode) {\n callback();\n }\n\n callback();\n });\n\n if (isDevelopment && fiber.devStrictMode) {\n void renderResourceFiber(fiber, committedPropsRef.current);\n }\n\n render = renderResourceFiber(fiber, committedPropsRef.current);\n }\n\n if (scheduler.isDirty)\n throw new Error(\"Scheduler is dirty, this should never happen\");\n\n commitRoot(fiber.root);\n queue.length = 0;\n\n if (isMountedRef.current) {\n commitResourceFiber(fiber, render);\n }\n\n if (scheduler.isDirty || valueRef.current === render.output) return;\n valueRef.current = render.output;\n subscribers.forEach((callback) => callback());\n });\n\n tapEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n unmountResourceFiber(fiber);\n };\n }, [fiber]);\n\n tapEffect(() => {\n committedPropsRef.current = render.props;\n commitRoot(fiber.root);\n commitResourceFiber(fiber, render);\n\n if (scheduler.isDirty || valueRef.current === render.output) return;\n valueRef.current = render.output;\n subscribers.forEach((callback) => callback());\n });\n\n return tapMemo(\n () => ({\n getValue: () => valueRef.current,\n subscribe: (listener: () => void) => {\n subscribers.add(listener);\n return () => subscribers.delete(listener);\n },\n }),\n [],\n );\n};\n"],"mappings":";;;;;;;;;;AAsCA,MAAa,mBACX,YACiD;CACjD,MAAM,YAAY,eACV,IAAI,sBAAsB,aAAa,IAAI,CAAC,GAClD,CAAC,CACH;CACA,MAAM,QAAQ,eAAe,CAAC,GAAqB,CAAC,CAAC;CAErD,MAAM,QAAQ,cAAc;EAC1B,QAAa;EAEb,OAAO,oBACL,QAAQ,MACR,yBAAyB,aAAa;GACpC,IAAI,CAAC,UAAU,WAAW,CAAC,SAAS,GAAG;GACvC,MAAM,KAAK,QAAQ;GACnB,UAAU,UAAU;EACtB,CAAC,CACH;CACF,GAAG,CAAC,QAAQ,MAAM,QAAQ,GAAG,CAAC;CAE9B,eAAe,MAAM,MAAM,MAAM,KAAK,gBAAgB;CACtD,MAAM,SAAS,oBAAoB,OAAO,QAAQ,KAAK;CAEvD,MAAM,eAAe,OAAO,KAAK;CACjC,MAAM,oBAAoB,OAAO,QAAQ,KAAK;CAC9C,MAAM,WAAW,OAAe,OAAO,MAAM;CAC7C,MAAM,cAAc,+BAAe,IAAI,IAAgB,GAAG,CAAC,CAAC;CAC5D,MAAM,eAAe,gBAAgB,WAAgC;EACnE,IAAI,WAAW,MAAM;GACnB,eAAe,MAAM,MAAM,CAAC;GAC5B,eAAe,MAAM,MAAM,CAAC;GAE5B,MAAM,SAAS,aAAa;IAC1B,IAAI,iBAAiB,MAAM,eACzB,SAAS;IAGX,SAAS;GACX,CAAC;GAED,IAAI,iBAAiB,MAAM,eACzB,oBAAyB,OAAO,kBAAkB,OAAO;GAG3D,SAAS,oBAAoB,OAAO,kBAAkB,OAAO;EAC/D;EAEA,IAAI,UAAU,SACZ,MAAM,IAAI,MAAM,8CAA8C;EAEhE,WAAW,MAAM,IAAI;EACrB,MAAM,SAAS;EAEf,IAAI,aAAa,SACf,oBAAoB,OAAO,MAAM;EAGnC,IAAI,UAAU,WAAW,SAAS,YAAY,OAAO,QAAQ;EAC7D,SAAS,UAAU,OAAO;EAC1B,YAAY,SAAS,aAAa,SAAS,CAAC;CAC9C,CAAC;CAED,gBAAgB;EACd,aAAa,UAAU;EACvB,aAAa;GACX,aAAa,UAAU;GACvB,qBAAqB,KAAK;EAC5B;CACF,GAAG,CAAC,KAAK,CAAC;CAEV,gBAAgB;EACd,kBAAkB,UAAU,OAAO;EACnC,WAAW,MAAM,IAAI;EACrB,oBAAoB,OAAO,MAAM;EAEjC,IAAI,UAAU,WAAW,SAAS,YAAY,OAAO,QAAQ;EAC7D,SAAS,UAAU,OAAO;EAC1B,YAAY,SAAS,aAAa,SAAS,CAAC;CAC9C,CAAC;CAED,OAAO,eACE;EACL,gBAAgB,SAAS;EACzB,YAAY,aAAyB;GACnC,YAAY,IAAI,QAAQ;GACxB,aAAa,YAAY,OAAO,QAAQ;EAC1C;CACF,IACA,CAAC,CACH;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/tap",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.14",
|
|
4
4
|
"description": "Zero-dependency reactive state management inspired by React hooks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"state-management",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"react": "^19.2.6",
|
|
55
55
|
"react-dom": "^19.2.6",
|
|
56
56
|
"vitest": "^4.1.7",
|
|
57
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
57
|
+
"@assistant-ui/x-buildutils": "0.0.10"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public",
|
|
@@ -91,20 +91,22 @@ describe("tapEffect - Basic Functionality", () => {
|
|
|
91
91
|
describe("Multiple Effects", () => {
|
|
92
92
|
it("should execute multiple effects in registration order", () => {
|
|
93
93
|
const executionOrder: string[] = [];
|
|
94
|
-
const effects = [
|
|
94
|
+
const effects: tapEffect.EffectCallback[] = [
|
|
95
95
|
() => {
|
|
96
96
|
executionOrder.push("effect1");
|
|
97
|
+
return undefined;
|
|
97
98
|
},
|
|
98
99
|
() => {
|
|
99
100
|
executionOrder.push("effect2");
|
|
101
|
+
return undefined;
|
|
100
102
|
},
|
|
101
103
|
() => {
|
|
102
104
|
executionOrder.push("effect3");
|
|
105
|
+
return undefined;
|
|
103
106
|
},
|
|
104
107
|
];
|
|
105
108
|
|
|
106
109
|
const testFiber = createTestResource(() => {
|
|
107
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
108
110
|
effects.forEach((fn) => tapEffect(fn));
|
|
109
111
|
return null;
|
|
110
112
|
});
|
|
@@ -132,7 +134,6 @@ describe("tapEffect - Basic Functionality", () => {
|
|
|
132
134
|
}, []);
|
|
133
135
|
|
|
134
136
|
// Effect with deps - runs when deps change
|
|
135
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: test
|
|
136
137
|
tapEffect(() => {
|
|
137
138
|
effectCalls.conditional++;
|
|
138
139
|
}, [props.value]);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/* oxlint-disable tap-hooks/exhaustive-deps -- tests deliberately exercise invalid dep arrays */
|
|
2
2
|
import { describe, it, expect, vi } from "vitest";
|
|
3
3
|
import { tapEffect } from "../../hooks/tap-effect";
|
|
4
4
|
import { tapState } from "../../hooks/tap-state";
|
|
@@ -83,9 +83,8 @@ describe("Errors - Effect Errors", () => {
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
// Should throw aggregate error
|
|
86
|
-
expect(() =>
|
|
87
|
-
|
|
88
|
-
).toThrowErrorMatchingInlineSnapshot(`
|
|
86
|
+
expect(() => renderTest(resource, undefined))
|
|
87
|
+
.toThrowErrorMatchingInlineSnapshot(`
|
|
89
88
|
[AggregateError: Errors during commit]
|
|
90
89
|
`);
|
|
91
90
|
expect(goodEffect).toHaveBeenCalledTimes(1);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/* oxlint-disable tap-hooks/exhaustive-deps -- tests deliberately exercise invalid dep arrays */
|
|
2
2
|
import { describe, it, expect, vi } from "vitest";
|
|
3
3
|
import { tapEffect } from "../../hooks/tap-effect";
|
|
4
4
|
import { tapState } from "../../hooks/tap-state";
|
|
@@ -13,7 +13,6 @@ describe("Lifecycle - Mount/Unmount", () => {
|
|
|
13
13
|
const effects = [vi.fn(), vi.fn(), vi.fn()];
|
|
14
14
|
|
|
15
15
|
const resource = createTestResource(() => {
|
|
16
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
17
16
|
effects.forEach((fn) => tapEffect(fn));
|
|
18
17
|
return null;
|
|
19
18
|
});
|
|
@@ -36,11 +35,9 @@ describe("Lifecycle - Mount/Unmount", () => {
|
|
|
36
35
|
});
|
|
37
36
|
|
|
38
37
|
renderTest(resource, undefined);
|
|
39
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
40
38
|
cleanups.forEach((fn) => expect(fn).not.toHaveBeenCalled());
|
|
41
39
|
|
|
42
40
|
unmountResource(resource);
|
|
43
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
44
41
|
cleanups.forEach((fn) => expect(fn).toHaveBeenCalledTimes(1));
|
|
45
42
|
});
|
|
46
43
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Tests to verify React's strict mode behavior
|
|
3
3
|
* These tests verify React's own behavior, not tap's implementation
|
|
4
4
|
*/
|
|
5
|
+
/* oxlint-disable tap-hooks/exhaustive-deps -- intentional missing-dep patterns for strict-mode tests */
|
|
5
6
|
|
|
6
7
|
import { describe, it, expect } from "vitest";
|
|
7
8
|
import { render } from "@testing-library/react";
|
|
@@ -711,7 +712,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
711
712
|
const [count, setCount] = useState(0);
|
|
712
713
|
events.push(`render count=${count}`);
|
|
713
714
|
|
|
714
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
715
715
|
useEffect(() => {
|
|
716
716
|
effectRunCount++;
|
|
717
717
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -762,7 +762,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
762
762
|
const [count, setCount] = useState(0);
|
|
763
763
|
events.push(`render count=${count}`);
|
|
764
764
|
|
|
765
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
766
765
|
useEffect(() => {
|
|
767
766
|
effectRunCount++;
|
|
768
767
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -813,7 +812,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
813
812
|
const [count, setCount] = useState(0);
|
|
814
813
|
events.push(`render count=${count}`);
|
|
815
814
|
|
|
816
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
817
815
|
useEffect(() => {
|
|
818
816
|
effectRunCount++;
|
|
819
817
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* for different sources of setState calls
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { describe, it, expect } from "vitest";
|
|
6
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
7
7
|
import { render, fireEvent, waitFor } from "@testing-library/react";
|
|
8
|
-
import { StrictMode, useState, useEffect } from "react";
|
|
8
|
+
import { StrictMode, useState, useEffect, useLayoutEffect } from "react";
|
|
9
9
|
|
|
10
10
|
describe("React Strict Mode - Rerender Sources", () => {
|
|
11
11
|
describe("Source 1: Initial render", () => {
|
|
@@ -190,7 +190,17 @@ describe("React Strict Mode - Rerender Sources", () => {
|
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
describe("Source 5: setState in setTimeout", () => {
|
|
193
|
+
afterEach(() => {
|
|
194
|
+
vi.useRealTimers();
|
|
195
|
+
});
|
|
196
|
+
|
|
193
197
|
it("should double-render AND double-call setTimeout callback (React 19)", async () => {
|
|
198
|
+
// Use fake timers so both strict-mode setTimeout callbacks fire
|
|
199
|
+
// synchronously before React gets a chance to flush a re-render
|
|
200
|
+
// between them. Without this, slow CI can process the first
|
|
201
|
+
// setTimeout, run its renders, and only then fire the second.
|
|
202
|
+
vi.useFakeTimers();
|
|
203
|
+
|
|
194
204
|
const events: string[] = [];
|
|
195
205
|
|
|
196
206
|
function TestComponent() {
|
|
@@ -215,9 +225,12 @@ describe("React Strict Mode - Rerender Sources", () => {
|
|
|
215
225
|
</StrictMode>,
|
|
216
226
|
);
|
|
217
227
|
|
|
218
|
-
//
|
|
228
|
+
// Fire both setTimeout callbacks synchronously via fake timers
|
|
229
|
+
vi.advanceTimersByTime(10);
|
|
230
|
+
// Restore real timers and wait for React's scheduler (MessageChannel) to flush
|
|
231
|
+
vi.useRealTimers();
|
|
219
232
|
await waitFor(() => {
|
|
220
|
-
expect(events).
|
|
233
|
+
expect(events).toHaveLength(6);
|
|
221
234
|
});
|
|
222
235
|
|
|
223
236
|
// ACTUAL: setTimeout callback runs TWICE and renders are DOUBLED
|
|
@@ -353,7 +366,6 @@ describe("React Strict Mode - Rerender Sources", () => {
|
|
|
353
366
|
describe("Source 8: setState in useLayoutEffect", () => {
|
|
354
367
|
it("should double-render after setState in useLayoutEffect", () => {
|
|
355
368
|
const events: string[] = [];
|
|
356
|
-
const { useLayoutEffect } = require("react");
|
|
357
369
|
|
|
358
370
|
function TestComponent() {
|
|
359
371
|
const [count, setCount] = useState(0);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Tests to verify when tap strict mode causes double-rendering
|
|
3
3
|
* These tests should mirror the React strict mode behavior
|
|
4
4
|
*/
|
|
5
|
+
/* oxlint-disable tap-hooks/exhaustive-deps -- empty dep arrays are part of the test scenarios */
|
|
5
6
|
|
|
6
7
|
import { afterEach, describe, it, expect, vi } from "vitest";
|
|
7
8
|
import { resource } from "../../core/resource";
|
|
@@ -550,7 +551,6 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
550
551
|
const [count, setCount] = tapState(0);
|
|
551
552
|
events.push(`render count=${count}`);
|
|
552
553
|
|
|
553
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
554
554
|
tapEffect(() => {
|
|
555
555
|
effectRunCount++;
|
|
556
556
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -597,7 +597,6 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
597
597
|
const [count, setCount] = tapState(0);
|
|
598
598
|
events.push(`render count=${count}`);
|
|
599
599
|
|
|
600
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
601
600
|
tapEffect(() => {
|
|
602
601
|
effectRunCount++;
|
|
603
602
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -643,7 +642,6 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
643
642
|
const [count, setCount] = tapState(0);
|
|
644
643
|
events.push(`render count=${count}`);
|
|
645
644
|
|
|
646
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
647
645
|
tapEffect(() => {
|
|
648
646
|
effectRunCount++;
|
|
649
647
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -74,7 +74,6 @@ export function unmountResource<R, P>(fiber: ResourceFiber<R, P>) {
|
|
|
74
74
|
* Cleans up all resources. Should be called after each test.
|
|
75
75
|
*/
|
|
76
76
|
export function cleanupAllResources() {
|
|
77
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
78
77
|
activeResources.forEach((fiber) => unmountResourceFiber(fiber));
|
|
79
78
|
activeResources.clear();
|
|
80
79
|
}
|
package/src/core/helpers/root.ts
CHANGED
|
@@ -4,6 +4,6 @@ export const tapCallback = <T extends (...args: any[]) => any>(
|
|
|
4
4
|
fn: T,
|
|
5
5
|
deps: readonly unknown[],
|
|
6
6
|
): T => {
|
|
7
|
-
//
|
|
7
|
+
// oxlint-disable-next-line tap-hooks/exhaustive-deps -- user-provided dep array forwarded verbatim
|
|
8
8
|
return tapMemo(() => fn, deps);
|
|
9
9
|
};
|
|
@@ -32,9 +32,9 @@ export function tapResource<E extends ResourceElement<any, any>>(
|
|
|
32
32
|
}, [element.type, element.key, parentFiber]);
|
|
33
33
|
|
|
34
34
|
const result = propsDeps
|
|
35
|
-
?
|
|
36
|
-
tapMemo(
|
|
35
|
+
? tapMemo(
|
|
37
36
|
() => renderResourceFiber(fiber, element.props),
|
|
37
|
+
// oxlint-disable-next-line tap-hooks/exhaustive-deps -- props identity replaced by user-provided deps
|
|
38
38
|
[fiber, ...propsDeps, versionRef.current],
|
|
39
39
|
)
|
|
40
40
|
: renderResourceFiber(fiber, element.props);
|
|
@@ -43,7 +43,7 @@ export function tapResources<E extends ResourceElement<any, any>>(
|
|
|
43
43
|
const fibers = tapConst(() => new Map<string | number, FiberState>(), []);
|
|
44
44
|
|
|
45
45
|
const getElementsMemo = getElementsDeps
|
|
46
|
-
? //
|
|
46
|
+
? // oxlint-disable-next-line tap-hooks/exhaustive-deps -- deps forwarded by caller
|
|
47
47
|
tapCallback(getElements, getElementsDeps)
|
|
48
48
|
: getElements;
|
|
49
49
|
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
const useDevStrictMode = () => {
|
|
21
21
|
if (!isDevelopment) return null;
|
|
22
22
|
|
|
23
|
-
//
|
|
23
|
+
// oxlint-disable-next-line react-hooks/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build
|
|
24
24
|
const count = useRef(0);
|
|
25
25
|
const isFirstRender = count.current === 0;
|
|
26
|
-
//
|
|
26
|
+
// oxlint-disable-next-line react-hooks/rules-of-hooks -- isDevelopment is a build-time constant, so this branch is stable per build
|
|
27
27
|
useState(() => count.current++);
|
|
28
28
|
if (count.current !== 2) return null;
|
|
29
29
|
return isFirstRender ? ("child" as const) : ("root" as const);
|
package/src/tapResourceRoot.ts
CHANGED
|
@@ -97,7 +97,6 @@ export const tapResourceRoot = <TState>(
|
|
|
97
97
|
|
|
98
98
|
if (scheduler.isDirty || valueRef.current === render.output) return;
|
|
99
99
|
valueRef.current = render.output;
|
|
100
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
101
100
|
subscribers.forEach((callback) => callback());
|
|
102
101
|
});
|
|
103
102
|
|
|
@@ -116,7 +115,6 @@ export const tapResourceRoot = <TState>(
|
|
|
116
115
|
|
|
117
116
|
if (scheduler.isDirty || valueRef.current === render.output) return;
|
|
118
117
|
valueRef.current = render.output;
|
|
119
|
-
// biome-ignore lint/suspicious/useIterableCallbackReturn: forEach callback intentionally has no return
|
|
120
118
|
subscribers.forEach((callback) => callback());
|
|
121
119
|
});
|
|
122
120
|
|