From 4f74a0f14979cac897dbd035b21041eedbcea273 Mon Sep 17 00:00:00 2001 From: Ethan Standel Date: Sat, 3 Feb 2024 22:25:50 -0500 Subject: [PATCH] feat: modifiable structure (#19) --- .commitlintrc.json | 8 + .github/workflows/release.yml | 8 +- package-lock.json | 725 ++++++++++++++++++++++++++-- package.json | 15 +- packages/core/package.json | 2 +- packages/core/src/core.test.tsx | 22 +- packages/core/src/core.ts | 80 ++- packages/preact/package.json | 4 +- packages/preact/src/preact.test.tsx | 77 ++- packages/preact/src/preact.ts | 4 +- packages/react/package.json | 4 +- packages/react/src/react.test.tsx | 78 ++- packages/react/src/react.ts | 4 +- scripts/publish-all.ts | 27 ++ 14 files changed, 963 insertions(+), 95 deletions(-) create mode 100644 scripts/publish-all.ts diff --git a/.commitlintrc.json b/.commitlintrc.json index dddf9b6..390825f 100644 --- a/.commitlintrc.json +++ b/.commitlintrc.json @@ -8,6 +8,14 @@ 2, "always", [ + "feat", + "fix", + "chore", + "docs", + "style", + "refactor", + "perf", + "test", "release" ] ], diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37ac446..154e656 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,14 +16,12 @@ jobs: - name: install run: npm i - name: build - run: npm run build --workspaces + run: npm run build - name: test - run: npm run test --workspaces + run: npm run test - name: publish run: | echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" > ~/.npmrc - npm publish --workspace=@deepsignal/core - npm publish --workspace=@deepsignal/preact - npm publish --workspace=@deepsignal/react + npm run publish-all env: NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} diff --git a/package-lock.json b/package-lock.json index 649303b..3c831b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "husky": "^8.0.1", "lint-staged": "^13.0.3", "prettier": "^2.6.2", + "tsx": "^4.7.0", "typescript": "~4.8.2" }, "engines": { @@ -829,6 +830,22 @@ "resolved": "packages/react", "link": true }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", @@ -845,6 +862,150 @@ "node": ">=12" } }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-loong64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", @@ -861,6 +1022,182 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -1232,6 +1569,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.2.1.tgz", "integrity": "sha512-aqzRMNFU1hoQyP4Kb1ldJrUTCnA9vqPDa7qHEQzHJ3upnBOcC2pjmvjAuTqGuY4AVTtUkCQV0FvOCuIQQ2hSdA==", + "dev": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -4136,9 +4474,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -4251,6 +4589,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -6500,6 +6850,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -7259,6 +7618,95 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsx": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", + "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "dev": true, + "dependencies": { + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7870,7 +8318,7 @@ }, "packages/core": { "name": "@deepsignal/core", - "version": "3.0.3", + "version": "4.0.0", "license": "MIT", "devDependencies": { "@preact/preset-vite": "^2.3.0", @@ -7896,10 +8344,10 @@ }, "packages/preact": { "name": "@deepsignal/preact", - "version": "3.0.3", + "version": "4.0.0", "license": "MIT", "dependencies": { - "@deepsignal/core": "3.0.2" + "@deepsignal/core": "4.0.0" }, "devDependencies": { "@preact/preset-vite": "^2.3.0", @@ -7919,14 +8367,6 @@ "@preact/signals": "1.x.x" } }, - "packages/preact/node_modules/@deepsignal/core": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@deepsignal/core/-/core-3.0.2.tgz", - "integrity": "sha512-gVh43+VpjYdqV4xTJtDV2VVC1H0J5BZU+Hg+hzrrOjUHdyvpIg2IcysJrleJGTPqy6DLoobdPTlSgzIXP9l5ng==", - "peerDependencies": { - "@preact/signals-core": "1.x.x" - } - }, "packages/preact/node_modules/@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -7935,10 +8375,10 @@ }, "packages/react": { "name": "@deepsignal/react", - "version": "3.0.3", + "version": "4.0.0", "license": "MIT", "dependencies": { - "@deepsignal/core": "3.0.2" + "@deepsignal/core": "4.0.0" }, "devDependencies": { "@preact/signals-react": "^1.1.1", @@ -7959,14 +8399,6 @@ "@preact/signals-react": "1.x.x" } }, - "packages/react/node_modules/@deepsignal/core": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@deepsignal/core/-/core-3.0.2.tgz", - "integrity": "sha512-gVh43+VpjYdqV4xTJtDV2VVC1H0J5BZU+Hg+hzrrOjUHdyvpIg2IcysJrleJGTPqy6DLoobdPTlSgzIXP9l5ng==", - "peerDependencies": { - "@preact/signals-core": "1.x.x" - } - }, "packages/react/node_modules/@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -8599,7 +9031,7 @@ "@deepsignal/preact": { "version": "file:packages/preact", "requires": { - "@deepsignal/core": "3.0.2", + "@deepsignal/core": "4.0.0", "@preact/preset-vite": "^2.3.0", "@preact/signals": "^1.1.1", "@testing-library/preact": "^3.2.2", @@ -8614,12 +9046,6 @@ "vitest": "^0.23.1" }, "dependencies": { - "@deepsignal/core": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@deepsignal/core/-/core-3.0.2.tgz", - "integrity": "sha512-gVh43+VpjYdqV4xTJtDV2VVC1H0J5BZU+Hg+hzrrOjUHdyvpIg2IcysJrleJGTPqy6DLoobdPTlSgzIXP9l5ng==", - "requires": {} - }, "@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -8631,7 +9057,7 @@ "@deepsignal/react": { "version": "file:packages/react", "requires": { - "@deepsignal/core": "3.0.2", + "@deepsignal/core": "4.0.0", "@preact/signals-react": "^1.1.1", "@testing-library/react": "13.4.0", "@types/node": "^18.7.16", @@ -8647,12 +9073,6 @@ "vitest": "^0.23.1" }, "dependencies": { - "@deepsignal/core": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@deepsignal/core/-/core-3.0.2.tgz", - "integrity": "sha512-gVh43+VpjYdqV4xTJtDV2VVC1H0J5BZU+Hg+hzrrOjUHdyvpIg2IcysJrleJGTPqy6DLoobdPTlSgzIXP9l5ng==", - "requires": {} - }, "@types/node": { "version": "18.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", @@ -8661,6 +9081,13 @@ } } }, + "@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "dev": true, + "optional": true + }, "@esbuild/android-arm": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", @@ -8668,6 +9095,69 @@ "dev": true, "optional": true }, + "@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "dev": true, + "optional": true + }, "@esbuild/linux-loong64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", @@ -8675,6 +9165,83 @@ "dev": true, "optional": true }, + "@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "dev": true, + "optional": true + }, "@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -8968,7 +9535,8 @@ "@preact/signals-core": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.2.1.tgz", - "integrity": "sha512-aqzRMNFU1hoQyP4Kb1ldJrUTCnA9vqPDa7qHEQzHJ3upnBOcC2pjmvjAuTqGuY4AVTtUkCQV0FvOCuIQQ2hSdA==" + "integrity": "sha512-aqzRMNFU1hoQyP4Kb1ldJrUTCnA9vqPDa7qHEQzHJ3upnBOcC2pjmvjAuTqGuY4AVTtUkCQV0FvOCuIQQ2hSdA==", + "dev": true }, "@preact/signals-react": { "version": "1.1.1", @@ -11068,9 +11636,9 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, @@ -11143,6 +11711,15 @@ "get-intrinsic": "^1.1.1" } }, + "get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -12740,6 +13317,12 @@ "global-dirs": "^0.1.1" } }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -13301,6 +13884,64 @@ } } }, + "tsx": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", + "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "dev": true, + "requires": { + "esbuild": "~0.19.10", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.2" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + } + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index eaa44bb..eb62ef1 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,13 @@ "version": "0.0.0", "license": "MIT", "scripts": { - "prepare": "husky install" + "prepare": "husky install", + "build": "npm run build --workspaces", + "test": "npm run test --workspaces", + "test-core": "npm run test --workspace=@deepsignal/core", + "test-preact": "npm run test --workspace=@deepsignal/preact", + "test-react": "npm run test --workspace=@deepsignal/react", + "publish-all": "npx tsx ./scripts/publish-all.ts" }, "private": true, "devDependencies": { @@ -21,6 +27,7 @@ "husky": "^8.0.1", "lint-staged": "^13.0.3", "prettier": "^2.6.2", + "tsx": "^4.7.0", "typescript": "~4.8.2" }, "lint-staged": { @@ -30,10 +37,10 @@ "packages/*" ], "engines": { - "node": "16.x.x", - "npm": "8.x.x" + "node": "18.x.x", + "npm": "9.x.x" }, "engineStrict": true, "homepage": "https://github.com/EthanStandel/deepsignal#readme", "repository": "https://github.com/EthanStandel/deepsignal" -} +} \ No newline at end of file diff --git a/packages/core/package.json b/packages/core/package.json index 628c2c2..ee53208 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@deepsignal/core", "private": false, - "version": "3.0.3", + "version": "4.0.0-alpha.0", "type": "module", "files": [ "dist" diff --git a/packages/core/src/core.test.tsx b/packages/core/src/core.test.tsx index 0474666..ffd5aa9 100644 --- a/packages/core/src/core.test.tsx +++ b/packages/core/src/core.test.tsx @@ -3,7 +3,7 @@ import { describe, it, expect } from "vitest"; import { deepSignal, DeepSignal } from "./core"; -describe("deepSignal", () => { +describe("@deepsignal/core", () => { it("turns string properties into Signals", () => { const testStore = deepSignal({ hello: "world", @@ -64,6 +64,26 @@ describe("deepSignal", () => { expect(testStore.hello.world.foo.peek()[0]).toBe(3); }); + it("allows for structural modifications of deepSignals", () => { + const testStore = deepSignal({ + record: {} as Record, + }); + testStore.record.value = { foo: { name: "Foo" } }; + expect(testStore.record.foo instanceof DeepSignal).toBeTruthy(); + expect(testStore.record.foo.name instanceof Signal).toBeTruthy(); + }); + + it("naturally treats Map, Set, & Date as atomic", () => { + const testStore = deepSignal({ + map: new Map(), + set: new Set(), + date: new Date(), + }); + expect(testStore.map instanceof Signal).toBeTruthy(); + expect(testStore.set instanceof Signal).toBeTruthy(); + expect(testStore.date instanceof Signal).toBeTruthy(); + }); + it("doesn't allow you to set a property with keys named peek or value", () => { expect(() => deepSignal({ value: "hello" })).toThrowError( /reserved property name/ diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index e55be0d..b5a65ad 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -9,7 +9,10 @@ export type AtomicState = | bigint | symbol | undefined - | null; + | null + | Map + | Set + | Date; export type DeepState = { [key: string]: (() => unknown) | AtomicState | DeepState; @@ -21,7 +24,8 @@ export type ReadOnlyDeep = { export interface DeepSignalAccessors { value: ReadOnlyDeep; - peek: () => ReadOnlyDeep; + readonly peek: () => ReadOnlyDeep; + readonly __structure: Signal; } export type DeepSignalType = DeepSignalAccessors & { @@ -33,53 +37,88 @@ export type DeepSignalType = DeepSignalAccessors & { }; export class DeepSignal implements DeepSignalAccessors { - get value(): ReadOnlyDeep { - return getValue(this as DeepSignalType); - } + constructor(initialValue: unknown = {}) { + Object.defineProperty(this, "value", { + get(): ReadOnlyDeep { + return getValue(this as DeepSignalType); + }, + set(payload: ReadOnlyDeep) { + batch(() => setValue(this as DeepSignalType, payload)); + }, + enumerable: false, + configurable: false, + }); - set value(payload: ReadOnlyDeep) { - batch(() => setValue(this as DeepSignalType, payload)); - } + Object.defineProperty(this, "peek", { + //@ts-expect-error + value: () => getValue(this as DeepSignalType, { peek: true }), + writable: false, + enumerable: false, + configurable: false, + }); - peek(): ReadOnlyDeep { - return getValue(this as DeepSignalType, { peek: true }); + Object.defineProperty(this, "__structure", { + value: new Signal(initialValue), + writable: false, + enumerable: false, + configurable: false, + }); } + + value!: ReadOnlyDeep; + readonly peek!: () => ReadOnlyDeep; + // internal use only! + readonly __structure!: Signal; } export const deepSignal = ( initialValue: T ): DeepSignalType => Object.assign( - new DeepSignal(), + new DeepSignal(initialValue), Object.entries(initialValue).reduce((acc, [key, value]) => { - if (["value", "peek"].some(iKey => iKey === key)) { + if (["value", "peek", "__structure"].some(iKey => iKey === key)) { throw new Error(`${key} is a reserved property name`); } else if ( typeof value !== "object" || + value?.constructor === Date || + value?.constructor === Map || + value?.constructor === Set || value === null || Array.isArray(value) ) { acc[key] = signal(value); } else { - acc[key] = deepSignal(value); + acc[key] = deepSignal(value as DeepState); } return acc; }, {} as { [key: string]: unknown }) ) as DeepSignalType; const setValue = >( - deepSignal: T, + deep: T, payload: U -): void => - Object.keys(payload).forEach( - (key: keyof U) => (deepSignal[key].value = payload[key]) - ); +): void => { + Object.keys(payload).forEach((key: keyof U) => { + if (deep[key]) { + deep[key].value = payload[key]; + } else { + // @ts-ignore + deep[key] = deepSignal(payload[key]); + } + }); + deep.__structure.value = payload; +}; const getValue = >( deepSignal: T, { peek = false }: { peek?: boolean } = {} -): ReadOnlyDeep => - Object.entries(deepSignal).reduce((acc, [key, value]) => { +): ReadOnlyDeep => { + if (!peek) { + // calling the value to track the structure of this DeepSignal + deepSignal.__structure.value; + } + return Object.entries(deepSignal).reduce((acc, [key, value]) => { if (value instanceof Signal) { acc[key] = peek ? value.peek() : value.value; } else if (value instanceof DeepSignal) { @@ -87,3 +126,4 @@ const getValue = >( } return acc; }, {} as { [key: string]: unknown }) as ReadOnlyDeep; +}; diff --git a/packages/preact/package.json b/packages/preact/package.json index 9a13518..876f99d 100644 --- a/packages/preact/package.json +++ b/packages/preact/package.json @@ -1,7 +1,7 @@ { "name": "@deepsignal/preact", "private": false, - "version": "3.0.3", + "version": "4.0.0-alpha.0", "type": "module", "files": [ "dist" @@ -21,7 +21,7 @@ "test": "vitest run --coverage" }, "dependencies": { - "@deepsignal/core": "3.0.2" + "@deepsignal/core": "4.0.0-alpha.0" }, "peerDependencies": { "@preact/signals": "1.x.x" diff --git a/packages/preact/src/preact.test.tsx b/packages/preact/src/preact.test.tsx index 7288d68..ebd94d2 100644 --- a/packages/preact/src/preact.test.tsx +++ b/packages/preact/src/preact.test.tsx @@ -1,11 +1,12 @@ import { render, fireEvent } from "@testing-library/preact"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import { h, Fragment } from "preact"; +import { memo } from "preact/compat"; import { it, expect, describe } from "vitest"; import { deepSignal, useDeepSignal } from "./preact"; -describe("deepSignal", () => { +describe("@deepsignal/preact", () => { it("rerenders if inner Signal is updated but the DeepSignal is subscribed to", () => { let renderCount = -1; const deepSignalInstance = deepSignal({ inner: { count: 0 } }); @@ -122,13 +123,75 @@ describe("deepSignal", () => { page.unmount(); }); - it("doesn't allow you to set a property with keys named peek or value", () => { - expect(() => deepSignal({ value: "hello" })).toThrowError( - /reserved property name/ - ); + it("can render modified structures", () => { + const deepSignalInstance = deepSignal({ + input: "", + record: {} as Record, + }); - expect(() => deepSignal({ peek: "hello" })).toThrowError( - /reserved property name/ + const Test = () => ( + <> + + (deepSignalInstance.input.value = e.currentTarget.value) + } + /> + +
    + {Object.keys(deepSignalInstance.record.value).map(key => ( + + ))} +
+ ); + + let renderCount = -1; + const TestItem = memo(({ name }: { name: string }) => { + renderCount++; + return ( +
  • + + (deepSignalInstance.record[name].name.value = + e.currentTarget.value) + } + /> + {deepSignalInstance.record[name].name} +
  • + ); + }); + + const page = render(); + const newItemInput = page.getByTestId("add-new-item-input"); + const addNewItemButton = page.getByTestId("add-new-item-button"); + fireEvent.input(newItemInput, { target: { value: "Foo" } }); + expect(page.queryByText("Foo")).toBeFalsy(); + fireEvent.click(addNewItemButton); + expect(page.getByText("Foo")).toBeTruthy(); + expect(renderCount).toBe(0); + const fooNameInput = page.getByTestId("Foo-name-input"); + fireEvent.input(fooNameInput, { target: { value: "Bar" } }); + expect(page.queryByText("Foo")).toBeFalsy(); + expect(page.getByText("Bar")).toBeTruthy(); + expect(renderCount).toBe(0); + page.unmount(); }); }); diff --git a/packages/preact/src/preact.ts b/packages/preact/src/preact.ts index 5de1bb5..75fba65 100644 --- a/packages/preact/src/preact.ts +++ b/packages/preact/src/preact.ts @@ -2,10 +2,10 @@ import { deepSignal, DeepState } from "@deepsignal/core"; import { useMemo } from "preact/hooks"; import "@preact/signals"; -const useDeepSignal = (initial: T | (() => T)) => +export const useDeepSignal = (initial: T | (() => T)) => useMemo( () => deepSignal(typeof initial === "function" ? initial() : initial), [] ); -export { useDeepSignal, deepSignal }; +export * from "@deepsignal/core"; diff --git a/packages/react/package.json b/packages/react/package.json index 4a8b692..0eaf8a5 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,7 +1,7 @@ { "name": "@deepsignal/react", "private": false, - "version": "3.0.3", + "version": "4.0.0-alpha.0", "type": "module", "files": [ "dist" @@ -21,7 +21,7 @@ "test": "vitest run --coverage" }, "dependencies": { - "@deepsignal/core": "3.0.2" + "@deepsignal/core": "4.0.0-alpha.0" }, "peerDependencies": { "@preact/signals-react": "1.x.x" diff --git a/packages/react/src/react.test.tsx b/packages/react/src/react.test.tsx index 51f7f5e..2903556 100644 --- a/packages/react/src/react.test.tsx +++ b/packages/react/src/react.test.tsx @@ -1,9 +1,11 @@ +import { memo } from "react"; + import { render, fireEvent } from "@testing-library/react"; import { it, expect, describe } from "vitest"; import { deepSignal, useDeepSignal } from "./react"; -describe("deepSignal", () => { +describe("@deepsignal/react", () => { it("rerenders if inner Signal is updated but the DeepSignal is subscribed to", () => { let renderCount = -1; const deepSignalInstance = deepSignal({ inner: { count: 0 } }); @@ -120,13 +122,75 @@ describe("deepSignal", () => { page.unmount(); }); - it("doesn't allow you to set a property with keys named peek or value", () => { - expect(() => deepSignal({ value: "hello" })).toThrowError( - /reserved property name/ - ); + it("can render modified structures", () => { + const deepSignalInstance = deepSignal({ + input: "", + record: {} as Record, + }); - expect(() => deepSignal({ peek: "hello" })).toThrowError( - /reserved property name/ + const Test = () => ( + <> + + (deepSignalInstance.input.value = e.currentTarget.value) + } + /> + +
      + {Object.keys(deepSignalInstance.record.value).map(key => ( + + ))} +
    + ); + + let renderCount = -1; + const TestItem = memo(({ name }: { name: string }) => { + renderCount++; + return ( +
  • + + (deepSignalInstance.record[name].name.value = + e.currentTarget.value) + } + /> + {deepSignalInstance.record[name].name as any} +
  • + ); + }); + + const page = render(); + const newItemInput = page.getByTestId("add-new-item-input"); + const addNewItemButton = page.getByTestId("add-new-item-button"); + fireEvent.change(newItemInput, { target: { value: "Foo" } }); + expect(page.queryByText("Foo")).toBeFalsy(); + fireEvent.click(addNewItemButton); + expect(page.getByText("Foo")).toBeTruthy(); + expect(renderCount).toBe(0); + const fooNameInput = page.getByTestId("Foo-name-input"); + fireEvent.change(fooNameInput, { target: { value: "Bar" } }); + expect(page.queryByText("Foo")).toBeFalsy(); + expect(page.getByText("Bar")).toBeTruthy(); + expect(renderCount).toBe(0); + page.unmount(); }); }); diff --git a/packages/react/src/react.ts b/packages/react/src/react.ts index 243861d..2e59876 100644 --- a/packages/react/src/react.ts +++ b/packages/react/src/react.ts @@ -3,10 +3,10 @@ import { useMemo } from "react"; import { deepSignal, DeepState } from "@deepsignal/core"; import "@preact/signals-react"; -const useDeepSignal = (initial: T | (() => T)) => +export const useDeepSignal = (initial: T | (() => T)) => useMemo( () => deepSignal(typeof initial === "function" ? initial() : initial), [] ); -export { useDeepSignal, deepSignal }; +export * from "@deepsignal/core"; diff --git a/scripts/publish-all.ts b/scripts/publish-all.ts new file mode 100644 index 0000000..80414b5 --- /dev/null +++ b/scripts/publish-all.ts @@ -0,0 +1,27 @@ +import { execSync } from "node:child_process"; + +import { version as coreVersion } from "../packages/core/package.json"; +import { version as preactVersion } from "../packages/preact/package.json"; +import { version as reactVersion } from "../packages/react/package.json"; + +const tags = { + core: coreVersion.split("-").slice(1).join("-").split(".")[0], + preact: preactVersion.split("-").slice(1).join("-").split(".")[0], + react: reactVersion.split("-").slice(1).join("-").split(".")[0], +}; + +execSync( + `npm publish --workspace=@deepsignal/core ${ + tags.core ? `--tag ${tags.core}` : "" + }` +); +execSync( + `npm publish --workspace=@deepsignal/preact ${ + tags.preact ? `--tag ${tags.preact}` : "" + }` +); +execSync( + `npm publish --workspace=@deepsignal/react ${ + tags.react ? `--tag ${tags.react}` : "" + }` +);