From bebb44631606b028b9005f324817a58f5df1594f Mon Sep 17 00:00:00 2001 From: "w5s-automator[bot]" <308143805+w5s-automator[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 23:39:40 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A8=20Upgrade=20dependency=20@w5s/?= =?UTF-8?q?eslint-config=20to=20v3.20.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- pnpm-lock.yaml | 629 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 453 insertions(+), 178 deletions(-) diff --git a/package.json b/package.json index ec45f6ebf4..c504df0275 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@w5s/commitlint-config": "3.8.0", "@w5s/conventional-changelog": "3.9.0", "@w5s/cspell-config": "3.8.0", - "@w5s/eslint-config": "3.11.0", + "@w5s/eslint-config": "3.20.0", "@w5s/tsconfig": "3.1.20", "@w5s/tsdown-config": "1.0.0-alpha.21", "cspell": "10.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f423a0b92..25b4372e95 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,8 +50,8 @@ importers: specifier: 3.8.0 version: 3.8.0(cspell@10.0.1) '@w5s/eslint-config': - specifier: 3.11.0 - version: 3.11.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0))) + specifier: 3.20.0 + version: 3.20.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0))) '@w5s/tsconfig': specifier: 3.1.20 version: 3.1.20(typescript@6.0.3) @@ -2076,8 +2076,8 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@es-joy/jsdoccomment@0.87.0': - resolution: {integrity: sha512-mFXZloZMzuJZXSHUmAFu/pXTk0ZJTJBluuAkrvbzidpTN8W6F2bpRFuedSH+85kbdlRLJqc+gfN+kD3JOLJK5g==} + '@es-joy/jsdoccomment@0.88.0': + resolution: {integrity: sha512-GK/HL/claLLNo5KG705auIlZMwEtmn88ofSGuLsmVZwKBqMPJhW9DiznYNq07QEqz9BPtA3LBfYImtZmhVvRAw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@es-joy/resolve.exports@1.2.0': @@ -2406,50 +2406,50 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-react/ast@5.9.2': - resolution: {integrity: sha512-206StJvea00Bs9etMOEG94muuBP/gQ6NPK2Tg/m/Dbx1o3hEOpoblxKqBF1jYx91C1DIrbuzqaqI1N/XTfGYxw==} + '@eslint-react/ast@5.17.1': + resolution: {integrity: sha512-C/Xu7inuG//EU4+LfDWO79GE71y94Ae0X1SSzGFu7IoplTH10tyjd6jQNMG4VYxI1zSMgCg0h+QcCWoBGV+ZWA==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/core@5.9.2': - resolution: {integrity: sha512-GcXEaMAyjFgbIP7g1TQ+p7VohhnM4g1wtEccj4MNXb1jzTKioPcWxRWN95lrBnrCYskvZXsPCWM4ERQjMQGU2g==} + '@eslint-react/core@5.17.1': + resolution: {integrity: sha512-bf2XjVvqxiKF0B1h6csLWiKG5dQvDgltki6voRSfK5oGMyiwYD27ODczLAwVubggqTeZNOStQY+dZzfVE1ePCQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/eslint-plugin@5.9.2': - resolution: {integrity: sha512-o1rSyib/uWlWU8qPg6E1U0ME/mrS/YZYSr4ruSw7dGoQTNZBOFVs0T0KivioK5YfLksHH2ynPOCn6w4EUnH47w==} + '@eslint-react/eslint-plugin@5.17.1': + resolution: {integrity: sha512-wXd5WHjSbWlAUye+Y1P0KSf5xpuKTikLimZBXlRNlV2sgatSYnLgxyS7JfNJmD02gSMRMu8vJ7tgZlgBO9mVpA==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/eslint@5.9.2': - resolution: {integrity: sha512-8Fr+dqE8NoB7XRlp8AQp/IE5koQYxprXYAzktCmySVtwH6/I2HDQsVy/wcNMuIcCM7EPkiAbtl9MOiFvcbTAkw==} + '@eslint-react/eslint@5.17.1': + resolution: {integrity: sha512-8HH62nFp1AoESCQaQUHtRvs3SBDn28NWIg818+c4AAFTCTkUYjLEqBrJHJxc/eSF4MduLCy06xnWMXE4J6LtDQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/jsx@5.9.2': - resolution: {integrity: sha512-rag1x+7lZHDOTT8WfWeS22fymh5JVr11O8m2SptTyI68ao0TWjTc5+BBHtv/lvQlea+VZpRH1n4pZV3e4Hkspw==} + '@eslint-react/jsx@5.17.1': + resolution: {integrity: sha512-1uTcGS+yevc/RW7A25z+X8P9qq7HC8zYEO3lXHrVBruHyY8jhd7k+/iLQI3JpKlE/QPmPjxo+H/p0/FFyBU0bQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/shared@5.9.2': - resolution: {integrity: sha512-NU3pHMA3iADBH7HEPql/KSZTgooGp1HShT6TyeG46TApA42Z+X+gBk5MFmwazF/HPd/q3T2N6KU5gLWRNqXgng==} + '@eslint-react/shared@5.17.1': + resolution: {integrity: sha512-3210sOtv7b18qVo0QCCl+bmgb3r1pmeLkcF2JwqnTGH5jPNReWYX524xQqMdQqy7O73BBO5nPG0MnBMPdMHT/Q==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - '@eslint-react/var@5.9.2': - resolution: {integrity: sha512-9+J8GmsKi3diHF2Ij++vb5HVs6IO9rbLUs2i4pzCeqrGZstyrTVp3BMSSzn2GamRODCU9Zz/Shl8vhwrSkqYsQ==} + '@eslint-react/var@5.17.1': + resolution: {integrity: sha512-UPfhOHUHGecm7QFc2KLf+XoW7NOgR6A2me9SGvo5DRu4GZAbJ1bvn3/3h+10sCK5MS5pS16m9hilZLfQfYdE4w==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' @@ -3951,6 +3951,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.65.0': + resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/scope-manager@8.59.2': resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3959,6 +3965,10 @@ packages: resolution: {integrity: sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.65.0': + resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.59.2': resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3971,6 +3981,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.65.0': + resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.59.2': resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3978,8 +3994,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.62.0': - resolution: {integrity: sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==} + '@typescript-eslint/type-utils@8.65.0': + resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3993,6 +4009,10 @@ packages: resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.65.0': + resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.59.2': resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4005,6 +4025,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/typescript-estree@8.65.0': + resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.59.2': resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4019,6 +4045,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.65.0': + resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/visitor-keys@8.59.2': resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4027,12 +4060,16 @@ packages: resolution: {integrity: sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.65.0': + resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} deprecated: Potential CWE-502 - Update to 1.3.1 or higher - '@vitest/eslint-plugin@1.6.16': - resolution: {integrity: sha512-2pBN1F1JXq6zTSaYC58CMJa7pGxXIRsLfOioeZM4cPE3pRdSh1ySTSoHPQlOTEF5WgoVzWZQxhGQ3ygT78hOVg==} + '@vitest/eslint-plugin@1.6.23': + resolution: {integrity: sha512-CbrXxQpIUMbeyylGlxaxTgnWYM44et4Nx58swl7+vrTyC9Ttx+hQoy8BGCregbbZ08K5qFhRHeoad1VvERUbkg==} engines: {node: '>=18'} peerDependencies: '@typescript-eslint/eslint-plugin': '*' @@ -4101,12 +4138,12 @@ packages: cspell: optional: true - '@w5s/dev@3.4.7': - resolution: {integrity: sha512-3qsVdeAABfCRuvK766rWscGcozZfO0/+bpR0tzckQABUIhT/3X6RtWOOAzgQnRUlPyfrx84siB12/8NPEViukA==} + '@w5s/dev@3.11.0': + resolution: {integrity: sha512-8ICVhgW9VW2A6xV7anAibGlX9tXQmKJVNmEyhLPrzWvPD3nHGILugcdbWm9+hFDdgiq/jpTq1DdJ1t2NJ/Js5Q==} engines: {node: '>=22.0.0'} - '@w5s/eslint-config-ignore@1.2.7': - resolution: {integrity: sha512-py7WhSjqNGA2M+5clzHxmYCaxoqrKPfPYtlCfTnf78zRr7ulIyYv8HKEdzAskiUpLdgSYi5jy4SLOi7omwReIw==} + '@w5s/eslint-config-ignore@1.10.0': + resolution: {integrity: sha512-0n/1zWvWY846U/2w+EI43x9qR8S3b8bxpJK+1rUme9MrXOFO3nh/bemEHPSOwKnSnLYieEESCyCdTplxywWxFQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: 9.x || 10.x @@ -4117,20 +4154,23 @@ packages: typescript: optional: true - '@w5s/eslint-config@3.11.0': - resolution: {integrity: sha512-QyTbdYS9ZM4mV/i0Am8FF2tLM9y0bWjC4F6dh7mFHbxSiPVnE+URdt/HC2N3C0KXMayctwnGICkpKnOmNZJwKQ==} + '@w5s/eslint-config@3.20.0': + resolution: {integrity: sha512-6tHUwMaL64Gzl41kXjMcoPWiVkpTF3qSKYSks6+ZqVwKim01BlkgCI5NvtoCJIo5i6LBVJLVqI9VR9j2DJzodg==} engines: {node: '>=22.0.0'} peerDependencies: eslint: 9.x || 10.x + eslint-plugin-jsx-a11y: '>=6.10.2' typescript: 4.x || 5.x || 6.x peerDependenciesMeta: eslint: optional: true + eslint-plugin-jsx-a11y: + optional: true typescript: optional: true - '@w5s/prettier-config@3.1.15': - resolution: {integrity: sha512-Mj9Tu+fy2TLgoROvoV4WEFa9mXVu1BgRXQKHXo4CyWt+7MeFROXTSw25iepZBrQNjMV+L9LRy+qhjCgINi05kg==} + '@w5s/prettier-config@3.5.0': + resolution: {integrity: sha512-x0uYClwC/9GAWodURIYN+PR2WPrpvkPNsveLXC+6dISu3o/ePezrr9dKIlmfIFQQx6X4cnE67ZWcnYr1WF/c+Q==} engines: {node: '>=22.0.0'} peerDependencies: prettier: 2.x || 3.x @@ -4567,6 +4607,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + baseline-browser-mapping@2.11.1: + resolution: {integrity: sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==} + engines: {node: '>=6.0.0'} + hasBin: true + batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} @@ -4590,8 +4635,8 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - birecord@0.1.1: - resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + birecord@0.1.2: + resolution: {integrity: sha512-5PAPTTmMpMEb+GuMb5DebfBkipRGyIW9+gtwEBSoDA9xkhHILm04+hZQ702pMksu3d8YAuGkmgTzQWcKqTPScA==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -4633,6 +4678,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -4712,6 +4762,9 @@ packages: caniuse-lite@1.0.30001791: resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} + caniuse-lite@1.0.30001806: + resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4985,6 +5038,10 @@ packages: engines: {node: '>=22'} hasBin: true + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -5407,6 +5464,9 @@ packages: electron-to-chromium@1.5.349: resolution: {integrity: sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==} + electron-to-chromium@1.5.395: + resolution: {integrity: sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==} + emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -5615,20 +5675,20 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jsdoc@63.0.10: - resolution: {integrity: sha512-A9UIWsCquaKnit7rasXxYf12hhGIdDRjv65/RUE3AxbT6rdKBvr3MjH37g3gP+g4ipQMXuMn9slFKjO+vqNfkg==} + eslint-plugin-jsdoc@63.1.0: + resolution: {integrity: sha512-Vo0Mvhxi6B63gLIDI86QChkiKE79MxxM0I16gMN/HJn0rvJvMIG/nmn+KPcsx+GWYDQq6X0UfNRjRK1+97NYVg==} engines: {node: ^22.13.0 || >=24} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-jsonc@3.2.0: - resolution: {integrity: sha512-eQSxJypkpNycQAFE/ph/j+bDD2MiCcojxNb+7nugYzuQZvELYg4YO1Cv1y/8MbjPIEw5u3Lx0VPOTlqJJIhPPw==} + eslint-plugin-jsonc@3.3.0: + resolution: {integrity: sha512-CsTR8aDcShDg6A71ZppLaWiPoSo2J1Ivjm5/c4Mnb9sxgwWq+WG2PgeoAnj7SwzDPJB75tlHvLrGy6ntooIitg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: '>=9.38.0' - eslint-plugin-n@18.1.0: - resolution: {integrity: sha512-hkUm9EtnFV2h2fE16jNVUfCVUqvPzI7fGLsFdun5lFt/pbmf2kCgDx6ymi9rx+NCUSggBmurJCZOfG20JBs/kg==} + eslint-plugin-n@18.2.2: + resolution: {integrity: sha512-gOO0lIqwEjZ750kv9/SptCWArUoAZXJoBr0vYWTO2dCBxctHUXlBIigiC8xuxxr/NKqgIT6Ehz1xRcilj8a5cA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: eslint: '>=8.57.1' @@ -5640,56 +5700,71 @@ packages: typescript: optional: true - eslint-plugin-react-dom@5.9.2: - resolution: {integrity: sha512-9pOLfUWBSR49OLZxCIDLngyfqOozsoilPl1Tv3pxoW389AVB/Gg3So4Rf+UPpQtEjJP6840hnTZkmY+A44umng==} + eslint-plugin-perfectionist@5.10.0: + resolution: {integrity: sha512-HiqpDrUDbGrMC6iHQbemgDyHJ0366Vyz/qRWmxQcSAkmG25cXr8BdRgx8yAhOKhEfBXn8Rnf/mTCsV4EqUJSxg==} + engines: {node: ^20.0.0 || >=22.0.0} + peerDependencies: + eslint: ^8.45.0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react-dom@5.17.1: + resolution: {integrity: sha512-Tb1Tahle1L03x3JnU88Te7P13V695zdPE86pAElMbfJqN9Wz+hSxXt0l7HRzFSw9zzY2LmbLEWs5Tfj2aJ15CQ==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-jsx@5.9.2: - resolution: {integrity: sha512-LPogjhB5FevfPp7dUdh2qrku+DbWvVuqWYwO4Kb9ty1RYKQN9DsZx1Db1WVmd8x/W2NBDLgzkupH76SJ+ukR1w==} + eslint-plugin-react-jsx@5.17.1: + resolution: {integrity: sha512-BkDgTNQz8IjoebL9BKK8FyQn0GNnGN6dNDIm+ne6uLwnHf4SPpeBciC1kEnCygiCX5Y8XmAj3NEDLHxRAFJn1Q==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-naming-convention@5.9.2: - resolution: {integrity: sha512-ODgENIpcxYoE4SjvlyA7loPVTjcphpU2Y2jehdRI6LZluxmtkUgKTJc8MAk/vSCJoKfWK6+kVu7oMqGAyW/wuQ==} + eslint-plugin-react-naming-convention@5.17.1: + resolution: {integrity: sha512-Y8Czg68OHg/zfP1p+JMaCMeEhW1Pv9PUGnuQJsP/0kDCCjHb6aXI2pRHIQPcwAeFEAgOFUsB2DURESlsx6XUAA==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-rsc@5.9.2: - resolution: {integrity: sha512-jb5nqTKn7ODscQWffvdUIy4qE+QJIL2tHY+7NlPFjfduPhnw2Daphx7qW0qfX5qSe1rcxQCBMDiEkS2/H6lgIA==} + eslint-plugin-react-rsc@5.17.1: + resolution: {integrity: sha512-4numrKqQd2ld62sAVZDmcXkS3bOmzSCNNz5Tlpu7q8hjLt9cgD4+yFdx3zHdC1WZt8JV0emfM1Xwea8Bkoxvnw==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-web-api@5.9.2: - resolution: {integrity: sha512-uw/yBHdciPPsYEiuBABLfKYOtPaCBJmcKwxybEdKqIZFTCAweVlRqqucNulKEsWE1CnA5p6e25AyzUMB8xBgMw==} + eslint-plugin-react-web-api@5.17.1: + resolution: {integrity: sha512-QUVp4mRpsnFgdVAx58lv5+tKmbuKkJgaHRSTELRCKyVePPGWwqF++MW1YXcqp1nY7XTuio21iLLDQJBd4h6Kiw==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-react-x@5.9.2: - resolution: {integrity: sha512-aex/DzgcGdYF46LKShrTYVmZFWEd7lrX9PD85pADbTUmFpQoovGFQOK3nO6uqPUCrMuG97g/v66RyfzPBx0g5A==} + eslint-plugin-react-x@5.17.1: + resolution: {integrity: sha512-PE/PYQP8aYdLit3qt5/KsrHzmbRKqERGTLijVzOUjeAAylBS1JbrPdmmGJkTdsCqMamdS/UOpgArr5p6UYG0yA==} engines: {node: '>=22.0.0'} peerDependencies: eslint: '*' typescript: '*' - eslint-plugin-unicorn@68.0.0: - resolution: {integrity: sha512-mHYWvX948Q4H3bGc39bsNMxD/leOuNI+Iws9NVsoSz5VA7EGP86wnz7mZ/SPSvRhefT8L4hd8DHfDuGC+lIoCQ==} + eslint-plugin-unicorn@71.1.0: + resolution: {integrity: sha512-dn3YmR3qLLUeYyo/os3ubZ7UHQJ1WbBAgC9cIhnLTyMj9J6kivuc2U1fCmYetLexUlTDVYtBqhjSj/VaebTe6Q==} engines: {node: '>=22'} peerDependencies: eslint: '>=10.4' - eslint-plugin-yml@3.5.0: - resolution: {integrity: sha512-u2UkSIp/+th1wYCt0QWeCI6agf24dxX6PbFfCCN18gGQHmXh3Cn9D/U5OiP5RNYTEwjXCLusj1OJRK+zwdvFqQ==} + eslint-plugin-unused-imports@4.4.1: + resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^10.0.0 || ^9.0.0 || ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + + eslint-plugin-yml@3.6.0: + resolution: {integrity: sha512-8lSqBIiOJO8ms1gktdlNaVGm3zXQJiYeKhQmtIG66XzU58kFDOjQae4sufQEMGHC4bP8VxiaH3tjU5PpDB6euw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} peerDependencies: eslint: '>=9.38.0' @@ -6010,6 +6085,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} + function.prototype.name@1.1.8: resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} @@ -6118,6 +6197,10 @@ packages: resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} engines: {node: '>=18'} + globals@17.7.0: + resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -6365,6 +6448,10 @@ packages: peerDependencies: postcss: ^8.1.0 + identifier-regex@1.1.0: + resolution: {integrity: sha512-SLX4H/vtcYlYnL7XqnuJKHU7Z8517TgsW9nmQiGOgMCjQ8V/deLYu6bEmbGoXe7WMMhc9+EUGyFFneHja8KabA==} + engines: {node: '>=18'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -6562,6 +6649,10 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-identifier@1.1.0: + resolution: {integrity: sha512-NhOds0mDx9lJu+1lBRO0xbwFo5nobA7GCk/0e5xjr6+6XugX985+0OyGX35BNrTkPAsdLcIKg02HUQJOK8D8kw==} + engines: {node: '>=18'} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -7007,6 +7098,10 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-asynchronous@1.1.0: + resolution: {integrity: sha512-ayF7iT+44LXdxJLTrTd3TLQpFDDvPCBxXxbv+pMUSuHA5Q8zyAfwkRP6aHHwNVFBUFWtxAHqwNJxF8vMZLAbVg==} + engines: {node: '>=18'} + make-fetch-happen@15.0.5: resolution: {integrity: sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==} engines: {node: ^20.17.0 || >=22.9.0} @@ -7434,6 +7529,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + natural-orderby@5.0.0: + resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} + engines: {node: '>=18'} + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -7488,6 +7587,10 @@ packages: node-releases@2.0.38: resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} + node-releases@2.0.51: + resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + engines: {node: '>=18'} + nopt@9.0.0: resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} engines: {node: ^20.17.0 || >=22.9.0} @@ -7632,6 +7735,10 @@ packages: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} engines: {node: '>=12.20'} + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -7680,6 +7787,10 @@ packages: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -8323,6 +8434,10 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + quote-js-string@0.1.0: + resolution: {integrity: sha512-Y3NoRtprEEZQD8RfxMCfS0ZTqc4e+i18OrXEXAvpM6TfC/3y+0L5rNbZiSnbBBEkDfFzbpd8o+cE8q3/anjMGA==} + engines: {node: '>=22'} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -8468,6 +8583,10 @@ packages: resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} hasBin: true + regjsparser@0.13.2: + resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} + hasBin: true + rehype-raw@7.0.0: resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} @@ -9010,6 +9129,10 @@ packages: peerDependencies: postcss: ^8.4.31 + super-regex@1.1.0: + resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -9093,6 +9216,10 @@ packages: thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + timers-ext@0.1.8: resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} engines: {node: '>=0.12'} @@ -9249,6 +9376,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -9546,6 +9677,9 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-worker@1.5.0: + resolution: {integrity: sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -12113,7 +12247,7 @@ snapshots: tslib: 2.8.1 optional: true - '@es-joy/jsdoccomment@0.87.0': + '@es-joy/jsdoccomment@0.88.0': dependencies: '@types/estree': 1.0.9 '@typescript-eslint/types': 8.62.0 @@ -12286,73 +12420,73 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint-react/ast@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/ast@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) string-ts: 2.3.1 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/core@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/core@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/jsx': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint-plugin@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/eslint-plugin@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) - eslint-plugin-react-dom: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-react-jsx: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-react-naming-convention: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-react-rsc: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-react-web-api: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-react-x: 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-dom: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-jsx: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-naming-convention: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-rsc: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-web-api: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-x: 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/eslint@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/eslint@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/jsx@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/jsx@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@eslint-react/shared@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/shared@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 @@ -12360,13 +12494,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint-react/var@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@eslint-react/var@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 @@ -13984,6 +14118,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.65.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.59.2': dependencies: '@typescript-eslint/types': 8.59.2 @@ -13994,6 +14137,11 @@ snapshots: '@typescript-eslint/types': 8.62.0 '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/scope-manager@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + '@typescript-eslint/tsconfig-utils@8.59.2(typescript@6.0.3)': dependencies: typescript: 6.0.3 @@ -14002,6 +14150,10 @@ snapshots: dependencies: typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.65.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/type-utils@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.59.2 @@ -14014,11 +14166,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 eslint: 10.7.0(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) @@ -14030,6 +14182,8 @@ snapshots: '@typescript-eslint/types@8.62.0': {} + '@typescript-eslint/types@8.65.0': {} + '@typescript-eslint/typescript-estree@8.59.2(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.59.2(typescript@6.0.3) @@ -14060,6 +14214,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.65.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.65.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) @@ -14082,6 +14251,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@6.0.3) + eslint: 10.7.0(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.59.2': dependencies: '@typescript-eslint/types': 8.59.2 @@ -14092,9 +14272,14 @@ snapshots: '@typescript-eslint/types': 8.62.0 eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + eslint-visitor-keys: 5.0.1 + '@ungap/structured-clone@1.3.0': {} - '@vitest/eslint-plugin@1.6.16(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0)))': + '@vitest/eslint-plugin@1.6.23(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0)))': dependencies: '@typescript-eslint/scope-manager': 8.62.0 '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) @@ -14166,39 +14351,42 @@ snapshots: optionalDependencies: cspell: 10.0.1 - '@w5s/dev@3.4.7': + '@w5s/dev@3.11.0': dependencies: '@types/eslint': 9.6.1 - '@w5s/eslint-config-ignore@1.2.7(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': + '@w5s/eslint-config-ignore@1.10.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)': dependencies: find-up: 8.0.0 + minimatch: 10.2.5 parse-gitignore: 2.0.0 optionalDependencies: eslint: 10.7.0(jiti@2.7.0) typescript: 6.0.3 - '@w5s/eslint-config@3.11.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0)))': + '@w5s/eslint-config@3.20.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0)))': dependencies: '@e18e/eslint-plugin': 0.5.1(eslint@10.7.0(jiti@2.7.0)) - '@eslint-react/eslint-plugin': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint-plugin': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) '@eslint/js': 10.0.1(eslint@10.7.0(jiti@2.7.0)) '@eslint/markdown': 8.0.1 '@next/eslint-plugin-next': 16.2.9 '@stylistic/eslint-plugin': 5.10.0(eslint@10.7.0(jiti@2.7.0)) '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/parser': 8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@vitest/eslint-plugin': 1.6.16(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0))) - '@w5s/dev': 3.4.7 - '@w5s/eslint-config-ignore': 1.2.7(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@w5s/prettier-config': 3.1.15 + '@vitest/eslint-plugin': 1.6.23(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3)(vitest@4.1.10(@types/node@20.19.43)(vite@7.3.3(@types/node@20.19.43)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.2)(yaml@2.9.0))) + '@w5s/dev': 3.11.0 + '@w5s/eslint-config-ignore': 1.10.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@w5s/prettier-config': 3.5.0 eslint-merge-processors: 2.0.0(eslint@10.7.0(jiti@2.7.0)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0)) - eslint-plugin-jsdoc: 63.0.10(eslint@10.7.0(jiti@2.7.0)) - eslint-plugin-jsonc: 3.2.0(eslint@10.7.0(jiti@2.7.0)) - eslint-plugin-n: 18.1.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3) - eslint-plugin-unicorn: 68.0.0(eslint@10.7.0(jiti@2.7.0)) - eslint-plugin-yml: 3.5.0(eslint@10.7.0(jiti@2.7.0)) + eslint-plugin-jsdoc: 63.1.0(eslint@10.7.0(jiti@2.7.0)) + eslint-plugin-jsonc: 3.3.0(eslint@10.7.0(jiti@2.7.0)) + eslint-plugin-n: 18.2.2(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3) + eslint-plugin-perfectionist: 5.10.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-unicorn: 71.1.0(eslint@10.7.0(jiti@2.7.0)) + eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0)) + eslint-plugin-yml: 3.6.0(eslint@10.7.0(jiti@2.7.0)) globals: 17.6.0 jsonc-eslint-parser: 3.1.0 parse-gitignore: 2.0.0 @@ -14216,7 +14404,7 @@ snapshots: - ts-declaration-location - vitest - '@w5s/prettier-config@3.1.15': {} + '@w5s/prettier-config@3.5.0': {} '@w5s/tsconfig@3.1.20(typescript@6.0.3)': optionalDependencies: @@ -14624,6 +14812,8 @@ snapshots: baseline-browser-mapping@2.10.27: {} + baseline-browser-mapping@2.11.1: {} + batch@0.6.1: {} before-after-hook@4.0.0: {} @@ -14646,7 +14836,7 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - birecord@0.1.1: {} + birecord@0.1.2: {} bl@4.1.0: dependencies: @@ -14725,6 +14915,14 @@ snapshots: node-releases: 2.0.38 update-browserslist-db: 1.2.3(browserslist@4.28.2) + browserslist@4.28.7: + dependencies: + baseline-browser-mapping: 2.11.1 + caniuse-lite: 1.0.30001806 + electron-to-chromium: 1.5.395 + node-releases: 2.0.51 + update-browserslist-db: 1.2.3(browserslist@4.28.7) + buffer-from@1.1.2: {} buffer@5.7.1: @@ -14810,6 +15008,8 @@ snapshots: caniuse-lite@1.0.30001791: {} + caniuse-lite@1.0.30001806: {} + ccount@2.0.1: {} chai@6.2.2: {} @@ -15090,6 +15290,8 @@ snapshots: conventional-commits-filter: 6.0.1 conventional-commits-parser: 7.1.0 + convert-hrtime@5.0.0: {} + convert-source-map@2.0.0: {} cookie-signature@1.0.7: {} @@ -15548,6 +15750,8 @@ snapshots: electron-to-chromium@1.5.349: {} + electron-to-chromium@1.5.395: {} + emoji-regex-xs@1.0.0: {} emoji-regex@10.6.0: {} @@ -15858,9 +16062,9 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsdoc@63.0.10(eslint@10.7.0(jiti@2.7.0)): + eslint-plugin-jsdoc@63.1.0(eslint@10.7.0(jiti@2.7.0)): dependencies: - '@es-joy/jsdoccomment': 0.87.0 + '@es-joy/jsdoccomment': 0.88.0 '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 comment-parser: 1.4.7 @@ -15878,7 +16082,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-jsonc@3.2.0(eslint@10.7.0(jiti@2.7.0)): + eslint-plugin-jsonc@3.3.0(eslint@10.7.0(jiti@2.7.0)): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) '@eslint/core': 1.2.1 @@ -15893,7 +16097,7 @@ snapshots: transitivePeerDependencies: - '@eslint/json' - eslint-plugin-n@18.1.0(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3): + eslint-plugin-n@18.2.2(eslint@10.7.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) enhanced-resolve: 5.21.0 @@ -15908,91 +16112,100 @@ snapshots: ts-declaration-location: 1.0.7(typescript@6.0.3) typescript: 6.0.3 - eslint-plugin-react-dom@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-perfectionist@5.10.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/jsx': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.7.0(jiti@2.7.0) + natural-orderby: 5.0.0 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-react-dom@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) compare-versions: 6.1.1 eslint: 10.7.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-jsx@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-react-jsx@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/core': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/jsx': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-naming-convention@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-react-naming-convention@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/core': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-rsc@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-react-rsc@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/core': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) eslint: 10.7.0(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-web-api@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + eslint-plugin-react-web-api@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/core': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - birecord: 0.1.1 + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + birecord: 0.1.2 eslint: 10.7.0(jiti@2.7.0) ts-pattern: 5.9.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-x@5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): - dependencies: - '@eslint-react/ast': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/core': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/eslint': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/jsx': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/shared': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@eslint-react/var': 5.9.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/type-utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-react-x@5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@eslint-react/ast': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/core': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/eslint': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/jsx': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/shared': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@eslint-react/var': 5.17.1(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/type-utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) compare-versions: 6.1.1 eslint: 10.7.0(jiti@2.7.0) string-ts: 2.3.1 @@ -16002,27 +16215,34 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-unicorn@68.0.0(eslint@10.7.0(jiti@2.7.0)): + eslint-plugin-unicorn@71.1.0(eslint@10.7.0(jiti@2.7.0)): dependencies: - '@babel/helper-validator-identifier': 7.29.7 '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) - browserslist: 4.28.2 + browserslist: 4.28.7 change-case: 5.4.4 ci-info: 4.4.0 core-js-compat: 3.49.0 detect-indent: 7.0.2 eslint: 10.7.0(jiti@2.7.0) find-up-simple: 1.0.1 - globals: 17.6.0 + globals: 17.7.0 indent-string: 5.0.0 is-builtin-module: 5.0.0 - jsesc: 3.1.0 + is-identifier: 1.1.0 pluralize: 8.0.0 - regjsparser: 0.13.1 + quote-js-string: 0.1.0 + regjsparser: 0.13.2 + reserved-identifiers: 1.2.0 semver: 7.8.5 strip-indent: 4.1.1 - eslint-plugin-yml@3.5.0(eslint@10.7.0(jiti@2.7.0)): + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0)): + dependencies: + eslint: 10.7.0(jiti@2.7.0) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.7.0(jiti@2.7.0))(typescript@6.0.3) + + eslint-plugin-yml@3.6.0(eslint@10.7.0(jiti@2.7.0)): dependencies: '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.2 @@ -16410,6 +16630,8 @@ snapshots: function-bind@1.1.2: {} + function-timeout@1.0.2: {} + function.prototype.name@1.1.8: dependencies: call-bind: 1.0.9 @@ -16516,6 +16738,8 @@ snapshots: globals@17.6.0: {} + globals@17.7.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -16892,6 +17116,10 @@ snapshots: dependencies: postcss: 8.5.14 + identifier-regex@1.1.0: + dependencies: + reserved-identifiers: 1.2.0 + ieee754@1.2.1: {} ignore-walk@8.0.0: @@ -17053,6 +17281,11 @@ snapshots: is-hexadecimal@2.0.1: {} + is-identifier@1.1.0: + dependencies: + identifier-regex: 1.1.0 + super-regex: 1.1.0 + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -17436,6 +17669,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + make-asynchronous@1.1.0: + dependencies: + p-event: 6.0.1 + type-fest: 4.41.0 + web-worker: 1.5.0 + make-fetch-happen@15.0.5: dependencies: '@gar/promise-retry': 1.0.3 @@ -18198,6 +18437,8 @@ snapshots: natural-compare@1.4.0: {} + natural-orderby@5.0.0: {} + negotiator@0.6.3: {} negotiator@0.6.4: {} @@ -18252,6 +18493,8 @@ snapshots: node-releases@2.0.38: {} + node-releases@2.0.51: {} + nopt@9.0.0: dependencies: abbrev: 4.0.0 @@ -18422,6 +18665,10 @@ snapshots: p-cancelable@3.0.0: {} + p-event@6.0.1: + dependencies: + p-timeout: 6.1.4 + p-finally@1.0.0: {} p-limit@2.3.0: @@ -18469,6 +18716,8 @@ snapshots: dependencies: p-finally: 1.0.0 + p-timeout@6.1.4: {} + p-try@2.2.0: {} package-json@8.1.1: @@ -19189,6 +19438,8 @@ snapshots: quick-lru@5.1.1: {} + quote-js-string@0.1.0: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -19387,6 +19638,10 @@ snapshots: dependencies: jsesc: 3.1.0 + regjsparser@0.13.2: + dependencies: + jsesc: 3.1.0 + rehype-raw@7.0.0: dependencies: '@types/hast': 3.0.4 @@ -20102,6 +20357,12 @@ snapshots: postcss: 8.5.14 postcss-selector-parser: 6.1.2 + super-regex@1.1.0: + dependencies: + function-timeout: 1.0.2 + make-asynchronous: 1.1.0 + time-span: 5.1.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -20198,6 +20459,10 @@ snapshots: thunky@1.1.0: {} + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + timers-ext@0.1.8: dependencies: es5-ext: 0.10.64 @@ -20333,6 +20598,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@4.41.0: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -20493,6 +20760,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.7): + dependencies: + browserslist: 4.28.7 + escalade: 3.2.0 + picocolors: 1.1.1 + update-notifier@6.0.2: dependencies: boxen: 7.1.1 @@ -20614,6 +20887,8 @@ snapshots: web-namespaces@2.0.1: {} + web-worker@1.5.0: {} + webidl-conversions@3.0.1: {} webpack-bundle-analyzer@4.10.2: From 151bfdb813956a2b089275c8e64d97c14e01ad0a Mon Sep 17 00:00:00 2001 From: Julien Polo Date: Fri, 24 Jul 2026 20:18:11 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/website/docusaurus.config.ts | 232 +++++++++--------- apps/website/eslint.config.js | 8 +- apps/website/sidebars.js | 2 +- apps/website/src/components/Def/index.tsx | 7 +- .../src/components/HomepageFeatures/index.tsx | 71 +++--- .../components/PackageBadgeGroup/index.tsx | 14 +- .../components/PackageInstallBlock/index.tsx | 6 +- apps/website/src/pages/index.tsx | 38 +-- apps/website/src/pages/markdown-page.md | 7 - eslint.config.js | 56 ++--- packages/application/README.md | 2 +- packages/application/example/.eslintrc.cjs | 2 +- packages/application/src/ConfigurationRef.ts | 18 +- packages/application/src/index.spec.ts | 5 +- packages/application/src/index.ts | 4 +- packages/application/src/internal/registry.ts | 7 +- .../application/src/useConfiguration.spec.ts | 3 +- packages/application/src/useConfiguration.ts | 14 +- packages/application/src/useNamespace.spec.ts | 5 +- packages/application/src/useNamespace.ts | 9 +- packages/application/src/useRef.spec.ts | 3 +- packages/application/src/useRef.ts | 70 +++--- packages/application/src/useState.spec.ts | 3 +- packages/application/src/useState.ts | 8 +- packages/async/example/.eslintrc.cjs | 2 +- packages/async/src/clearImmediate.ts | 1 + packages/async/src/defer.spec.ts | 3 +- packages/async/src/defer.ts | 2 +- packages/async/src/delay.spec.ts | 3 +- packages/async/src/delay.ts | 3 +- packages/async/src/index.spec.ts | 7 +- packages/async/src/index.ts | 4 +- .../async/src/internal/promiseFromTimer.ts | 3 +- packages/async/src/isPromise.spec.ts | 1 + packages/async/src/isPromiseLike.spec.ts | 1 + packages/async/src/setImmediate.ts | 1 + packages/async/src/tryCall.spec.ts | 1 + packages/async/src/tryCall.ts | 1 + packages/bigdecimal/example/.eslintrc.cjs | 2 +- packages/bigdecimal/src/BigDecimal.spec.ts | 21 +- packages/bigdecimal/src/BigDecimal.ts | 29 +-- .../src/BigDecimal/BigDecimal.spec.ts | 37 +-- .../bigdecimal/src/BigDecimal/BigDecimal.ts | 21 +- .../src/BigDecimal/BigDecimalAsString.spec.ts | 5 +- .../src/BigDecimal/BigDecimalAsString.ts | 3 +- .../BigDecimal/BigDecimalComparable.spec.ts | 15 +- .../src/BigDecimal/BigDecimalComparable.ts | 2 + .../src/BigDecimal/BigDecimalNegate.spec.ts | 7 +- .../src/BigDecimal/BigDecimalNegate.ts | 3 +- .../src/BigDecimal/BigDecimalNumeric.spec.ts | 9 +- .../src/BigDecimal/BigDecimalNumeric.ts | 24 +- .../src/BigDecimal/BigDecimalSigned.spec.ts | 17 +- .../src/BigDecimal/BigDecimalSigned.ts | 7 +- .../src/BigDecimal/BigDecimalZero.spec.ts | 5 +- .../src/BigDecimal/BigDecimalZero.ts | 4 +- .../bigdecimal/src/BigDecimal/call.spec.ts | 3 +- packages/bigdecimal/src/BigDecimal/call.ts | 8 +- packages/bigdecimal/src/BigDecimal/compare.ts | 5 +- .../bigdecimal/src/BigDecimal/format.spec.ts | 3 +- packages/bigdecimal/src/BigDecimal/format.ts | 3 +- .../src/BigDecimal/fromBigInt.spec.ts | 1 + .../bigdecimal/src/BigDecimal/fromBigInt.ts | 1 + .../bigdecimal/src/BigDecimal/fromInt.spec.ts | 5 +- packages/bigdecimal/src/BigDecimal/fromInt.ts | 4 +- .../src/BigDecimal/normalize.spec.ts | 7 +- .../bigdecimal/src/BigDecimal/normalize.ts | 1 + packages/bigdecimal/src/BigDecimal/of.spec.ts | 7 +- packages/bigdecimal/src/BigDecimal/of.ts | 4 +- .../bigdecimal/src/BigDecimal/parse.spec.ts | 3 +- packages/bigdecimal/src/BigDecimal/parse.ts | 2 + .../bigdecimal/src/BigDecimal/scale.spec.ts | 3 +- packages/bigdecimal/src/BigDecimal/scale.ts | 1 + .../src/BigDecimal/truncate.spec.ts | 3 +- .../bigdecimal/src/BigDecimal/truncate.ts | 1 + packages/bigdecimal/src/index.spec.ts | 3 +- .../src/internal/bigDecimalScaleValue.ts | 4 +- packages/byte-size/example/.eslintrc.cjs | 2 +- packages/byte-size/src/ByteSize.spec.ts | 5 +- packages/byte-size/src/ByteSize.ts | 4 +- .../byte-size/src/ByteSize/ByteSize.spec.ts | 23 +- packages/byte-size/src/ByteSize/ByteSize.ts | 11 +- .../byte-size/src/ByteSize/format.spec.ts | 3 +- packages/byte-size/src/ByteSize/format.ts | 5 +- packages/byte-size/src/ByteSize/parse.spec.ts | 1 + packages/byte-size/src/ByteSize/parse.ts | 2 + packages/byte-size/src/ByteSizeFormat.ts | 4 +- packages/byte-size/src/ByteSizeFormat/data.ts | 1 + packages/byte-size/src/index.spec.ts | 3 +- packages/collection/example/.eslintrc.cjs | 2 +- packages/collection/src/Array.spec.ts | 13 +- packages/collection/src/Array.ts | 3 +- packages/collection/src/Array/at.spec.ts | 3 +- packages/collection/src/Array/concat.spec.ts | 3 +- packages/collection/src/Array/concat.ts | 3 +- .../collection/src/Array/deleteAt.spec.ts | 3 +- packages/collection/src/Array/deleteAt.ts | 1 + packages/collection/src/Array/empty.spec.ts | 1 + packages/collection/src/Array/every.spec.ts | 3 +- packages/collection/src/Array/every.ts | 1 + packages/collection/src/Array/filter.spec.ts | 5 +- packages/collection/src/Array/filter.ts | 2 + packages/collection/src/Array/find.spec.ts | 5 +- packages/collection/src/Array/find.ts | 1 + .../collection/src/Array/findIndex.spec.ts | 3 +- packages/collection/src/Array/findIndex.ts | 1 + .../collection/src/Array/findLast.spec.ts | 3 +- packages/collection/src/Array/findLast.ts | 1 + .../src/Array/findLastIndex.spec.ts | 3 +- .../collection/src/Array/findLastIndex.ts | 1 + packages/collection/src/Array/flatMap.spec.ts | 5 +- packages/collection/src/Array/flatMap.ts | 1 + .../collection/src/Array/fromAsync.spec.ts | 7 +- packages/collection/src/Array/fromAsync.ts | 4 +- .../collection/src/Array/generate.spec.ts | 1 + packages/collection/src/Array/generate.ts | 2 + .../collection/src/Array/hasInstance.spec.ts | 3 +- packages/collection/src/Array/include.spec.ts | 1 + packages/collection/src/Array/includes.ts | 1 + packages/collection/src/Array/indexOf.spec.ts | 3 +- packages/collection/src/Array/indexOf.ts | 1 + .../collection/src/Array/insertAt.spec.ts | 3 +- packages/collection/src/Array/insertAt.ts | 1 + packages/collection/src/Array/isEmpty.spec.ts | 1 + .../collection/src/Array/lastIndexOf.spec.ts | 3 +- packages/collection/src/Array/lastIndexOf.ts | 1 + packages/collection/src/Array/map.spec.ts | 3 +- packages/collection/src/Array/map.ts | 1 + packages/collection/src/Array/of.spec.ts | 1 + packages/collection/src/Array/of.ts | 2 +- packages/collection/src/Array/reduce.spec.ts | 3 +- packages/collection/src/Array/reduce.ts | 1 + .../collection/src/Array/reduceRight.spec.ts | 3 +- packages/collection/src/Array/reduceRight.ts | 1 + packages/collection/src/Array/reverse.spec.ts | 5 +- packages/collection/src/Array/reverse.ts | 2 + packages/collection/src/Array/setAt.spec.ts | 5 +- packages/collection/src/Array/setAt.ts | 1 + packages/collection/src/Array/size.spec.ts | 1 + packages/collection/src/Array/slice.spec.ts | 18 +- packages/collection/src/Array/slice.ts | 2 + packages/collection/src/Array/some.spec.ts | 3 +- packages/collection/src/Array/some.ts | 1 + packages/collection/src/Array/sort.spec.ts | 6 +- packages/collection/src/Array/sort.ts | 1 + packages/collection/src/Array/splice.spec.ts | 5 +- packages/collection/src/Array/splice.ts | 5 +- packages/collection/src/Record.spec.ts | 19 +- packages/collection/src/Record.ts | 4 +- packages/collection/src/Record/delete.spec.ts | 1 + packages/collection/src/Record/delete.ts | 2 +- .../collection/src/Record/entries.spec.ts | 1 + packages/collection/src/Record/entries.ts | 1 + .../collection/src/Record/forEach.spec.ts | 1 + packages/collection/src/Record/forEach.ts | 1 + packages/collection/src/Record/from.spec.ts | 1 + packages/collection/src/Record/from.ts | 4 +- packages/collection/src/Record/get.spec.ts | 3 +- packages/collection/src/Record/get.ts | 2 + packages/collection/src/Record/has.spec.ts | 1 + packages/collection/src/Record/keys.spec.ts | 3 +- packages/collection/src/Record/keys.ts | 2 +- packages/collection/src/Record/set.spec.ts | 1 + packages/collection/src/Record/size.spec.ts | 3 +- packages/collection/src/Record/size.ts | 1 + packages/collection/src/Record/values.spec.ts | 1 + packages/collection/src/Record/values.ts | 1 + packages/collection/src/index.spec.ts | 3 +- packages/console/example/.eslintrc.cjs | 2 +- packages/console/src/ANSICode.spec.ts | 11 +- packages/console/src/ANSICode.ts | 10 +- packages/console/src/ANSICode/color.spec.ts | 3 +- packages/console/src/ANSICode/color.ts | 6 +- .../console/src/ANSICode/fontStyle.spec.ts | 3 +- packages/console/src/ANSICode/fontStyle.ts | 2 +- .../console/src/ANSICode/fontWeight.spec.ts | 3 +- packages/console/src/ANSICode/fontWeight.ts | 4 +- packages/console/src/ANSICode/format.spec.ts | 3 +- packages/console/src/ANSICode/format.ts | 2 +- packages/console/src/ANSICode/strip.spec.ts | 3 +- packages/console/src/ANSICode/style.spec.ts | 3 +- packages/console/src/ANSICode/style.ts | 8 +- packages/console/src/ANSICode/wrap.spec.ts | 3 +- packages/console/src/ANSICode/wrap.ts | 14 +- packages/console/src/Console.spec.ts | 5 +- packages/console/src/Console.ts | 12 +- packages/console/src/Console/debug.ts | 3 +- packages/console/src/Console/error.ts | 3 +- packages/console/src/Console/info.ts | 3 +- packages/console/src/Console/isWeb.ts | 4 +- packages/console/src/Console/log.ts | 3 +- packages/console/src/Console/warn.ts | 3 +- packages/console/src/Console/write.ts | 5 +- packages/console/src/index.spec.ts | 7 +- packages/console/src/index.ts | 2 +- packages/core-type/src/AnyFunction.ts | 2 +- packages/core-type/src/Awaitable.ts | 2 +- packages/core-type/src/EmptyObject.test-d.ts | 5 +- packages/core-type/src/JSONArray.test-d.ts | 3 +- packages/core-type/src/JSONObject.test-d.ts | 2 +- packages/core-type/src/JSONObject.ts | 2 + .../core-type/src/JSONPrimitive.test-d.ts | 2 +- packages/core-type/src/JSONPrimitive.ts | 2 +- packages/core-type/src/JSONValue.ts | 2 +- packages/core-type/src/Nullable.test-d.ts | 5 +- packages/core-type/src/Nullable.ts | 2 +- packages/core-type/src/ObjectLike.test-d.ts | 2 +- packages/core-type/src/ObjectLike.ts | 2 +- packages/core-type/src/PartialKeys.test-d.ts | 7 +- packages/core-type/src/Pretty.test-d.ts | 5 +- packages/core-type/src/Primitive.test-d.ts | 2 +- packages/core-type/src/Primitive.ts | 2 +- packages/core-type/src/RequiredKeys.test-d.ts | 7 +- packages/core-type/src/Tag.test-d.ts | 3 +- packages/core-type/src/Tag.ts | 8 +- packages/core-type/src/TestingLibrary.ts | 43 ++-- packages/core-type/src/ValueOf.test-d.ts | 7 +- packages/core-type/src/assertType.ts | 30 +-- packages/core-type/src/index.test-d.ts | 2 +- packages/core/README.md | 10 +- packages/core/example/.eslintrc.cjs | 2 +- packages/core/example/usage.ts | 10 +- packages/core/src/Boolean.spec.ts | 5 +- .../src/Boolean/BooleanComparable.spec.ts | 3 +- packages/core/src/Boolean/BooleanNot.spec.ts | 1 + packages/core/src/Boolean/compare.ts | 1 + packages/core/src/Bounded.ts | 12 +- packages/core/src/Callable.spec.ts | 1 + packages/core/src/Callable.ts | 11 +- packages/core/src/Char.spec.ts | 9 +- packages/core/src/Char.ts | 4 +- packages/core/src/Char/CharBounded.spec.ts | 3 +- packages/core/src/Char/CharComparable.spec.ts | 3 +- packages/core/src/Char/CharComparable.ts | 1 + packages/core/src/Char/CharIndexable.spec.ts | 3 +- packages/core/src/Char/CharIndexable.ts | 2 +- packages/core/src/Char/compare.ts | 1 + packages/core/src/Char/fromCodePoint.spec.ts | 3 +- packages/core/src/Char/fromCodePoint.ts | 2 +- packages/core/src/Codec.spec.ts | 7 +- packages/core/src/Codec.ts | 21 +- packages/core/src/Codec/decode.spec.ts | 3 +- packages/core/src/Codec/decode.ts | 17 +- packages/core/src/Codec/encode.spec.ts | 3 +- packages/core/src/Codec/lazy.spec.ts | 13 +- packages/core/src/Codec/lazy.ts | 1 + packages/core/src/Codec/schema.spec.ts | 3 +- packages/core/src/CodecError.spec.ts | 7 +- packages/core/src/CodecError.ts | 2 +- packages/core/src/Comparable.spec.ts | 1 + packages/core/src/Comparable.ts | 78 +++--- packages/core/src/Enum.spec.ts | 3 +- packages/core/src/Enum.ts | 28 ++- packages/core/src/Enum/define.spec.ts | 62 ++--- packages/core/src/Enum/define.ts | 7 +- packages/core/src/Enum/keys.spec.ts | 7 +- packages/core/src/Enum/keys.ts | 1 + packages/core/src/Enum/values.spec.ts | 7 +- packages/core/src/Enum/values.ts | 1 + packages/core/src/Equal.spec.ts | 1 + packages/core/src/Equal.ts | 40 +-- packages/core/src/Indexable.spec.ts | 12 +- packages/core/src/Indexable.ts | 55 +++-- packages/core/src/JSON.spec.ts | 3 +- packages/core/src/JSON.ts | 10 +- packages/core/src/Numeric/Integral.spec.ts | 19 +- packages/core/src/Numeric/Integral.ts | 11 +- packages/core/src/Numeric/Numeric.spec.ts | 42 ++-- packages/core/src/Numeric/Numeric.ts | 56 +++-- packages/core/src/Numeric/One.ts | 16 +- packages/core/src/Numeric/Signed.ts | 16 +- packages/core/src/Numeric/Zero.ts | 16 +- packages/core/src/Option.spec.ts | 11 +- packages/core/src/Option.ts | 11 +- packages/core/src/Option/None.spec.ts | 3 +- packages/core/src/Option/Some.spec.ts | 1 + packages/core/src/Option/andThen.spec.ts | 1 + packages/core/src/Option/andThen.ts | 1 + packages/core/src/Option/from.spec.ts | 1 + packages/core/src/Option/getOrElse.spec.ts | 1 + packages/core/src/Option/getOrElse.ts | 2 +- packages/core/src/Option/getOrThrow.spec.ts | 3 +- packages/core/src/Option/isNone.spec.ts | 4 +- packages/core/src/Option/isSome.spec.ts | 4 +- packages/core/src/Option/isSome.ts | 3 +- packages/core/src/Option/map.spec.ts | 3 +- packages/core/src/Option/map.ts | 1 + packages/core/src/Option/orElse.spec.ts | 3 +- packages/core/src/Option/orElse.ts | 1 + packages/core/src/Order.spec.ts | 9 +- packages/core/src/Order.ts | 9 +- packages/core/src/Order/combine.spec.ts | 30 +-- packages/core/src/Order/combine.ts | 3 +- packages/core/src/Order/compareBy.spec.ts | 23 +- packages/core/src/Order/primitive.spec.ts | 3 +- packages/core/src/Order/reverse.spec.ts | 7 +- packages/core/src/Order/reverse.ts | 1 + packages/core/src/Ordering.spec.ts | 5 +- packages/core/src/Ordering/reverse.spec.ts | 5 +- packages/core/src/Range.ts | 8 +- packages/core/src/Ref.spec.ts | 7 +- packages/core/src/Ref.ts | 2 +- packages/core/src/Ref/modify.spec.ts | 3 +- packages/core/src/Ref/property.spec.ts | 11 +- packages/core/src/Ref/read.spec.ts | 5 +- packages/core/src/Ref/write.spec.ts | 5 +- packages/core/src/Result.spec.ts | 21 +- packages/core/src/Result.ts | 40 +-- packages/core/src/Result/Error.spec.ts | 10 +- packages/core/src/Result/Error.ts | 3 +- packages/core/src/Result/Ok.spec.ts | 6 +- packages/core/src/Result/andThen.spec.ts | 1 + packages/core/src/Result/andThen.ts | 1 + packages/core/src/Result/get.spec.ts | 12 +- packages/core/src/Result/get.ts | 1 + packages/core/src/Result/getError.spec.ts | 14 +- packages/core/src/Result/getError.ts | 1 + packages/core/src/Result/getOrElse.spec.ts | 9 +- packages/core/src/Result/getOrElse.ts | 1 + packages/core/src/Result/getOrThrow.spec.ts | 5 +- packages/core/src/Result/getOrThrow.ts | 1 + packages/core/src/Result/hasInstance.spec.ts | 3 +- packages/core/src/Result/hasInstance.ts | 1 + packages/core/src/Result/isError.spec.ts | 3 +- packages/core/src/Result/isError.ts | 1 + packages/core/src/Result/isOk.spec.ts | 3 +- packages/core/src/Result/map.spec.ts | 3 +- packages/core/src/Result/map.ts | 3 +- packages/core/src/Result/mapError.spec.ts | 3 +- packages/core/src/Result/mapError.ts | 1 + packages/core/src/Result/orElse.spec.ts | 3 +- packages/core/src/Result/orElse.ts | 1 + packages/core/src/Result/tryCall.spec.ts | 9 +- packages/core/src/Result/tryCall.ts | 6 +- packages/core/src/String.spec.ts | 23 +- packages/core/src/String.ts | 20 +- .../core/src/String/StringComparable.spec.ts | 3 +- packages/core/src/String/at.spec.ts | 5 +- packages/core/src/String/compare.ts | 1 + packages/core/src/String/concat.spec.ts | 3 +- packages/core/src/String/endsWith.spec.ts | 3 +- packages/core/src/String/includes.spec.ts | 3 +- packages/core/src/String/indexOf.spec.ts | 3 +- packages/core/src/String/isEmpty.spec.ts | 1 + packages/core/src/String/join.spec.ts | 1 + packages/core/src/String/lastIndexOf.spec.ts | 3 +- packages/core/src/String/of.spec.ts | 3 +- packages/core/src/String/padEnd.spec.ts | 3 +- packages/core/src/String/padStart.spec.ts | 3 +- packages/core/src/String/size.spec.ts | 1 + packages/core/src/String/split.spec.ts | 1 + packages/core/src/String/split.ts | 2 +- packages/core/src/String/startsWith.spec.ts | 1 + packages/core/src/String/truncate.spec.ts | 9 +- packages/core/src/String/truncate.ts | 4 +- packages/core/src/Struct.spec.ts | 5 +- packages/core/src/Struct.ts | 44 ++-- packages/core/src/Struct/Struct.spec.ts | 11 +- packages/core/src/Struct/Struct.ts | 11 +- packages/core/src/Symbol.spec.ts | 1 + packages/core/src/Symbol.ts | 126 +++++----- packages/core/src/Tag.spec.ts | 5 +- packages/core/src/Tag.ts | 18 +- packages/core/src/Tag/define.spec.ts | 20 +- packages/core/src/Tag/define.ts | 5 +- packages/core/src/Testing.spec.ts | 3 +- packages/core/src/Testing.ts | 2 +- .../core/src/Testing/defaultTestingLibrary.ts | 1 + packages/core/src/Testing/describeAdd.ts | 5 +- packages/core/src/Testing/describeAsString.ts | 5 +- packages/core/src/Testing/describeBounded.ts | 5 +- .../core/src/Testing/describeCheckedAdd.ts | 5 +- .../core/src/Testing/describeCheckedDivide.ts | 5 +- .../src/Testing/describeCheckedMultiply.ts | 5 +- .../core/src/Testing/describeCheckedPower.ts | 5 +- .../src/Testing/describeCheckedRemainder.ts | 5 +- .../src/Testing/describeCheckedSubtract.ts | 5 +- .../core/src/Testing/describeCodec.spec.ts | 16 +- packages/core/src/Testing/describeCodec.ts | 15 +- .../src/Testing/describeComparable.spec.ts | 3 +- .../core/src/Testing/describeComparable.ts | 9 +- packages/core/src/Testing/describeDivide.ts | 5 +- .../core/src/Testing/describeEqual.spec.ts | 11 +- packages/core/src/Testing/describeEqual.ts | 11 +- .../core/src/Testing/describeIndexable.ts | 27 +- packages/core/src/Testing/describeMultiply.ts | 5 +- packages/core/src/Testing/describeNegate.ts | 7 +- packages/core/src/Testing/describeNot.ts | 5 +- packages/core/src/Testing/describeNumeric.ts | 22 +- packages/core/src/Testing/describePower.ts | 5 +- .../core/src/Testing/describeRemainder.ts | 5 +- packages/core/src/Testing/describeSigned.ts | 23 +- packages/core/src/Testing/describeSubtract.ts | 5 +- .../core/src/Testing/describeType.spec.ts | 12 +- packages/core/src/Testing/describeType.ts | 20 +- packages/core/src/Testing/describeZero.ts | 5 +- packages/core/src/Testing/withOrder.ts | 1 + packages/core/src/Type.spec.ts | 80 +++--- packages/core/src/Type.ts | 118 ++++----- packages/core/src/Type/Array.spec.ts | 23 +- packages/core/src/Type/Array.ts | 14 +- packages/core/src/Type/Char.spec.ts | 11 +- packages/core/src/Type/Char.ts | 9 +- packages/core/src/Type/Int.spec.ts | 13 +- packages/core/src/Type/Int.ts | 3 +- packages/core/src/Type/Object.spec.ts | 43 ++-- packages/core/src/Type/Object.ts | 41 ++-- packages/core/src/Type/Option.spec.ts | 19 +- packages/core/src/Type/Option.ts | 13 +- packages/core/src/Type/Ordering.spec.ts | 7 +- packages/core/src/Type/Ordering.ts | 15 +- packages/core/src/Type/Record.spec.ts | 22 +- packages/core/src/Type/Record.ts | 29 +-- packages/core/src/Type/RegExp.spec.ts | 25 +- packages/core/src/Type/RegExp.ts | 9 +- packages/core/src/Type/Tuple.spec.ts | 13 +- packages/core/src/Type/Tuple.ts | 13 +- packages/core/src/Type/URL.spec.ts | 11 +- packages/core/src/Type/URL.ts | 7 +- packages/core/src/Type/UUID.spec.ts | 9 +- packages/core/src/Type/UUID.ts | 13 +- packages/core/src/Type/bigint.spec.ts | 27 +- packages/core/src/Type/bigint.ts | 8 +- packages/core/src/Type/boolean.spec.ts | 21 +- packages/core/src/Type/boolean.ts | 2 +- packages/core/src/Type/constant.spec.ts | 15 +- packages/core/src/Type/constant.ts | 12 +- packages/core/src/Type/define.spec.ts | 17 +- packages/core/src/Type/define.ts | 15 +- packages/core/src/Type/ensure.spec.ts | 5 +- packages/core/src/Type/number.spec.ts | 21 +- packages/core/src/Type/number.ts | 2 +- packages/core/src/Type/string.spec.ts | 21 +- packages/core/src/Type/string.ts | 2 +- packages/core/src/Type/union.spec.ts | 29 +-- packages/core/src/Type/union.ts | 5 +- packages/core/src/Type/unknown.spec.ts | 17 +- packages/core/src/Type/unknown.ts | 4 +- packages/core/src/identity.spec.ts | 3 +- packages/core/src/ignore.spec.ts | 3 +- packages/core/src/ignore.ts | 3 +- packages/core/src/index.spec.ts | 10 +- packages/core/src/index.ts | 2 +- packages/core/src/lazy.spec.ts | 3 +- packages/core/src/omit.spec.ts | 11 +- packages/core/src/omit.ts | 2 +- packages/core/src/pick.spec.ts | 11 +- packages/core/src/pick.ts | 2 +- packages/database/README.md | 4 +- packages/database/example/.eslintrc.cjs | 2 +- packages/database/example/usage.ts | 4 +- packages/database/src/SQLDataType.spec.ts | 7 +- packages/database/src/SQLDataType.ts | 183 +++++++------- packages/database/src/SQLQuery.spec.ts | 21 +- packages/database/src/SQLQuery.ts | 137 ++++++----- packages/database/src/configuration.spec.ts | 1 + packages/database/src/configuration.ts | 1 + packages/database/src/driver.ts | 19 +- packages/database/src/driver/mock.spec.ts | 5 +- packages/database/src/driver/mock.ts | 3 +- packages/database/src/driver/mysql.spec.ts | 10 +- packages/database/src/driver/mysql.ts | 14 +- packages/database/src/driver/sqlite3.spec.ts | 6 +- packages/database/src/driver/sqlite3.ts | 23 +- packages/database/src/error.spec.ts | 7 +- packages/database/src/error.ts | 2 +- packages/database/src/execute.spec.ts | 5 +- packages/database/src/execute.ts | 9 +- packages/database/src/index.spec.ts | 13 +- packages/database/src/index.ts | 8 +- packages/database/src/sql.spec.ts | 3 +- packages/database/src/sql.ts | 26 +- packages/env/example/.eslintrc.cjs | 2 +- packages/env/src/Env.spec.ts | 1 + packages/env/src/Env.ts | 11 +- packages/env/src/index.spec.ts | 3 +- packages/error/README.md | 6 +- packages/error/example/.eslintrc.cjs | 2 +- packages/error/example/usage.ts | 6 +- packages/error/src/AbortError.spec.ts | 7 +- packages/error/src/AbortError.ts | 2 +- packages/error/src/AggregateError.spec.ts | 1 + packages/error/src/AggregateError.ts | 8 +- packages/error/src/ArgumentError.spec.ts | 7 +- packages/error/src/ArgumentError.ts | 2 +- packages/error/src/CustomError.spec.ts | 41 ++-- packages/error/src/CustomError.ts | 36 +-- .../error/src/CustomError/asString.spec.ts | 19 +- packages/error/src/Error.spec.ts | 1 + packages/error/src/Error.ts | 12 +- packages/error/src/ErrorClass.ts | 111 ++++----- packages/error/src/EvalError.spec.ts | 1 + packages/error/src/InvariantError.spec.ts | 7 +- packages/error/src/InvariantError.ts | 2 +- .../error/src/NotImplementedError.spec.ts | 7 +- packages/error/src/NotImplementedError.ts | 2 +- packages/error/src/RangeError.spec.ts | 1 + packages/error/src/ReferenceError.spec.ts | 1 + packages/error/src/RuntimeError.spec.ts | 7 +- packages/error/src/RuntimeError.ts | 2 +- packages/error/src/SyntaxError.spec.ts | 1 + packages/error/src/Testing/describeError.ts | 10 +- packages/error/src/TimeoutError.spec.ts | 9 +- packages/error/src/TimeoutError.ts | 2 +- packages/error/src/TypeError.spec.ts | 1 + packages/error/src/URIError.spec.ts | 1 + packages/error/src/assertNever.spec.ts | 5 +- packages/error/src/index.spec.ts | 3 +- packages/error/src/index.ts | 2 +- packages/error/src/invariant.spec.ts | 3 +- packages/error/src/invariant.ts | 6 +- packages/error/src/isDOMException.spec.ts | 3 +- packages/error/src/isError.spec.ts | 5 +- packages/error/src/panic.spec.ts | 3 +- packages/error/src/warning.spec.ts | 3 +- packages/error/src/warning.ts | 2 +- packages/global-storage/example/.eslintrc.cjs | 2 +- packages/global-storage/src/index.spec.ts | 7 +- packages/global-storage/src/index.ts | 6 +- packages/global-storage/src/useGlobal.spec.ts | 1 + .../global-storage/src/useStorage.spec.ts | 3 +- packages/global-storage/src/useStorage.ts | 7 +- packages/http/README.md | 4 +- packages/http/example/.eslintrc.cjs | 2 +- packages/http/example/usage.ts | 4 +- packages/http/scripts/buildStatus.ts | 41 ++-- packages/http/src/BodyReader.ts | 48 ++-- packages/http/src/Client.spec.ts | 13 +- packages/http/src/Client.ts | 56 +++-- packages/http/src/HTTPError.spec.ts | 13 +- packages/http/src/HTTPError.ts | 9 +- packages/http/src/HTTPError/InvalidURL.ts | 2 +- packages/http/src/HTTPError/NetworkError.ts | 2 +- packages/http/src/HTTPError/ParserError.ts | 2 +- packages/http/src/Headers.spec.ts | 3 +- packages/http/src/Headers.ts | 5 +- packages/http/src/Headers/Headers.spec.ts | 12 +- packages/http/src/Headers/Headers.ts | 1 + packages/http/src/Headers/empty.spec.ts | 3 +- packages/http/src/ReferrerPolicy.spec.ts | 1 + packages/http/src/ReferrerPolicy.ts | 7 +- packages/http/src/Request.ts | 62 ++--- packages/http/src/RequestCache.spec.ts | 1 + packages/http/src/RequestCache.ts | 9 +- packages/http/src/RequestCredentials.spec.ts | 1 + packages/http/src/RequestCredentials.ts | 3 +- packages/http/src/RequestDestination.spec.ts | 1 + packages/http/src/RequestDestination.ts | 5 +- packages/http/src/RequestMode.spec.ts | 1 + packages/http/src/RequestMode.ts | 5 +- packages/http/src/RequestRedirect.spec.ts | 1 + packages/http/src/RequestRedirect.ts | 5 +- packages/http/src/RequestTimeout.ts | 1 + packages/http/src/Response.spec.ts | 11 +- packages/http/src/Response.ts | 36 +-- packages/http/src/Response/from.ts | 29 +-- packages/http/src/ResponseParser.spec.ts | 12 +- packages/http/src/ResponseParser.ts | 51 ++-- packages/http/src/ResponseType.ts | 1 + packages/http/src/Status.spec.ts | 7 +- packages/http/src/Status.ts | 3 +- packages/http/src/Status/Status.ts | 1 + .../http/src/Status/StatusBounded.spec.ts | 5 +- packages/http/src/Status/StatusBounded.ts | 4 +- .../http/src/Status/StatusComparable.spec.ts | 9 +- packages/http/src/Status/StatusComparable.ts | 4 +- .../http/src/Status/StatusIndexable.spec.ts | 11 +- packages/http/src/Status/StatusIndexable.ts | 8 +- packages/http/src/Status/compare.ts | 4 +- packages/http/src/Status/status.all.ts | 1 + packages/http/src/Testing.spec.ts | 3 +- packages/http/src/Testing/FakeClient.ts | 1 + .../__snapshots__/ReferrerPolicy.spec.ts.snap | 4 +- .../__snapshots__/RequestCache.spec.ts.snap | 6 +- .../RequestDestination.spec.ts.snap | 2 +- .../__snapshots__/RequestMode.spec.ts.snap | 2 +- .../RequestRedirect.spec.ts.snap | 2 +- packages/http/src/index.spec.ts | 9 +- packages/http/src/index.ts | 8 +- packages/http/src/requestSend.spec.ts | 41 ++-- packages/http/src/requestSend.ts | 36 +-- packages/iterable/example/.eslintrc.cjs | 2 +- packages/iterable/src/AsyncIterable.spec.ts | 21 +- packages/iterable/src/AsyncIterable.ts | 24 +- .../iterable/src/AsyncIterable/chunks.spec.ts | 3 +- .../iterable/src/AsyncIterable/concat.spec.ts | 5 +- .../iterable/src/AsyncIterable/create.spec.ts | 5 +- .../iterable/src/AsyncIterable/drop.spec.ts | 5 +- .../iterable/src/AsyncIterable/empty.spec.ts | 5 +- .../iterable/src/AsyncIterable/every.spec.ts | 5 +- packages/iterable/src/AsyncIterable/every.ts | 1 + .../iterable/src/AsyncIterable/filter.spec.ts | 5 +- packages/iterable/src/AsyncIterable/filter.ts | 1 + .../iterable/src/AsyncIterable/find.spec.ts | 5 +- packages/iterable/src/AsyncIterable/find.ts | 3 +- .../src/AsyncIterable/flatMap.spec.ts | 5 +- .../iterable/src/AsyncIterable/flatMap.ts | 1 + .../iterable/src/AsyncIterable/from.spec.ts | 8 +- .../src/AsyncIterable/generate.spec.ts | 5 +- .../iterable/src/AsyncIterable/generate.ts | 1 + .../src/AsyncIterable/hasInstance.spec.ts | 4 +- .../iterable/src/AsyncIterable/map.spec.ts | 5 +- packages/iterable/src/AsyncIterable/map.ts | 1 + .../iterable/src/AsyncIterable/of.spec.ts | 5 +- packages/iterable/src/AsyncIterable/of.ts | 2 +- .../iterable/src/AsyncIterable/reduce.spec.ts | 3 +- packages/iterable/src/AsyncIterable/reduce.ts | 1 + .../iterable/src/AsyncIterable/size.spec.ts | 3 +- packages/iterable/src/AsyncIterable/size.ts | 4 +- .../iterable/src/AsyncIterable/some.spec.ts | 3 +- packages/iterable/src/AsyncIterable/some.ts | 1 + .../iterable/src/AsyncIterable/take.spec.ts | 5 +- .../iterable/src/AsyncIterable/zip.spec.ts | 5 +- packages/iterable/src/AsyncIterable/zip.ts | 1 + packages/iterable/src/Iterable.spec.ts | 21 +- packages/iterable/src/Iterable.ts | 26 +- packages/iterable/src/Iterable/chunks.spec.ts | 3 +- packages/iterable/src/Iterable/concat.spec.ts | 3 +- packages/iterable/src/Iterable/create.spec.ts | 5 +- packages/iterable/src/Iterable/drop.spec.ts | 5 +- packages/iterable/src/Iterable/empty.spec.ts | 5 +- packages/iterable/src/Iterable/every.spec.ts | 5 +- packages/iterable/src/Iterable/filter.spec.ts | 5 +- packages/iterable/src/Iterable/find.spec.ts | 5 +- .../iterable/src/Iterable/flatMap.spec.ts | 5 +- packages/iterable/src/Iterable/from.spec.ts | 7 +- packages/iterable/src/Iterable/from.ts | 2 +- .../iterable/src/Iterable/generate.spec.ts | 5 +- packages/iterable/src/Iterable/generate.ts | 1 + .../iterable/src/Iterable/hasInstance.spec.ts | 3 +- packages/iterable/src/Iterable/map.spec.ts | 5 +- packages/iterable/src/Iterable/of.spec.ts | 5 +- packages/iterable/src/Iterable/of.ts | 2 +- packages/iterable/src/Iterable/reduce.spec.ts | 3 +- packages/iterable/src/Iterable/size.spec.ts | 3 +- packages/iterable/src/Iterable/size.ts | 1 + packages/iterable/src/Iterable/some.spec.ts | 3 +- packages/iterable/src/Iterable/take.spec.ts | 5 +- packages/iterable/src/Iterable/zip.spec.ts | 5 +- .../iterable/src/Testing/withAsyncIterable.ts | 50 ++-- packages/iterable/src/Testing/withIterable.ts | 18 +- packages/iterable/src/index.spec.ts | 3 +- packages/log/example/.eslintrc.cjs | 2 +- packages/log/src/Log.spec.ts | 7 +- packages/log/src/Log.ts | 2 +- packages/log/src/Log/handle.spec.ts | 7 +- packages/log/src/Log/handle.ts | 19 +- packages/log/src/Log/send.spec.ts | 23 +- packages/log/src/Log/sendWith.spec.ts | 23 +- packages/log/src/Log/sendWith.ts | 9 +- packages/log/src/LogHandler.spec.ts | 7 +- packages/log/src/LogHandler.ts | 8 +- packages/log/src/LogHandler/Console.spec.ts | 19 +- packages/log/src/LogHandler/Console.ts | 30 +-- packages/log/src/LogHandler/filter.spec.ts | 5 +- packages/log/src/LogHandler/filter.ts | 4 +- packages/log/src/LogLevel.spec.ts | 7 +- packages/log/src/LogLevel.ts | 13 +- packages/log/src/LogLevel/LogLevel.spec.ts | 17 +- packages/log/src/LogLevel/LogLevel.ts | 8 +- .../log/src/LogLevel/LogLevelAsInt.spec.ts | 3 +- packages/log/src/LogLevel/LogLevelAsInt.ts | 1 + .../log/src/LogLevel/LogLevelAsString.spec.ts | 3 +- packages/log/src/LogLevel/LogLevelAsString.ts | 1 + .../log/src/LogLevel/LogLevelBounded.spec.ts | 7 +- packages/log/src/LogLevel/LogLevelBounded.ts | 6 +- .../src/LogLevel/LogLevelComparable.spec.ts | 7 +- .../log/src/LogLevel/LogLevelComparable.ts | 1 + .../log/src/LogLevel/LogLevelValue.spec.ts | 3 +- packages/log/src/LogLevel/LogLevelValue.ts | 7 +- packages/log/src/LogLevel/compare.spec.ts | 3 +- packages/log/src/LogLevel/compare.ts | 2 + packages/log/src/LogLevel/from.spec.ts | 11 +- packages/log/src/LogLevel/of.spec.ts | 3 +- packages/log/src/LogLevel/of.ts | 1 + packages/log/src/LogMessage.spec.ts | 3 +- packages/log/src/LogMessage.ts | 2 + packages/log/src/LogMessage/create.spec.ts | 3 +- packages/log/src/LogMessage/create.ts | 1 + packages/log/src/LogMessage/of.spec.ts | 3 +- packages/log/src/LogMessage/of.ts | 1 + packages/log/src/LogRecord.spec.ts | 17 +- packages/log/src/LogRecord.ts | 2 + packages/log/src/LogRecord/LogRecord.ts | 38 +-- .../log/src/LogRecord/messageWithData.spec.ts | 9 +- packages/log/src/Testing/fakeLogRecord.ts | 9 +- packages/log/src/configuration.spec.ts | 1 + packages/log/src/configuration.ts | 4 +- packages/log/src/index.spec.ts | 21 +- packages/log/src/index.ts | 6 +- packages/log/src/level.spec.ts | 15 +- packages/log/src/level.ts | 55 +++-- packages/money/README.md | 2 +- packages/money/example/.eslintrc.cjs | 2 +- packages/money/example/usage.ts | 2 +- packages/money/scripts/buildCurrencies.js | 62 ++--- packages/money/src/Currency.spec.ts | 3 +- packages/money/src/Currency.ts | 3 +- packages/money/src/Currency/Currency.spec.ts | 11 +- packages/money/src/Currency/Currency.ts | 34 +-- .../src/Currency/CurrencyAsString.spec.ts | 7 +- .../money/src/Currency/CurrencyAsString.ts | 1 + .../src/Currency/CurrencyComparable.spec.ts | 13 +- .../money/src/Currency/CurrencyComparable.ts | 2 + packages/money/src/Currency/compare.ts | 4 +- packages/money/src/CurrencyRegistry.spec.ts | 3 +- packages/money/src/CurrencyRegistry.ts | 5 +- packages/money/src/Money.spec.ts | 7 +- packages/money/src/Money.ts | 13 +- packages/money/src/Money/Money.spec.ts | 41 ++-- packages/money/src/Money/Money.ts | 15 +- .../money/src/Money/MoneyAsString.spec.ts | 9 +- packages/money/src/Money/MoneyAsString.ts | 7 +- .../money/src/Money/MoneyComparable.spec.ts | 17 +- packages/money/src/Money/MoneyComparable.ts | 2 + packages/money/src/Money/MoneyNegate.spec.ts | 7 +- packages/money/src/Money/MoneyNegate.ts | 2 + packages/money/src/Money/MoneyNumeric.spec.ts | 11 +- packages/money/src/Money/MoneyNumeric.ts | 44 ++-- packages/money/src/Money/MoneySigned.spec.ts | 5 +- packages/money/src/Money/MoneySigned.ts | 13 +- packages/money/src/Money/MoneyZero.spec.ts | 5 +- packages/money/src/Money/MoneyZero.ts | 1 + packages/money/src/Money/compare.ts | 7 +- packages/money/src/Money/factory.spec.ts | 17 +- packages/money/src/Money/factory.ts | 9 +- packages/money/src/Money/format.spec.ts | 7 +- packages/money/src/Money/format.ts | 1 + packages/money/src/Money/normalize.spec.ts | 7 +- packages/money/src/Money/normalize.ts | 3 +- packages/money/src/Money/of.ts | 4 +- packages/money/src/Money/parse.spec.ts | 9 +- packages/money/src/Money/parse.ts | 3 + packages/money/src/Testing.spec.ts | 3 +- packages/money/src/Testing/anyCurrency.ts | 2 +- packages/money/src/configuration.spec.ts | 1 + packages/money/src/configuration.ts | 1 + packages/money/src/index.spec.ts | 7 +- packages/money/src/index.ts | 2 +- packages/money/src/internal/moneyMapAmount.ts | 1 + packages/money/src/moneyFactory.all.spec.ts | 3 +- packages/money/src/moneyFactory.all.ts | 4 +- packages/num/example/.eslintrc.cjs | 2 +- packages/num/src/BigInt.spec.ts | 11 +- packages/num/src/BigInt.ts | 11 +- .../num/src/BigInt/BigIntComparable.spec.ts | 5 +- packages/num/src/BigInt/BigIntComparable.ts | 1 + .../num/src/BigInt/BigIntIndexable.spec.ts | 11 +- packages/num/src/BigInt/BigIntIndexable.ts | 2 +- .../num/src/BigInt/BigIntIntegral.spec.ts | 15 +- packages/num/src/BigInt/BigIntIntegral.ts | 30 +-- packages/num/src/BigInt/compare.ts | 3 +- packages/num/src/BigInt/format.spec.ts | 1 + packages/num/src/BigInt/fromInt.spec.ts | 1 + packages/num/src/BigInt/fromNumber.spec.ts | 1 + packages/num/src/BigInt/fromNumber.ts | 1 + packages/num/src/BigInt/parse.spec.ts | 1 + packages/num/src/Int.spec.ts | 19 +- packages/num/src/Int.ts | 30 +-- packages/num/src/Int/IntBounded.spec.ts | 5 +- packages/num/src/Int/IntBounded.ts | 1 + packages/num/src/Int/IntComparable.spec.ts | 5 +- packages/num/src/Int/IntComparable.ts | 2 + packages/num/src/Int/IntIndexable.spec.ts | 5 +- packages/num/src/Int/IntIndexable.ts | 3 +- packages/num/src/Int/IntIntegral.spec.ts | 15 +- packages/num/src/Int/IntIntegral.ts | 20 +- packages/num/src/Int/compare.ts | 4 +- packages/num/src/Int/format.spec.ts | 3 +- packages/num/src/Int/format.ts | 1 + packages/num/src/Int/fromNumber.spec.ts | 5 +- packages/num/src/Int/fromNumber.ts | 1 + packages/num/src/Int/parse.spec.ts | 5 +- packages/num/src/Int/parse.ts | 4 +- packages/num/src/Number.spec.ts | 19 +- packages/num/src/Number.ts | 5 +- packages/num/src/Number/compare.ts | 3 +- packages/num/src/Number/format.spec.ts | 3 +- packages/num/src/Number/parse.spec.ts | 3 +- packages/num/src/NumberConversion.spec.ts | 9 +- packages/num/src/NumberConversion.ts | 30 +-- packages/num/src/NumberConversion/Add.spec.ts | 3 +- packages/num/src/NumberConversion/Add.ts | 2 + .../num/src/NumberConversion/Bounded.spec.ts | 7 +- packages/num/src/NumberConversion/Bounded.ts | 2 + .../src/NumberConversion/Comparable.spec.ts | 15 +- .../num/src/NumberConversion/Comparable.ts | 4 +- .../num/src/NumberConversion/Multiply.spec.ts | 3 +- packages/num/src/NumberConversion/Multiply.ts | 2 + .../num/src/NumberConversion/Negate.spec.ts | 7 +- packages/num/src/NumberConversion/Negate.ts | 4 +- .../num/src/NumberConversion/Power.spec.ts | 3 +- packages/num/src/NumberConversion/Power.ts | 2 + .../src/NumberConversion/Remainder.spec.ts | 3 +- .../num/src/NumberConversion/Remainder.ts | 2 + .../num/src/NumberConversion/Signed.spec.ts | 45 ++-- packages/num/src/NumberConversion/Signed.ts | 6 +- .../num/src/NumberConversion/Subtract.spec.ts | 3 +- packages/num/src/NumberConversion/Subtract.ts | 2 + .../num/src/NumberConversion/Zero.spec.ts | 5 +- packages/num/src/NumberConversion/Zero.ts | 6 +- packages/num/src/RoundingMode.spec.ts | 3 +- packages/num/src/RoundingMode.ts | 90 +++---- .../__snapshots__/RoundingMode.spec.ts.snap | 10 +- packages/num/src/index.spec.ts | 3 +- .../num/src/internal/defaultConversion.ts | 2 +- .../num/src/internal/uncheckedOperator.ts | 2 +- packages/object-id/example/.eslintrc.cjs | 2 +- packages/object-id/src/index.spec.ts | 3 +- packages/object-id/src/index.ts | 2 +- packages/object-id/src/internal/state.ts | 2 + packages/object-id/src/objectId.spec.ts | 9 +- packages/object-id/src/objectId.ts | 11 +- packages/playground/src/Hash.spec.ts | 3 +- packages/playground/src/Hash.ts | 16 +- packages/playground/src/PartialFunction.ts | 72 +++--- packages/playground/src/Spread.ts | 14 +- packages/playground/src/assign.spec.ts | 9 +- packages/playground/src/assign.ts | 2 +- .../playground/src/collection/Seq.spec.ts | 7 +- packages/playground/src/collection/Seq.ts | 8 +- packages/playground/src/collection/Seq/Seq.ts | 5 +- .../src/collection/Seq/from.spec.ts | 3 +- .../src/collection/Seq/hasInstance.spec.ts | 3 +- .../src/collection/Seq/hasInstance.ts | 2 + .../playground/src/collection/Seq/of.spec.ts | 3 +- packages/playground/src/collection/Seq/of.ts | 3 +- .../src/collection/internal/useSeqState.ts | 12 +- .../playground/src/csv/CSVEncodeOptions.ts | 1 + packages/playground/src/csv/CSVParseResult.ts | 3 +- packages/playground/src/csv/CSVRecord.ts | 8 +- .../playground/src/csv/decodeByName.spec.ts | 9 +- packages/playground/src/csv/decodeByName.ts | 19 +- packages/playground/src/csv/encodeByName.ts | 11 +- packages/playground/src/csv/readLines.spec.ts | 3 +- packages/playground/src/date/Duration.spec.ts | 27 +- packages/playground/src/date/Duration.ts | 43 ++-- .../playground/src/di/ContainerKey.spec.ts | 5 +- packages/playground/src/di/ContainerKey.ts | 11 +- .../playground/src/di/ContainerProvider.ts | 4 +- .../src/di/ContainerProviderFunction.ts | 4 +- packages/playground/src/di/index.spec.ts | 3 +- packages/playground/src/di/index.ts | 2 +- packages/playground/src/di/provide.spec.ts | 5 +- packages/playground/src/di/provide.ts | 3 +- packages/playground/src/di/use.spec.ts | 10 +- packages/playground/src/di/use.ts | 64 ++--- packages/playground/src/extend.spec.ts | 13 +- packages/playground/src/fiber/Fiber/resume.ts | 3 +- .../playground/src/fiber/Fiber/run.spec.ts | 5 +- packages/playground/src/fiber/Fiber/run.ts | 1 + .../src/fiber/Fiber/suspend.spec.ts | 7 +- .../playground/src/fiber/Fiber/suspend.ts | 3 +- .../src/fiber/Fiber/terminate.spec.ts | 5 +- .../playground/src/fiber/Fiber/terminate.ts | 3 +- packages/playground/src/fiber/FiberId.ts | 2 +- .../src/fiber/Scheduler/Scheduler.ts | 89 +++---- .../fiber/Scheduler/SchedulerFiberState.ts | 9 +- packages/playground/src/fiber/index.spec.ts | 5 +- packages/playground/src/fiber/index.ts | 4 +- .../internal/requestScheduledCallback.ts | 17 +- .../src/fiber/internal/scheduler.spec.ts | 5 +- .../initializer-example/initializers/init1.ts | 3 +- .../initializer-example/initializers/init2.ts | 3 +- .../src/initializer-example/main.ts | 3 +- .../src/initializer/InitializerStatus.spec.ts | 3 +- .../src/initializer/InitializerStatus.ts | 6 +- .../src/initializer/internal/state.ts | 2 + .../playground/src/initializer/start.spec.ts | 3 +- packages/playground/src/initializer/start.ts | 1 + .../src/initializer/startAll.spec.ts | 1 + .../playground/src/initializer/startAll.ts | 8 +- packages/playground/src/job/Job.ts | 14 +- packages/playground/src/job/JobProvider.ts | 4 +- .../src/job/MemoryJobProvider.spec.ts | 13 +- .../playground/src/job/MemoryJobProvider.ts | 43 ++-- packages/playground/src/job/configuration.ts | 6 +- packages/playground/src/main.ts | 86 +++---- packages/playground/src/net/IPv4.spec.ts | 21 +- packages/playground/src/net/IPv4.ts | 43 ++-- packages/playground/src/net/IPv6.spec.ts | 15 +- packages/playground/src/net/IPv6.ts | 67 ++--- packages/playground/src/pipe.spec.ts | 1 + packages/playground/src/pipe.ts | 208 ++++++++-------- packages/playground/src/secret/Secret.ts | 9 +- .../playground/src/secret/Secret/Secret.ts | 5 +- .../src/secret/Secret/SecretAsString.ts | 1 + packages/playground/src/secret/Secret/of.ts | 1 + .../playground/src/secret/Secret/value.ts | 3 +- packages/playground/src/secret/index.spec.ts | 3 +- .../playground/src/secret/internal/state.ts | 1 + packages/playground/src/shallowEqual.spec.ts | 11 +- packages/playground/src/shallowEqual.ts | 3 +- packages/playground/src/slackClient.ts | 89 +++---- .../playground/src/task-abortable/abort.ts | 1 + .../src/task-abortable/abortable.spec.ts | 5 +- .../src/task-abortable/abortable.ts | 4 +- .../src/task-abortable/index.spec.ts | 7 +- .../playground/src/task-abortable/index.ts | 2 +- .../playground/src/task-disposable/dispose.ts | 3 +- .../src/task-disposable/index.spec.ts | 3 +- .../playground/src/task-disposable/using.ts | 15 +- .../playground/src/task-retry/retry.spec.ts | 23 +- packages/playground/src/task-retry/retry.ts | 139 ++++++----- packages/random/README.md | 10 +- packages/random/example/.eslintrc.cjs | 2 +- packages/random/example/usage.ts | 10 +- packages/random/src/Random.spec.ts | 3 +- packages/random/src/Random/next.spec.ts | 5 +- packages/random/src/Random/next.ts | 4 +- packages/random/src/Testing.spec.ts | 3 +- .../random/src/Testing/fakeRandomGenerator.ts | 1 + packages/random/src/configuration.spec.ts | 1 + packages/random/src/configuration.ts | 13 +- packages/random/src/index.spec.ts | 5 +- packages/random/src/index.ts | 4 +- packages/random/src/randomBoolean.spec.ts | 7 +- packages/random/src/randomBoolean.ts | 5 +- packages/random/src/randomInt.spec.ts | 15 +- packages/random/src/randomInt.ts | 5 +- packages/random/src/randomNumber.spec.ts | 13 +- packages/random/src/randomNumber.ts | 5 +- packages/system/README.md | 2 +- packages/system/example/.eslintrc.cjs | 2 +- packages/system/example/usage.ts | 2 +- packages/system/src/FileError.spec.ts | 12 +- packages/system/src/FileError.ts | 8 +- packages/system/src/FilePath.spec.ts | 33 +-- packages/system/src/FilePath.ts | 138 ++++++----- packages/system/src/FileSize.spec.ts | 3 +- packages/system/src/FileStatus.ts | 202 +++++++-------- packages/system/src/FileSystem.spec.ts | 5 +- packages/system/src/FileSystem.ts | 12 +- .../system/src/FileSystem/copyFile.spec.ts | 5 +- packages/system/src/FileSystem/copyFile.ts | 4 +- .../src/FileSystem/createDirectory.spec.ts | 5 +- .../system/src/FileSystem/createDirectory.ts | 6 +- .../src/FileSystem/createSymbolicLink.spec.ts | 5 +- .../src/FileSystem/createSymbolicLink.ts | 4 +- .../src/FileSystem/emptyDirectory.spec.ts | 5 +- .../system/src/FileSystem/emptyDirectory.ts | 32 +-- packages/system/src/FileSystem/ensure.spec.ts | 27 +- packages/system/src/FileSystem/ensure.ts | 67 ++--- .../src/FileSystem/listDirectory.spec.ts | 5 +- .../system/src/FileSystem/listDirectory.ts | 8 +- packages/system/src/FileSystem/move.spec.ts | 33 +-- packages/system/src/FileSystem/move.ts | 65 ++--- .../system/src/FileSystem/readFile.spec.ts | 11 +- packages/system/src/FileSystem/readFile.ts | 13 +- .../src/FileSystem/readFileStatus.spec.ts | 13 +- .../system/src/FileSystem/readFileStatus.ts | 54 ++-- .../src/FileSystem/readSymbolicLink.spec.ts | 5 +- .../system/src/FileSystem/readSymbolicLink.ts | 8 +- packages/system/src/FileSystem/remove.spec.ts | 5 +- packages/system/src/FileSystem/remove.ts | 6 +- packages/system/src/FileSystem/rename.spec.ts | 5 +- packages/system/src/FileSystem/rename.ts | 4 +- .../system/src/FileSystem/writeFile.spec.ts | 11 +- packages/system/src/FileSystem/writeFile.ts | 29 ++- packages/system/src/Internal.spec.ts | 20 +- packages/system/src/Internal.ts | 29 ++- packages/system/src/Process.spec.ts | 7 +- packages/system/src/Process.ts | 5 +- packages/system/src/Testing.spec.ts | 3 +- packages/system/src/Testing/fsStub.spec.ts | 7 +- packages/system/src/Testing/fsStub.ts | 107 ++++---- packages/system/src/Testing/withFile.spec.ts | 17 +- packages/system/src/Testing/withFile.ts | 51 ++-- packages/system/src/_test/config.ts | 43 ++-- packages/system/src/index.spec.ts | 3 +- packages/system/src/index.ts | 6 +- packages/task-timeout/README.md | 18 +- packages/task-timeout/example/.eslintrc.cjs | 2 +- packages/task-timeout/example/usage.ts | 18 +- packages/task-timeout/src/index.spec.ts | 3 +- packages/task-timeout/src/timeout.spec.ts | 7 +- packages/task-timeout/src/timeout.ts | 19 +- packages/task/README.md | 18 +- packages/task/example/.eslintrc.cjs | 2 +- packages/task/example/usage.ts | 18 +- packages/task/src/Task.spec.ts | 25 +- packages/task/src/Task.ts | 124 +++++----- packages/task/src/Task/Task.spec.ts | 3 +- packages/task/src/Task/Task.ts | 3 + packages/task/src/Task/TaskAggregateState.ts | 81 +++--- packages/task/src/Task/_stub.spec.ts | 2 +- packages/task/src/Task/all.spec.ts | 16 +- packages/task/src/Task/all.ts | 11 +- packages/task/src/Task/allKeyed.spec.ts | 18 +- packages/task/src/Task/allKeyed.ts | 4 +- packages/task/src/Task/allSettled.spec.ts | 9 +- packages/task/src/Task/allSettled.ts | 11 +- .../task/src/Task/allSettledKeyed.spec.ts | 14 +- packages/task/src/Task/allSettledKeyed.ts | 7 +- packages/task/src/Task/andRun.spec.ts | 7 +- packages/task/src/Task/andRun.ts | 1 + packages/task/src/Task/andThen.spec.ts | 19 +- packages/task/src/Task/andThen.ts | 5 +- packages/task/src/Task/any.spec.ts | 18 +- packages/task/src/Task/any.ts | 14 +- packages/task/src/Task/create.spec.ts | 21 +- packages/task/src/Task/create.ts | 9 +- packages/task/src/Task/error.spec.ts | 3 +- packages/task/src/Task/from.spec.ts | 5 +- packages/task/src/Task/from.ts | 4 +- packages/task/src/Task/hasInstance.spec.ts | 6 +- packages/task/src/Task/hasInstance.ts | 1 + packages/task/src/Task/ignore.spec.ts | 5 +- packages/task/src/Task/ignore.ts | 5 +- packages/task/src/Task/map.spec.ts | 11 +- packages/task/src/Task/map.ts | 5 +- packages/task/src/Task/mapError.spec.ts | 11 +- packages/task/src/Task/mapError.ts | 5 +- packages/task/src/Task/mapResult.spec.ts | 3 +- packages/task/src/Task/mapResult.ts | 10 +- packages/task/src/Task/ok.spec.ts | 3 +- packages/task/src/Task/orElse.spec.ts | 17 +- packages/task/src/Task/orElse.ts | 3 +- packages/task/src/Task/reject.spec.ts | 8 +- packages/task/src/Task/reject.ts | 2 +- packages/task/src/Task/resolve.spec.ts | 8 +- packages/task/src/Task/resolve.ts | 2 +- packages/task/src/Task/run.spec.ts | 5 +- packages/task/src/Task/run.ts | 4 +- packages/task/src/Task/tryCall.spec.ts | 7 +- packages/task/src/Task/tryCall.ts | 9 +- packages/task/src/Task/unsafeCall.ts | 2 + packages/task/src/Testing.spec.ts | 3 +- packages/task/src/Testing/FakeTask.spec.ts | 5 +- packages/task/src/Testing/FakeTask.ts | 44 ++-- packages/task/src/Testing/withTask.ts | 72 +++--- packages/task/src/index.spec.ts | 3 +- packages/task/src/internal/taskRun.ts | 15 +- packages/time/README.md | 2 +- packages/time/example/.eslintrc.cjs | 2 +- packages/time/example/usage.ts | 2 +- packages/time/src/Time.spec.ts | 13 +- packages/time/src/Time.ts | 26 +- packages/time/src/Time/Time.spec.ts | 17 +- packages/time/src/Time/Time.ts | 11 +- packages/time/src/Time/TimeBounded.spec.ts | 5 +- packages/time/src/Time/TimeBounded.ts | 1 + packages/time/src/Time/TimeComparable.spec.ts | 3 +- packages/time/src/Time/TimeComparable.ts | 4 +- packages/time/src/Time/TimeNumeric.spec.ts | 5 +- packages/time/src/Time/TimeNumeric.ts | 3 +- packages/time/src/Time/compare.ts | 2 + packages/time/src/Time/delay.spec.ts | 5 +- packages/time/src/Time/delay.ts | 4 +- packages/time/src/Time/format.spec.ts | 3 +- packages/time/src/Time/from.spec.ts | 9 +- packages/time/src/Time/from.ts | 32 +-- packages/time/src/Time/now.spec.ts | 3 +- packages/time/src/Time/now.ts | 2 + packages/time/src/Time/of.spec.ts | 5 +- packages/time/src/Time/parse.spec.ts | 3 +- packages/time/src/Time/parse.ts | 1 + packages/time/src/TimeDuration.spec.ts | 31 +-- packages/time/src/TimeDuration.ts | 31 +-- .../src/TimeDuration/TimeDuration.spec.ts | 15 +- .../time/src/TimeDuration/TimeDuration.ts | 2 +- .../TimeDuration/TimeDurationAsString.spec.ts | 5 +- .../src/TimeDuration/TimeDurationAsString.ts | 1 + .../TimeDurationComparable.spec.ts | 3 +- .../TimeDuration/TimeDurationComparable.ts | 4 +- .../TimeDuration/TimeDurationNegate.spec.ts | 7 +- .../src/TimeDuration/TimeDurationNegate.ts | 2 + .../TimeDuration/TimeDurationNumeric.spec.ts | 3 +- .../src/TimeDuration/TimeDurationNumeric.ts | 8 +- .../TimeDuration/TimeDurationSigned.spec.ts | 13 +- .../src/TimeDuration/TimeDurationSigned.ts | 2 + .../src/TimeDuration/TimeDurationZero.spec.ts | 3 +- .../time/src/TimeDuration/TimeDurationZero.ts | 2 + packages/time/src/TimeDuration/compare.ts | 2 + packages/time/src/TimeDuration/from.spec.ts | 3 +- packages/time/src/TimeDuration/from.ts | 19 +- packages/time/src/TimeDuration/toDays.spec.ts | 5 +- packages/time/src/TimeDuration/toDays.ts | 3 +- .../time/src/TimeDuration/toHours.spec.ts | 5 +- packages/time/src/TimeDuration/toHours.ts | 3 +- .../time/src/TimeDuration/toMinutes.spec.ts | 5 +- packages/time/src/TimeDuration/toMinutes.ts | 3 +- .../time/src/TimeDuration/toSeconds.spec.ts | 5 +- packages/time/src/TimeDuration/toSeconds.ts | 3 +- .../time/src/TimeDuration/toWeeks.spec.ts | 5 +- packages/time/src/TimeDuration/toWeeks.ts | 3 +- packages/time/src/index.spec.ts | 3 +- packages/uuid/README.md | 12 +- packages/uuid/example/.eslintrc.cjs | 2 +- packages/uuid/example/usage.ts | 12 +- packages/uuid/src/UUID.spec.ts | 7 +- packages/uuid/src/UUID.ts | 5 +- packages/uuid/src/UUID/empty.spec.ts | 3 +- packages/uuid/src/UUID/of.spec.ts | 6 +- packages/uuid/src/UUID/of.ts | 1 + packages/uuid/src/UUID/toBigInt.spec.ts | 5 +- packages/uuid/src/UUID/toUint32Array.spec.ts | 5 +- packages/uuid/src/configuration.spec.ts | 1 + packages/uuid/src/configuration.ts | 16 +- packages/uuid/src/index.spec.ts | 5 +- packages/uuid/src/index.ts | 2 +- packages/uuid/src/randomUUID.spec.ts | 5 +- packages/uuid/src/randomUUID.ts | 3 + 1102 files changed, 6181 insertions(+), 5091 deletions(-) delete mode 100644 apps/website/src/pages/markdown-page.md diff --git a/apps/website/docusaurus.config.ts b/apps/website/docusaurus.config.ts index a5526575a1..18f8bf9579 100644 --- a/apps/website/docusaurus.config.ts +++ b/apps/website/docusaurus.config.ts @@ -1,18 +1,20 @@ -import type { Config } from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; -import fs from 'node:fs'; +import type { Config } from '@docusaurus/types'; import type typedocPluginFunction from 'docusaurus-plugin-typedoc-api'; + +import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import { themes } from 'prism-react-renderer'; -import packageJSON from './package.json'; -type TypedocPluginOptions = Parameters[1]; +import packageJSON from './package.json'; export interface CustomFields { - metaTitle?: string; metaDescription?: string; + metaTitle?: string; } +type TypedocPluginOptions = Parameters[1]; + const fileExists = (path: fs.PathLike) => { try { fs.accessSync(path, fs.constants.F_OK); @@ -35,12 +37,12 @@ const packageList = fs const path = `packages/${entry}`; const hasTesting = fileExists(`${projectRoot}/${path}/src/testing.ts`); return { - path, - package: JSON.parse(fs.readFileSync(`${projectRoot}/packages/${entry}/package.json`, 'utf8')), entry: { - index: { path: 'src/index.ts', label: undefined as unknown as string }, - ...(hasTesting ? { testing: { path: 'src/Testing.ts', label: 'Testing utilities' } } : undefined), + index: { label: undefined as unknown as string, path: 'src/index.ts' }, + ...(hasTesting ? { testing: { label: 'Testing utilities', path: 'src/Testing.ts' } } : undefined), }, + package: JSON.parse(fs.readFileSync(`${projectRoot}/packages/${entry}/package.json`, 'utf8')), + path, }; }) .filter((_) => _.package.private !== true); @@ -50,42 +52,23 @@ const config: Config = (() => { const tagline = 'A collection of type safe, functional style packages for building great applications and libraries'; const organizationName = 'w5s'; return { - title, - tagline, - favicon: 'img/favicon.ico', - - // Set the production url of your site here - // url: 'https://your-docusaurus-test-site.com', - url: `https://${organizationName}.github.io/`, - // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' // baseUrl: '/', get baseUrl() { return `/${this.projectName}`; }, + customFields: { + metaDescription: tagline, + metaTitle: 'Build faster, cleaner and safer apps', + } satisfies CustomFields, + favicon: 'img/favicon.ico', // Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future future: { v4: true, // Improve compatibility with the upcoming Docusaurus v4 }, - // GitHub pages deployment config. - // If you aren't using GitHub pages, you don't need these. - organizationName, // Usually your GitHub org/user name. - projectName: 'std', // Usually your repo name. - - onBrokenLinks: 'throw', - markdown: { - mdx1Compat: { - comments: true, - headingIds: true, - }, - hooks: { - onBrokenMarkdownLinks: 'warn', - }, - }, - // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want // to replace "en" with "zh-Hans". @@ -94,26 +77,53 @@ const config: Config = (() => { locales: ['en', 'fr'], }, - customFields: { - metaTitle: 'Build faster, cleaner and safer apps', - metaDescription: tagline, - } satisfies CustomFields, + markdown: { + hooks: { + onBrokenMarkdownLinks: 'warn', + }, + mdx1Compat: { + comments: true, + headingIds: true, + }, + }, + + onBrokenLinks: 'throw', + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName, // Usually your GitHub org/user name. + plugins: [ + [ + '@apify/docusaurus-plugin-typedoc-api', + { + gitRefName: 'main', + minimal: true, + packages: packageList.map(({ entry, path }) => ({ + entry, + path, + })), + projectRoot, + readmes: true, + // debug: true, + tsconfigName: 'tsconfig.json', + } satisfies Partial, + ], + ], presets: [ [ 'classic', { - docs: { - sidebarPath: fileURLToPath(new URL('sidebars.js', import.meta.url)), + blog: { // Please change this to your repo. // Remove this to remove the "edit this page" links. - editUrl: `${githubHref}/tree/main/apps/website/`, - }, - blog: { + editUrl: `${githubHref}/tree/main/apps/website/blog/`, showReadingTime: true, + }, + docs: { // Please change this to your repo. // Remove this to remove the "edit this page" links. - editUrl: `${githubHref}/tree/main/apps/website/blog/`, + editUrl: `${githubHref}/tree/main/apps/website/`, + sidebarPath: fileURLToPath(new URL('sidebars.js', import.meta.url)), }, theme: { customCss: fileURLToPath(new URL('src/css/custom.css', import.meta.url)), @@ -122,71 +132,28 @@ const config: Config = (() => { ], ], + projectName: 'std', // Usually your repo name. + + tagline, + themeConfig: { - // Replace with your project's social card - image: 'img/w5s_social_cover.png', - metadata: [ - { name: 'keywords', content: 'functional, typescript, javascript, fp, rust, ocaml' }, - { name: 'revisit-after', content: '7 days' }, - { name: 'robots', content: 'archive,follow,imageindex,index,odp,snippet,translate' }, - { name: 'googlebot', content: 'index,follow' }, - { name: 'summary', content: tagline }, - { name: 'target', content: 'all' }, - /* cspell:disable-next-line */ - { name: 'google-site-verification', content: 'crTDqUN2i_LENrHWPhxylaLVKPZ8EdHYemMbluuGhIA' }, - ], - navbar: { - title: 'Standard Library', - logo: { - alt: 'W5S standard library', - src: 'img/logo.svg', - }, - items: [ - { - label: `v${packageList[0].package.version[0]}`, - position: 'left', - items: packageList.map(({ package: _package }) => ({ - label: `v${_package.version} · ${_package.name.split('/')[1]}`, - href: `https://www.npmjs.com/package/${_package.name}`, - })), - }, - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Docs', - }, - { - to: 'api', - label: 'API', - position: 'left', - }, - // { to: '/blog', label: 'Blog', position: 'left' }, - { - href: githubHref, - label: 'GitHub', - position: 'right', - }, - ], - }, footer: { - style: 'dark', + copyright: `Copyright © ${new Date().getFullYear()} Julien Polo. Built with Docusaurus.`, links: [ { - title: 'Docs', items: [ { label: 'Tutorial', to: '/docs/getting-started/Introduction', }, ], + title: 'Docs', }, { - title: 'Community', items: [ { - label: 'Stack Overflow', href: 'https://stackoverflow.com/questions/tagged/w5s', + label: 'Stack Overflow', }, // { // label: 'Discord', @@ -197,47 +164,82 @@ const config: Config = (() => { // href: 'https://twitter.com/docusaurus', // }, ], + title: 'Community', }, { - title: 'More', items: [ { label: 'Blog', to: '/blog', }, { - label: 'GitHub', href: githubHref, + label: 'GitHub', }, ], + title: 'More', }, ], - copyright: `Copyright © ${new Date().getFullYear()} Julien Polo. Built with Docusaurus.`, + style: 'dark', + }, + // Replace with your project's social card + image: 'img/w5s_social_cover.png', + metadata: [ + { content: 'functional, typescript, javascript, fp, rust, ocaml', name: 'keywords' }, + { content: '7 days', name: 'revisit-after' }, + { content: 'archive,follow,imageindex,index,odp,snippet,translate', name: 'robots' }, + { content: 'index,follow', name: 'googlebot' }, + { content: tagline, name: 'summary' }, + { content: 'all', name: 'target' }, + /* cspell:disable-next-line */ + { content: 'crTDqUN2i_LENrHWPhxylaLVKPZ8EdHYemMbluuGhIA', name: 'google-site-verification' }, + ], + navbar: { + items: [ + { + items: packageList.map(({ package: _package }) => ({ + href: `https://www.npmjs.com/package/${_package.name}`, + label: `v${_package.version} · ${_package.name.split('/')[1]}`, + })), + label: `v${packageList[0].package.version[0]}`, + position: 'left', + }, + { + label: 'Docs', + position: 'left', + sidebarId: 'tutorialSidebar', + type: 'docSidebar', + }, + { + label: 'API', + position: 'left', + to: 'api', + }, + // { to: '/blog', label: 'Blog', position: 'left' }, + { + href: githubHref, + label: 'GitHub', + position: 'right', + }, + ], + logo: { + alt: 'W5S standard library', + src: 'img/logo.svg', + }, + title: 'Standard Library', }, prism: { - theme: lightTheme, - darkTheme, additionalLanguages: ['bash', 'diff', 'json'], + darkTheme, + theme: lightTheme, }, } satisfies Preset.ThemeConfig, - plugins: [ - [ - '@apify/docusaurus-plugin-typedoc-api', - { - projectRoot, - packages: packageList.map(({ path, entry }) => ({ - path, - entry, - })), - minimal: true, - readmes: true, - // debug: true, - tsconfigName: 'tsconfig.json', - gitRefName: 'main', - } satisfies Partial, - ], - ], + title, + + // Set the production url of your site here + // url: 'https://your-docusaurus-test-site.com', + url: `https://${organizationName}.github.io/`, }; })(); diff --git a/apps/website/eslint.config.js b/apps/website/eslint.config.js index 4c059cebe5..e20f144008 100644 --- a/apps/website/eslint.config.js +++ b/apps/website/eslint.config.js @@ -4,15 +4,15 @@ export default [ ...rootConfig, { rules: { + // End + 'global-require': 'off', + 'import/extensions': 'off', 'ts/no-require-imports': 'off', /// FIXME: Start 'ts/no-unsafe-assignment': 'off', - 'ts/no-var-requires': 'off', 'ts/no-unsafe-member-access': 'off', - // End - 'global-require': 'off', + 'ts/no-var-requires': 'off', 'unicorn/prefer-module': 'off', - 'import/extensions': 'off', }, }, ]; diff --git a/apps/website/sidebars.js b/apps/website/sidebars.js index 2dfe3f7950..79d40ef770 100644 --- a/apps/website/sidebars.js +++ b/apps/website/sidebars.js @@ -14,7 +14,7 @@ /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { // By default, Docusaurus generates a sidebar from the docs folder structure - tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], + tutorialSidebar: [{ dirName: '.', type: 'autogenerated' }], // But you can create a sidebar manually /* diff --git a/apps/website/src/components/Def/index.tsx b/apps/website/src/components/Def/index.tsx index b079592ae7..8e214cdc12 100644 --- a/apps/website/src/components/Def/index.tsx +++ b/apps/website/src/components/Def/index.tsx @@ -1,7 +1,8 @@ -import React from 'react'; import clsx from 'clsx'; -import styles from './styles.module.css'; +import React from 'react'; + import { definitions } from './definitions'; +import styles from './styles.module.css'; export interface DefProps extends Omit, 'children'> { abbr: keyof typeof definitions; @@ -15,5 +16,5 @@ export interface DefProps extends Omit, 'childr * @param props */ export function Def(props: DefProps) { - return ; + return ; } diff --git a/apps/website/src/components/HomepageFeatures/index.tsx b/apps/website/src/components/HomepageFeatures/index.tsx index 82287a22b8..ad80ffb108 100644 --- a/apps/website/src/components/HomepageFeatures/index.tsx +++ b/apps/website/src/components/HomepageFeatures/index.tsx @@ -1,23 +1,22 @@ -import React from 'react'; -import clsx from 'clsx'; -import styles from './styles.module.css'; -import { Def } from '../Def'; -import Stripes from '@site/static/img/stripes.svg'; import Circle from '@site/static/img/circle.svg'; +import Feather from '@site/static/img/feather.svg'; import Infinity from '@site/static/img/infinity.svg'; import Jewel from '@site/static/img/jewel.svg'; -import Feather from '@site/static/img/feather.svg'; +import Stripes from '@site/static/img/stripes.svg'; +import clsx from 'clsx'; +import React from 'react'; -type FeatureItem = { - title: string; - Svg: React.ComponentType>; +import { Def } from '../Def'; +import styles from './styles.module.css'; + +interface FeatureItem { description: React.ReactNode; -}; + Svg: React.ComponentType>; + title: string; +} -const FeatureList: FeatureItem[] = [ +const FeatureList: Array = [ { - title: 'Standardized', - Svg: Stripes, description: ( <> Standardized code and conventions for high productivity @@ -36,10 +35,10 @@ const FeatureList: FeatureItem[] = [ ), + Svg: Stripes, + title: 'Standardized', }, { - title: 'Simple', - Svg: Circle, description: ( <> Functional programming, done simple. @@ -62,10 +61,10 @@ const FeatureList: FeatureItem[] = [ ), + Svg: Circle, + title: 'Simple', }, { - title: 'Stable', - Svg: Infinity, description: ( <> Fight framework obsolescence ! @@ -84,10 +83,10 @@ const FeatureList: FeatureItem[] = [ ), + Svg: Infinity, + title: 'Stable', }, { - title: 'Safe', - Svg: Jewel, description: ( <> One ambitious goal : 0 bug in production @@ -106,10 +105,10 @@ const FeatureList: FeatureItem[] = [ ), + Svg: Jewel, + title: 'Safe', }, { - title: 'Slim', - Svg: Feather, description: ( <> Because CI performances and environment matters @@ -131,6 +130,8 @@ const FeatureList: FeatureItem[] = [ ), + Svg: Feather, + title: 'Slim', }, ]; @@ -141,20 +142,6 @@ const renderTitle = (value: string) => ( ); -function Feature({ title, Svg, description }: FeatureItem) { - return ( -
-
- -
-
-

{renderTitle(title)}

-

{description}

-
-
- ); -} - export function HomepageFeatures(): React.JSX.Element { return (
@@ -168,3 +155,17 @@ export function HomepageFeatures(): React.JSX.Element {
); } + +function Feature({ description, Svg, title }: FeatureItem) { + return ( +
+
+ +
+
+

{renderTitle(title)}

+

{description}

+
+
+ ); +} diff --git a/apps/website/src/components/PackageBadgeGroup/index.tsx b/apps/website/src/components/PackageBadgeGroup/index.tsx index 04e6062fcf..996d209469 100644 --- a/apps/website/src/components/PackageBadgeGroup/index.tsx +++ b/apps/website/src/components/PackageBadgeGroup/index.tsx @@ -1,19 +1,19 @@ import Link from '@docusaurus/Link'; -import IconExternalLink from '@theme/Icon/ExternalLink'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import IconExternalLink from '@theme/Icon/ExternalLink'; + import styles from './styles.module.css'; -export type BadgeStyle = 'flat' | 'flat-square' | 'plastic' | 'for-the-badge' | 'social'; +export type BadgeStyle = 'flat' | 'flat-square' | 'for-the-badge' | 'plastic' | 'social'; -export type BadgeType = 'bundle-size' | 'npm-version' | 'npm-license'; +export type BadgeType = 'bundle-size' | 'npm-license' | 'npm-version'; const renderBadge = ( - // eslint-disable-next-line ts/no-unused-vars - { siteConfig }: ReturnType, + _context: ReturnType, props: PackageBadgeGroupProps, badgeProps: { - badgeType: BadgeType; badgeStyle?: BadgeStyle; + badgeType: BadgeType; }, ) => { const defaultBadgeProps = { @@ -57,8 +57,8 @@ const renderBadge = ( }; export interface PackageBadgeGroupProps { - packageName?: string; apiHref?: string; + packageName?: string; } export function PackageBadgeGroup(props: PackageBadgeGroupProps) { diff --git a/apps/website/src/components/PackageInstallBlock/index.tsx b/apps/website/src/components/PackageInstallBlock/index.tsx index 0422cbed1c..031e221a5f 100644 --- a/apps/website/src/components/PackageInstallBlock/index.tsx +++ b/apps/website/src/components/PackageInstallBlock/index.tsx @@ -1,6 +1,6 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; export interface PackageInstallBlockProps { packageName: string; @@ -9,8 +9,8 @@ export interface PackageInstallBlockProps { export function PackageInstallBlock({ packageName }: PackageInstallBlockProps) { return ( + +
+ +
+ + ); +} + function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); return ( @@ -34,17 +50,3 @@ function HomepageHeader() { ); } - -export default function Home(): React.JSX.Element { - const { siteConfig } = useDocusaurusContext(); - const { metaTitle = siteConfig.title, metaDescription = siteConfig.tagline } = (siteConfig.customFields ?? - {}) as CustomFields; - return ( - - -
- -
-
- ); -} diff --git a/apps/website/src/pages/markdown-page.md b/apps/website/src/pages/markdown-page.md deleted file mode 100644 index 9756c5b668..0000000000 --- a/apps/website/src/pages/markdown-page.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Markdown page example ---- - -# Markdown page example - -You don't need React to write simple standalone pages. diff --git a/eslint.config.js b/eslint.config.js index 52ed86ee53..63f5d4ca61 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,40 +1,41 @@ import { defineConfig } from '@w5s/eslint-config'; -export default [...(await defineConfig({ +export default await defineConfig({ ignores: [ '**/build', '**/dist', ], - node: { - rules: { + plugins: { + node: { + rules: { // Temporarily disabled globally: eslint-plugin-n `node/no-sync` crashes on TS files // without parser services in this monorepo; keep local `node/no-sync` disables where needed. - 'node/no-sync': 'off', + 'node/no-sync': 'off', + }, }, - }, - ts: { - rules: { - 'jsdoc/check-tag-names': 'off', - 'jsdoc/require-example': [ - 'warn', - { - checkConstructors: false, - exemptedBy: [ - 'type', - ], - }, - ], - 'ts/naming-convention': 'off', - // `void` in unions is intentionally used across public type-level APIs. - // Converting to `undefined` would be a semantic change with compatibility risk. - 'ts/no-invalid-void-type': 'off', - // Existing APIs intentionally rely on non-null assertions; replacing them safely - // needs deeper refactors and test expansion to avoid runtime regressions. - 'ts/no-non-null-assertion': 'off', + react: false, + ts: { + rules: { + 'jsdoc/check-tag-names': 'off', + 'jsdoc/require-example': [ + 'warn', + { + checkConstructors: false, + exemptedBy: [ + 'type', + ], + }, + ], + 'ts/naming-convention': 'off', + // `void` in unions is intentionally used across public type-level APIs. + // Converting to `undefined` would be a semantic change with compatibility risk. + 'ts/no-invalid-void-type': 'off', + // Existing APIs intentionally rely on non-null assertions; replacing them safely + // needs deeper refactors and test expansion to avoid runtime regressions. + 'ts/no-non-null-assertion': 'off', + }, }, }, -})), -{ // TODO: move this to eslint-config or find a solution rules: { 'e18e/prefer-array-at': 'off', @@ -58,5 +59,4 @@ export default [...(await defineConfig({ 'unicorn/prefer-unicode-code-point-escapes': 'off', 'unicorn/prefer-url-href': 'off', }, -}, -]; +}); diff --git a/packages/application/README.md b/packages/application/README.md index 1c89da352c..7cdb4fdd45 100644 --- a/packages/application/README.md +++ b/packages/application/README.md @@ -18,7 +18,7 @@ npm install @w5s/application ```ts -import { useStorage, useRef } from '@w5s/application'; +import { useRef, useStorage } from '@w5s/application'; export function main(): void { const globalStorage = useStorage(globalThis); diff --git a/packages/application/example/.eslintrc.cjs b/packages/application/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/application/example/.eslintrc.cjs +++ b/packages/application/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/application/src/ConfigurationRef.ts b/packages/application/src/ConfigurationRef.ts index 20198fc564..fc9fed93e8 100644 --- a/packages/application/src/ConfigurationRef.ts +++ b/packages/application/src/ConfigurationRef.ts @@ -1,11 +1,6 @@ import type { Ref } from '@w5s/core'; export interface ConfigurationRef extends Ref { - /** - * Initial configuration - */ - readonly initial: Configuration; - /** * Get a specific configuration value by key * @@ -14,11 +9,9 @@ export interface ConfigurationRef extends Ref { get(key: Key): Configuration[Key]; /** - * Update the configuration by merging the current configuration with the given patch - * - * @param patch the partial configuration to merge with the current configuration + * Initial configuration */ - update(patch: Partial): void; + readonly initial: Configuration; /** * Modify the configuration using a mapping function @@ -26,4 +19,11 @@ export interface ConfigurationRef extends Ref { * @param mapFn a function that takes the current configuration and returns a new configuration */ modify(mapFn: (current: Configuration) => Configuration): void; + + /** + * Update the configuration by merging the current configuration with the given patch + * + * @param patch the partial configuration to merge with the current configuration + */ + update(patch: Partial): void; } diff --git a/packages/application/src/index.spec.ts b/packages/application/src/index.spec.ts index 196219ec28..06c3781d43 100644 --- a/packages/application/src/index.spec.ts +++ b/packages/application/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { @@ -7,8 +8,8 @@ describe('index', () => { new Set([ // public exports 'meta', - 'useRef', 'useConfiguration', + 'useRef', 'useState', ]), ); diff --git a/packages/application/src/index.ts b/packages/application/src/index.ts index afbe9341c6..d6e1e8039f 100644 --- a/packages/application/src/index.ts +++ b/packages/application/src/index.ts @@ -1,7 +1,7 @@ -export * from './meta.js'; export * from './ConfigurationRef.js'; +export * from './meta.js'; export * from './State.js'; export * from './StateKey.js'; export * from './useConfiguration.js'; -export * from './useState.js'; export * from './useRef.js'; +export * from './useState.js'; diff --git a/packages/application/src/internal/registry.ts b/packages/application/src/internal/registry.ts index 14a3015183..c85364c7e2 100644 --- a/packages/application/src/internal/registry.ts +++ b/packages/application/src/internal/registry.ts @@ -1,6 +1,9 @@ -import { useGlobal } from '@w5s/global-storage'; -import { meta } from '../meta.js'; import type { Ref } from '@w5s/core'; + +import { useGlobal } from '@w5s/global-storage'; + import type { StateKey } from '../StateKey.js'; +import { meta } from '../meta.js'; + export const registry = useGlobal(meta.name + '/useRefRegistry', () => new WeakMap>>()); diff --git a/packages/application/src/useConfiguration.spec.ts b/packages/application/src/useConfiguration.spec.ts index bc59747407..1980020ce6 100644 --- a/packages/application/src/useConfiguration.spec.ts +++ b/packages/application/src/useConfiguration.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Ref } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { useConfiguration } from './useConfiguration.js'; describe(useConfiguration, () => { diff --git a/packages/application/src/useConfiguration.ts b/packages/application/src/useConfiguration.ts index 5019c37b70..56c690bff0 100644 --- a/packages/application/src/useConfiguration.ts +++ b/packages/application/src/useConfiguration.ts @@ -1,9 +1,11 @@ -import type { ConfigurationRef } from './ConfigurationRef.js'; -import { useRef } from './useRef.js'; -import { useNamespace } from './useNamespace.js'; import type { Ref } from '@w5s/core'; -import type { State } from './State.js'; + +import type { ConfigurationRef } from './ConfigurationRef.js'; import type { Meta } from './meta.js'; +import type { State } from './State.js'; + +import { useNamespace } from './useNamespace.js'; +import { useRef } from './useRef.js'; /** * @@ -39,9 +41,9 @@ export function useConfiguration( } return Object.assign(configuration, { - initial, get, - update, + initial, modify, + update, }); } diff --git a/packages/application/src/useNamespace.spec.ts b/packages/application/src/useNamespace.spec.ts index d8a189972f..33ee76cf39 100644 --- a/packages/application/src/useNamespace.spec.ts +++ b/packages/application/src/useNamespace.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Ref } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { useNamespace } from './useNamespace.js'; describe(useNamespace, () => { @@ -32,8 +33,8 @@ describe(useNamespace, () => { namespace.current = { configuration: { retries: 2 } }; expect(store.current).toEqual({ - other: { state: { value: 1 } }, app: { configuration: { retries: 2 } }, + other: { state: { value: 1 } }, }); }); }); diff --git a/packages/application/src/useNamespace.ts b/packages/application/src/useNamespace.ts index ee1bd3fc9d..293e39c058 100644 --- a/packages/application/src/useNamespace.ts +++ b/packages/application/src/useNamespace.ts @@ -1,8 +1,11 @@ -import { useRef } from './useRef.js'; -import { useStorage } from '@w5s/global-storage'; import type { Ref } from '@w5s/core'; -import type { State } from './State.js'; + +import { useStorage } from '@w5s/global-storage'; + import type { Meta } from './meta.js'; +import type { State } from './State.js'; + +import { useRef } from './useRef.js'; /** * Return a new `Ref` containing the namespace for the given `meta.name`. diff --git a/packages/application/src/useRef.spec.ts b/packages/application/src/useRef.spec.ts index c9cfb46564..4b2753a364 100644 --- a/packages/application/src/useRef.spec.ts +++ b/packages/application/src/useRef.spec.ts @@ -1,6 +1,7 @@ -import { describe, expect, it } from 'vitest'; import { Ref } from '@w5s/core'; import { useStorage } from '@w5s/global-storage'; +import { describe, expect, it } from 'vitest'; + import { useRef } from './useRef.js'; describe(useRef, () => { diff --git a/packages/application/src/useRef.ts b/packages/application/src/useRef.ts index 2b5213aae3..a1ffd7c2f6 100644 --- a/packages/application/src/useRef.ts +++ b/packages/application/src/useRef.ts @@ -1,41 +1,9 @@ import type { Ref } from '@w5s/core'; import type { Storage } from '@w5s/global-storage'; -import { registry } from './internal/registry.js'; -import type { StateKey } from './StateKey.js'; - -function useRefMap(ref: Ref>, propertyName: StateKey, initialValue: T): Ref { - const propertyRef: Ref = { - get current() { - return ref.current[propertyName] as T; - }, - set current(value) { - ref.current = { - ...ref.current, - [propertyName]: value, - }; - }, - }; - if (!Object.hasOwn(ref.current, propertyName)) { - propertyRef.current = initialValue; - } - return propertyRef; -} +import type { StateKey } from './StateKey.js'; -function useRefStorage(hostObject: Storage, key: StateKey, initialValue: V): Ref { - const ref: Ref = { - get current() { - return hostObject.get(key) as V; - }, - set current(value: V) { - hostObject.set(key, value); - }, - }; - if (!hostObject.has(key)) { - ref.current = initialValue; - } - return ref; -} +import { registry } from './internal/registry.js'; /** * Return a new `Ref` stored at `storage.get(key)` or `ref.value[key]` @@ -71,3 +39,37 @@ export function useRef( } return returnValue; } + +function useRefMap(ref: Ref>, propertyName: StateKey, initialValue: T): Ref { + const propertyRef: Ref = { + get current() { + return ref.current[propertyName] as T; + }, + set current(value) { + ref.current = { + ...ref.current, + [propertyName]: value, + }; + }, + }; + + if (!Object.hasOwn(ref.current, propertyName)) { + propertyRef.current = initialValue; + } + return propertyRef; +} + +function useRefStorage(hostObject: Storage, key: StateKey, initialValue: V): Ref { + const ref: Ref = { + get current() { + return hostObject.get(key) as V; + }, + set current(value: V) { + hostObject.set(key, value); + }, + }; + if (!hostObject.has(key)) { + ref.current = initialValue; + } + return ref; +} diff --git a/packages/application/src/useState.spec.ts b/packages/application/src/useState.spec.ts index ecbe64e6fd..89ac57a79b 100644 --- a/packages/application/src/useState.spec.ts +++ b/packages/application/src/useState.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Ref } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { useState } from './useState.js'; describe(useState, () => { diff --git a/packages/application/src/useState.ts b/packages/application/src/useState.ts index 9adf5a41b9..cb0f17f42a 100644 --- a/packages/application/src/useState.ts +++ b/packages/application/src/useState.ts @@ -1,9 +1,11 @@ import type { Ref } from '@w5s/core'; -import { useNamespace } from './useNamespace.js'; -import { useRef } from './useRef.js'; + +import type { Meta } from './meta.js'; import type { State } from './State.js'; import type { StateKey } from './StateKey.js'; -import type { Meta } from './meta.js'; + +import { useNamespace } from './useNamespace.js'; +import { useRef } from './useRef.js'; /** * Return a new `Ref` containing the state for the given `meta.name` and `key`. diff --git a/packages/async/example/.eslintrc.cjs b/packages/async/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/async/example/.eslintrc.cjs +++ b/packages/async/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/async/src/clearImmediate.ts b/packages/async/src/clearImmediate.ts index 0a28bdf93c..f5996957e1 100644 --- a/packages/async/src/clearImmediate.ts +++ b/packages/async/src/clearImmediate.ts @@ -1,4 +1,5 @@ import type { ImmediateId } from './ImmediateId.js'; + import { globalClearImmediate } from './internal/globalClearImmediate.js'; /** diff --git a/packages/async/src/defer.spec.ts b/packages/async/src/defer.spec.ts index 9e64c6e644..b178bd21f4 100644 --- a/packages/async/src/defer.spec.ts +++ b/packages/async/src/defer.spec.ts @@ -1,5 +1,6 @@ // packages/async/src/__tests__/defer.test.ts -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { defer } from './defer.js'; describe(defer, () => { diff --git a/packages/async/src/defer.ts b/packages/async/src/defer.ts index 1ec272518f..ad3ff02da8 100644 --- a/packages/async/src/defer.ts +++ b/packages/async/src/defer.ts @@ -11,7 +11,7 @@ import { promiseWithResolvers } from './internal/promiseWithResolver.js'; * return promise; * } * ``` - * @returns {PromiseWithResolvers} An object with the properties promise, resolve, and reject. + * @returns An object with the properties promise, resolve, and reject. */ export function defer(): PromiseWithResolvers { return promiseWithResolvers(); diff --git a/packages/async/src/delay.spec.ts b/packages/async/src/delay.spec.ts index 16d9573a7e..72d1b0da39 100644 --- a/packages/async/src/delay.spec.ts +++ b/packages/async/src/delay.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { AbortError } from '@w5s/error'; +import { describe, expect, it } from 'vitest'; + import { delay } from './delay.js'; describe(delay, () => { diff --git a/packages/async/src/delay.ts b/packages/async/src/delay.ts index bfac1225b7..9a79861ad9 100644 --- a/packages/async/src/delay.ts +++ b/packages/async/src/delay.ts @@ -1,6 +1,7 @@ -import { promiseFromTimer } from './internal/promiseFromTimer.js'; import type { TimerOptions } from './TimerOptions.js'; +import { promiseFromTimer } from './internal/promiseFromTimer.js'; + /** * Resolves a promise after waiting `milliseconds` * diff --git a/packages/async/src/index.spec.ts b/packages/async/src/index.spec.ts index c2da765917..dc7c867f90 100644 --- a/packages/async/src/index.spec.ts +++ b/packages/async/src/index.spec.ts @@ -1,15 +1,16 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { - expect(Object.keys(Module)).toMatchInlineSnapshot(` + expect(Object.keys(Module).toSorted((left, right) => left.localeCompare(right))).toMatchInlineSnapshot(` [ "clearImmediate", "defer", "delay", - "isPromiseLike", "isPromise", + "isPromiseLike", "setImmediate", "tryCall", ] diff --git a/packages/async/src/index.ts b/packages/async/src/index.ts index f7895c6b51..1024c38b2f 100644 --- a/packages/async/src/index.ts +++ b/packages/async/src/index.ts @@ -3,8 +3,8 @@ export * from './clearImmediate.js'; export * from './defer.js'; export * from './delay.js'; export * from './ImmediateId.js'; -export * from './isPromiseLike.js'; export * from './isPromise.js'; +export * from './isPromiseLike.js'; export * from './setImmediate.js'; -export * from './tryCall.js'; export type * from './TimerOptions.js'; +export * from './tryCall.js'; diff --git a/packages/async/src/internal/promiseFromTimer.ts b/packages/async/src/internal/promiseFromTimer.ts index ee2edf1036..027ecb3763 100644 --- a/packages/async/src/internal/promiseFromTimer.ts +++ b/packages/async/src/internal/promiseFromTimer.ts @@ -1,5 +1,6 @@ import { AbortError } from '@w5s/error/dist/AbortError.js'; import { isDOMException } from '@w5s/error/dist/isDOMException.js'; + import type { TimerOptions } from '../TimerOptions.js'; const toAbortError = (reason: any): AbortError => { @@ -19,7 +20,7 @@ export function promiseFromTimer( /** * Resolver */ - resolve: (value: void | PromiseLike) => void, + resolve: (value: PromiseLike | void) => void, /** * Rejecter diff --git a/packages/async/src/isPromise.spec.ts b/packages/async/src/isPromise.spec.ts index c6336ce53b..445761423f 100644 --- a/packages/async/src/isPromise.spec.ts +++ b/packages/async/src/isPromise.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { isPromise } from './isPromise.js'; describe(isPromise, () => { diff --git a/packages/async/src/isPromiseLike.spec.ts b/packages/async/src/isPromiseLike.spec.ts index 2dd31ba329..17421c350a 100644 --- a/packages/async/src/isPromiseLike.spec.ts +++ b/packages/async/src/isPromiseLike.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { isPromiseLike } from './isPromiseLike.js'; describe('isPromiseLike()', () => { diff --git a/packages/async/src/setImmediate.ts b/packages/async/src/setImmediate.ts index 56ebe5f8a7..4a6c0d52d2 100644 --- a/packages/async/src/setImmediate.ts +++ b/packages/async/src/setImmediate.ts @@ -1,4 +1,5 @@ import type { ImmediateId } from './ImmediateId.js'; + import { globalSetImmediate } from './internal/globalSetImmediate.js'; /** diff --git a/packages/async/src/tryCall.spec.ts b/packages/async/src/tryCall.spec.ts index 0a0282649d..4bbc9bbccc 100644 --- a/packages/async/src/tryCall.spec.ts +++ b/packages/async/src/tryCall.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { tryCall } from './tryCall.js'; describe('tryCall', () => { diff --git a/packages/async/src/tryCall.ts b/packages/async/src/tryCall.ts index b22f39a2a5..a63929cb5f 100644 --- a/packages/async/src/tryCall.ts +++ b/packages/async/src/tryCall.ts @@ -1,4 +1,5 @@ import type { Awaitable } from './Awaitable.js'; + import { isPromiseLike } from './isPromiseLike.js'; /** diff --git a/packages/bigdecimal/example/.eslintrc.cjs b/packages/bigdecimal/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/bigdecimal/example/.eslintrc.cjs +++ b/packages/bigdecimal/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/bigdecimal/src/BigDecimal.spec.ts b/packages/bigdecimal/src/BigDecimal.spec.ts index 0be76e74aa..26fa80c9e4 100644 --- a/packages/bigdecimal/src/BigDecimal.spec.ts +++ b/packages/bigdecimal/src/BigDecimal.spec.ts @@ -1,18 +1,19 @@ import { describe, expect, it } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; -import { parse } from './BigDecimal/parse.js'; -import { format } from './BigDecimal/format.js'; -import { of } from './BigDecimal/of.js'; -import { scale } from './BigDecimal/scale.js'; -import { normalize } from './BigDecimal/normalize.js'; -import { BigDecimalComparable } from './BigDecimal/BigDecimalComparable.js'; -import { BigDecimalSigned } from './BigDecimal/BigDecimalSigned.js'; -import { BigDecimalNumeric } from './BigDecimal/BigDecimalNumeric.js'; import { BigDecimalAsString } from './BigDecimal/BigDecimalAsString.js'; +import { BigDecimalComparable } from './BigDecimal/BigDecimalComparable.js'; import { BigDecimalNegate } from './BigDecimal/BigDecimalNegate.js'; +import { BigDecimalNumeric } from './BigDecimal/BigDecimalNumeric.js'; +import { BigDecimalSigned } from './BigDecimal/BigDecimalSigned.js'; import { BigDecimalZero } from './BigDecimal/BigDecimalZero.js'; +import { format } from './BigDecimal/format.js'; import { fromBigInt } from './BigDecimal/fromBigInt.js'; import { fromInt } from './BigDecimal/fromInt.js'; +import { normalize } from './BigDecimal/normalize.js'; +import { of } from './BigDecimal/of.js'; +import { parse } from './BigDecimal/parse.js'; +import { scale } from './BigDecimal/scale.js'; import { truncate } from './BigDecimal/truncate.js'; describe('BigDecimal', () => { @@ -27,12 +28,12 @@ describe('BigDecimal', () => { expect.objectContaining({ compare: expect.any(Function), format, + fromBigInt, + fromInt, normalize, of, parse, scale, - fromBigInt, - fromInt, truncate, }), ); diff --git a/packages/bigdecimal/src/BigDecimal.ts b/packages/bigdecimal/src/BigDecimal.ts index 4f5281da3d..d0c61fba13 100644 --- a/packages/bigdecimal/src/BigDecimal.ts +++ b/packages/bigdecimal/src/BigDecimal.ts @@ -1,27 +1,28 @@ import { Callable } from '@w5s/core/dist/Callable.js'; -import { format } from './BigDecimal/format.js'; -import { parse } from './BigDecimal/parse.js'; -import { BigDecimalComparable } from './BigDecimal/BigDecimalComparable.js'; -import { of } from './BigDecimal/of.js'; + +import { BigDecimal as BigDecimalType } from './BigDecimal/BigDecimal.js'; import { BigDecimalAsString } from './BigDecimal/BigDecimalAsString.js'; -import { scale } from './BigDecimal/scale.js'; -import { normalize } from './BigDecimal/normalize.js'; +import { BigDecimalComparable } from './BigDecimal/BigDecimalComparable.js'; +import { BigDecimalNegate } from './BigDecimal/BigDecimalNegate.js'; import { BigDecimalNumeric } from './BigDecimal/BigDecimalNumeric.js'; -import { BigDecimal as BigDecimalType } from './BigDecimal/BigDecimal.js'; import { BigDecimalSigned } from './BigDecimal/BigDecimalSigned.js'; -import { BigDecimalNegate } from './BigDecimal/BigDecimalNegate.js'; import { BigDecimalZero } from './BigDecimal/BigDecimalZero.js'; +import { format } from './BigDecimal/format.js'; import { fromBigInt } from './BigDecimal/fromBigInt.js'; import { fromInt } from './BigDecimal/fromInt.js'; +import { normalize } from './BigDecimal/normalize.js'; +import { of } from './BigDecimal/of.js'; +import { parse } from './BigDecimal/parse.js'; +import { scale } from './BigDecimal/scale.js'; import { truncate } from './BigDecimal/truncate.js'; +export type BigDecimal = BigDecimalType; + /** * Valid BigDecimal string representation */ export type BigDecimalString = `${number}`; -export type BigDecimal = BigDecimalType; - /** * A collection of functions to manipulate `BigDecimal` * @@ -35,12 +36,12 @@ export const BigDecimal = Callable({ ...BigDecimalSigned, ...BigDecimalZero, ...BigDecimalAsString, - normalize, - of, - scale, - parse, format, fromBigInt, fromInt, + normalize, + of, + parse, + scale, truncate, }); diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimal.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimal.spec.ts index 50a51b4bde..eff0df5994 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimal.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimal.spec.ts @@ -1,37 +1,38 @@ -import { describe, expect, it } from 'vitest'; -import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { CodecError, Result } from '@w5s/core'; +import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; describe('()', () => { it('constructs from parameters', () => { expect(BigDecimal(1n, 100)).toMatchObject({ _: 'BigDecimal', - value: 1n, scale: 100, + value: 1n, }); }); describeType(BigDecimal, () => ({ - typeName: 'BigDecimal', - instances: [BigDecimal.create({ value: 0n, scale: 0 }), BigDecimal.create({ value: -2n, scale: 0 })], - notInstances: [null, undefined, '-2', 2], inspect: [ - [BigDecimal.create({ value: 0n, scale: 0 }), '0m'], - [BigDecimal.create({ value: 11n, scale: 1 }), '1.1m'], + [BigDecimal.create({ scale: 0, value: 0n }), '0m'], + [BigDecimal.create({ scale: 1, value: 11n }), '1.1m'], ], + instances: [BigDecimal.create({ scale: 0, value: 0n }), BigDecimal.create({ scale: 0, value: -2n })], + notInstances: [null, undefined, '-2', 2], + typeName: 'BigDecimal', })); describeCodec(BigDecimal, () => ({ - encode: [ - [BigDecimal.create({ value: 0n, scale: 0 }), '0m'], - [BigDecimal.create({ value: 11n, scale: 1 }), '1.1m'], - ], decode: [ - ['1.0m', Result.Ok(BigDecimal.create({ value: 10n, scale: 1 }))], - ['-2.1m', Result.Ok(BigDecimal.create({ value: -21n, scale: 1 }))], - ['2.1', Result.Error(new CodecError({ message: 'Cannot decode "2.1" as BigDecimal', input: '2.1' }))], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as BigDecimal', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as BigDecimal', input: null }))], + ['1.0m', Result.Ok(BigDecimal.create({ scale: 1, value: 10n }))], + ['-2.1m', Result.Ok(BigDecimal.create({ scale: 1, value: -21n }))], + ['2.1', Result.Error(new CodecError({ input: '2.1', message: 'Cannot decode "2.1" as BigDecimal' }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as BigDecimal' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as BigDecimal' }))], + ], + encode: [ + [BigDecimal.create({ scale: 0, value: 0n }), '0m'], + [BigDecimal.create({ scale: 1, value: 11n }), '1.1m'], ], - schema: { type: 'string', format: 'bigdecimal' }, + schema: { format: 'bigdecimal', type: 'string' }, })); }); diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimal.ts b/packages/bigdecimal/src/BigDecimal/BigDecimal.ts index 07c9238fc2..08d7185c77 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimal.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimal.ts @@ -1,15 +1,14 @@ import { Callable } from '@w5s/core/dist/Callable.js'; import { Struct } from '@w5s/core/dist/Struct.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; -import { parse } from './parse.js'; + import { BigDecimalAsString } from './BigDecimalAsString.js'; import { call } from './call.js'; +import { parse } from './parse.js'; const bigDecimalEncode = (self: BigDecimal) => `${BigDecimalAsString.asString(self)}m`; const BigDecimalStruct = Struct.define({ - typeName: 'BigDecimal', - [Symbol.encode]: bigDecimalEncode, - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string' && input.endsWith('m')) { const parsed = parse(input.slice(0, -1)); if (parsed != null) { @@ -18,11 +17,13 @@ const BigDecimalStruct = Struct.define({ } return error(input, 'BigDecimal'); }, + [Symbol.encode]: bigDecimalEncode, + [Symbol.inspect]: bigDecimalEncode, [Symbol.schema]: () => ({ - type: 'string', format: 'bigdecimal', + type: 'string', }), - [Symbol.inspect]: bigDecimalEncode, + typeName: 'BigDecimal', ...BigDecimalAsString, }); @@ -33,14 +34,14 @@ export interface BigDecimal extends Struct<{ _: 'BigDecimal'; /** - * The base denominator + * The decimal scale N = value / (2 ** scale) */ - value: bigint; + scale: number; /** - * The decimal scale N = value / (2 ** scale) + * The base denominator */ - scale: number; + value: bigint; }> {} export const BigDecimal = Callable({ diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.spec.ts index f486d21ef0..c126326003 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.spec.ts @@ -1,7 +1,8 @@ -import { describe } from 'vitest'; import { describeAsString } from '@w5s/core/dist/Testing.js'; -import { BigDecimalAsString } from './BigDecimalAsString.js'; +import { describe } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalAsString } from './BigDecimalAsString.js'; describe('BigDecimalAsString', () => { describeAsString(BigDecimalAsString, () => [ diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.ts index b2d710a5b7..c76e140786 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalAsString.ts @@ -1,4 +1,5 @@ import type { AsString } from '@w5s/core'; + import type { BigDecimal } from './BigDecimal.js'; export const BigDecimalAsString: AsString = { @@ -12,7 +13,7 @@ export const BigDecimalAsString: AsString = { * @param self */ asString(self: BigDecimal): string { - const { value, scale } = self; + const { scale, value } = self; const valueString = String(value); const negative = value < 0n; const absolute = negative ? valueString.slice(1) : valueString; diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.spec.ts index 2357696d6f..948b065746 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.spec.ts @@ -1,8 +1,15 @@ import { describeComparable } from '@w5s/core/dist/Testing.js'; -import { BigDecimalComparable } from './BigDecimalComparable.js'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalComparable } from './BigDecimalComparable.js'; describeComparable(BigDecimalComparable, { + equivalent: () => [ + [BigDecimal('0'), BigDecimal('0')], + [BigDecimal('1.0'), BigDecimal('1')], + [BigDecimal('0.1'), BigDecimal('0.1')], + [BigDecimal('-0.1'), BigDecimal('-0.1')], + ], ordered: () => [ BigDecimal('-10.0'), BigDecimal('-0.11'), @@ -12,10 +19,4 @@ describeComparable(BigDecimalComparable, { BigDecimal('0.11'), BigDecimal('10.0'), ], - equivalent: () => [ - [BigDecimal('0'), BigDecimal('0')], - [BigDecimal('1.0'), BigDecimal('1')], - [BigDecimal('0.1'), BigDecimal('0.1')], - [BigDecimal('-0.1'), BigDecimal('-0.1')], - ], }); diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.ts index 4818f830b8..f29acf11f4 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalComparable.ts @@ -1,5 +1,7 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import type { BigDecimal } from './BigDecimal.js'; + import { compare } from './compare.js'; export const BigDecimalComparable: Comparable = Comparable({ diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.spec.ts index 6d3ad7dc18..eaaa593c44 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.spec.ts @@ -1,8 +1,9 @@ -import { describe } from 'vitest'; import { describeNegate } from '@w5s/core/dist/Testing.js'; -import { BigDecimalNegate } from './BigDecimalNegate.js'; -import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { describe } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { BigDecimalNegate } from './BigDecimalNegate.js'; describe('BigDecimalNegate', () => { describeNegate( diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.ts index 9157fbad49..1878890cee 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalNegate.ts @@ -1,6 +1,7 @@ import type { Numeric } from '@w5s/core'; + import { BigDecimal } from './BigDecimal.js'; export const BigDecimalNegate: Numeric.Negate = { - negate: ({ value, scale }) => BigDecimal.create({ value: -value, scale }), + negate: ({ scale, value }) => BigDecimal.create({ scale, value: -value }), }; diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.spec.ts index f3e3f05c85..7cae9c83dd 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.spec.ts @@ -1,9 +1,10 @@ -import { describe } from 'vitest'; -import { describeAdd, describeCheckedRemainder, describeMultiply, describeSubtract } from '@w5s/core/dist/Testing.js'; import { Option } from '@w5s/core'; -import { BigDecimalNumeric } from './BigDecimalNumeric.js'; -import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { describeAdd, describeCheckedRemainder, describeMultiply, describeSubtract } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { BigDecimalNumeric } from './BigDecimalNumeric.js'; describe('BigDecimalNumeric', () => { const subject = { diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.ts index 498a26d494..f3601d4bfb 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalNumeric.ts @@ -1,7 +1,16 @@ import type { Numeric } from '@w5s/core'; + import type { BigDecimal } from './BigDecimal.js'; -import { of } from './of.js'; + import { bigDecimalScaleValue } from '../internal/bigDecimalScaleValue.js'; +import { of } from './of.js'; + +interface BigDecimalNumeric + extends + Numeric.Add, + Numeric.CheckedRemainder, + Numeric.Multiply, + Numeric.Subtract {} function combine2(combineFn: (left: bigint, right: bigint) => bigint) { return (left: BigDecimal, right: BigDecimal) => @@ -12,17 +21,7 @@ function combine2(combineFn: (left: bigint, right: bigint) => bigint) { : of(combineFn(left.value, right.value), left.scale); } -interface BigDecimalNumeric - extends - Numeric.Add, - Numeric.Subtract, - Numeric.Multiply, - Numeric.CheckedRemainder {} - export const BigDecimalNumeric: BigDecimalNumeric = { - '+': combine2((l, r) => l + r), - '-': combine2((l, r) => l - r), - '*': (l, r) => of(l.value * r.value, l.scale + r.scale), '%?': (self, divisor) => { if (divisor.value === 0n) { return undefined; @@ -30,4 +29,7 @@ export const BigDecimalNumeric: BigDecimalNumeric = { const max = Math.max(self.scale, divisor.scale); return of(bigDecimalScaleValue(self, max) % bigDecimalScaleValue(divisor, max), max); }, + '*': (l, r) => of(l.value * r.value, l.scale + r.scale), + '+': combine2((l, r) => l + r), + '-': combine2((l, r) => l - r), }; diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.spec.ts index 0d94d5a90a..89c973079a 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.spec.ts @@ -1,8 +1,9 @@ -import { describe } from 'vitest'; import { describeSigned } from '@w5s/core/dist/Testing.js'; -import { BigDecimalSigned } from './BigDecimalSigned.js'; -import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { describe } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalComparable } from './BigDecimalComparable.js'; +import { BigDecimalSigned } from './BigDecimalSigned.js'; describe('BigDecimalSigned', () => { describeSigned( @@ -12,11 +13,11 @@ describe('BigDecimalSigned', () => { }, { values: () => [ - { value: BigDecimal('-1'), type: 'negative', sign: BigDecimal('-1'), abs: BigDecimal('1') }, - { value: BigDecimal('-0.5'), type: 'negative', sign: BigDecimal('-1'), abs: BigDecimal('0.5') }, - { value: BigDecimal('0'), type: 'zero', sign: BigDecimal('0'), abs: BigDecimal('0') }, - { value: BigDecimal('0.5'), type: 'positive', sign: BigDecimal('1'), abs: BigDecimal('0.5') }, - { value: BigDecimal('1'), type: 'positive', sign: BigDecimal('1'), abs: BigDecimal('1') }, + { abs: BigDecimal('1'), sign: BigDecimal('-1'), type: 'negative', value: BigDecimal('-1') }, + { abs: BigDecimal('0.5'), sign: BigDecimal('-1'), type: 'negative', value: BigDecimal('-0.5') }, + { abs: BigDecimal('0'), sign: BigDecimal('0'), type: 'zero', value: BigDecimal('0') }, + { abs: BigDecimal('0.5'), sign: BigDecimal('1'), type: 'positive', value: BigDecimal('0.5') }, + { abs: BigDecimal('1'), sign: BigDecimal('1'), type: 'positive', value: BigDecimal('1') }, ], }, ); diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.ts index ed3b2270a0..25795d437a 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalSigned.ts @@ -1,13 +1,16 @@ import type { Numeric } from '@w5s/core'; + import { BigIntIntegral } from '@w5s/num/dist/BigInt/BigIntIntegral.js'; + import type { BigDecimal } from './BigDecimal.js'; + import { of } from './of.js'; -const { abs: bigIntAbs, sign: bigIntSign, isNegative: bigIntIsNegative, isPositive: bigIntIsPositive } = BigIntIntegral; +const { abs: bigIntAbs, isNegative: bigIntIsNegative, isPositive: bigIntIsPositive, sign: bigIntSign } = BigIntIntegral; export const BigDecimalSigned: Numeric.Signed = { abs: (self) => of(bigIntAbs(self.value), self.scale), - sign: (self) => of(bigIntSign(self.value), 0), isNegative: (self) => bigIntIsNegative(self.value), isPositive: (self) => bigIntIsPositive(self.value), + sign: (self) => of(bigIntSign(self.value), 0), }; diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalZero.spec.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalZero.spec.ts index e1e40bb2d4..2f703d3d45 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalZero.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalZero.spec.ts @@ -1,7 +1,8 @@ -import { describe } from 'vitest'; import { describeZero } from '@w5s/core/dist/Testing.js'; -import { BigDecimalZero } from './BigDecimalZero.js'; +import { describe } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { BigDecimalZero } from './BigDecimalZero.js'; describe('BigDecimalZero', () => { describeZero(BigDecimalZero, { diff --git a/packages/bigdecimal/src/BigDecimal/BigDecimalZero.ts b/packages/bigdecimal/src/BigDecimal/BigDecimalZero.ts index 65d0b3d72b..86cdfddaa4 100644 --- a/packages/bigdecimal/src/BigDecimal/BigDecimalZero.ts +++ b/packages/bigdecimal/src/BigDecimal/BigDecimalZero.ts @@ -1,8 +1,10 @@ import type { Numeric } from '@w5s/core'; + import { lazy } from '@w5s/core/dist/lazy.js'; + import { BigDecimal } from './BigDecimal.js'; export const BigDecimalZero: Numeric.Zero = { - zero: lazy(() => BigDecimal('0')), isZero: (self) => self.value === 0n, + zero: lazy(() => BigDecimal('0')), }; diff --git a/packages/bigdecimal/src/BigDecimal/call.spec.ts b/packages/bigdecimal/src/BigDecimal/call.spec.ts index b9ad6fbe51..4e5c3b52a7 100644 --- a/packages/bigdecimal/src/BigDecimal/call.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/call.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { call } from './call.js'; describe(call, () => { diff --git a/packages/bigdecimal/src/BigDecimal/call.ts b/packages/bigdecimal/src/BigDecimal/call.ts index bf1aae7352..9c285e8fc1 100644 --- a/packages/bigdecimal/src/BigDecimal/call.ts +++ b/packages/bigdecimal/src/BigDecimal/call.ts @@ -1,12 +1,14 @@ import { panic } from '@w5s/error/dist/panic.js'; -import { of } from './of.js'; -import { parse } from './parse.js'; + import type { BigDecimalString } from '../BigDecimal.js'; import type { BigDecimal } from './BigDecimal.js'; +import { of } from './of.js'; +import { parse } from './parse.js'; + export function call(stringValue: BigDecimalString): BigDecimal; export function call(value: bigint, scale?: number): BigDecimal; -export function call(value: string | bigint, scale?: number): BigDecimal { +export function call(value: bigint | string, scale?: number): BigDecimal { return typeof value === 'string' ? (parse(value) ?? panic(new TypeError(`${String(value)} is not a valid BigDecimal`))) : of(value, scale ?? 0); diff --git a/packages/bigdecimal/src/BigDecimal/compare.ts b/packages/bigdecimal/src/BigDecimal/compare.ts index 5458a485a1..19472827f4 100644 --- a/packages/bigdecimal/src/BigDecimal/compare.ts +++ b/packages/bigdecimal/src/BigDecimal/compare.ts @@ -1,6 +1,9 @@ -import { compare as bigIntCompare } from '@w5s/num/dist/BigInt/compare.js'; import type { Ordering } from '@w5s/core'; + +import { compare as bigIntCompare } from '@w5s/num/dist/BigInt/compare.js'; + import type { BigDecimal } from './BigDecimal.js'; + import { bigDecimalScaleValue } from '../internal/bigDecimalScaleValue.js'; export function compare(left: BigDecimal, right: BigDecimal): Ordering { diff --git a/packages/bigdecimal/src/BigDecimal/format.spec.ts b/packages/bigdecimal/src/BigDecimal/format.spec.ts index 878466f5ef..3ce94f2ee9 100644 --- a/packages/bigdecimal/src/BigDecimal/format.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/format.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { format } from './format.js'; + import { BigDecimal } from './BigDecimal.js'; +import { format } from './format.js'; describe(format, () => { it.each([ diff --git a/packages/bigdecimal/src/BigDecimal/format.ts b/packages/bigdecimal/src/BigDecimal/format.ts index 6df19fe66f..9ab9ff8b59 100644 --- a/packages/bigdecimal/src/BigDecimal/format.ts +++ b/packages/bigdecimal/src/BigDecimal/format.ts @@ -1,6 +1,7 @@ -import { BigDecimalAsString } from './BigDecimalAsString.js'; import type { BigDecimal } from './BigDecimal.js'; +import { BigDecimalAsString } from './BigDecimalAsString.js'; + /** * Returns a string representation of a BigDecimal * diff --git a/packages/bigdecimal/src/BigDecimal/fromBigInt.spec.ts b/packages/bigdecimal/src/BigDecimal/fromBigInt.spec.ts index d8711d4147..884032ccfb 100644 --- a/packages/bigdecimal/src/BigDecimal/fromBigInt.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/fromBigInt.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; import { fromBigInt } from './fromBigInt.js'; diff --git a/packages/bigdecimal/src/BigDecimal/fromBigInt.ts b/packages/bigdecimal/src/BigDecimal/fromBigInt.ts index cce8363397..6153bc9a77 100644 --- a/packages/bigdecimal/src/BigDecimal/fromBigInt.ts +++ b/packages/bigdecimal/src/BigDecimal/fromBigInt.ts @@ -1,4 +1,5 @@ import type { BigDecimal } from './BigDecimal.js'; + import { of } from './of.js'; /** diff --git a/packages/bigdecimal/src/BigDecimal/fromInt.spec.ts b/packages/bigdecimal/src/BigDecimal/fromInt.spec.ts index a63a0f2e9e..3bfc50415d 100644 --- a/packages/bigdecimal/src/BigDecimal/fromInt.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/fromInt.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; import { Int } from '@w5s/num'; -import { fromInt } from './fromInt.js'; +import { describe, expect, it } from 'vitest'; + import { BigDecimal } from './BigDecimal.js'; +import { fromInt } from './fromInt.js'; describe(fromInt, () => { it.each([ diff --git a/packages/bigdecimal/src/BigDecimal/fromInt.ts b/packages/bigdecimal/src/BigDecimal/fromInt.ts index e42e317757..47bf7b13a8 100644 --- a/packages/bigdecimal/src/BigDecimal/fromInt.ts +++ b/packages/bigdecimal/src/BigDecimal/fromInt.ts @@ -1,7 +1,9 @@ import type { Int } from '@w5s/num'; -import { of } from './of.js'; + import type { BigDecimal } from './BigDecimal.js'; +import { of } from './of.js'; + /** * Converts an integer to a big decimal. * diff --git a/packages/bigdecimal/src/BigDecimal/normalize.spec.ts b/packages/bigdecimal/src/BigDecimal/normalize.spec.ts index 667538159d..54c1fecb49 100644 --- a/packages/bigdecimal/src/BigDecimal/normalize.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/normalize.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { normalize } from './normalize.js'; + import { BigDecimal } from './BigDecimal.js'; +import { normalize } from './normalize.js'; describe(normalize, () => { it('returns a normalized value (i.e. with no trailing 0 scale)', () => { @@ -10,8 +11,8 @@ describe(normalize, () => { expect(normalize(BigDecimal('-0.000123000'))).toEqual(BigDecimal(-123n, 6)); expect(normalize(BigDecimal('-123.000'))).toEqual(BigDecimal(-123n, 0)); expect(normalize(BigDecimal('12300000'))).toEqual(BigDecimal(123n, -5)); - expect(normalize(BigDecimal.create({ value: 123n, scale: -1 }))).toEqual( - BigDecimal.create({ value: 1230n, scale: 0 }), + expect(normalize(BigDecimal.create({ scale: -1, value: 123n }))).toEqual( + BigDecimal.create({ scale: 0, value: 1230n }), ); }); }); diff --git a/packages/bigdecimal/src/BigDecimal/normalize.ts b/packages/bigdecimal/src/BigDecimal/normalize.ts index 442d59e17c..e0cd3857d0 100644 --- a/packages/bigdecimal/src/BigDecimal/normalize.ts +++ b/packages/bigdecimal/src/BigDecimal/normalize.ts @@ -1,4 +1,5 @@ import type { BigDecimal } from './BigDecimal.js'; + import { scale } from './scale.js'; /** diff --git a/packages/bigdecimal/src/BigDecimal/of.spec.ts b/packages/bigdecimal/src/BigDecimal/of.spec.ts index c60eb2dcc8..5cefcfd0ca 100644 --- a/packages/bigdecimal/src/BigDecimal/of.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/of.spec.ts @@ -1,19 +1,20 @@ import { describe, expect, it } from 'vitest'; -import { of } from './of.js'; + import { BigDecimal } from './BigDecimal.js'; +import { of } from './of.js'; describe(of, () => { it('constructs from parameters', () => { expect(of(1n, 100)).toEqual( BigDecimal.create({ - value: 1n, scale: 100, + value: 1n, }), ); expect(of(1n, -1)).toEqual( BigDecimal.create({ - value: 10n, scale: 0, + value: 10n, }), ); }); diff --git a/packages/bigdecimal/src/BigDecimal/of.ts b/packages/bigdecimal/src/BigDecimal/of.ts index e0cfe2e890..0c0fdd3b2a 100644 --- a/packages/bigdecimal/src/BigDecimal/of.ts +++ b/packages/bigdecimal/src/BigDecimal/of.ts @@ -15,11 +15,11 @@ import { BigDecimal } from './BigDecimal.js'; export function of(value: bigint, scale: number): BigDecimal { return scale < 0 ? BigDecimal.create({ - value: value * 10n ** BigInt(-scale), scale: 0, + value: value * 10n ** BigInt(-scale), }) : BigDecimal.create({ - value, scale, + value, }); } diff --git a/packages/bigdecimal/src/BigDecimal/parse.spec.ts b/packages/bigdecimal/src/BigDecimal/parse.spec.ts index 4d75abdc48..b3dfcc56cb 100644 --- a/packages/bigdecimal/src/BigDecimal/parse.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/parse.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { parse } from './parse.js'; + import { BigDecimal } from './BigDecimal.js'; +import { parse } from './parse.js'; describe(parse, () => { it.each([ diff --git a/packages/bigdecimal/src/BigDecimal/parse.ts b/packages/bigdecimal/src/BigDecimal/parse.ts index 9d1d54b48d..a7805b51de 100644 --- a/packages/bigdecimal/src/BigDecimal/parse.ts +++ b/packages/bigdecimal/src/BigDecimal/parse.ts @@ -1,5 +1,7 @@ import type { Option } from '@w5s/core'; + import type { BigDecimal } from './BigDecimal.js'; + import { of } from './of.js'; const dotRegex = /\./; diff --git a/packages/bigdecimal/src/BigDecimal/scale.spec.ts b/packages/bigdecimal/src/BigDecimal/scale.spec.ts index 31f5c5c58f..03288d1e4c 100644 --- a/packages/bigdecimal/src/BigDecimal/scale.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/scale.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { scale } from './scale.js'; + import { BigDecimal } from './BigDecimal.js'; +import { scale } from './scale.js'; describe(scale, () => { it('returns identity if scale is the same', () => { diff --git a/packages/bigdecimal/src/BigDecimal/scale.ts b/packages/bigdecimal/src/BigDecimal/scale.ts index 6028e57902..1ef06cba54 100644 --- a/packages/bigdecimal/src/BigDecimal/scale.ts +++ b/packages/bigdecimal/src/BigDecimal/scale.ts @@ -1,4 +1,5 @@ import type { BigDecimal } from './BigDecimal.js'; + import { bigDecimalScaleValue } from '../internal/bigDecimalScaleValue.js'; import { of } from './of.js'; diff --git a/packages/bigdecimal/src/BigDecimal/truncate.spec.ts b/packages/bigdecimal/src/BigDecimal/truncate.spec.ts index 604691bfff..eafd6e140c 100644 --- a/packages/bigdecimal/src/BigDecimal/truncate.spec.ts +++ b/packages/bigdecimal/src/BigDecimal/truncate.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { truncate } from './truncate.js'; + import { BigDecimal } from './BigDecimal.js'; +import { truncate } from './truncate.js'; describe(truncate, () => { it.each([ diff --git a/packages/bigdecimal/src/BigDecimal/truncate.ts b/packages/bigdecimal/src/BigDecimal/truncate.ts index f4348d90a1..b675d0bf7e 100644 --- a/packages/bigdecimal/src/BigDecimal/truncate.ts +++ b/packages/bigdecimal/src/BigDecimal/truncate.ts @@ -1,4 +1,5 @@ import type { BigDecimal } from './BigDecimal.js'; + import { of } from './of.js'; /** diff --git a/packages/bigdecimal/src/index.spec.ts b/packages/bigdecimal/src/index.spec.ts index c5680476b4..23d97e1c2a 100644 --- a/packages/bigdecimal/src/index.spec.ts +++ b/packages/bigdecimal/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/bigdecimal/src/internal/bigDecimalScaleValue.ts b/packages/bigdecimal/src/internal/bigDecimalScaleValue.ts index 008711e48f..0ccc8fd588 100644 --- a/packages/bigdecimal/src/internal/bigDecimalScaleValue.ts +++ b/packages/bigdecimal/src/internal/bigDecimalScaleValue.ts @@ -4,11 +4,11 @@ import type { BigDecimal } from '../BigDecimal/BigDecimal.js'; * @internal * @param self the BigDecimal to scale * @param newScale the new scale to apply - * @returns {bigint} the scaled BigDecimal value + * @returns the scaled BigDecimal value * @example */ export function bigDecimalScaleValue(self: BigDecimal, newScale: number): bigint { - const { value, scale } = self; + const { scale, value } = self; if (newScale > scale) { return value * 10n ** BigInt(newScale - scale); } diff --git a/packages/byte-size/example/.eslintrc.cjs b/packages/byte-size/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/byte-size/example/.eslintrc.cjs +++ b/packages/byte-size/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/byte-size/src/ByteSize.spec.ts b/packages/byte-size/src/ByteSize.spec.ts index 56f59ea710..b981e87332 100644 --- a/packages/byte-size/src/ByteSize.spec.ts +++ b/packages/byte-size/src/ByteSize.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { ByteSize } from './ByteSize.js'; import { format } from './ByteSize/format.js'; import { parse } from './ByteSize/parse.js'; @@ -7,8 +8,8 @@ describe(ByteSize, () => { it('contains alias to functions', () => { expect(ByteSize).toEqual( expect.objectContaining({ - parse, format, + parse, }), ); }); diff --git a/packages/byte-size/src/ByteSize.ts b/packages/byte-size/src/ByteSize.ts index 497f71d996..41e1a0431c 100644 --- a/packages/byte-size/src/ByteSize.ts +++ b/packages/byte-size/src/ByteSize.ts @@ -1,6 +1,8 @@ +import type { Integral } from '@w5s/core/dist/Numeric/Integral.js'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { IntIntegral } from '@w5s/num/dist/Int/IntIntegral.js'; -import type { Integral } from '@w5s/core/dist/Numeric/Integral.js'; + import { ByteSize as ByteSizeType } from './ByteSize/ByteSize.js'; import { format } from './ByteSize/format.js'; import { parse } from './ByteSize/parse.js'; diff --git a/packages/byte-size/src/ByteSize/ByteSize.spec.ts b/packages/byte-size/src/ByteSize/ByteSize.spec.ts index 4332c999aa..abca6fb761 100644 --- a/packages/byte-size/src/ByteSize/ByteSize.spec.ts +++ b/packages/byte-size/src/ByteSize/ByteSize.spec.ts @@ -1,21 +1,16 @@ -import { describe } from 'vitest'; -import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { CodecError, Result } from '@w5s/core'; +import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { ByteSize } from './ByteSize.js'; describe(ByteSize, () => { describeType(ByteSize, () => ({ - typeName: 'ByteSize', instances: [ByteSize(1), ByteSize(0), ByteSize(1024)], notInstances: [null, undefined, [], NaN], + typeName: 'ByteSize', })); describeCodec(ByteSize, () => ({ - encode: [ - [ByteSize(1), '1 B'], - [ByteSize(0), '0 B'], - [ByteSize(512 * 1000), '512 KB'], - [ByteSize(21_000_000), '21 MB'], - ], decode: [ ['0 B', Result.Ok(ByteSize(0))], ['1 KB', Result.Ok(ByteSize(1000))], @@ -24,15 +19,21 @@ describe(ByteSize, () => { null, Result.Error( new CodecError({ - message: 'Cannot decode null as ByteSize', input: null, + message: 'Cannot decode null as ByteSize', }), ), ], ], + encode: [ + [ByteSize(1), '1 B'], + [ByteSize(0), '0 B'], + [ByteSize(512 * 1000), '512 KB'], + [ByteSize(21_000_000), '21 MB'], + ], schema: { - type: 'string', format: 'byte-size', + type: 'string', }, })); }); diff --git a/packages/byte-size/src/ByteSize/ByteSize.ts b/packages/byte-size/src/ByteSize/ByteSize.ts index 9f992d15d4..14f328457a 100644 --- a/packages/byte-size/src/ByteSize/ByteSize.ts +++ b/packages/byte-size/src/ByteSize/ByteSize.ts @@ -1,9 +1,10 @@ import { Symbol } from '@w5s/core/dist/Symbol.js'; import { Tag } from '@w5s/core/dist/Tag.js'; import { Int } from '@w5s/core/dist/Type/Int.js'; + +import { defaultFormat } from './defaultFormat.js'; import { format } from './format.js'; import { parse } from './parse.js'; -import { defaultFormat } from './defaultFormat.js'; const formatOptions = { standard: defaultFormat }; @@ -16,15 +17,15 @@ export type ByteSize = number & Tag<'ByteSize'>; * @namespace */ export const ByteSize = Tag.define({ - typeName: 'ByteSize' as const, hasInstance: Int.hasInstance, - [Symbol.encode]: (value) => format(value, formatOptions), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { const size = typeof input === 'string' ? parse(input) : undefined; return size == null ? error(input, 'ByteSize') : ok(size); }, + [Symbol.encode]: (value) => format(value, formatOptions), [Symbol.schema]: () => ({ - type: 'string', format: 'byte-size', + type: 'string', }), + typeName: 'ByteSize' as const, }); diff --git a/packages/byte-size/src/ByteSize/format.spec.ts b/packages/byte-size/src/ByteSize/format.spec.ts index a9ce9283ca..211af54bf8 100644 --- a/packages/byte-size/src/ByteSize/format.spec.ts +++ b/packages/byte-size/src/ByteSize/format.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { format } from './format.js'; + import { ByteSize } from './ByteSize.js'; +import { format } from './format.js'; describe(format, () => { describe('IEC', () => { diff --git a/packages/byte-size/src/ByteSize/format.ts b/packages/byte-size/src/ByteSize/format.ts index 42967f3aca..e41e2e706f 100644 --- a/packages/byte-size/src/ByteSize/format.ts +++ b/packages/byte-size/src/ByteSize/format.ts @@ -1,6 +1,7 @@ -import type { ByteSize } from './ByteSize.js'; import type { ByteSizeFormat } from '../ByteSizeFormat.js'; -import { byteSizePrefixes, byteSizeFormatData } from '../ByteSizeFormat/data.js'; +import type { ByteSize } from './ByteSize.js'; + +import { byteSizeFormatData, byteSizePrefixes } from '../ByteSizeFormat/data.js'; import { defaultFormat } from './defaultFormat.js'; export interface FormatOptions { diff --git a/packages/byte-size/src/ByteSize/parse.spec.ts b/packages/byte-size/src/ByteSize/parse.spec.ts index 20ad9df72b..9e0ec32590 100644 --- a/packages/byte-size/src/ByteSize/parse.spec.ts +++ b/packages/byte-size/src/ByteSize/parse.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { parse } from './parse.js'; describe(parse, () => { diff --git a/packages/byte-size/src/ByteSize/parse.ts b/packages/byte-size/src/ByteSize/parse.ts index 80ea405ccd..fe2b184db2 100644 --- a/packages/byte-size/src/ByteSize/parse.ts +++ b/packages/byte-size/src/ByteSize/parse.ts @@ -1,5 +1,7 @@ import type { Option } from '@w5s/core'; + import type { ByteSize } from './ByteSize.js'; + import { byteSizeFormatIndex } from '../ByteSizeFormat/data.js'; const byteSizeRegex = /^([\d,.]+)\s*([a-z]+)?$/i; diff --git a/packages/byte-size/src/ByteSizeFormat.ts b/packages/byte-size/src/ByteSizeFormat.ts index be548fb21d..795e38c8ba 100644 --- a/packages/byte-size/src/ByteSizeFormat.ts +++ b/packages/byte-size/src/ByteSizeFormat.ts @@ -4,9 +4,9 @@ import { Enum } from '@w5s/core/dist/Enum.js'; * Byte size formats */ export const ByteSizeFormat = Enum.define({ - typeName: 'ByteSizeFormat' as const, - IEC: 'IEC', + SI: 'SI', + typeName: 'ByteSizeFormat' as const, }); export type ByteSizeFormat = Enum.ValueOf; diff --git a/packages/byte-size/src/ByteSizeFormat/data.ts b/packages/byte-size/src/ByteSizeFormat/data.ts index a4328e12f0..11f51a0734 100644 --- a/packages/byte-size/src/ByteSizeFormat/data.ts +++ b/packages/byte-size/src/ByteSizeFormat/data.ts @@ -1,4 +1,5 @@ import { lazy } from '@w5s/core/dist/lazy.js'; + import type { ByteSizeFormat } from '../ByteSizeFormat.js'; export const byteSizePrefixes = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] as const; diff --git a/packages/byte-size/src/index.spec.ts b/packages/byte-size/src/index.spec.ts index d538b8e188..434b6a21b7 100644 --- a/packages/byte-size/src/index.spec.ts +++ b/packages/byte-size/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/collection/example/.eslintrc.cjs b/packages/collection/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/collection/example/.eslintrc.cjs +++ b/packages/collection/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/collection/src/Array.spec.ts b/packages/collection/src/Array.spec.ts index 9d730ce509..0f8d978c10 100644 --- a/packages/collection/src/Array.spec.ts +++ b/packages/collection/src/Array.spec.ts @@ -1,14 +1,18 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Array } from './Array.js'; import { at } from './Array/at.js'; import { concat } from './Array/concat.js'; import { deleteAt } from './Array/deleteAt.js'; import { empty } from './Array/empty.js'; import { every } from './Array/every.js'; -import { find } from './Array/find.js'; import { filter } from './Array/filter.js'; +import { find } from './Array/find.js'; import { findIndex } from './Array/findIndex.js'; +import { findLast } from './Array/findLast.js'; +import { findLastIndex } from './Array/findLastIndex.js'; import { flatMap } from './Array/flatMap.js'; +import { fromAsync } from './Array/fromAsync.js'; import { generate } from './Array/generate.js'; import { hasInstance } from './Array/hasInstance.js'; import { includes } from './Array/includes.js'; @@ -27,9 +31,6 @@ import { slice } from './Array/slice.js'; import { some } from './Array/some.js'; import { sort } from './Array/sort.js'; import { splice } from './Array/splice.js'; -import { findLast } from './Array/findLast.js'; -import { findLastIndex } from './Array/findLastIndex.js'; -import { fromAsync } from './Array/fromAsync.js'; describe('Array', () => { it('is an alias to functions', () => { @@ -61,9 +62,9 @@ describe('Array', () => { setAt, size, slice, - splice, some, sort, + splice, }); }); }); diff --git a/packages/collection/src/Array.ts b/packages/collection/src/Array.ts index 559509e43a..6a7063bd5e 100644 --- a/packages/collection/src/Array.ts +++ b/packages/collection/src/Array.ts @@ -1,4 +1,5 @@ import type { Array as CoreArray } from '@w5s/core-type'; + import { at } from './Array/at.js'; import { concat } from './Array/concat.js'; import { deleteAt } from './Array/deleteAt.js'; @@ -76,7 +77,7 @@ export const Array = { setAt, size, slice, - splice, some, sort, + splice, }; diff --git a/packages/collection/src/Array/at.spec.ts b/packages/collection/src/Array/at.spec.ts index c673ede698..e480cea28d 100644 --- a/packages/collection/src/Array/at.spec.ts +++ b/packages/collection/src/Array/at.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { at } from './at.js'; describe(at, () => { diff --git a/packages/collection/src/Array/concat.spec.ts b/packages/collection/src/Array/concat.spec.ts index 80759b3aee..ddd02af612 100644 --- a/packages/collection/src/Array/concat.spec.ts +++ b/packages/collection/src/Array/concat.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { concat } from './concat.js'; describe(concat, () => { diff --git a/packages/collection/src/Array/concat.ts b/packages/collection/src/Array/concat.ts index a83ef23f30..3ff2be3cb7 100644 --- a/packages/collection/src/Array/concat.ts +++ b/packages/collection/src/Array/concat.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { isEmpty } from './isEmpty.js'; /** @@ -12,6 +13,6 @@ import { isEmpty } from './isEmpty.js'; * @param self The array object * @param extensions The other arrays to append */ -export function concat(self: Array, ...extensions: Array[]): Array { +export function concat(self: Array, ...extensions: Array>): Array { return extensions.length > 0 && !extensions.every(isEmpty) ? [...self, ...extensions.flat()] : self; } diff --git a/packages/collection/src/Array/deleteAt.spec.ts b/packages/collection/src/Array/deleteAt.spec.ts index 3ebc09bbc6..fd5ec3f530 100644 --- a/packages/collection/src/Array/deleteAt.spec.ts +++ b/packages/collection/src/Array/deleteAt.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { deleteAt } from './deleteAt.js'; import { empty } from './empty.js'; diff --git a/packages/collection/src/Array/deleteAt.ts b/packages/collection/src/Array/deleteAt.ts index 0a141534d1..05ad6c166f 100644 --- a/packages/collection/src/Array/deleteAt.ts +++ b/packages/collection/src/Array/deleteAt.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { empty } from './empty.js'; import { splice } from './splice.js'; diff --git a/packages/collection/src/Array/empty.spec.ts b/packages/collection/src/Array/empty.spec.ts index 61e2849533..69472f47b7 100644 --- a/packages/collection/src/Array/empty.spec.ts +++ b/packages/collection/src/Array/empty.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; describe(empty, () => { diff --git a/packages/collection/src/Array/every.spec.ts b/packages/collection/src/Array/every.spec.ts index be25e48ff3..f13f04441f 100644 --- a/packages/collection/src/Array/every.spec.ts +++ b/packages/collection/src/Array/every.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { every } from './every.js'; describe(every, () => { diff --git a/packages/collection/src/Array/every.ts b/packages/collection/src/Array/every.ts index 22e1062150..7ceba6be09 100644 --- a/packages/collection/src/Array/every.ts +++ b/packages/collection/src/Array/every.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/filter.spec.ts b/packages/collection/src/Array/filter.spec.ts index 5872be4697..9ae14594e2 100644 --- a/packages/collection/src/Array/filter.spec.ts +++ b/packages/collection/src/Array/filter.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { filter } from './filter.js'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { filter } from './filter.js'; describe('.filter', () => { it('should return unchanged if empty', () => { diff --git a/packages/collection/src/Array/filter.ts b/packages/collection/src/Array/filter.ts index 6f56f68591..325eaf945c 100644 --- a/packages/collection/src/Array/filter.ts +++ b/packages/collection/src/Array/filter.ts @@ -1,5 +1,7 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; + import { empty } from './empty.js'; /** diff --git a/packages/collection/src/Array/find.spec.ts b/packages/collection/src/Array/find.spec.ts index dc6c8f968d..cc8bf5382a 100644 --- a/packages/collection/src/Array/find.spec.ts +++ b/packages/collection/src/Array/find.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { find } from './find.js'; +import { describe, expect, it, vi } from 'vitest'; + import { Option } from '../../../core/src/Option.js'; +import { find } from './find.js'; describe(find, () => { it('should map each value to callback', () => { diff --git a/packages/collection/src/Array/find.ts b/packages/collection/src/Array/find.ts index e518a21069..60dc2257ca 100644 --- a/packages/collection/src/Array/find.ts +++ b/packages/collection/src/Array/find.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/findIndex.spec.ts b/packages/collection/src/Array/findIndex.spec.ts index 547c6d6c62..d71cc5b768 100644 --- a/packages/collection/src/Array/findIndex.spec.ts +++ b/packages/collection/src/Array/findIndex.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { findIndex } from './findIndex.js'; describe(findIndex, () => { diff --git a/packages/collection/src/Array/findIndex.ts b/packages/collection/src/Array/findIndex.ts index da2cd28ffa..f9f10f3755 100644 --- a/packages/collection/src/Array/findIndex.ts +++ b/packages/collection/src/Array/findIndex.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/findLast.spec.ts b/packages/collection/src/Array/findLast.spec.ts index ac65659daa..ff8ebf3db7 100644 --- a/packages/collection/src/Array/findLast.spec.ts +++ b/packages/collection/src/Array/findLast.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect, vi } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it, vi } from 'vitest'; + import { findLast } from './findLast.js'; describe(findLast, () => { diff --git a/packages/collection/src/Array/findLast.ts b/packages/collection/src/Array/findLast.ts index 0ac13eb9d3..d6c654e976 100644 --- a/packages/collection/src/Array/findLast.ts +++ b/packages/collection/src/Array/findLast.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/findLastIndex.spec.ts b/packages/collection/src/Array/findLastIndex.spec.ts index 242d219a43..3ee13b9b34 100644 --- a/packages/collection/src/Array/findLastIndex.spec.ts +++ b/packages/collection/src/Array/findLastIndex.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { findLastIndex } from './findLastIndex.js'; describe(findLastIndex, () => { diff --git a/packages/collection/src/Array/findLastIndex.ts b/packages/collection/src/Array/findLastIndex.ts index 55a40c2959..f0dcc2375d 100644 --- a/packages/collection/src/Array/findLastIndex.ts +++ b/packages/collection/src/Array/findLastIndex.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/flatMap.spec.ts b/packages/collection/src/Array/flatMap.spec.ts index 21b2d6e242..4c51df314d 100644 --- a/packages/collection/src/Array/flatMap.spec.ts +++ b/packages/collection/src/Array/flatMap.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { flatMap } from './flatMap.js'; +import { describe, expect, it, vi } from 'vitest'; + import { empty } from './empty.js'; +import { flatMap } from './flatMap.js'; describe(flatMap, () => { it('should return unchanged if empty', () => { diff --git a/packages/collection/src/Array/flatMap.ts b/packages/collection/src/Array/flatMap.ts index e345f946a7..ed0961d79b 100644 --- a/packages/collection/src/Array/flatMap.ts +++ b/packages/collection/src/Array/flatMap.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/fromAsync.spec.ts b/packages/collection/src/Array/fromAsync.spec.ts index fc1771bd36..1b2b251a99 100644 --- a/packages/collection/src/Array/fromAsync.spec.ts +++ b/packages/collection/src/Array/fromAsync.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { fromAsync } from './fromAsync.js'; describe(fromAsync, () => { @@ -26,7 +27,7 @@ describe(fromAsync, () => { }); it.skip('should process items sequentially by default', async () => { - const order: number[] = []; + const order: Array = []; const array = [1, 2, 3]; await fromAsync(array, async (x) => { @@ -43,7 +44,7 @@ describe(fromAsync, () => { it('should pass the index as the second parameter to the mapping function', async () => { const array = ['a', 'b', 'c']; - const indexes: number[] = []; + const indexes: Array = []; await fromAsync(array, async (_, index) => { indexes.push(index); diff --git a/packages/collection/src/Array/fromAsync.ts b/packages/collection/src/Array/fromAsync.ts index 4507ea954d..d572f5923a 100644 --- a/packages/collection/src/Array/fromAsync.ts +++ b/packages/collection/src/Array/fromAsync.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { arrayFromAsync } from '../internal/arrayFromAsync.js'; /** @@ -16,8 +17,7 @@ import { arrayFromAsync } from '../internal/arrayFromAsync.js'; * });// [0, 1, 2, 3, 4] * ``` */ -export function fromAsync(iterableOrArrayLike: AsyncIterable | Iterable>): Promise>; - +export function fromAsync(iterableOrArrayLike: AsyncIterable | Iterable | T>): Promise>; /** * Creates an array from an async iterator or iterable object. * diff --git a/packages/collection/src/Array/generate.spec.ts b/packages/collection/src/Array/generate.spec.ts index bdbeb6ce78..f598d50c69 100644 --- a/packages/collection/src/Array/generate.spec.ts +++ b/packages/collection/src/Array/generate.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { generate } from './generate.js'; describe(generate, () => { diff --git a/packages/collection/src/Array/generate.ts b/packages/collection/src/Array/generate.ts index a97832100d..4f8e2e2b5c 100644 --- a/packages/collection/src/Array/generate.ts +++ b/packages/collection/src/Array/generate.ts @@ -1,5 +1,7 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; + import { empty } from './empty.js'; /** diff --git a/packages/collection/src/Array/hasInstance.spec.ts b/packages/collection/src/Array/hasInstance.spec.ts index c4106def43..90aaa95010 100644 --- a/packages/collection/src/Array/hasInstance.spec.ts +++ b/packages/collection/src/Array/hasInstance.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { hasInstance } from './hasInstance.js'; + import { empty } from './empty.js'; +import { hasInstance } from './hasInstance.js'; describe(hasInstance, () => { it('should return true for Array', () => { diff --git a/packages/collection/src/Array/include.spec.ts b/packages/collection/src/Array/include.spec.ts index 741967185a..0d9bd48fbd 100644 --- a/packages/collection/src/Array/include.spec.ts +++ b/packages/collection/src/Array/include.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { includes } from './includes.js'; describe(includes, () => { diff --git a/packages/collection/src/Array/includes.ts b/packages/collection/src/Array/includes.ts index 222a84dbe7..5507695a35 100644 --- a/packages/collection/src/Array/includes.ts +++ b/packages/collection/src/Array/includes.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { indexOf } from './indexOf.js'; /** diff --git a/packages/collection/src/Array/indexOf.spec.ts b/packages/collection/src/Array/indexOf.spec.ts index 31f13726bb..104d31d416 100644 --- a/packages/collection/src/Array/indexOf.spec.ts +++ b/packages/collection/src/Array/indexOf.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { indexOf } from './indexOf.js'; describe(indexOf, () => { diff --git a/packages/collection/src/Array/indexOf.ts b/packages/collection/src/Array/indexOf.ts index 015b865ba4..2a9a62e8c3 100644 --- a/packages/collection/src/Array/indexOf.ts +++ b/packages/collection/src/Array/indexOf.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/insertAt.spec.ts b/packages/collection/src/Array/insertAt.spec.ts index d5d0fe9570..c3c1eb11f5 100644 --- a/packages/collection/src/Array/insertAt.spec.ts +++ b/packages/collection/src/Array/insertAt.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; import { insertAt } from './insertAt.js'; diff --git a/packages/collection/src/Array/insertAt.ts b/packages/collection/src/Array/insertAt.ts index 7cc674eb9c..5869ae687b 100644 --- a/packages/collection/src/Array/insertAt.ts +++ b/packages/collection/src/Array/insertAt.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { splice } from './splice.js'; /** diff --git a/packages/collection/src/Array/isEmpty.spec.ts b/packages/collection/src/Array/isEmpty.spec.ts index 8e059db068..8a5dfa0d5d 100644 --- a/packages/collection/src/Array/isEmpty.spec.ts +++ b/packages/collection/src/Array/isEmpty.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { isEmpty } from './isEmpty.js'; describe(isEmpty, () => { diff --git a/packages/collection/src/Array/lastIndexOf.spec.ts b/packages/collection/src/Array/lastIndexOf.spec.ts index 2859131b60..3ed4f511d5 100644 --- a/packages/collection/src/Array/lastIndexOf.spec.ts +++ b/packages/collection/src/Array/lastIndexOf.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { lastIndexOf } from './lastIndexOf.js'; describe(lastIndexOf, () => { diff --git a/packages/collection/src/Array/lastIndexOf.ts b/packages/collection/src/Array/lastIndexOf.ts index 4d9092cbf7..2c69c30ad8 100644 --- a/packages/collection/src/Array/lastIndexOf.ts +++ b/packages/collection/src/Array/lastIndexOf.ts @@ -1,4 +1,5 @@ import type { Int, Option } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/map.spec.ts b/packages/collection/src/Array/map.spec.ts index ff09ee7aef..7682cf4534 100644 --- a/packages/collection/src/Array/map.spec.ts +++ b/packages/collection/src/Array/map.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; import { map } from './map.js'; diff --git a/packages/collection/src/Array/map.ts b/packages/collection/src/Array/map.ts index b5d5f25690..cae25b57ee 100644 --- a/packages/collection/src/Array/map.ts +++ b/packages/collection/src/Array/map.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/of.spec.ts b/packages/collection/src/Array/of.spec.ts index dbb995c40f..5cc3e30848 100644 --- a/packages/collection/src/Array/of.spec.ts +++ b/packages/collection/src/Array/of.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; describe(of, () => { diff --git a/packages/collection/src/Array/of.ts b/packages/collection/src/Array/of.ts index 0d7de3ae98..352a497190 100644 --- a/packages/collection/src/Array/of.ts +++ b/packages/collection/src/Array/of.ts @@ -10,6 +10,6 @@ import type { Array } from '../Array.js'; * @category Constructor * @param items A set of items to include in the new array object. */ -export function of(...items: Item[]): Array { +export function of(...items: Array): Array { return items; } diff --git a/packages/collection/src/Array/reduce.spec.ts b/packages/collection/src/Array/reduce.spec.ts index bfacb0e980..246e84df2f 100644 --- a/packages/collection/src/Array/reduce.spec.ts +++ b/packages/collection/src/Array/reduce.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { reduce } from './reduce.js'; describe(reduce, () => { diff --git a/packages/collection/src/Array/reduce.ts b/packages/collection/src/Array/reduce.ts index 93cfdeb52e..072d35f13f 100644 --- a/packages/collection/src/Array/reduce.ts +++ b/packages/collection/src/Array/reduce.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/reduceRight.spec.ts b/packages/collection/src/Array/reduceRight.spec.ts index ba5c7cbdde..1c23da294d 100644 --- a/packages/collection/src/Array/reduceRight.spec.ts +++ b/packages/collection/src/Array/reduceRight.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { reduceRight } from './reduceRight.js'; describe(reduceRight, () => { diff --git a/packages/collection/src/Array/reduceRight.ts b/packages/collection/src/Array/reduceRight.ts index 2166dd7c89..8ae244c7d5 100644 --- a/packages/collection/src/Array/reduceRight.ts +++ b/packages/collection/src/Array/reduceRight.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/reverse.spec.ts b/packages/collection/src/Array/reverse.spec.ts index 8ba6bb58de..a6b11a22c1 100644 --- a/packages/collection/src/Array/reverse.spec.ts +++ b/packages/collection/src/Array/reverse.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { reverse } from './reverse.js'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { reverse } from './reverse.js'; describe(reverse, () => { it('should return unchanged if empty', () => { diff --git a/packages/collection/src/Array/reverse.ts b/packages/collection/src/Array/reverse.ts index 2b2a3c2e79..85a0f9ef8e 100644 --- a/packages/collection/src/Array/reverse.ts +++ b/packages/collection/src/Array/reverse.ts @@ -1,5 +1,7 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; + import { map } from './map.js'; /** diff --git a/packages/collection/src/Array/setAt.spec.ts b/packages/collection/src/Array/setAt.spec.ts index 7c7ae7fee6..54ff007eac 100644 --- a/packages/collection/src/Array/setAt.spec.ts +++ b/packages/collection/src/Array/setAt.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { setAt } from './setAt.js'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { setAt } from './setAt.js'; describe(setAt, () => { it('returns unchanged when empty', () => { diff --git a/packages/collection/src/Array/setAt.ts b/packages/collection/src/Array/setAt.ts index 5a76da8c95..6374ee6e91 100644 --- a/packages/collection/src/Array/setAt.ts +++ b/packages/collection/src/Array/setAt.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { splice } from './splice.js'; /** diff --git a/packages/collection/src/Array/size.spec.ts b/packages/collection/src/Array/size.spec.ts index 1d2a76f713..5092ba0850 100644 --- a/packages/collection/src/Array/size.spec.ts +++ b/packages/collection/src/Array/size.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { size } from './size.js'; describe(size, () => { diff --git a/packages/collection/src/Array/slice.spec.ts b/packages/collection/src/Array/slice.spec.ts index 14bead58f7..6d07da46d6 100644 --- a/packages/collection/src/Array/slice.spec.ts +++ b/packages/collection/src/Array/slice.spec.ts @@ -1,26 +1,26 @@ -import { describe, it, expect } from 'vitest'; -import { slice } from './slice.js'; +/* eslint-disable perfectionist/sort-objects */ +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { slice } from './slice.js'; describe(slice, () => { const anyArray = [11, 4, 6, 2]; - type ItemType = ArrayType extends readonly (infer ElementType)[] + type ItemType> = ArrayType extends ReadonlyArray ? ElementType : never; - const generate = }>( + const generate = >>( input: T, ): Array<{ [K in keyof T]: ItemType }> => { const addProperty = (element: O, property: P, values: Array) => values.map((value) => ({ ...element, [property]: value })); const genArray = (array: Array, property: P, values: Array) => array.reduce< - (O & { - [x: string]: V; - })[] + Array> >((_, element) => [..._, ...addProperty(element, property, values)], []); // @ts-ignore hard to type - return Object.keys(input).reduce((acc, property) => { + return ['start', 'end'].reduce((acc, property) => { const values = input[property]!; return acc.length === 0 ? addProperty({}, property, values) : genArray(acc, property, values); @@ -31,8 +31,8 @@ describe(slice, () => { it('should generate data for test cases', () => { expect( generate({ - start: [undefined, 0, 1, -1], end: [undefined, -1, 1, 2], + start: [undefined, 0, 1, -1], }), ).toEqual([ { diff --git a/packages/collection/src/Array/slice.ts b/packages/collection/src/Array/slice.ts index b0da8ce133..18038f1a61 100644 --- a/packages/collection/src/Array/slice.ts +++ b/packages/collection/src/Array/slice.ts @@ -1,5 +1,7 @@ import type { Option } from '@w5s/core'; + import type { Array } from '../Array.js'; + import { empty } from './empty.js'; /** diff --git a/packages/collection/src/Array/some.spec.ts b/packages/collection/src/Array/some.spec.ts index a14b46be44..1472e739cd 100644 --- a/packages/collection/src/Array/some.spec.ts +++ b/packages/collection/src/Array/some.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { some } from './some.js'; describe(some, () => { diff --git a/packages/collection/src/Array/some.ts b/packages/collection/src/Array/some.ts index 83c4900ae7..a74f5180be 100644 --- a/packages/collection/src/Array/some.ts +++ b/packages/collection/src/Array/some.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/sort.spec.ts b/packages/collection/src/Array/sort.spec.ts index 2f7deacb0f..19d0c41a03 100644 --- a/packages/collection/src/Array/sort.spec.ts +++ b/packages/collection/src/Array/sort.spec.ts @@ -1,7 +1,9 @@ -import { describe, it, expect } from 'vitest'; import type { Ordering } from '@w5s/core'; -import { sort } from './sort.js'; + +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { sort } from './sort.js'; describe(sort, () => { const compare = (a: number, b: number): Ordering => (a === b ? 0 : a < b ? -1 : 1); diff --git a/packages/collection/src/Array/sort.ts b/packages/collection/src/Array/sort.ts index 6f0d46c58c..f5859bf988 100644 --- a/packages/collection/src/Array/sort.ts +++ b/packages/collection/src/Array/sort.ts @@ -1,4 +1,5 @@ import type { Ordering } from '@w5s/core'; + import type { Array } from '../Array.js'; /** diff --git a/packages/collection/src/Array/splice.spec.ts b/packages/collection/src/Array/splice.spec.ts index 1a38ca4c8e..1227d6f5d4 100644 --- a/packages/collection/src/Array/splice.spec.ts +++ b/packages/collection/src/Array/splice.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { splice } from './splice.js'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; +import { splice } from './splice.js'; describe(splice, () => { it('should return unchanged when empty', () => { diff --git a/packages/collection/src/Array/splice.ts b/packages/collection/src/Array/splice.ts index 0c520cf82d..bc23fb2630 100644 --- a/packages/collection/src/Array/splice.ts +++ b/packages/collection/src/Array/splice.ts @@ -1,4 +1,5 @@ import type { Array } from '../Array.js'; + import { empty } from './empty.js'; /** @@ -17,9 +18,9 @@ import { empty } from './empty.js'; * @param self The array object * @param start The position of the inserted item in the array * @param deleteCount The number of deleted items - * @param {...any} items + * @param items */ -export function splice(self: Array, start: number, deleteCount: number, ...items: Item[]): Array { +export function splice(self: Array, start: number, deleteCount: number, ...items: Array): Array { const result = self.toSpliced(start, deleteCount, ...items); return result.length === 0 ? empty() : result; } diff --git a/packages/collection/src/Record.spec.ts b/packages/collection/src/Record.spec.ts index 447dc97a8e..88db4a9b57 100644 --- a/packages/collection/src/Record.spec.ts +++ b/packages/collection/src/Record.spec.ts @@ -1,31 +1,32 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Record } from './Record.js'; +import { $delete } from './Record/delete.js'; import { empty } from './Record/empty.js'; +import { entries } from './Record/entries.js'; +import { forEach } from './Record/forEach.js'; import { from } from './Record/from.js'; -import { keys } from './Record/keys.js'; -import { size } from './Record/size.js'; +import { get } from './Record/get.js'; import { has } from './Record/has.js'; +import { keys } from './Record/keys.js'; import { set } from './Record/set.js'; -import { forEach } from './Record/forEach.js'; +import { size } from './Record/size.js'; import { values } from './Record/values.js'; -import { entries } from './Record/entries.js'; -import { get } from './Record/get.js'; -import { $delete } from './Record/delete.js'; describe('Record', () => { it('is an alias to functions', () => { expect(Record).toEqual({ + delete: $delete, empty, entries, forEach, from, - has, get, + has, keys, set, size, values, - delete: $delete, }); }); }); diff --git a/packages/collection/src/Record.ts b/packages/collection/src/Record.ts index 2e4183caa7..c841a12620 100644 --- a/packages/collection/src/Record.ts +++ b/packages/collection/src/Record.ts @@ -10,13 +10,13 @@ import { set } from './Record/set.js'; import { size } from './Record/size.js'; import { values } from './Record/values.js'; -export type RecordKey = string | symbol; - /** * A Record is an immutable mapping `{ [string]: value }` */ export type Record = Readonly>; +export type RecordKey = string | symbol; + /** * A collection of functions to manipulate Record * diff --git a/packages/collection/src/Record/delete.spec.ts b/packages/collection/src/Record/delete.spec.ts index 5aa3891e3c..1d79c973be 100644 --- a/packages/collection/src/Record/delete.spec.ts +++ b/packages/collection/src/Record/delete.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { $delete } from './delete.js'; describe('.delete', () => { diff --git a/packages/collection/src/Record/delete.ts b/packages/collection/src/Record/delete.ts index 0a50005cea..fb0721136c 100644 --- a/packages/collection/src/Record/delete.ts +++ b/packages/collection/src/Record/delete.ts @@ -1,4 +1,5 @@ import type { RecordKey } from '../Record.js'; + import { has } from './has.js'; /** @@ -14,7 +15,6 @@ import { has } from './has.js'; */ export function $delete(self: Record, key: Key): Record { if (has(self, key)) { - // eslint-disable-next-line ts/no-unused-vars const { [key]: _, ...newRecord } = self; return newRecord as Record; diff --git a/packages/collection/src/Record/entries.spec.ts b/packages/collection/src/Record/entries.spec.ts index dfe27fddf3..c26717b212 100644 --- a/packages/collection/src/Record/entries.spec.ts +++ b/packages/collection/src/Record/entries.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { entries } from './entries.js'; describe(entries, () => { diff --git a/packages/collection/src/Record/entries.ts b/packages/collection/src/Record/entries.ts index a1cf977ddb..2c133bfa73 100644 --- a/packages/collection/src/Record/entries.ts +++ b/packages/collection/src/Record/entries.ts @@ -1,4 +1,5 @@ import type { RecordKey } from '../Record.js'; + import { keys } from './keys.js'; /** diff --git a/packages/collection/src/Record/forEach.spec.ts b/packages/collection/src/Record/forEach.spec.ts index 9bf899d3e2..681267041d 100644 --- a/packages/collection/src/Record/forEach.spec.ts +++ b/packages/collection/src/Record/forEach.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it, vi } from 'vitest'; + import { forEach } from './forEach.js'; describe(forEach, () => { diff --git a/packages/collection/src/Record/forEach.ts b/packages/collection/src/Record/forEach.ts index b8dd5976aa..af69e8783f 100644 --- a/packages/collection/src/Record/forEach.ts +++ b/packages/collection/src/Record/forEach.ts @@ -1,4 +1,5 @@ import type { RecordKey } from '../Record.js'; + import { keys } from './keys.js'; /** diff --git a/packages/collection/src/Record/from.spec.ts b/packages/collection/src/Record/from.spec.ts index 73855d1a97..4592f38086 100644 --- a/packages/collection/src/Record/from.spec.ts +++ b/packages/collection/src/Record/from.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { from } from './from.js'; describe(from, () => { diff --git a/packages/collection/src/Record/from.ts b/packages/collection/src/Record/from.ts index 0c4852d01f..a40ca32641 100644 --- a/packages/collection/src/Record/from.ts +++ b/packages/collection/src/Record/from.ts @@ -11,9 +11,7 @@ import type { RecordKey } from '../Record.js'; * @category Constructor */ export function from(iterable: Iterable<[Key, Value]>): Record { - const returnValue = {} as unknown as { - [P in Key]: Value; - }; + const returnValue = {} as unknown as Record; for (const [key, value] of iterable) { returnValue[key] = value; } diff --git a/packages/collection/src/Record/get.spec.ts b/packages/collection/src/Record/get.spec.ts index 237201bec1..635ff85d7e 100644 --- a/packages/collection/src/Record/get.spec.ts +++ b/packages/collection/src/Record/get.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { get } from './get.js'; describe(get, () => { diff --git a/packages/collection/src/Record/get.ts b/packages/collection/src/Record/get.ts index 311346bb5d..3fc5bb232d 100644 --- a/packages/collection/src/Record/get.ts +++ b/packages/collection/src/Record/get.ts @@ -1,5 +1,7 @@ import type { Option } from '@w5s/core'; + import type { RecordKey } from '../Record.js'; + import { has } from './has.js'; /** diff --git a/packages/collection/src/Record/has.spec.ts b/packages/collection/src/Record/has.spec.ts index 2b160ed2fb..dc8a2ab40a 100644 --- a/packages/collection/src/Record/has.spec.ts +++ b/packages/collection/src/Record/has.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { has } from './has.js'; describe(has, () => { diff --git a/packages/collection/src/Record/keys.spec.ts b/packages/collection/src/Record/keys.spec.ts index 07978b64a9..0431cfff51 100644 --- a/packages/collection/src/Record/keys.spec.ts +++ b/packages/collection/src/Record/keys.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { keys } from './keys.js'; describe(keys, () => { @@ -15,8 +16,8 @@ describe(keys, () => { it('should handle symbol keys', () => { expect( [...keys({ - [anySymbolKey]: 'anyValue', anyOtherKey: 'anyOtherValue', + [anySymbolKey]: 'anyValue', })], ).toEqual(['anyOtherKey', anySymbolKey]); }); diff --git a/packages/collection/src/Record/keys.ts b/packages/collection/src/Record/keys.ts index d5e1166835..8519683ede 100644 --- a/packages/collection/src/Record/keys.ts +++ b/packages/collection/src/Record/keys.ts @@ -1,6 +1,6 @@ import type { RecordKey } from '../Record.js'; -const ownKeys = (record: Record) => Reflect.ownKeys(record) as Key[]; +const ownKeys = (record: Record) => Reflect.ownKeys(record) as Array; /** * Return an iterator over all keys diff --git a/packages/collection/src/Record/set.spec.ts b/packages/collection/src/Record/set.spec.ts index 87935b04b4..41f984df4e 100644 --- a/packages/collection/src/Record/set.spec.ts +++ b/packages/collection/src/Record/set.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { set } from './set.js'; describe(set, () => { diff --git a/packages/collection/src/Record/size.spec.ts b/packages/collection/src/Record/size.spec.ts index 0114a7622c..3f12549ac6 100644 --- a/packages/collection/src/Record/size.spec.ts +++ b/packages/collection/src/Record/size.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { size } from './size.js'; + import { empty } from './empty.js'; +import { size } from './size.js'; describe(size, () => { it('should return 0 for empty', () => { diff --git a/packages/collection/src/Record/size.ts b/packages/collection/src/Record/size.ts index 9e2bcfe577..fe24ad7cf6 100644 --- a/packages/collection/src/Record/size.ts +++ b/packages/collection/src/Record/size.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { RecordKey } from '../Record.js'; /** diff --git a/packages/collection/src/Record/values.spec.ts b/packages/collection/src/Record/values.spec.ts index 5f3ef2eb37..37342cc01f 100644 --- a/packages/collection/src/Record/values.spec.ts +++ b/packages/collection/src/Record/values.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { values } from './values.js'; describe(values, () => { diff --git a/packages/collection/src/Record/values.ts b/packages/collection/src/Record/values.ts index 51fef15585..6e51ee988e 100644 --- a/packages/collection/src/Record/values.ts +++ b/packages/collection/src/Record/values.ts @@ -1,4 +1,5 @@ import type { RecordKey } from '../Record.js'; + import { keys } from './keys.js'; /** diff --git a/packages/collection/src/index.spec.ts b/packages/collection/src/index.spec.ts index f94af4d38c..37e96f2311 100644 --- a/packages/collection/src/index.spec.ts +++ b/packages/collection/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/console/example/.eslintrc.cjs b/packages/console/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/console/example/.eslintrc.cjs +++ b/packages/console/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/console/src/ANSICode.spec.ts b/packages/console/src/ANSICode.spec.ts index aac374059d..55251312dd 100644 --- a/packages/console/src/ANSICode.spec.ts +++ b/packages/console/src/ANSICode.spec.ts @@ -1,20 +1,21 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { ANSICode } from './ANSICode.js'; -import { strip } from './ANSICode/strip.js'; -import { format } from './ANSICode/format.js'; -import { wrap } from './ANSICode/wrap.js'; import { color } from './ANSICode/color.js'; import { fontStyle } from './ANSICode/fontStyle.js'; import { fontWeight } from './ANSICode/fontWeight.js'; +import { format } from './ANSICode/format.js'; +import { strip } from './ANSICode/strip.js'; import { style } from './ANSICode/style.js'; +import { wrap } from './ANSICode/wrap.js'; describe('ANSICode', () => { it('is an alias to functions', () => { expect(ANSICode).toEqual( expect.objectContaining({ color, - fontWeight, fontStyle, + fontWeight, format, strip, style, diff --git a/packages/console/src/ANSICode.ts b/packages/console/src/ANSICode.ts index 06f659e059..54d5a24ffd 100644 --- a/packages/console/src/ANSICode.ts +++ b/packages/console/src/ANSICode.ts @@ -1,18 +1,18 @@ -import { strip } from './ANSICode/strip.js'; -import { format } from './ANSICode/format.js'; -import { wrap } from './ANSICode/wrap.js'; import { color } from './ANSICode/color.js'; -import { fontWeight } from './ANSICode/fontWeight.js'; import { fontStyle } from './ANSICode/fontStyle.js'; +import { fontWeight } from './ANSICode/fontWeight.js'; +import { format } from './ANSICode/format.js'; +import { strip } from './ANSICode/strip.js'; import { style } from './ANSICode/style.js'; +import { wrap } from './ANSICode/wrap.js'; /** * @namespace */ export const ANSICode = { color, - fontWeight, fontStyle, + fontWeight, format, strip, style, diff --git a/packages/console/src/ANSICode/color.spec.ts b/packages/console/src/ANSICode/color.spec.ts index 0b1a44e212..595e9e7d7a 100644 --- a/packages/console/src/ANSICode/color.spec.ts +++ b/packages/console/src/ANSICode/color.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { color } from './color.js'; describe(color, () => { diff --git a/packages/console/src/ANSICode/color.ts b/packages/console/src/ANSICode/color.ts index 6e572ed557..a5eeec1ea7 100644 --- a/packages/console/src/ANSICode/color.ts +++ b/packages/console/src/ANSICode/color.ts @@ -1,12 +1,12 @@ +import type { ANSIWrapper } from './wrap.js'; + /* cSpell:disable */ import { wrap } from './wrap.js'; -import type { ANSIWrapper } from './wrap.js'; - /** * ANSI Color */ -export type Color = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white'; +export type Color = 'black' | 'blue' | 'cyan' | 'green' | 'magenta' | 'red' | 'white' | 'yellow'; const colorMap = new Map( ( diff --git a/packages/console/src/ANSICode/fontStyle.spec.ts b/packages/console/src/ANSICode/fontStyle.spec.ts index 589a40b7fa..d2efafcfea 100644 --- a/packages/console/src/ANSICode/fontStyle.spec.ts +++ b/packages/console/src/ANSICode/fontStyle.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { fontStyle } from './fontStyle.js'; describe(fontStyle, () => { diff --git a/packages/console/src/ANSICode/fontStyle.ts b/packages/console/src/ANSICode/fontStyle.ts index 1171babd12..b312600d96 100644 --- a/packages/console/src/ANSICode/fontStyle.ts +++ b/packages/console/src/ANSICode/fontStyle.ts @@ -4,7 +4,7 @@ import { wrap } from './wrap.js'; /** * Font weight */ -export type FontStyle = 'normal' | 'italic'; +export type FontStyle = 'italic' | 'normal'; const fontStyleMap = new Map( ( diff --git a/packages/console/src/ANSICode/fontWeight.spec.ts b/packages/console/src/ANSICode/fontWeight.spec.ts index 0b99b9176b..cc7dd4d5db 100644 --- a/packages/console/src/ANSICode/fontWeight.spec.ts +++ b/packages/console/src/ANSICode/fontWeight.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { fontWeight } from './fontWeight.js'; describe(fontWeight, () => { diff --git a/packages/console/src/ANSICode/fontWeight.ts b/packages/console/src/ANSICode/fontWeight.ts index 561e3bd250..8e2f9ae393 100644 --- a/packages/console/src/ANSICode/fontWeight.ts +++ b/packages/console/src/ANSICode/fontWeight.ts @@ -1,10 +1,10 @@ /* cSpell:disable */ -import { wrap, type ANSIWrapper } from './wrap.js'; +import { type ANSIWrapper, wrap } from './wrap.js'; /** * Font weight */ -export type FontWeight = 'normal' | 'bold' | 'dim'; +export type FontWeight = 'bold' | 'dim' | 'normal'; const fontWeightMap = new Map( ( diff --git a/packages/console/src/ANSICode/format.spec.ts b/packages/console/src/ANSICode/format.spec.ts index 3915924a9d..cb077abd90 100644 --- a/packages/console/src/ANSICode/format.spec.ts +++ b/packages/console/src/ANSICode/format.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { format } from './format.js'; describe(format, () => { diff --git a/packages/console/src/ANSICode/format.ts b/packages/console/src/ANSICode/format.ts index abfe1c4a9f..8c78568605 100644 --- a/packages/console/src/ANSICode/format.ts +++ b/packages/console/src/ANSICode/format.ts @@ -9,6 +9,6 @@ * @param code a code suffix * @returns A formatted ANSI escape sequence. */ -export function format(args: number[], code: string): string { +export function format(args: Array, code: string): string { return `\u{1B}[${args.join(';')}${code}`; } diff --git a/packages/console/src/ANSICode/strip.spec.ts b/packages/console/src/ANSICode/strip.spec.ts index 48d7ffd3b5..252e44103b 100644 --- a/packages/console/src/ANSICode/strip.spec.ts +++ b/packages/console/src/ANSICode/strip.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { strip } from './strip.js'; describe(strip, () => { diff --git a/packages/console/src/ANSICode/style.spec.ts b/packages/console/src/ANSICode/style.spec.ts index 2a8bd6f23e..ae01f8c37a 100644 --- a/packages/console/src/ANSICode/style.spec.ts +++ b/packages/console/src/ANSICode/style.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { style } from './style.js'; describe(style, () => { diff --git a/packages/console/src/ANSICode/style.ts b/packages/console/src/ANSICode/style.ts index c55e8e1225..ecf915f410 100644 --- a/packages/console/src/ANSICode/style.ts +++ b/packages/console/src/ANSICode/style.ts @@ -9,14 +9,14 @@ export interface Style { color: Color; /** - * The font weight to apply to the string. + * The font style to apply to the string. */ - fontWeight: FontWeight; + fontStyle: FontStyle; /** - * The font style to apply to the string. + * The font weight to apply to the string. */ - fontStyle: FontStyle; + fontWeight: FontWeight; } const andThen = diff --git a/packages/console/src/ANSICode/wrap.spec.ts b/packages/console/src/ANSICode/wrap.spec.ts index 8f55457cbe..83c8989487 100644 --- a/packages/console/src/ANSICode/wrap.spec.ts +++ b/packages/console/src/ANSICode/wrap.spec.ts @@ -1,5 +1,6 @@ /* cSpell:disable */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { wrap } from './wrap.js'; describe(wrap, () => { diff --git a/packages/console/src/ANSICode/wrap.ts b/packages/console/src/ANSICode/wrap.ts index a1978a4bf1..8037652f0f 100644 --- a/packages/console/src/ANSICode/wrap.ts +++ b/packages/console/src/ANSICode/wrap.ts @@ -1,7 +1,7 @@ /* cSpell: ignore mfoo */ import { format } from './format.js'; -const identity = Object.assign((_: string): string => _, { open: undefined, close: undefined }); +const identity = Object.assign((_: string): string => _, { close: undefined, open: undefined }); export interface ANSIWrapper { /** @@ -10,14 +10,14 @@ export interface ANSIWrapper { (text: string): string; /** - * Open tag + * Close tag */ - open: string | undefined; + close: string | undefined; /** - * Close tag + * Open tag */ - close: string | undefined; + open: string | undefined; } /** @@ -32,14 +32,14 @@ export interface ANSIWrapper { * @param code A string representing the ANSI code suffix. * @returns A function that takes a string and returns it wrapped with the specified ANSI codes. */ -export function wrap(open: number[], close: number, code: string): ANSIWrapper { +export function wrap(open: Array, close: number, code: string): ANSIWrapper { if (open.length === 0) return identity; const openTag = format(open, code); const closeTag = format([close], code); const regexp = new RegExp(String.raw`\x1b\[${close}m`, 'g'); return Object.assign((text: string): string => `${openTag}${text.replace(regexp, openTag)}${closeTag}`, { - open: openTag, close: closeTag, + open: openTag, }); } diff --git a/packages/console/src/Console.spec.ts b/packages/console/src/Console.spec.ts index 10925f20e1..eda798c115 100644 --- a/packages/console/src/Console.spec.ts +++ b/packages/console/src/Console.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { Console } from './Console.js'; describe('Console', () => { @@ -12,7 +13,7 @@ describe('Console', () => { [Console.info, 'info'], [Console.warn, 'warn'], [Console.error, 'error'], - ] as [typeof Console.log, 'log' | 'warn' | 'info' | 'error'][])('%p', (task, consoleProperty) => { + ] as Array<[typeof Console.log, 'error' | 'info' | 'log' | 'warn']>)('%p', (task, consoleProperty) => { it(`should call console.${consoleProperty}`, async () => { vi.spyOn(console, consoleProperty).mockImplementation(doNothing); expectTask(task('a', 'b')).toResolveSync(undefined); diff --git a/packages/console/src/Console.ts b/packages/console/src/Console.ts index a763427116..dcc88d985a 100644 --- a/packages/console/src/Console.ts +++ b/packages/console/src/Console.ts @@ -1,9 +1,9 @@ import { debug } from './Console/debug.js'; -import { log } from './Console/log.js'; -import { info } from './Console/info.js'; -import { warn } from './Console/warn.js'; import { error } from './Console/error.js'; +import { info } from './Console/info.js'; import { isWeb } from './Console/isWeb.js'; +import { log } from './Console/log.js'; +import { warn } from './Console/warn.js'; /** * A collection of functions to write in stdin (NodeJS) or WebConsole (browser) @@ -12,9 +12,9 @@ import { isWeb } from './Console/isWeb.js'; */ export const Console = { debug, - log, - info, - warn, error, + info, isWeb, + log, + warn, }; diff --git a/packages/console/src/Console/debug.ts b/packages/console/src/Console/debug.ts index 6752accac1..edb7c7e2f7 100644 --- a/packages/console/src/Console/debug.ts +++ b/packages/console/src/Console/debug.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { write } from './write.js'; /** @@ -10,6 +11,6 @@ import { write } from './write.js'; * ``` * @param parameters an array of values to be logged */ -export function debug(...parameters: [required: unknown, ...optionalParameters: unknown[]]): Task { +export function debug(...parameters: [required: unknown, ...optionalParameters: Array]): Task { return write('debug', parameters); } diff --git a/packages/console/src/Console/error.ts b/packages/console/src/Console/error.ts index d13789919a..33ef799224 100644 --- a/packages/console/src/Console/error.ts +++ b/packages/console/src/Console/error.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { write } from './write.js'; /** @@ -10,6 +11,6 @@ import { write } from './write.js'; * ``` * @param parameters an array of values to be logged */ -export function error(...parameters: [required: unknown, ...optionalParameters: unknown[]]): Task { +export function error(...parameters: [required: unknown, ...optionalParameters: Array]): Task { return write('error', parameters); } diff --git a/packages/console/src/Console/info.ts b/packages/console/src/Console/info.ts index 526ede6fbb..86f8fd979b 100644 --- a/packages/console/src/Console/info.ts +++ b/packages/console/src/Console/info.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { write } from './write.js'; /** @@ -10,6 +11,6 @@ import { write } from './write.js'; * ``` * @param parameters an array of values to be logged */ -export function info(...parameters: [required: unknown, ...optionalParameters: unknown[]]): Task { +export function info(...parameters: [required: unknown, ...optionalParameters: Array]): Task { return write('info', parameters); } diff --git a/packages/console/src/Console/isWeb.ts b/packages/console/src/Console/isWeb.ts index a9f016cdb2..2cb163749d 100644 --- a/packages/console/src/Console/isWeb.ts +++ b/packages/console/src/Console/isWeb.ts @@ -1,8 +1,8 @@ export function isWeb(): boolean { const consoleWithStreams = console as Partial<{ - _stdout: WritableStream; _stderr: WritableStream; + _stdout: WritableStream; }>; - const { _stdout: stdout, _stderr: stderr } = consoleWithStreams; + const { _stderr: stderr, _stdout: stdout } = consoleWithStreams; return stderr == null || stdout == null; } diff --git a/packages/console/src/Console/log.ts b/packages/console/src/Console/log.ts index 40f0212b5b..5b8af37793 100644 --- a/packages/console/src/Console/log.ts +++ b/packages/console/src/Console/log.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { write } from './write.js'; /** @@ -10,6 +11,6 @@ import { write } from './write.js'; * ``` * @param parameters an array of values to be logged */ -export function log(...parameters: [required: unknown, ...optionalParameters: unknown[]]): Task { +export function log(...parameters: [required: unknown, ...optionalParameters: Array]): Task { return write('log', parameters); } diff --git a/packages/console/src/Console/warn.ts b/packages/console/src/Console/warn.ts index d9c2828bf1..dd039d8a46 100644 --- a/packages/console/src/Console/warn.ts +++ b/packages/console/src/Console/warn.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { write } from './write.js'; /** @@ -10,6 +11,6 @@ import { write } from './write.js'; * ``` * @param parameters an array of values to be logged */ -export function warn(...parameters: [required: unknown, ...optionalParameters: unknown[]]): Task { +export function warn(...parameters: [required: unknown, ...optionalParameters: Array]): Task { return write('warn', parameters); } diff --git a/packages/console/src/Console/write.ts b/packages/console/src/Console/write.ts index 55fe98a0b4..005a0c54d8 100644 --- a/packages/console/src/Console/write.ts +++ b/packages/console/src/Console/write.ts @@ -1,9 +1,10 @@ import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; export function write( - method: 'debug' | 'log' | 'info' | 'warn' | 'error', - message: [required: unknown, ...optionalParameters: unknown[]], + method: 'debug' | 'error' | 'info' | 'log' | 'warn', + message: [required: unknown, ...optionalParameters: Array], ): Task { return taskFrom(({ resolve }) => resolve(console[method](...message))); } diff --git a/packages/console/src/index.spec.ts b/packages/console/src/index.spec.ts index c6216db189..639363db6c 100644 --- a/packages/console/src/index.spec.ts +++ b/packages/console/src/index.spec.ts @@ -1,12 +1,13 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { - expect(Object.keys(Module)).toMatchInlineSnapshot(` + expect(Object.keys(Module).toSorted((left, right) => left.localeCompare(right))).toMatchInlineSnapshot(` [ - "Console", "ANSICode", + "Console", ] `); }); diff --git a/packages/console/src/index.ts b/packages/console/src/index.ts index 123f987641..882e068a09 100644 --- a/packages/console/src/index.ts +++ b/packages/console/src/index.ts @@ -1,2 +1,2 @@ -export * from './Console.js'; export * from './ANSICode.js'; +export * from './Console.js'; diff --git a/packages/core-type/src/AnyFunction.ts b/packages/core-type/src/AnyFunction.ts index b269687b51..92704e70ca 100644 --- a/packages/core-type/src/AnyFunction.ts +++ b/packages/core-type/src/AnyFunction.ts @@ -8,4 +8,4 @@ * } * ``` */ -export type AnyFunction = (...args: any[]) => any; +export type AnyFunction = (...args: Array) => any; diff --git a/packages/core-type/src/Awaitable.ts b/packages/core-type/src/Awaitable.ts index ea10735880..55cf0303dd 100644 --- a/packages/core-type/src/Awaitable.ts +++ b/packages/core-type/src/Awaitable.ts @@ -4,4 +4,4 @@ * * @see https://stackoverflow.com/a/56129545 */ -export type Awaitable = T | PromiseLike; +export type Awaitable = PromiseLike | T; diff --git a/packages/core-type/src/EmptyObject.test-d.ts b/packages/core-type/src/EmptyObject.test-d.ts index 7c05ed0334..3dd66d3a88 100644 --- a/packages/core-type/src/EmptyObject.test-d.ts +++ b/packages/core-type/src/EmptyObject.test-d.ts @@ -1,7 +1,8 @@ -/* eslint-disable ts/no-unused-vars */ -import { assertType } from './assertType.js'; +/* eslint-disable unused-imports/no-unused-vars */ import type { EmptyObject } from './EmptyObject.js'; +import { assertType } from './assertType.js'; + declare let foo: EmptyObject; // @ts-expect-error For array diff --git a/packages/core-type/src/JSONArray.test-d.ts b/packages/core-type/src/JSONArray.test-d.ts index 7bd38965bc..d0f31dce97 100644 --- a/packages/core-type/src/JSONArray.test-d.ts +++ b/packages/core-type/src/JSONArray.test-d.ts @@ -1,5 +1,6 @@ +/* eslint-disable unused-imports/no-unused-vars */ /* eslint-disable ts/ban-ts-comment */ -/* eslint-disable ts/no-unused-vars */ + import type { JSONArray } from './JSONArray.js'; // @ts-expect-error diff --git a/packages/core-type/src/JSONObject.test-d.ts b/packages/core-type/src/JSONObject.test-d.ts index fe74a452e5..abe0a08d51 100644 --- a/packages/core-type/src/JSONObject.test-d.ts +++ b/packages/core-type/src/JSONObject.test-d.ts @@ -1,5 +1,5 @@ /* eslint-disable ts/ban-ts-comment */ -/* eslint-disable ts/no-unused-vars */ +/* eslint-disable unused-imports/no-unused-vars */ import type { JSONObject } from './JSONObject.js'; // @ts-expect-error diff --git a/packages/core-type/src/JSONObject.ts b/packages/core-type/src/JSONObject.ts index 6b01dd6bd7..15fc9a9b76 100644 --- a/packages/core-type/src/JSONObject.ts +++ b/packages/core-type/src/JSONObject.ts @@ -1,3 +1,5 @@ +/* eslint-disable ts/consistent-indexed-object-style */ +/* eslint-disable ts/consistent-type-definitions */ import type { JSONValue } from './JSONValue.js'; /** diff --git a/packages/core-type/src/JSONPrimitive.test-d.ts b/packages/core-type/src/JSONPrimitive.test-d.ts index 4e1c4f7e4f..8f132c6e2e 100644 --- a/packages/core-type/src/JSONPrimitive.test-d.ts +++ b/packages/core-type/src/JSONPrimitive.test-d.ts @@ -1,4 +1,4 @@ -/* eslint-disable ts/no-unused-vars */ +/* eslint-disable unused-imports/no-unused-vars */ import type { JSONPrimitive } from './JSONPrimitive.js'; const num: JSONPrimitive = 1; diff --git a/packages/core-type/src/JSONPrimitive.ts b/packages/core-type/src/JSONPrimitive.ts index e0fe9e6c46..37e76304c8 100644 --- a/packages/core-type/src/JSONPrimitive.ts +++ b/packages/core-type/src/JSONPrimitive.ts @@ -6,4 +6,4 @@ * - number * - string */ -export type JSONPrimitive = null | boolean | number | string; +export type JSONPrimitive = boolean | null | number | string; diff --git a/packages/core-type/src/JSONValue.ts b/packages/core-type/src/JSONValue.ts index 68af0006be..05dc1e2095 100644 --- a/packages/core-type/src/JSONValue.ts +++ b/packages/core-type/src/JSONValue.ts @@ -5,4 +5,4 @@ import type { JSONPrimitive } from './JSONPrimitive.js'; /** * Any valid JSON value */ -export type JSONValue = JSONPrimitive | JSONArray | JSONObject; +export type JSONValue = JSONArray | JSONObject | JSONPrimitive; diff --git a/packages/core-type/src/Nullable.test-d.ts b/packages/core-type/src/Nullable.test-d.ts index a6ed62a920..a75f8b8ec5 100644 --- a/packages/core-type/src/Nullable.test-d.ts +++ b/packages/core-type/src/Nullable.test-d.ts @@ -1,4 +1,5 @@ -import { assertType } from './assertType.js'; import type { Nullable } from './Nullable.js'; -assertType>(true); +import { assertType } from './assertType.js'; + +assertType>(true); diff --git a/packages/core-type/src/Nullable.ts b/packages/core-type/src/Nullable.ts index 0fdbc87e26..20ca1364b1 100644 --- a/packages/core-type/src/Nullable.ts +++ b/packages/core-type/src/Nullable.ts @@ -10,4 +10,4 @@ * } * ``` */ -export type Nullable = null | undefined | T; +export type Nullable = null | T | undefined; diff --git a/packages/core-type/src/ObjectLike.test-d.ts b/packages/core-type/src/ObjectLike.test-d.ts index 8b5bb4d854..ee69dc27fd 100644 --- a/packages/core-type/src/ObjectLike.test-d.ts +++ b/packages/core-type/src/ObjectLike.test-d.ts @@ -1,4 +1,4 @@ -/* eslint-disable ts/no-unused-vars */ +/* eslint-disable unused-imports/no-unused-vars */ import type { ObjectLike } from './ObjectLike.js'; // @ts-expect-error Number diff --git a/packages/core-type/src/ObjectLike.ts b/packages/core-type/src/ObjectLike.ts index 875bf872e2..fc601c29ab 100644 --- a/packages/core-type/src/ObjectLike.ts +++ b/packages/core-type/src/ObjectLike.ts @@ -6,4 +6,4 @@ * - object (null is excluded) * - function */ -export type ObjectLike = symbol | object | Function; +export type ObjectLike = Function | object | symbol; diff --git a/packages/core-type/src/PartialKeys.test-d.ts b/packages/core-type/src/PartialKeys.test-d.ts index 24fddba6ee..05b20ec2a0 100644 --- a/packages/core-type/src/PartialKeys.test-d.ts +++ b/packages/core-type/src/PartialKeys.test-d.ts @@ -1,6 +1,7 @@ -import { assertType } from './assertType.js'; import type { PartialKeys } from './PartialKeys.js'; -type PartialObject = PartialKeys<{ foo: boolean; bar: string; optional?: number }, 'bar'>; +import { assertType } from './assertType.js'; + +type PartialObject = PartialKeys<{ bar: string; foo: boolean; optional?: number }, 'bar'>; -assertType(true); +assertType(true); diff --git a/packages/core-type/src/Pretty.test-d.ts b/packages/core-type/src/Pretty.test-d.ts index 58053f44bf..b8355c4193 100644 --- a/packages/core-type/src/Pretty.test-d.ts +++ b/packages/core-type/src/Pretty.test-d.ts @@ -1,4 +1,5 @@ -import { assertType } from './assertType.js'; import type { Pretty } from './Pretty.js'; -assertType<{ foo: number; bar: string }, Pretty<{ foo: number } & { bar: string }>>(true); +import { assertType } from './assertType.js'; + +assertType<{ bar: string; foo: number }, Pretty<{ bar: string } & { foo: number }>>(true); diff --git a/packages/core-type/src/Primitive.test-d.ts b/packages/core-type/src/Primitive.test-d.ts index f89fa51b69..3e6a5e55e2 100644 --- a/packages/core-type/src/Primitive.test-d.ts +++ b/packages/core-type/src/Primitive.test-d.ts @@ -1,4 +1,4 @@ -/* eslint-disable ts/no-unused-vars */ +/* eslint-disable unused-imports/no-unused-vars */ import type { Primitive } from './Primitive.js'; const num: Primitive = 1; diff --git a/packages/core-type/src/Primitive.ts b/packages/core-type/src/Primitive.ts index fdcdf995ec..68f6e71fde 100644 --- a/packages/core-type/src/Primitive.ts +++ b/packages/core-type/src/Primitive.ts @@ -12,4 +12,4 @@ * * @see https://developer.mozilla.org/en-US/docs/Glossary/Primitive */ -export type Primitive = string | number | symbol | bigint | boolean | null | undefined; +export type Primitive = bigint | boolean | null | number | string | symbol | undefined; diff --git a/packages/core-type/src/RequiredKeys.test-d.ts b/packages/core-type/src/RequiredKeys.test-d.ts index 80c35a96ce..f66d31b65a 100644 --- a/packages/core-type/src/RequiredKeys.test-d.ts +++ b/packages/core-type/src/RequiredKeys.test-d.ts @@ -1,6 +1,7 @@ -import { assertType } from './assertType.js'; import type { RequiredKeys } from './RequiredKeys.js'; -type RequiredObject = RequiredKeys<{ foo?: boolean; bar?: string; optional: number }, 'bar'>; +import { assertType } from './assertType.js'; + +type RequiredObject = RequiredKeys<{ bar?: string; foo?: boolean; optional: number }, 'bar'>; -assertType(true); +assertType(true); diff --git a/packages/core-type/src/Tag.test-d.ts b/packages/core-type/src/Tag.test-d.ts index cd6afe5a1b..2717742305 100644 --- a/packages/core-type/src/Tag.test-d.ts +++ b/packages/core-type/src/Tag.test-d.ts @@ -1,5 +1,6 @@ -import { assertType } from './assertType.js'; import type { Tag } from './Tag.js'; +import { assertType } from './assertType.js'; + assertType, Tag<'Bar'>>(false); assertType, number>(false); diff --git a/packages/core-type/src/Tag.ts b/packages/core-type/src/Tag.ts index 4f67c2f6c0..99253a6d9b 100644 --- a/packages/core-type/src/Tag.ts +++ b/packages/core-type/src/Tag.ts @@ -13,8 +13,6 @@ * } * ``` */ -export type Tag = { - readonly '@@tag': { - readonly [K in T]: Value; - }; -}; +export interface Tag { + readonly '@@tag': Readonly>; +} diff --git a/packages/core-type/src/TestingLibrary.ts b/packages/core-type/src/TestingLibrary.ts index 84f6dbe701..2911518bba 100644 --- a/packages/core-type/src/TestingLibrary.ts +++ b/packages/core-type/src/TestingLibrary.ts @@ -1,27 +1,39 @@ /* eslint-disable ts/no-unsafe-function-type */ import type { Awaitable } from './Awaitable.js'; +export type ExpectAssertion = ExpectAssertionObject & { + not: ExpectAssertionObject; +}; + export interface ExpectAssertionObject { - toBeLessThan: (anyValue: any) => void; - toBeGreaterThan: (anyValue: any) => void; toBe: (anyValue: unknown) => void; + toBeGreaterThan: (anyValue: any) => void; + toBeLessThan: (anyValue: any) => void; toEqual(expected: unknown): void; - toHaveProperty(property: string | (string | number)[], value: unknown): void; + toHaveProperty(property: Array | string, value: unknown): void; toThrow(error: unknown): void; } -export type ExpectAssertion = ExpectAssertionObject & { - not: ExpectAssertionObject; -}; - export interface ExpectFunction { (value: unknown): ExpectAssertion & { - resolves: ExpectAssertion; rejects: ExpectAssertion; + resolves: ExpectAssertion; }; fail: (message: string) => never; } +export interface TestEachFunction { + >(cases: ReadonlyArray): TestEachFunctionReturn; + >(cases: ReadonlyArray): TestEachFunctionReturn>; + (cases: ReadonlyArray): TestEachFunctionReturn>; + (...args: [TemplateStringsArray, ...any]): TestEachFunctionReturn>; +} + +export interface TestEachFunctionReturn> { + (name: Function | string, fn: (...args: T) => Awaitable /* , options?: number | TestCollectorOptions */): void; + (name: Function | string, /* , options: TestCollectorOptions, */ fn: (...args: T) => Awaitable): void; +} + /** * Common interface for testing libraries like jest and vitest */ @@ -30,23 +42,12 @@ export interface TestingLibrary { (description: string, fn: () => void): void; todo: (description: string, fn: () => void) => void; }; + expect: ExpectFunction; it: { (description: string, fn: () => void): void; - todo: (description: string, fn: () => void) => void; each: TestEachFunction; + todo: (description: string, fn: () => void) => void; }; - expect: ExpectFunction; -} - -export interface TestEachFunctionReturn { - (name: string | Function, fn: (...args: T) => Awaitable /* , options?: number | TestCollectorOptions */): void; - (name: string | Function, /* , options: TestCollectorOptions, */ fn: (...args: T) => Awaitable): void; -} -export interface TestEachFunction { - (cases: ReadonlyArray): TestEachFunctionReturn; - >(cases: ReadonlyArray): TestEachFunctionReturn>; - (cases: ReadonlyArray): TestEachFunctionReturn; - (...args: [TemplateStringsArray, ...any]): TestEachFunctionReturn; } type ExtractEachCallbackArgs> = { diff --git a/packages/core-type/src/ValueOf.test-d.ts b/packages/core-type/src/ValueOf.test-d.ts index 8424b8af1f..aa17c1e8fa 100644 --- a/packages/core-type/src/ValueOf.test-d.ts +++ b/packages/core-type/src/ValueOf.test-d.ts @@ -1,7 +1,8 @@ -import { assertType } from './assertType.js'; import type { ValueOf } from './ValueOf.js'; -type GivenObject = { Foo: boolean; Bar: 'bar'; Baz: 'baz' }; +import { assertType } from './assertType.js'; + +interface GivenObject { Bar: 'bar'; Baz: 'baz'; Foo: boolean } assertType, 'bar' | 'baz' | boolean>(true); -assertType, 'bar' | 'baz'>(true); +assertType, 'bar' | 'baz'>(true); diff --git a/packages/core-type/src/assertType.ts b/packages/core-type/src/assertType.ts index 3b271eecb5..f2721addb9 100644 --- a/packages/core-type/src/assertType.ts +++ b/packages/core-type/src/assertType.ts @@ -1,3 +1,18 @@ +type AnyToBrand = IsAny extends true ? { __assertTypeAny__: undefined } : T; + +type DeepMakeRequiredForIsExact = { + [P in keyof T]-?: DeepMakeRequiredForIsExact>; +}; +type IsAny = 0 extends 1 & T ? true : false; +type IsExact = + TupleMatches, AnyToBrand> extends true + ? TupleMatches, DeepMakeRequiredForIsExact> extends true // catch optional properties + ? true + : false + : false; +type Matches = T extends U ? (U extends T ? true : false) : false; +type TupleMatches = Matches<[T], [U]> extends true ? true : false; + /** * Raise a compile error when `Actual` is not strictly equal to `Expected`. * This is a type helper and does nothing at run time. @@ -11,18 +26,3 @@ * @param _shouldBeEqual an inferred value */ export function assertType(_shouldBeEqual: IsExact): void {} - -type IsExact = - TupleMatches, AnyToBrand> extends true - ? TupleMatches, DeepMakeRequiredForIsExact> extends true // catch optional properties - ? true - : false - : false; -type DeepMakeRequiredForIsExact = { - [P in keyof T]-?: DeepMakeRequiredForIsExact>; -}; -type IsAny = 0 extends 1 & T ? true : false; -type TupleMatches = Matches<[T], [U]> extends true ? true : false; -type Matches = T extends U ? (U extends T ? true : false) : false; - -type AnyToBrand = IsAny extends true ? { __assertTypeAny__: undefined } : T; diff --git a/packages/core-type/src/index.test-d.ts b/packages/core-type/src/index.test-d.ts index b4435d0a63..5e3361794a 100644 --- a/packages/core-type/src/index.test-d.ts +++ b/packages/core-type/src/index.test-d.ts @@ -1,4 +1,4 @@ -/* eslint-disable ts/no-unused-vars */ +/* eslint-disable unused-imports/no-unused-imports */ // Test import import type { diff --git a/packages/core/README.md b/packages/core/README.md index 72d653a871..cc47422e3d 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -38,6 +38,11 @@ npm install @w5s/core ```ts import { Result } from '@w5s/core'; +export function main() { + const parsed = parseNumber('1.1'); // Result.Ok(1.1) + return Result.map(parsed, (amount) => amount + 2); // Result.Ok(3.1) +} + function parseNumber(expr: string) { const parsed = Number(expr); @@ -47,11 +52,6 @@ function parseNumber(expr: string) { return Number.isNaN(parsed) ? Result.Ok(parsed) : Result.Error('NotANumber'); } -export function main() { - const parsed = parseNumber('1.1'); // Result.Ok(1.1) - return Result.map(parsed, (amount) => amount + 2); // Result.Ok(3.1) -} - // runTask is impure and should be put at the edge of the program void main(); // prints { _: 'Result/Ok', value: 3.1 } ``` diff --git a/packages/core/example/.eslintrc.cjs b/packages/core/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/core/example/.eslintrc.cjs +++ b/packages/core/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/core/example/usage.ts b/packages/core/example/usage.ts index 8c11e673cc..03ab32ac61 100644 --- a/packages/core/example/usage.ts +++ b/packages/core/example/usage.ts @@ -1,5 +1,10 @@ import { Result } from '@w5s/core'; +export function main() { + const parsed = parseNumber('1.1'); // Result.Ok(1.1) + return Result.map(parsed, (amount) => amount + 2); // Result.Ok(3.1) +} + function parseNumber(expr: string) { const parsed = Number(expr); @@ -9,10 +14,5 @@ function parseNumber(expr: string) { return Number.isNaN(parsed) ? Result.Ok(parsed) : Result.Error('NotANumber'); } -export function main() { - const parsed = parseNumber('1.1'); // Result.Ok(1.1) - return Result.map(parsed, (amount) => amount + 2); // Result.Ok(3.1) -} - // runTask is impure and should be put at the edge of the program void main(); // prints { _: 'Result/Ok', value: 3.1 } diff --git a/packages/core/src/Boolean.spec.ts b/packages/core/src/Boolean.spec.ts index 2a7614cb1c..fb8b9b6e70 100644 --- a/packages/core/src/Boolean.spec.ts +++ b/packages/core/src/Boolean.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect } from 'vitest'; -import { Type } from './Type.js'; +import { describe, expect, it } from 'vitest'; + import { Boolean } from './Boolean.js'; import { BooleanComparable } from './Boolean/BooleanComparable.js'; import { BooleanNot } from './Boolean/BooleanNot.js'; +import { Type } from './Type.js'; describe('Boolean', () => { it('is an alias to functions', () => { diff --git a/packages/core/src/Boolean/BooleanComparable.spec.ts b/packages/core/src/Boolean/BooleanComparable.spec.ts index f4145ebcbb..92cbbdbba6 100644 --- a/packages/core/src/Boolean/BooleanComparable.spec.ts +++ b/packages/core/src/Boolean/BooleanComparable.spec.ts @@ -1,13 +1,14 @@ import { describe } from 'vitest'; + import { describeComparable } from '../Testing.js'; import { BooleanComparable } from './BooleanComparable.js'; describe('BooleanComparable', () => { describeComparable(BooleanComparable, { - ordered: () => [false, true], equivalent: () => [ [true, true], [false, false], ], + ordered: () => [false, true], }); }); diff --git a/packages/core/src/Boolean/BooleanNot.spec.ts b/packages/core/src/Boolean/BooleanNot.spec.ts index e055f845bc..d809eecd5e 100644 --- a/packages/core/src/Boolean/BooleanNot.spec.ts +++ b/packages/core/src/Boolean/BooleanNot.spec.ts @@ -1,4 +1,5 @@ import { describe } from 'vitest'; + import { describeNot } from '../Testing.js'; import { BooleanNot } from './BooleanNot.js'; diff --git a/packages/core/src/Boolean/compare.ts b/packages/core/src/Boolean/compare.ts index 95e1712200..6e179e45af 100644 --- a/packages/core/src/Boolean/compare.ts +++ b/packages/core/src/Boolean/compare.ts @@ -1,4 +1,5 @@ import type { Order } from '../Order.js'; + import { primitive } from '../Order/primitive.js'; export const compare: Order = primitive; diff --git a/packages/core/src/Bounded.ts b/packages/core/src/Bounded.ts index 99f3629814..751e5725bf 100644 --- a/packages/core/src/Bounded.ts +++ b/packages/core/src/Bounded.ts @@ -3,26 +3,26 @@ */ export interface Bounded { /** - * Minimum value for this type + * Maximum value for this type * * @example * ```typescript * const anyNumber: number - * anyNumber > Number.minValue // true + * anyNumber < Number.maxValue // true * ``` * @category Bound */ - readonly minValue: T; + readonly maxValue: T; /** - * Maximum value for this type + * Minimum value for this type * * @example * ```typescript * const anyNumber: number - * anyNumber < Number.maxValue // true + * anyNumber > Number.minValue // true * ``` * @category Bound */ - readonly maxValue: T; + readonly minValue: T; } diff --git a/packages/core/src/Callable.spec.ts b/packages/core/src/Callable.spec.ts index 751e630eaa..52e67ba9c2 100644 --- a/packages/core/src/Callable.spec.ts +++ b/packages/core/src/Callable.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Callable } from './Callable.js'; describe(Callable, () => { diff --git a/packages/core/src/Callable.ts b/packages/core/src/Callable.ts index 1518ba5598..71d8f27eb8 100644 --- a/packages/core/src/Callable.ts +++ b/packages/core/src/Callable.ts @@ -1,10 +1,6 @@ import type { AnyFunction } from '@w5s/core-type'; -import { Symbol } from './Symbol.js'; -/** - * A callable function with callable interface - */ -export type CallableFunction> = T[typeof Callable.symbol] & T; +import { Symbol } from './Symbol.js'; /** * Callable interface @@ -18,6 +14,11 @@ export interface Callable { [Callable.symbol]: F; } +/** + * A callable function with callable interface + */ +export type CallableFunction> = T & T[typeof Callable.symbol]; + /** * @namespace */ diff --git a/packages/core/src/Char.spec.ts b/packages/core/src/Char.spec.ts index 10c0f680f0..56acd16545 100644 --- a/packages/core/src/Char.spec.ts +++ b/packages/core/src/Char.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Char } from './Char.js'; -import { Char as CharType } from './Type/Char.js'; -import { CharComparable } from './Char/CharComparable.js'; import { CharBounded } from './Char/CharBounded.js'; -import { fromCodePoint } from './Char/fromCodePoint.js'; +import { CharComparable } from './Char/CharComparable.js'; import { CharIndexable } from './Char/CharIndexable.js'; +import { fromCodePoint } from './Char/fromCodePoint.js'; +import { Char as CharType } from './Type/Char.js'; describe(Char, () => { it('is an alias to functions', () => { diff --git a/packages/core/src/Char.ts b/packages/core/src/Char.ts index d2e9e8fff8..b2d8f30b7d 100644 --- a/packages/core/src/Char.ts +++ b/packages/core/src/Char.ts @@ -1,9 +1,9 @@ -import { Char as CharType } from './Type/Char.js'; import { Callable } from './Callable.js'; -import { CharComparable } from './Char/CharComparable.js'; import { CharBounded } from './Char/CharBounded.js'; +import { CharComparable } from './Char/CharComparable.js'; import { CharIndexable } from './Char/CharIndexable.js'; import { fromCodePoint } from './Char/fromCodePoint.js'; +import { Char as CharType } from './Type/Char.js'; /** * Character value diff --git a/packages/core/src/Char/CharBounded.spec.ts b/packages/core/src/Char/CharBounded.spec.ts index b3b69cb648..57937e83cf 100644 --- a/packages/core/src/Char/CharBounded.spec.ts +++ b/packages/core/src/Char/CharBounded.spec.ts @@ -1,6 +1,7 @@ import { describe } from 'vitest'; -import { CharBounded } from './CharBounded.js'; + import { describeBounded } from '../Testing.js'; +import { CharBounded } from './CharBounded.js'; describe('CharBounded', () => { describeBounded(CharBounded, { diff --git a/packages/core/src/Char/CharComparable.spec.ts b/packages/core/src/Char/CharComparable.spec.ts index 20c0d83d56..133346d82f 100644 --- a/packages/core/src/Char/CharComparable.spec.ts +++ b/packages/core/src/Char/CharComparable.spec.ts @@ -1,13 +1,14 @@ import { describe } from 'vitest'; + import { describeComparable } from '../Testing.js'; import { CharComparable } from './CharComparable.js'; describe('CharComparable', () => { describeComparable(CharComparable, { - ordered: () => ['a', 'b', 'c'], equivalent: () => [ ['a', 'a'], ['b', 'b'], ], + ordered: () => ['a', 'b', 'c'], }); }); diff --git a/packages/core/src/Char/CharComparable.ts b/packages/core/src/Char/CharComparable.ts index 89d469ee46..130f3d802a 100644 --- a/packages/core/src/Char/CharComparable.ts +++ b/packages/core/src/Char/CharComparable.ts @@ -1,4 +1,5 @@ import type { Char } from '../Char.js'; + import { Comparable } from '../Comparable.js'; import { compare } from './compare.js'; diff --git a/packages/core/src/Char/CharIndexable.spec.ts b/packages/core/src/Char/CharIndexable.spec.ts index df7072b518..674187be05 100644 --- a/packages/core/src/Char/CharIndexable.spec.ts +++ b/packages/core/src/Char/CharIndexable.spec.ts @@ -1,7 +1,8 @@ import { describe } from 'vitest'; + +import { Char } from '../Char.js'; import { describeIndexable } from '../Testing.js'; import { CharIndexable } from './CharIndexable.js'; -import { Char } from '../Char.js'; describe('CharIndexable', () => { describeIndexable(CharIndexable, { diff --git a/packages/core/src/Char/CharIndexable.ts b/packages/core/src/Char/CharIndexable.ts index ff831f4468..0033f0d136 100644 --- a/packages/core/src/Char/CharIndexable.ts +++ b/packages/core/src/Char/CharIndexable.ts @@ -1,7 +1,7 @@ import { Indexable } from '../Indexable.js'; export const CharIndexable = Indexable({ - indexType: 'number', at: (index) => String.fromCodePoint(index), indexOf: (value) => value.codePointAt(0), + indexType: 'number', }); diff --git a/packages/core/src/Char/compare.ts b/packages/core/src/Char/compare.ts index 796fb426ad..136712e688 100644 --- a/packages/core/src/Char/compare.ts +++ b/packages/core/src/Char/compare.ts @@ -1,5 +1,6 @@ import type { Char } from '../Char.js'; import type { Order } from '../Order.js'; + import { primitive } from '../Order/primitive.js'; export const compare: Order = primitive; diff --git a/packages/core/src/Char/fromCodePoint.spec.ts b/packages/core/src/Char/fromCodePoint.spec.ts index 52e93f84bc..6ffe8d9bf0 100644 --- a/packages/core/src/Char/fromCodePoint.spec.ts +++ b/packages/core/src/Char/fromCodePoint.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { fromCodePoint } from './fromCodePoint.js'; describe(fromCodePoint, () => { diff --git a/packages/core/src/Char/fromCodePoint.ts b/packages/core/src/Char/fromCodePoint.ts index 51a20fa4c8..0bb8d3377d 100644 --- a/packages/core/src/Char/fromCodePoint.ts +++ b/packages/core/src/Char/fromCodePoint.ts @@ -10,6 +10,6 @@ import type { Char } from '../Char.js'; * @category Constructor * @param code an array of string codes */ -export function fromCodePoint(...code: number[]): Char { +export function fromCodePoint(...code: Array): Char { return globalThis.String.fromCodePoint(...code) as Char; } diff --git a/packages/core/src/Codec.spec.ts b/packages/core/src/Codec.spec.ts index 6d6544315f..4b94db2508 100644 --- a/packages/core/src/Codec.spec.ts +++ b/packages/core/src/Codec.spec.ts @@ -1,17 +1,18 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Codec } from './Codec.js'; import { decode } from './Codec/decode.js'; import { encode } from './Codec/encode.js'; -import { schema } from './Codec/schema.js'; import { lazy } from './Codec/lazy.js'; +import { schema } from './Codec/schema.js'; describe('Codec', () => { it('is an alias to functions', () => { expect(Codec).toEqual({ decode, encode, - schema, lazy, + schema, }); }); }); diff --git a/packages/core/src/Codec.ts b/packages/core/src/Codec.ts index 5b9e34b850..6b7430955d 100644 --- a/packages/core/src/Codec.ts +++ b/packages/core/src/Codec.ts @@ -1,10 +1,11 @@ -import type { Result } from './Result.js'; import type { JSONValue } from './JSON.js'; -import { CodecError } from './CodecError.js'; +import type { Result } from './Result.js'; + import { decode } from './Codec/decode.js'; import { encode } from './Codec/encode.js'; import { lazy } from './Codec/lazy.js'; import { schema } from './Codec/schema.js'; +import { CodecError } from './CodecError.js'; import { Symbol } from './Symbol.js'; export interface Codec { @@ -65,21 +66,21 @@ export const Codec = { schema, }; export namespace Codec { - export type TypeOf = V extends Codec ? Type : never; - export interface Context { /** - * Helper that returns a new Ok result + * Helper that returns a new Error result * - * @param value + * @param message */ - ok: (value: T) => Result; + error: (input: unknown, asType?: string) => Result; /** - * Helper that returns a new Error result + * Helper that returns a new Ok result * - * @param message + * @param value */ - error: (input: unknown, asType?: string) => Result; + ok: (value: T) => Result; } + + export type TypeOf = V extends Codec ? Type : never; } diff --git a/packages/core/src/Codec/decode.spec.ts b/packages/core/src/Codec/decode.spec.ts index fbd1dd5ef2..9619c008c9 100644 --- a/packages/core/src/Codec/decode.spec.ts +++ b/packages/core/src/Codec/decode.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; -import { decode } from './decode.js'; + import { Result } from '../Result.js'; import { Symbol } from '../Symbol.js'; +import { decode } from './decode.js'; describe(decode, () => { it('should call __encode__', () => { diff --git a/packages/core/src/Codec/decode.ts b/packages/core/src/Codec/decode.ts index d863e10e97..665851adc0 100644 --- a/packages/core/src/Codec/decode.ts +++ b/packages/core/src/Codec/decode.ts @@ -1,13 +1,10 @@ import type { Codec } from '../Codec.js'; import type { Result } from '../Result.js'; -import { Error } from '../Result/Error.js'; -import { Ok } from '../Result/Ok.js'; -import { CodecError } from '../CodecError.js'; import type { Symbol } from '../Symbol.js'; -function inspect(anyValue: unknown) { - return typeof anyValue === 'string' ? `"${anyValue}"` : String(anyValue); -} +import { CodecError } from '../CodecError.js'; +import { Error } from '../Result/Error.js'; +import { Ok } from '../Result/Ok.js'; /** * Returns a `Result` containing the decoded `input` @@ -23,13 +20,17 @@ function inspect(anyValue: unknown) { */ export function decode(codec: Pick, Symbol.decode>, input: unknown): Result { return codec.__decode__(input, { - ok: Ok as Codec.Context['ok'], error: (inputError, asType) => Error( new CodecError({ - message: `Cannot decode ${inspect(inputError)}${asType == null ? '' : ` as ${asType}`}`, input: inputError, + message: `Cannot decode ${inspect(inputError)}${asType == null ? '' : ` as ${asType}`}`, }), ), + ok: Ok as Codec.Context['ok'], }); } + +function inspect(anyValue: unknown) { + return typeof anyValue === 'string' ? `"${anyValue}"` : String(anyValue); +} diff --git a/packages/core/src/Codec/encode.spec.ts b/packages/core/src/Codec/encode.spec.ts index 8ada352eb7..05d76b8812 100644 --- a/packages/core/src/Codec/encode.spec.ts +++ b/packages/core/src/Codec/encode.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { encode } from './encode.js'; + import { Symbol } from '../Symbol.js'; +import { encode } from './encode.js'; describe(encode, () => { it('should call __encode__', () => { diff --git a/packages/core/src/Codec/lazy.spec.ts b/packages/core/src/Codec/lazy.spec.ts index 0c89c8f93d..f16b9814e4 100644 --- a/packages/core/src/Codec/lazy.spec.ts +++ b/packages/core/src/Codec/lazy.spec.ts @@ -1,20 +1,21 @@ import { describe } from 'vitest'; -import { lazy } from './lazy.js'; + import { Codec } from '../Codec.js'; import { Result } from '../Result.js'; -import { describeCodec } from '../Testing.js'; import { Symbol } from '../Symbol.js'; +import { describeCodec } from '../Testing.js'; +import { lazy } from './lazy.js'; describe(lazy, () => { const subject = lazy; const getCodec = (): Codec => ({ - [Symbol.encode]: (_) => `__${_}`, [Symbol.decode]: (_) => Result.Ok(String(_).slice(2)), - [Symbol.schema]: () => ({ type: 'string', format: 'test' }), + [Symbol.encode]: (_) => `__${_}`, + [Symbol.schema]: () => ({ format: 'test', type: 'string' }), }); describeCodec(subject(getCodec), () => ({ - encode: [['a', '__a']], decode: [['__a', Result.Ok('a')]], - schema: { type: 'string', format: 'test' }, + encode: [['a', '__a']], + schema: { format: 'test', type: 'string' }, })); }); diff --git a/packages/core/src/Codec/lazy.ts b/packages/core/src/Codec/lazy.ts index 964c123d6b..e2cfea8cf7 100644 --- a/packages/core/src/Codec/lazy.ts +++ b/packages/core/src/Codec/lazy.ts @@ -1,5 +1,6 @@ import type { Codec } from '../Codec.js'; import type { Option } from '../Option.js'; + import { Symbol } from '../Symbol.js'; import { decode } from './decode.js'; import { encode } from './encode.js'; diff --git a/packages/core/src/Codec/schema.spec.ts b/packages/core/src/Codec/schema.spec.ts index 3dbdeceff9..e0d5c61191 100644 --- a/packages/core/src/Codec/schema.spec.ts +++ b/packages/core/src/Codec/schema.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { schema } from './schema.js'; + import { Symbol } from '../Symbol.js'; +import { schema } from './schema.js'; describe(schema, () => { it('should call __schema__', () => { diff --git a/packages/core/src/CodecError.spec.ts b/packages/core/src/CodecError.spec.ts index 5c065959b1..f4a63fd58c 100644 --- a/packages/core/src/CodecError.spec.ts +++ b/packages/core/src/CodecError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; import { describeError } from '@w5s/error/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { CodecError } from './CodecError.js'; describe(CodecError, () => { - describeError({ describe, it, expect })(CodecError, { + describeError({ describe, expect, it })(CodecError, { defaultParameters: () => ({ input: 'some input' }), - expectedName: 'CodecError', expectedDefaultMessage: 'The encoding or decoding operation failed', + expectedName: 'CodecError', }); }); diff --git a/packages/core/src/CodecError.ts b/packages/core/src/CodecError.ts index 5d5514ee60..536650aee9 100644 --- a/packages/core/src/CodecError.ts +++ b/packages/core/src/CodecError.ts @@ -6,8 +6,8 @@ import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; * @category Constructor */ export class CodecError extends ErrorClass({ - errorName: 'CodecError', errorMessage: 'The encoding or decoding operation failed', + errorName: 'CodecError', })<{ /** * Input given for encoding/decoding diff --git a/packages/core/src/Comparable.spec.ts b/packages/core/src/Comparable.spec.ts index a288fa2456..d5d5816226 100644 --- a/packages/core/src/Comparable.spec.ts +++ b/packages/core/src/Comparable.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Comparable } from './Comparable.js'; describe('Comparable', () => { diff --git a/packages/core/src/Comparable.ts b/packages/core/src/Comparable.ts index aac0fa167d..03e767a58d 100644 --- a/packages/core/src/Comparable.ts +++ b/packages/core/src/Comparable.ts @@ -1,27 +1,27 @@ import type { Equal } from './Equal.js'; import type { Ordering } from './Ordering.js'; -export interface ComparableInterface { +/** + * Module interface for values that have total order + */ +export interface Comparable extends ComparableInterface, Equal { /** - * Return an {@link Ordering} that represents comparison result - * - * @see {@link Order} + * "Less than" operator * * @example * ```typescript * type T; * const TCompare: Comparable; - * const sorted = [3, 1, 1].sort(TCompare.compare); + * const smallerT: T; + * const greaterT: T; + * TCompare['<'](smallerT, smallerT); // false + * TCompare['<'](smallerT, greaterT); // true + * TCompare['<'](greaterT, smallerT); // false * ``` * @category Comparator */ - compare(this: void, left: T, right: T): Ordering; -} + '<'(this: void, left: T, right: T): boolean; -/** - * Module interface for values that have total order - */ -export interface Comparable extends Equal, ComparableInterface { /** * "Less than or equal to" operator * @@ -40,7 +40,7 @@ export interface Comparable extends Equal, ComparableInterface { '<='(this: void, left: T, right: T): boolean; /** - * "Less than" operator + * "Greater than" operator * * @example * ```typescript @@ -48,13 +48,13 @@ export interface Comparable extends Equal, ComparableInterface { * const TCompare: Comparable; * const smallerT: T; * const greaterT: T; - * TCompare['<'](smallerT, smallerT); // false - * TCompare['<'](smallerT, greaterT); // true - * TCompare['<'](greaterT, smallerT); // false + * TCompare['>'](smallerT, smallerT); // false + * TCompare['>'](smallerT, greaterT); // false + * TCompare['>'](greaterT, smallerT); // true * ``` * @category Comparator */ - '<'(this: void, left: T, right: T): boolean; + '>'(this: void, left: T, right: T): boolean; /** * "Greater than or equal to" operator @@ -74,24 +74,20 @@ export interface Comparable extends Equal, ComparableInterface { '>='(this: void, left: T, right: T): boolean; /** - * "Greater than" operator + * Clamp value between minValue and maxValue * * @example * ```typescript * type T; * const TCompare: Comparable; - * const smallerT: T; - * const greaterT: T; - * TCompare['>'](smallerT, smallerT); // false - * TCompare['>'](smallerT, greaterT); // false - * TCompare['>'](greaterT, smallerT); // true + * TCompare.clamp(value, min, max); // min if value < min, max if value > max, otherwise value itself * ``` * @category Comparator */ - '>'(this: void, left: T, right: T): boolean; + 'clamp'(this: void, value: T, minValue: T, maxValue: T): T; /** - * "minimum" operator + * "maximum" operator * * @example * ```typescript @@ -99,14 +95,14 @@ export interface Comparable extends Equal, ComparableInterface { * const TCompare: Comparable; * const smallerT: T; * const greaterT: T; - * TCompare.min(smallerT, greaterT); // smallerT + * TCompare.max(smallerT, greaterT); // greaterT * ``` * @category Comparator */ - 'min'(this: void, left: T, right: T): T; + 'max'(this: void, left: T, right: T): T; /** - * "maximum" operator + * "minimum" operator * * @example * ```typescript @@ -114,24 +110,28 @@ export interface Comparable extends Equal, ComparableInterface { * const TCompare: Comparable; * const smallerT: T; * const greaterT: T; - * TCompare.max(smallerT, greaterT); // greaterT + * TCompare.min(smallerT, greaterT); // smallerT * ``` * @category Comparator */ - 'max'(this: void, left: T, right: T): T; + 'min'(this: void, left: T, right: T): T; +} +export interface ComparableInterface { /** - * Clamp value between minValue and maxValue + * Return an {@link Ordering} that represents comparison result + * + * @see {@link Order} * * @example * ```typescript * type T; * const TCompare: Comparable; - * TCompare.clamp(value, min, max); // min if value < min, max if value > max, otherwise value itself + * const sorted = [3, 1, 1].sort(TCompare.compare); * ``` * @category Comparator */ - 'clamp'(this: void, value: T, minValue: T, maxValue: T): T; + compare(this: void, left: T, right: T): Ordering; } /** @@ -156,21 +156,21 @@ export function Comparable(properties: Comparable.Parameters): Comparable< const min = (left: T, right: T) => (compare(left, right) <= 0 ? left : right); const max = (left: T, right: T) => (compare(left, right) > 0 ? left : right); return { - compare, - equals, - '==': equals, '!=': (left: T, right: T) => compare(left, right) !== 0, '<': (left: T, right: T) => compare(left, right) < 0, '<=': (left: T, right: T) => compare(left, right) <= 0, + '==': equals, '>': (left: T, right: T) => compare(left, right) > 0, '>=': (left: T, right: T) => compare(left, right) >= 0, - min, - max, 'clamp': (value, minValue, maxValue) => min(max(value, minValue), maxValue), + compare, + equals, + max, + min, }; } export namespace Comparable { - export type Parameters = { + export interface Parameters { compare: (left: T, right: T) => Ordering; - }; + } } diff --git a/packages/core/src/Enum.spec.ts b/packages/core/src/Enum.spec.ts index 20e9eecc96..b153f4d5d6 100644 --- a/packages/core/src/Enum.spec.ts +++ b/packages/core/src/Enum.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Enum } from './Enum.js'; import { define } from './Enum/define.js'; import { keys } from './Enum/keys.js'; @@ -9,9 +10,9 @@ describe('Enum', () => { it('is an alias to functions', () => { expect(Enum).toEqual({ define, + enumKeys: Symbol.enumKeys, keys, values, - enumKeys: Symbol.enumKeys, }); }); }); diff --git a/packages/core/src/Enum.ts b/packages/core/src/Enum.ts index 1cfed13960..34aed6b810 100644 --- a/packages/core/src/Enum.ts +++ b/packages/core/src/Enum.ts @@ -1,42 +1,46 @@ +import type { Indexable } from './Indexable.js'; import type { Type } from './Type.js'; -import { Symbol } from './Symbol.js'; -import { keys } from './Enum/keys.js'; + import { define } from './Enum/define.js'; +import { keys } from './Enum/keys.js'; import { values } from './Enum/values.js'; -import type { Indexable } from './Indexable.js'; +import { Symbol } from './Symbol.js'; /** * @namespace */ export const Enum = { + define, + /** * Symbol for the property holding enum keys */ enumKeys: Symbol.enumKeys, - define, keys, values, }; export namespace Enum { - type ArrayValue = T extends ReadonlyArray ? V : never; - /** * Return enum keys of T */ export type KeyOf>> = ArrayValue; /** - * Return enum values of T + * Module containing methods for working with enum types */ - export type ValueOf>> = T[KeyOf]; + export interface Module = Record> + extends EnumLike, Indexable, Type.Module {} /** - * Module containing methods for working with enum types + * Return enum values of T */ - export interface Module = Record> - extends Type.Module, Indexable, EnumLike {} + export type ValueOf>> = T[KeyOf]; + + type ArrayValue = T extends ReadonlyArray ? V : never; } +export type Enum = Record> = Enum.Module> & T; + /** * Interface for objects that can be used as enums */ @@ -46,5 +50,3 @@ export interface EnumLike = Record; } - -export type Enum = Record> = T & Enum.Module>; diff --git a/packages/core/src/Enum/define.spec.ts b/packages/core/src/Enum/define.spec.ts index b2e4858d10..2df1d5763e 100644 --- a/packages/core/src/Enum/define.spec.ts +++ b/packages/core/src/Enum/define.spec.ts @@ -1,19 +1,21 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { describeCodec, describeIndexable, describeType } from '../Testing.js'; -import { define } from './define.js'; -import { Result } from '../Result.js'; -import { CodecError } from '../CodecError.js'; +import { describe, expect, it } from 'vitest'; + import type { Enum } from '../Enum.js'; -import { Symbol } from '../Symbol.js'; + +import { CodecError } from '../CodecError.js'; import { Option } from '../Option.js'; +import { Result } from '../Result.js'; +import { Symbol } from '../Symbol.js'; +import { describeCodec, describeIndexable, describeType } from '../Testing.js'; +import { define } from './define.js'; describe(define, () => { const MyEnumObject = define({ - typeName: 'MyEnumObject', - Foo: 'foo', Bar: 'bar', Baz: 'baz', + Foo: 'foo', + typeName: 'MyEnumObject', }); const MyEnum = { ...MyEnumObject, @@ -29,56 +31,56 @@ describe(define, () => { }, }; type MyEnum = Enum.ValueOf; - assertType(true); + assertType(true); type MyEnumKeys = Enum.KeyOf; - assertType(true); + assertType(true); it('returns a new type', () => { expect( define({ - Foo: 'foo', Bar: 'bar', Baz: 'baz', + Foo: 'foo', }), ).toEqual({ - Foo: 'foo', - Bar: 'bar', - Baz: 'baz', - typeName: expect.any(String), - hasInstance: expect.any(Function), - __schema__: expect.any(Function), __decode__: expect.any(Function), __encode__: expect.any(Function), + __schema__: expect.any(Function), asInstance: expect.any(Function), asString: expect.any(Function), - [Symbol.enumKeys]: ['Foo', 'Bar', 'Baz'], at: expect.any(Function), - indexType: 'number', + Bar: 'bar', + Baz: 'baz', + Foo: 'foo', + hasInstance: expect.any(Function), indexOf: expect.any(Function), + indexType: 'number', + inspect: Option.None, range: expect.any(Function), rangeSize: expect.any(Function), - inspect: Option.None, + [Symbol.enumKeys]: ['Bar', 'Baz', 'Foo'], + typeName: expect.any(String), }); }); it('generates a default typeName', () => { expect( define({ - Foo: 'foo', Bar: 'bar', Baz: 'baz', + Foo: 'foo', }), ).toEqual( expect.objectContaining({ - typeName: 'foo|bar|baz', + typeName: 'bar|baz|foo', }), ); }); describeType(MyEnumObject, () => ({ - typeName: 'MyEnumObject', instances: [MyEnumObject.Foo, MyEnumObject.Bar], notInstances: ['anything', null, undefined, MyEnumObject.hasInstance], + typeName: 'MyEnumObject', })); describeCodec(MyEnumObject, () => ({ decode: [ @@ -86,7 +88,7 @@ describe(define, () => { ['bar', Result.Ok(MyEnumObject.Bar)], [ 'foo_invalid', - Result.Error(new CodecError({ message: 'Cannot decode "foo_invalid" as MyEnumObject', input: 'foo_invalid' })), + Result.Error(new CodecError({ input: 'foo_invalid', message: 'Cannot decode "foo_invalid" as MyEnumObject' })), ], ], encode: [ @@ -94,19 +96,19 @@ describe(define, () => { [MyEnum.Bar, 'bar'], ], schema: { - enum: ['foo', 'bar', 'baz'], + enum: ['bar', 'baz', 'foo'], }, })); describeIndexable(MyEnumObject, { index: [ - [0, MyEnumObject.Foo], - [1, MyEnumObject.Bar], - [2, MyEnumObject.Baz], + [0, MyEnumObject.Bar], + [1, MyEnumObject.Baz], + [2, MyEnumObject.Foo], ], range: [ [MyEnumObject.Foo, MyEnumObject.Foo, [MyEnumObject.Foo]], - [MyEnumObject.Foo, MyEnumObject.Bar, [MyEnumObject.Foo, MyEnumObject.Bar]], - [MyEnumObject.Foo, MyEnumObject.Baz, [MyEnumObject.Foo, MyEnumObject.Bar, MyEnumObject.Baz]], + [MyEnumObject.Baz, MyEnumObject.Foo, [MyEnumObject.Baz, MyEnumObject.Foo]], + [MyEnumObject.Bar, MyEnumObject.Foo, [MyEnumObject.Bar, MyEnumObject.Baz, MyEnumObject.Foo]], ], }); }); diff --git a/packages/core/src/Enum/define.ts b/packages/core/src/Enum/define.ts index 0159a05270..a1f384d1d7 100644 --- a/packages/core/src/Enum/define.ts +++ b/packages/core/src/Enum/define.ts @@ -1,4 +1,5 @@ import type { Enum } from '../Enum.js'; + import { Indexable } from '../Indexable.js'; import { Symbol } from '../Symbol.js'; import { define as defineType } from '../Type/define.js'; @@ -16,7 +17,7 @@ import { define as defineType } from '../Type/define.js'; * ``` * @param enumObject */ -export function define>( +export function define>( enumObject: T & { typeName?: string }, ): Enum { type Value = T[keyof T]; @@ -26,18 +27,18 @@ export function define const enumValuesIndex = new Map(enumValuesList.map((value, index) => [value, index])); const EnumType = defineType({ - typeName: typeName ?? enumValuesList.join('|'), hasInstance(anyValue) { return enumValuesIndex.has(anyValue); }, [Symbol.schema]: () => ({ enum: enumValuesList, }), + typeName: typeName ?? enumValuesList.join('|'), }); const EnumIndexable = Indexable({ - indexType: 'number', at: (index) => enumValuesList[index], indexOf: (value) => enumValuesIndex.get(value), + indexType: 'number', }); // @ts-ignore ignore errors and rely on tests diff --git a/packages/core/src/Enum/keys.spec.ts b/packages/core/src/Enum/keys.spec.ts index df3cfd6d1e..eb595aa241 100644 --- a/packages/core/src/Enum/keys.spec.ts +++ b/packages/core/src/Enum/keys.spec.ts @@ -1,17 +1,18 @@ import { describe, expect, it } from 'vitest'; -import { keys } from './keys.js'; + import { define } from './define.js'; +import { keys } from './keys.js'; describe(keys, () => { it('returns the keys of Enum', () => { const MyEnum = { ...define({ - Foo: 'foo', Bar: 'bar', + Foo: 'foo', }), other: true, }; const actual = keys(MyEnum); - expect(actual).toEqual(['Foo', 'Bar']); + expect(actual).toEqual(['Bar', 'Foo']); }); }); diff --git a/packages/core/src/Enum/keys.ts b/packages/core/src/Enum/keys.ts index f06a320bee..eaca4c6df1 100644 --- a/packages/core/src/Enum/keys.ts +++ b/packages/core/src/Enum/keys.ts @@ -1,4 +1,5 @@ import type { Enum } from '../Enum.js'; + import { Symbol } from '../Symbol.js'; /** diff --git a/packages/core/src/Enum/values.spec.ts b/packages/core/src/Enum/values.spec.ts index 533ff7d757..74545d0752 100644 --- a/packages/core/src/Enum/values.spec.ts +++ b/packages/core/src/Enum/values.spec.ts @@ -1,17 +1,18 @@ import { describe, expect, it } from 'vitest'; -import { values } from './values.js'; + import { define } from './define.js'; +import { values } from './values.js'; describe(values, () => { it('returns the values of Enum', () => { const MyEnum = { ...define({ - Foo: 'foo', Bar: 'bar', + Foo: 'foo', }), other: true, }; const actual = values(MyEnum); - expect(actual).toEqual(['foo', 'bar']); + expect(actual).toEqual(['bar', 'foo']); }); }); diff --git a/packages/core/src/Enum/values.ts b/packages/core/src/Enum/values.ts index d4c370f526..8593f68b98 100644 --- a/packages/core/src/Enum/values.ts +++ b/packages/core/src/Enum/values.ts @@ -1,4 +1,5 @@ import type { Enum } from '../Enum.js'; + import { keys } from './keys.js'; /** diff --git a/packages/core/src/Equal.spec.ts b/packages/core/src/Equal.spec.ts index 24071a89ae..73cf746ca7 100644 --- a/packages/core/src/Equal.spec.ts +++ b/packages/core/src/Equal.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Equal } from './Equal.js'; describe('Equal', () => { diff --git a/packages/core/src/Equal.ts b/packages/core/src/Equal.ts index 0b5c0cafd8..aa215f472f 100644 --- a/packages/core/src/Equal.ts +++ b/packages/core/src/Equal.ts @@ -1,19 +1,3 @@ -export interface EqualsInterface { - /** - * Alias to '==' - * - * @example - * ```typescript - * type T = // ... - * const TEqual: Equal; - * TEqual.equals(value, value); // true - * TEqual.equals(value, otherValue); // false - * ``` - * @category Comparator - */ - equals(this: void, left: T, right: T): boolean; -} - /** * Module interface for values that have equivalence relation */ @@ -46,6 +30,22 @@ export interface Equal extends EqualsInterface { '=='(this: void, left: T, right: T): boolean; } +export interface EqualsInterface { + /** + * Alias to '==' + * + * @example + * ```typescript + * type T = // ... + * const TEqual: Equal; + * TEqual.equals(value, value); // true + * TEqual.equals(value, otherValue); // false + * ``` + * @category Comparator + */ + equals(this: void, left: T, right: T): boolean; +} + /** * Equal module constructor * @@ -66,14 +66,14 @@ export function Equal(properties: Equal.Parameters): Equal { const equals = (left: T, right: T) => properties.equals(left, right); const notEquals = (left: T, right: T) => !properties.equals(left, right); return { - 'equals': properties.equals, - '==': equals, '!=': notEquals, + '==': equals, + 'equals': properties.equals, }; } export namespace Equal { - export type Parameters = { + export interface Parameters { equals: (left: T, right: T) => boolean; - }; + } } diff --git a/packages/core/src/Indexable.spec.ts b/packages/core/src/Indexable.spec.ts index e345508308..a7a14e6012 100644 --- a/packages/core/src/Indexable.spec.ts +++ b/packages/core/src/Indexable.spec.ts @@ -1,21 +1,23 @@ -import { describe, it, expect, vi } from 'vitest'; import type { Int } from '@w5s/core'; + +import { describe, expect, it, vi } from 'vitest'; + import { Indexable } from './Indexable.js'; describe(Indexable, () => { const anyIndexOf = vi.fn(); const anyAt = vi.fn(); const defaultIndexable = { - indexType: 'number' as const, - indexOf: anyIndexOf, at: anyAt, + indexOf: anyIndexOf, + indexType: 'number' as const, }; const charIndexable = Indexable({ - indexType: 'number', + at: (index) => String.fromCodePoint(index), indexOf(value) { return value.codePointAt(0) as Int; }, - at: (index) => String.fromCodePoint(index), + indexType: 'number', }); describe('#at', () => { diff --git a/packages/core/src/Indexable.ts b/packages/core/src/Indexable.ts index 18e6b91c5e..d47c3fff73 100644 --- a/packages/core/src/Indexable.ts +++ b/packages/core/src/Indexable.ts @@ -1,5 +1,6 @@ /* eslint-disable ts/ban-ts-comment */ import type { PartialKeys } from '@w5s/core-type'; + import type { Int } from './Int.js'; import type { Option } from './Option.js'; import type { Range } from './Range.js'; @@ -7,14 +8,7 @@ import type { Range } from './Range.js'; /** * A type Indexable is a type with values that can be indexed by a number. */ -export interface Indexable { - /** - * Index type - * - * @category Indexable - */ - indexType: Index extends number ? 'number' : Index extends bigint ? 'bigint' : never; - +export interface Indexable { /** * Returns the value at the index * @@ -32,14 +26,11 @@ export interface Indexable { indexOf(value: T): Option; /** - * Returns the size of a range. - * If `start` or `end` is not in range then returns 0. + * Index type * * @category Indexable - * @param start the start of the range - * @param end the end of the range */ - rangeSize(start: T, end: T): Index; + indexType: Index extends number ? 'number' : Index extends bigint ? 'bigint' : never; /** * Returns an Iterable starting from `start` to `end`. @@ -50,31 +41,32 @@ export interface Indexable { * @param end the end of the range */ range(start: T, end: T): Range; + + /** + * Returns the size of a range. + * If `start` or `end` is not in range then returns 0. + * + * @category Indexable + * @param start the start of the range + * @param end the end of the range + */ + rangeSize(start: T, end: T): Index; } -export function Indexable( +export function Indexable( properties: Indexable.Parameters, ): Indexable { - const { indexType, indexOf, at, rangeSize, range } = properties; + const { at, indexOf, indexType, range, rangeSize } = properties; const zero = indexType === 'bigint' ? 0n : (0 as Int); const one = indexType === 'bigint' ? 1n : (1 as Int); return { at, indexOf, indexType, - rangeSize: - rangeSize ?? - ((start, end) => { - const startIndex = indexOf(start); - const endIndex = indexOf(end); - // @ts-ignore - - return startIndex == null || endIndex == null ? zero : endIndex - startIndex + one; - }), range: range ?? ((rangeStart, rangeEnd) => ({ - rangeStart, rangeEnd, + rangeStart, * [Symbol.iterator]() { const startIndex = indexOf(rangeStart); const endIndex = indexOf(rangeEnd); @@ -100,11 +92,20 @@ export function Indexable( } }, })), + rangeSize: + rangeSize ?? + ((start, end) => { + const startIndex = indexOf(start); + const endIndex = indexOf(end); + // @ts-ignore + + return startIndex == null || endIndex == null ? zero : endIndex - startIndex + one; + }), }; } export namespace Indexable { - export interface Parameters extends PartialKeys< + export interface Parameters extends PartialKeys< Indexable, - 'rangeSize' | 'range' + 'range' | 'rangeSize' > {} } diff --git a/packages/core/src/JSON.spec.ts b/packages/core/src/JSON.spec.ts index 985f07a38b..150f75e6a5 100644 --- a/packages/core/src/JSON.spec.ts +++ b/packages/core/src/JSON.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { JSON } from './JSON.js'; import { Result } from './Result.js'; diff --git a/packages/core/src/JSON.ts b/packages/core/src/JSON.ts index f7d10ef9fc..9d7c9c206f 100644 --- a/packages/core/src/JSON.ts +++ b/packages/core/src/JSON.ts @@ -1,7 +1,9 @@ -import type { TypeError, SyntaxError } from '@w5s/error'; +import type { SyntaxError, TypeError } from '@w5s/error'; + import type { Result } from './Result.js'; -import { Ok } from './Result/Ok.js'; + import { Error } from './Result/Error.js'; +import { Ok } from './Result/Ok.js'; const NativeJSON = globalThis.JSON; @@ -9,11 +11,11 @@ const NativeJSON = globalThis.JSON; * Any valid JSON value */ export type JSONValue = - | null | boolean + | null | number - | string | ReadonlyArray + | string | { readonly [key: string]: JSONValue; }; diff --git a/packages/core/src/Numeric/Integral.spec.ts b/packages/core/src/Numeric/Integral.spec.ts index d6a3e14606..c4235b6ddb 100644 --- a/packages/core/src/Numeric/Integral.spec.ts +++ b/packages/core/src/Numeric/Integral.spec.ts @@ -1,9 +1,12 @@ -import { describe, expect, it, vi } from 'vitest'; import type { Int } from '@w5s/core-type'; -import { Integral } from './Integral.js'; -import { Comparable } from '../Comparable.js'; + +import { describe, expect, it, vi } from 'vitest'; + import type { Ordering } from '../Ordering.js'; +import { Comparable } from '../Comparable.js'; +import { Integral } from './Integral.js'; + describe(Integral, () => { interface TestCustom { custom: boolean; @@ -14,14 +17,14 @@ describe(Integral, () => { }); const TestType = { ...Integral({ - 'compare': TestComparable.compare, - '+': (left, right) => ({ custom: true, value: (left.value + right.value) as Int }), + '%': (left, right) => ({ custom: true, value: (left.value % right.value) as Int }), '*': (left, right) => ({ custom: true, value: (left.value * right.value) as Int }), + '+': (left, right) => ({ custom: true, value: (left.value + right.value) as Int }), '/': (left, right) => ({ custom: true, value: (left.value / right.value) as Int }), - '%': (left, right) => ({ custom: true, value: (left.value % right.value) as Int }), - 'fromInt': (value: Int) => ({ custom: true, value }), 'asInt': (value) => value.value, + 'compare': TestComparable.compare, + 'fromInt': (value: Int) => ({ custom: true, value }), }), ...TestComparable, }; @@ -29,8 +32,8 @@ describe(Integral, () => { it('extends Numeric', () => { expect(TestType).toEqual( expect.objectContaining({ - '+': expect.any(Function), '*': expect.any(Function), + '+': expect.any(Function), }), ); }); diff --git a/packages/core/src/Numeric/Integral.ts b/packages/core/src/Numeric/Integral.ts index eabfeef647..9adcd78904 100644 --- a/packages/core/src/Numeric/Integral.ts +++ b/packages/core/src/Numeric/Integral.ts @@ -1,13 +1,12 @@ import type { Divide } from './Divide.js'; -import { Numeric, type NumericParameters } from './Numeric.js'; import type { Remainder } from './Remainder.js'; -export interface IntegralParameters extends NumericParameters, Divide, Remainder {} +import { Numeric, type NumericParameters } from './Numeric.js'; /** * Integral type */ -export interface Integral extends Numeric, Divide, Remainder { +export interface Integral extends Divide, Numeric, Remainder { /** * Quotient/Modulo operator * @@ -24,12 +23,14 @@ export interface Integral extends Numeric, Divide, Remainder { '/%'(this: void, base: T, divider: T): [quot: T, mod: T]; } +export interface IntegralParameters extends Divide, NumericParameters, Remainder {} + export function Integral(properties: IntegralParameters): Integral { - const { '/': quot, '%': mod } = properties; + const { '%': mod, '/': quot } = properties; return { ...Numeric(properties), - '/': quot, '%': mod, + '/': quot, '/%': (base, divider) => [quot(base, divider), mod(base, divider)], }; } diff --git a/packages/core/src/Numeric/Numeric.spec.ts b/packages/core/src/Numeric/Numeric.spec.ts index 9c2d6e5b7a..fe3986cb14 100644 --- a/packages/core/src/Numeric/Numeric.spec.ts +++ b/packages/core/src/Numeric/Numeric.spec.ts @@ -1,9 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; -import { Numeric } from './Numeric.js'; -import { Int } from '../Int.js'; +import { describe, expect, it, vi } from 'vitest'; + import type { Ordering } from '../Ordering.js'; -import { describeSigned } from '../Testing.js'; + import { Comparable } from '../Comparable.js'; +import { Int } from '../Int.js'; +import { describeSigned } from '../Testing.js'; +import { Numeric } from './Numeric.js'; describe(Numeric, () => { interface TestCustom { @@ -15,11 +17,11 @@ describe(Numeric, () => { }); const TestType = { ...Numeric({ - 'compare': TestComparable.compare, - '+': (left, right) => ({ custom: true, value: (left.value + right.value) as Int }), '*': (left, right) => ({ custom: true, value: (left.value * right.value) as Int }), - 'fromInt': (value: Int) => ({ custom: true, value }), + '+': (left, right) => ({ custom: true, value: (left.value + right.value) as Int }), 'asInt': (value) => value.value, + 'compare': TestComparable.compare, + 'fromInt': (value: Int) => ({ custom: true, value }), }), ...TestComparable, }; @@ -135,29 +137,29 @@ describe(Numeric, () => { describeSigned(TestType, { values: () => [ { - value: TestType.fromInt(Int(-2)), - type: 'negative', - sign: TestType.fromInt(Int(-1)), abs: TestType.fromInt(Int(2)), + sign: TestType.fromInt(Int(-1)), + type: 'negative', + value: TestType.fromInt(Int(-2)), }, { - value: TestType.fromInt(Int(-1)), - type: 'negative', - sign: TestType.fromInt(Int(-1)), abs: TestType.fromInt(Int(1)), + sign: TestType.fromInt(Int(-1)), + type: 'negative', + value: TestType.fromInt(Int(-1)), }, - { value: TestType.fromInt(Int(0)), type: 'zero', sign: TestType.fromInt(Int(0)), abs: TestType.fromInt(Int(0)) }, + { abs: TestType.fromInt(Int(0)), sign: TestType.fromInt(Int(0)), type: 'zero', value: TestType.fromInt(Int(0)) }, { - value: TestType.fromInt(Int(1)), - type: 'positive', - sign: TestType.fromInt(Int(1)), abs: TestType.fromInt(Int(1)), + sign: TestType.fromInt(Int(1)), + type: 'positive', + value: TestType.fromInt(Int(1)), }, { - value: TestType.fromInt(Int(2)), - type: 'positive', - sign: TestType.fromInt(Int(1)), abs: TestType.fromInt(Int(2)), + sign: TestType.fromInt(Int(1)), + type: 'positive', + value: TestType.fromInt(Int(2)), }, ], }); diff --git a/packages/core/src/Numeric/Numeric.ts b/packages/core/src/Numeric/Numeric.ts index f2df6dc533..b6efc96a1c 100644 --- a/packages/core/src/Numeric/Numeric.ts +++ b/packages/core/src/Numeric/Numeric.ts @@ -1,16 +1,17 @@ import type { PartialKeys } from '@w5s/core-type'; + +import type { AsInt } from '../AsInt.js'; import type { Comparable } from '../Comparable.js'; import type { Int } from '../Int.js'; -import type { One } from './One.js'; -import type { Zero } from './Zero.js'; -import type { Negate } from './Negate.js'; import type { Add } from './Add.js'; -import type { Subtract } from './Subtract.js'; import type { Multiply } from './Multiply.js'; +import type { Negate } from './Negate.js'; +import type { One } from './One.js'; import type { Signed } from './Signed.js'; -import type { AsInt } from '../AsInt.js'; +import type { Subtract } from './Subtract.js'; +import type { Zero } from './Zero.js'; -export interface Numeric extends Negate, One, Zero, Add, Signed, Subtract, Multiply, AsInt { +export interface Numeric extends Add, AsInt, Multiply, Negate, One, Signed, Subtract, Zero { /** * * @param value the Int value to convert to T @@ -20,45 +21,46 @@ export interface Numeric extends Negate, One, Zero, Add, Signed extends - PartialKeys, keyof Zero | keyof Negate | keyof One | keyof Signed | keyof Subtract>, - Comparable.Parameters {} + Comparable.Parameters, + PartialKeys, keyof Negate | keyof One | keyof Signed | keyof Subtract | keyof Zero> {} export function Numeric(BaseType: NumericParameters): Numeric { const { - fromInt, asInt, compare, - + fromInt, negate = (self) => fromInt(-asInt(self) as Int), + one = () => fromInt(1 as Int), + zero = () => fromInt(0 as Int), + } = BaseType; + const { + '*': multiply, '+': add, '-': subtract = (left, right) => add(left, negate(right)), - '*': multiply, - one = () => fromInt(1 as Int), + abs = (value: T) => (compare(value, zero()) < 0 ? negate(value) : value), + isNegative = (self: T) => compare(self, zero()) < 0, isOne = (self: T) => compare(self, one()) === 0, - zero = () => fromInt(0 as Int), + isPositive = (self: T) => compare(self, zero()) > 0, isZero = (self: T) => compare(self, zero()) === 0, - abs = (value: T) => (compare(value, zero()) < 0 ? negate(value) : value), sign = (value: T) => { const comparison = compare(value, zero()); return comparison === 0 ? zero() : comparison === 1 ? one() : negate(one()); }, - isPositive = (self: T) => compare(self, zero()) > 0, - isNegative = (self: T) => compare(self, zero()) < 0, } = BaseType; return { - negate, - zero, - isZero, - abs, - sign, - isPositive, - isNegative, - one, - isOne, + '*': multiply, '+': add, '-': subtract, - '*': multiply, - fromInt, + abs, asInt, + fromInt, + isNegative, + isOne, + isPositive, + isZero, + negate, + one, + sign, + zero, }; } diff --git a/packages/core/src/Numeric/One.ts b/packages/core/src/Numeric/One.ts index 0b3d763644..48989691f5 100644 --- a/packages/core/src/Numeric/One.ts +++ b/packages/core/src/Numeric/One.ts @@ -1,25 +1,25 @@ export interface One { /** - * Returns the additive identity element of `T`, 0. + * Returns true if self is equal to the multiplicative identity. * * @example * ```typescript - * Number.one(); // 1 + * Number.isOne(1); // true + * Number.isOne(0); // false * ``` * @category Numeric + * @param self the value to test */ - one(this: void): T; + isOne(this: void, self: T): boolean; /** - * Returns true if self is equal to the multiplicative identity. + * Returns the additive identity element of `T`, 0. * * @example * ```typescript - * Number.isOne(1); // true - * Number.isOne(0); // false + * Number.one(); // 1 * ``` * @category Numeric - * @param self the value to test */ - isOne(this: void, self: T): boolean; + one(this: void): T; } diff --git a/packages/core/src/Numeric/Signed.ts b/packages/core/src/Numeric/Signed.ts index fe996fcab5..732d28b0c5 100644 --- a/packages/core/src/Numeric/Signed.ts +++ b/packages/core/src/Numeric/Signed.ts @@ -14,32 +14,32 @@ export interface Signed { abs(this: void, value: T): T; /** - * Returns true if the number is positive and false if the number is zero or negative. + * Returns true if the number is negative and false if the number is zero or positive. * * @example * ```typescript - * Number.isPositive(-1);// false + * Number.isPositive(-1);// true * Number.isPositive(0);// false - * Number.isPositive(1);// true + * Number.isPositive(1);// false * ``` * @category Numeric * @param self the numeric value */ - isPositive(this: void, self: T): boolean; + isNegative(this: void, self: T): boolean; /** - * Returns true if the number is negative and false if the number is zero or positive. + * Returns true if the number is positive and false if the number is zero or negative. * * @example * ```typescript - * Number.isPositive(-1);// true + * Number.isPositive(-1);// false * Number.isPositive(0);// false - * Number.isPositive(1);// false + * Number.isPositive(1);// true * ``` * @category Numeric * @param self the numeric value */ - isNegative(this: void, self: T): boolean; + isPositive(this: void, self: T): boolean; /** * Sign of a number. It should satisfy `TSigned['*'](TSigned.abs(x), TSigned.sign(x)) == x` diff --git a/packages/core/src/Numeric/Zero.ts b/packages/core/src/Numeric/Zero.ts index 875b357c74..0f43c97028 100644 --- a/packages/core/src/Numeric/Zero.ts +++ b/packages/core/src/Numeric/Zero.ts @@ -1,25 +1,25 @@ export interface Zero { /** - * Returns the additive identity element of `T`, 0. + * Returns true if self is equal to the additive identity. * * @example * ```typescript - * Number.zero(); // 0 + * Number.isZero(0); // true + * Number.isZero(1); // false * ``` * @category Numeric + * @param self the value to test */ - zero(this: void): T; + isZero(this: void, self: T): boolean; /** - * Returns true if self is equal to the additive identity. + * Returns the additive identity element of `T`, 0. * * @example * ```typescript - * Number.isZero(0); // true - * Number.isZero(1); // false + * Number.zero(); // 0 * ``` * @category Numeric - * @param self the value to test */ - isZero(this: void, self: T): boolean; + zero(this: void): T; } diff --git a/packages/core/src/Option.spec.ts b/packages/core/src/Option.spec.ts index 55004b3c3a..d8dfe7a163 100644 --- a/packages/core/src/Option.spec.ts +++ b/packages/core/src/Option.spec.ts @@ -1,7 +1,6 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Option } from './Option.js'; -import { Some } from './Option/Some.js'; -import { None } from './Option/None.js'; import { andThen } from './Option/andThen.js'; import { from } from './Option/from.js'; import { getOrElse } from './Option/getOrElse.js'; @@ -9,13 +8,13 @@ import { getOrThrow } from './Option/getOrThrow.js'; import { isNone } from './Option/isNone.js'; import { isSome } from './Option/isSome.js'; import { map } from './Option/map.js'; +import { None } from './Option/None.js'; import { orElse } from './Option/orElse.js'; +import { Some } from './Option/Some.js'; describe('Option', () => { it('is an alias to functions', () => { expect(Option).toEqual({ - Some, - None, andThen, from, getOrElse, @@ -23,7 +22,9 @@ describe('Option', () => { isNone, isSome, map, + None, orElse, + Some, }); }); }); diff --git a/packages/core/src/Option.ts b/packages/core/src/Option.ts index 5849cf8ffc..f7d687bde9 100644 --- a/packages/core/src/Option.ts +++ b/packages/core/src/Option.ts @@ -1,6 +1,5 @@ import type { Nullable } from '@w5s/core-type'; -import { None } from './Option/None.js'; -import { Some } from './Option/Some.js'; + import { andThen } from './Option/andThen.js'; import { from } from './Option/from.js'; import { getOrElse } from './Option/getOrElse.js'; @@ -8,7 +7,9 @@ import { getOrThrow } from './Option/getOrThrow.js'; import { isNone } from './Option/isNone.js'; import { isSome } from './Option/isSome.js'; import { map } from './Option/map.js'; +import { None } from './Option/None.js'; import { orElse } from './Option/orElse.js'; +import { Some } from './Option/Some.js'; // https://doc.rust-lang.org/std/option/enum.Option.html @@ -42,7 +43,7 @@ import { orElse } from './Option/orElse.js'; * ``` * @param Value the type of the contained value */ -export type Option = Value | Option.None; +export type Option = Option.None | Value; /** * `OptionLike` is the type used to represent either a Nullable value @@ -53,8 +54,6 @@ export type OptionLike = Nullable; * @namespace */ export const Option = { - Some, - None, andThen, from, getOrElse, @@ -62,7 +61,9 @@ export const Option = { isNone, isSome, map, + None, orElse, + Some, }; export namespace Option { diff --git a/packages/core/src/Option/None.spec.ts b/packages/core/src/Option/None.spec.ts index 412c82c392..38fdd3eb97 100644 --- a/packages/core/src/Option/None.spec.ts +++ b/packages/core/src/Option/None.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { None } from './None.js'; + import { isNone } from './isNone.js'; +import { None } from './None.js'; describe('None', () => { it('should be an alias for undefined', () => { diff --git a/packages/core/src/Option/Some.spec.ts b/packages/core/src/Option/Some.spec.ts index 287a323e62..1be455db5d 100644 --- a/packages/core/src/Option/Some.spec.ts +++ b/packages/core/src/Option/Some.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Some } from './Some.js'; describe('Some', () => { diff --git a/packages/core/src/Option/andThen.spec.ts b/packages/core/src/Option/andThen.spec.ts index 5ab72a9c4e..cf7a3d1e1c 100644 --- a/packages/core/src/Option/andThen.spec.ts +++ b/packages/core/src/Option/andThen.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { andThen } from './andThen.js'; import { None } from './None.js'; import { Some } from './Some.js'; diff --git a/packages/core/src/Option/andThen.ts b/packages/core/src/Option/andThen.ts index dca1cc68fa..3a9608c277 100644 --- a/packages/core/src/Option/andThen.ts +++ b/packages/core/src/Option/andThen.ts @@ -1,4 +1,5 @@ import type { Option, OptionLike } from '../Option.js'; + import { from } from './from.js'; /** diff --git a/packages/core/src/Option/from.spec.ts b/packages/core/src/Option/from.spec.ts index bb01e978ca..124255cd4c 100644 --- a/packages/core/src/Option/from.spec.ts +++ b/packages/core/src/Option/from.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { from } from './from.js'; import { None } from './None.js'; diff --git a/packages/core/src/Option/getOrElse.spec.ts b/packages/core/src/Option/getOrElse.spec.ts index a964f32011..2ac6cde264 100644 --- a/packages/core/src/Option/getOrElse.spec.ts +++ b/packages/core/src/Option/getOrElse.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { getOrElse } from './getOrElse.js'; import { None } from './None.js'; import { Some } from './Some.js'; diff --git a/packages/core/src/Option/getOrElse.ts b/packages/core/src/Option/getOrElse.ts index c27fed5be2..c08cc20c4b 100644 --- a/packages/core/src/Option/getOrElse.ts +++ b/packages/core/src/Option/getOrElse.ts @@ -18,6 +18,6 @@ import type { OptionLike } from '../Option.js'; export function getOrElse( self: OptionLike, getDefaultValue: () => DefaultValue, -): Value | DefaultValue { +): DefaultValue | Value { return self ?? getDefaultValue(); } diff --git a/packages/core/src/Option/getOrThrow.spec.ts b/packages/core/src/Option/getOrThrow.spec.ts index 222b9020fa..e18e2ed758 100644 --- a/packages/core/src/Option/getOrThrow.spec.ts +++ b/packages/core/src/Option/getOrThrow.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + import { getOrThrow } from './getOrThrow.js'; import { Some } from './Some.js'; diff --git a/packages/core/src/Option/isNone.spec.ts b/packages/core/src/Option/isNone.spec.ts index 86e2c090df..44603a10f1 100644 --- a/packages/core/src/Option/isNone.spec.ts +++ b/packages/core/src/Option/isNone.spec.ts @@ -1,7 +1,9 @@ import { describe, expect, it } from 'vitest'; -import { isNone } from './isNone.js'; + import type { Option } from '../Option.js'; +import { isNone } from './isNone.js'; + describe(isNone, () => { it('should return false for any value', () => { expect(isNone({})).toBe(false); diff --git a/packages/core/src/Option/isSome.spec.ts b/packages/core/src/Option/isSome.spec.ts index fe0a0847e8..bf4d051b4d 100644 --- a/packages/core/src/Option/isSome.spec.ts +++ b/packages/core/src/Option/isSome.spec.ts @@ -1,7 +1,9 @@ import { describe, expect, it } from 'vitest'; -import { isSome } from './isSome.js'; + import type { Option } from '../Option.js'; +import { isSome } from './isSome.js'; + describe(isSome, () => { it('should return true for any value', () => { expect(isSome({})).toBe(true); diff --git a/packages/core/src/Option/isSome.ts b/packages/core/src/Option/isSome.ts index 664fc2d930..42d3a29b2c 100644 --- a/packages/core/src/Option/isSome.ts +++ b/packages/core/src/Option/isSome.ts @@ -1,6 +1,7 @@ -import { isNone } from './isNone.js'; import type { OptionLike } from '../Option.js'; +import { isNone } from './isNone.js'; + /** * Return `true` if `anyValue` is neither `null` nor `undefined` * diff --git a/packages/core/src/Option/map.spec.ts b/packages/core/src/Option/map.spec.ts index fc6ac2b8d1..7d64c66447 100644 --- a/packages/core/src/Option/map.spec.ts +++ b/packages/core/src/Option/map.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + import { map } from './map.js'; -import { Some } from './Some.js'; import { None } from './None.js'; +import { Some } from './Some.js'; describe(map, () => { it('should return true for Some() object', () => { diff --git a/packages/core/src/Option/map.ts b/packages/core/src/Option/map.ts index 1048baac8e..627704372b 100644 --- a/packages/core/src/Option/map.ts +++ b/packages/core/src/Option/map.ts @@ -1,4 +1,5 @@ import type { Option, OptionLike } from '../Option.js'; + import { isNone } from './isNone.js'; /** diff --git a/packages/core/src/Option/orElse.spec.ts b/packages/core/src/Option/orElse.spec.ts index 6a79988092..dcef082084 100644 --- a/packages/core/src/Option/orElse.spec.ts +++ b/packages/core/src/Option/orElse.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { orElse } from './orElse.js'; + import { None } from './None.js'; +import { orElse } from './orElse.js'; import { Some } from './Some.js'; describe(orElse, () => { diff --git a/packages/core/src/Option/orElse.ts b/packages/core/src/Option/orElse.ts index 51aad39876..c5259a84be 100644 --- a/packages/core/src/Option/orElse.ts +++ b/packages/core/src/Option/orElse.ts @@ -1,4 +1,5 @@ import type { Option, OptionLike } from '../Option.js'; + import { from } from './from.js'; /** diff --git a/packages/core/src/Order.spec.ts b/packages/core/src/Order.spec.ts index cf65b9005c..9852ce414d 100644 --- a/packages/core/src/Order.spec.ts +++ b/packages/core/src/Order.spec.ts @@ -1,16 +1,17 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Order } from './Order.js'; -import { reverse } from './Order/reverse.js'; import { combine } from './Order/combine.js'; -import { primitive } from './Order/primitive.js'; import { compareBy } from './Order/compareBy.js'; +import { primitive } from './Order/primitive.js'; +import { reverse } from './Order/reverse.js'; describe('Order', () => { it('is an alias to functions', () => { expect(Order).toEqual( expect.objectContaining({ - compareBy, combine, + compareBy, primitive, reverse, }), diff --git a/packages/core/src/Order.ts b/packages/core/src/Order.ts index a1a84d62a8..df9cdac72f 100644 --- a/packages/core/src/Order.ts +++ b/packages/core/src/Order.ts @@ -1,9 +1,10 @@ +import type { ComparableInterface } from './Comparable.js'; import type { Ordering } from './Ordering.js'; -import { reverse } from './Order/reverse.js'; + import { combine } from './Order/combine.js'; import { compareBy } from './Order/compareBy.js'; import { primitive } from './Order/primitive.js'; -import type { ComparableInterface } from './Comparable.js'; +import { reverse } from './Order/reverse.js'; /** * Return an {@link Ordering} thats represents the comparison result @@ -16,14 +17,14 @@ export type Order = (left: T, right: T) => Ordering; /** * A type that is an Order or Comparable with only compare property required */ -export type OrderLike = Order | ComparableInterface; +export type OrderLike = ComparableInterface | Order; /** * @namespace */ export const Order = { - compareBy, combine, + compareBy, primitive, reverse, }; diff --git a/packages/core/src/Order/combine.spec.ts b/packages/core/src/Order/combine.spec.ts index 1cd7cd9fbd..f9566fd613 100644 --- a/packages/core/src/Order/combine.spec.ts +++ b/packages/core/src/Order/combine.spec.ts @@ -1,16 +1,18 @@ import { describe, expect, it } from 'vitest'; -import { combine } from './combine.js'; + +import type { Ordering } from '../Ordering.js'; + import { String } from '../String.js'; import { withOrder } from '../Testing.js'; -import type { Ordering } from '../Ordering.js'; +import { combine } from './combine.js'; describe(combine, () => { const numberCompare = (a: number, b: number): Ordering => (a === b ? 0 : a < b ? -1 : 1); const expectOrder = withOrder(expect); interface Person { - lastName: string; - firstName: string; age: number; + firstName: string; + lastName: string; } it('combine two orders', () => { @@ -20,11 +22,11 @@ describe(combine, () => { ); expectOrder(compare).toSortValues([ - { lastName: 'A', firstName: 'Alice', age: 25 }, - { lastName: 'B', firstName: 'Alice', age: 25 }, - { lastName: 'B', firstName: 'Alice', age: 26 }, - { lastName: 'A', firstName: 'Bob', age: 25 }, - { lastName: 'B', firstName: 'Bob', age: 25 }, + { age: 25, firstName: 'Alice', lastName: 'A' }, + { age: 25, firstName: 'Alice', lastName: 'B' }, + { age: 26, firstName: 'Alice', lastName: 'B' }, + { age: 25, firstName: 'Bob', lastName: 'A' }, + { age: 25, firstName: 'Bob', lastName: 'B' }, ]); }); it('combine three orders', () => { @@ -34,11 +36,11 @@ describe(combine, () => { (left: Person, right: Person) => numberCompare(left.age, right.age), ); expectOrder(compare).toSortValues([ - { lastName: 'A', firstName: 'Alice', age: 25 }, - { lastName: 'B', firstName: 'Alice', age: 25 }, - { lastName: 'B', firstName: 'Alice', age: 26 }, - { lastName: 'B', firstName: 'Bob', age: 25 }, - { lastName: 'B', firstName: 'Bob', age: 25 }, + { age: 25, firstName: 'Alice', lastName: 'A' }, + { age: 25, firstName: 'Alice', lastName: 'B' }, + { age: 26, firstName: 'Alice', lastName: 'B' }, + { age: 25, firstName: 'Bob', lastName: 'B' }, + { age: 25, firstName: 'Bob', lastName: 'B' }, ]); }); }); diff --git a/packages/core/src/Order/combine.ts b/packages/core/src/Order/combine.ts index 1e50d65add..906b2595b9 100644 --- a/packages/core/src/Order/combine.ts +++ b/packages/core/src/Order/combine.ts @@ -18,13 +18,14 @@ import type { Order } from '../Order.js'; * @param self * @param others */ -export function combine(self: Order, ...others: Order[]): Order { +export function combine(self: Order, ...others: Array>): Order { return (left, right) => { let returnValue = self(left, right); if (returnValue !== 0) { return returnValue; } + // eslint-disable-next-line ts/prefer-for-of for (let index = 0; index < others.length; index += 1) { returnValue = others[index]!(left, right); if (returnValue !== 0) { diff --git a/packages/core/src/Order/compareBy.spec.ts b/packages/core/src/Order/compareBy.spec.ts index 6b4f568ddc..e1bf3e359e 100644 --- a/packages/core/src/Order/compareBy.spec.ts +++ b/packages/core/src/Order/compareBy.spec.ts @@ -1,35 +1,36 @@ // packages/core/src/Order/compareBy.spec.ts -import { describe, it, expect } from 'vitest'; -import { compareBy } from './compareBy.js'; +import { describe, expect, it } from 'vitest'; + import { String } from '../String.js'; import { withOrder } from '../Testing/withOrder.js'; +import { compareBy } from './compareBy.js'; describe(compareBy, () => { const expectOrder = withOrder(expect); interface Person { - name: string; age: number; + name: string; } it('returns a function that compares two values through the selectFn', async () => { const compareByName = compareBy((person: Person) => person.name, String.compare); expectOrder(compareByName).toSortValues([ - { name: 'Alice', age: 25 }, - { name: 'Alice', age: 26 }, - { name: 'Bob', age: 30 }, - { name: 'Bob', age: 31 }, + { age: 25, name: 'Alice' }, + { age: 26, name: 'Alice' }, + { age: 30, name: 'Bob' }, + { age: 31, name: 'Bob' }, ]); }); it('uses .compare when comparable', async () => { const compareByName = compareBy((person: Person) => person.name, String); expectOrder(compareByName).toSortValues([ - { name: 'Alice', age: 25 }, - { name: 'Alice', age: 26 }, - { name: 'Bob', age: 30 }, - { name: 'Bob', age: 31 }, + { age: 25, name: 'Alice' }, + { age: 26, name: 'Alice' }, + { age: 30, name: 'Bob' }, + { age: 31, name: 'Bob' }, ]); }); }); diff --git a/packages/core/src/Order/primitive.spec.ts b/packages/core/src/Order/primitive.spec.ts index 47797e7eaf..fe3fa4f0bd 100644 --- a/packages/core/src/Order/primitive.spec.ts +++ b/packages/core/src/Order/primitive.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { primitive } from './primitive.js'; describe(primitive, () => { diff --git a/packages/core/src/Order/reverse.spec.ts b/packages/core/src/Order/reverse.spec.ts index b9ea2d0c59..22341ee3ab 100644 --- a/packages/core/src/Order/reverse.spec.ts +++ b/packages/core/src/Order/reverse.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { reverse } from './reverse.js'; -import { withOrder } from '../Testing.js'; +import { describe, expect, it } from 'vitest'; + import { Comparable } from '../Comparable.js'; +import { withOrder } from '../Testing.js'; +import { reverse } from './reverse.js'; describe(reverse, () => { const NumberComparable = Comparable({ diff --git a/packages/core/src/Order/reverse.ts b/packages/core/src/Order/reverse.ts index 6bdbcaeea5..bd3dee08c5 100644 --- a/packages/core/src/Order/reverse.ts +++ b/packages/core/src/Order/reverse.ts @@ -1,4 +1,5 @@ import type { Order, OrderLike } from '../Order.js'; + import { reverse as orderingReverse } from '../Ordering/reverse.js'; /** diff --git a/packages/core/src/Ordering.spec.ts b/packages/core/src/Ordering.spec.ts index e6ff903299..ccf15d3fd8 100644 --- a/packages/core/src/Ordering.spec.ts +++ b/packages/core/src/Ordering.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Ordering } from './Ordering.js'; -import { Ordering as OrderingType } from './Type/Ordering.js'; import { reverse } from './Ordering/reverse.js'; +import { Ordering as OrderingType } from './Type/Ordering.js'; describe('Ordering', () => { it('is an alias to functions', () => { diff --git a/packages/core/src/Ordering/reverse.spec.ts b/packages/core/src/Ordering/reverse.spec.ts index b85598703e..f9ca048919 100644 --- a/packages/core/src/Ordering/reverse.spec.ts +++ b/packages/core/src/Ordering/reverse.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { reverse } from './reverse.js'; +import { describe, expect, it } from 'vitest'; + import { Ordering } from '../Ordering.js'; +import { reverse } from './reverse.js'; describe(reverse, () => { it('inverts less and greater', () => { diff --git a/packages/core/src/Range.ts b/packages/core/src/Range.ts index 5cf0e2c49d..1d17fa1ef6 100644 --- a/packages/core/src/Range.ts +++ b/packages/core/src/Range.ts @@ -5,12 +5,12 @@ */ export interface Range extends Iterable { /** - * Start of range + * End of range */ - readonly rangeStart: T; + readonly rangeEnd: T; /** - * End of range + * Start of range */ - readonly rangeEnd: T; + readonly rangeStart: T; } diff --git a/packages/core/src/Ref.spec.ts b/packages/core/src/Ref.spec.ts index b39214226f..e3ee059d13 100644 --- a/packages/core/src/Ref.spec.ts +++ b/packages/core/src/Ref.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + import { Ref } from './Ref.js'; -import { property } from './Ref/property.js'; import { modify } from './Ref/modify.js'; +import { property } from './Ref/property.js'; import { read } from './Ref/read.js'; import { write } from './Ref/write.js'; @@ -11,9 +12,9 @@ describe('Ref', () => { it('is an alias to functions', () => { expect(Ref).toEqual( expect.objectContaining({ - read, modify, property, + read, write, }), ); diff --git a/packages/core/src/Ref.ts b/packages/core/src/Ref.ts index 1bf7962f3a..6af7ca9ecc 100644 --- a/packages/core/src/Ref.ts +++ b/packages/core/src/Ref.ts @@ -51,9 +51,9 @@ export const Ref = Object.assign( anyValue != null && (typeof anyValue === 'object' || typeof anyValue === 'function') && 'current' in anyValue ); }, - read, modify, property, + read, write, }, ); diff --git a/packages/core/src/Ref/modify.spec.ts b/packages/core/src/Ref/modify.spec.ts index 935863c4fc..9b0bcc089a 100644 --- a/packages/core/src/Ref/modify.spec.ts +++ b/packages/core/src/Ref/modify.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Ref } from '../Ref.js'; import { modify } from './modify.js'; diff --git a/packages/core/src/Ref/property.spec.ts b/packages/core/src/Ref/property.spec.ts index 2d7b9c4bac..0894cf1b03 100644 --- a/packages/core/src/Ref/property.spec.ts +++ b/packages/core/src/Ref/property.spec.ts @@ -1,16 +1,17 @@ -import { describe, it, expect } from 'vitest'; -import { property } from './property.js'; +import { describe, expect, it } from 'vitest'; + import { Ref } from '../Ref.js'; +import { property } from './property.js'; describe(property, () => { it('forward getter and setter to sub property', () => { - const parent = Ref({ foo: true, bar: 1 }); + const parent = Ref({ bar: 1, foo: true }); const child = property(parent, 'foo'); - expect(parent).toEqual({ current: { foo: true, bar: 1 } }); + expect(parent).toEqual({ current: { bar: 1, foo: true } }); expect(child).toEqual({ current: true }); child.current = false; expect(child).toEqual({ current: false }); - expect(parent).toEqual({ current: { foo: false, bar: 1 } }); + expect(parent).toEqual({ current: { bar: 1, foo: false } }); }); }); diff --git a/packages/core/src/Ref/read.spec.ts b/packages/core/src/Ref/read.spec.ts index 8101d91fe6..d9706d566c 100644 --- a/packages/core/src/Ref/read.spec.ts +++ b/packages/core/src/Ref/read.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { read } from './read.js'; +import { describe, expect, it } from 'vitest'; + import { Ref } from '../Ref.js'; +import { read } from './read.js'; describe(read, () => { it('should return current value', () => { diff --git a/packages/core/src/Ref/write.spec.ts b/packages/core/src/Ref/write.spec.ts index 506b591222..c709bc8629 100644 --- a/packages/core/src/Ref/write.spec.ts +++ b/packages/core/src/Ref/write.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { write } from './write.js'; +import { describe, expect, it } from 'vitest'; + import { Ref } from '../Ref.js'; +import { write } from './write.js'; describe(write, () => { it('should set current value', () => { diff --git a/packages/core/src/Result.spec.ts b/packages/core/src/Result.spec.ts index b61bdaed64..a5d7e32ea9 100644 --- a/packages/core/src/Result.spec.ts +++ b/packages/core/src/Result.spec.ts @@ -1,35 +1,36 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Result } from './Result.js'; -import { Ok } from './Result/Ok.js'; -import { Error } from './Result/Error.js'; -import { isOk } from './Result/isOk.js'; -import { isError } from './Result/isError.js'; import { andThen } from './Result/andThen.js'; +import { Error } from './Result/Error.js'; import { get } from './Result/get.js'; import { getError } from './Result/getError.js'; import { getOrElse } from './Result/getOrElse.js'; import { getOrThrow } from './Result/getOrThrow.js'; import { hasInstance } from './Result/hasInstance.js'; -import { mapError } from './Result/mapError.js'; +import { isError } from './Result/isError.js'; +import { isOk } from './Result/isOk.js'; import { map } from './Result/map.js'; +import { mapError } from './Result/mapError.js'; +import { Ok } from './Result/Ok.js'; import { orElse } from './Result/orElse.js'; import { tryCall } from './Result/tryCall.js'; describe('Result', () => { it('is an alias to functions', () => { expect(Result).toEqual({ - Ok, - Error, - isOk, - isError, andThen, + Error, get, getError, getOrElse, getOrThrow, hasInstance, + isError, + isOk, map, mapError, + Ok, orElse, tryCall, }); diff --git a/packages/core/src/Result.ts b/packages/core/src/Result.ts index e0611f6612..4638cadf95 100644 --- a/packages/core/src/Result.ts +++ b/packages/core/src/Result.ts @@ -1,16 +1,16 @@ -import { Ok } from './Result/Ok.js'; +import { andThen } from './Result/andThen.js'; import { Error } from './Result/Error.js'; -import { isOk } from './Result/isOk.js'; -import { isError } from './Result/isError.js'; -import { map } from './Result/map.js'; import { get } from './Result/get.js'; import { getError } from './Result/getError.js'; import { getOrElse } from './Result/getOrElse.js'; -import { mapError } from './Result/mapError.js'; import { getOrThrow } from './Result/getOrThrow.js'; -import { andThen } from './Result/andThen.js'; -import { orElse } from './Result/orElse.js'; import { hasInstance } from './Result/hasInstance.js'; +import { isError } from './Result/isError.js'; +import { isOk } from './Result/isOk.js'; +import { map } from './Result/map.js'; +import { mapError } from './Result/mapError.js'; +import { Ok } from './Result/Ok.js'; +import { orElse } from './Result/orElse.js'; import { tryCall } from './Result/tryCall.js'; // https://doc.rust-lang.org/std/result/enum.Result.html @@ -44,15 +44,14 @@ import { tryCall } from './Result/tryCall.js'; * @param Value the type of value in case of `Ok` * @param Error the type of error in case of `Error` */ -export type Result = Result.Ok | Result.Error; +export type Result = Result.Error | Result.Ok; /** * @namespace */ export const Result = { - Ok, - Error, andThen, + Error, get, getError, getOrElse, @@ -62,32 +61,33 @@ export const Result = { isOk, map, mapError, + Ok, orElse, tryCall, }; export namespace Result { - export interface Ok { + export interface Error { /** - * `true` only for Ok objects + * The error value */ - readonly ok: true; + readonly error: E; /** - * The success value + * `false` only for Error objects */ - readonly value: V; + readonly ok: false; } - export interface Error { + export interface Ok { /** - * `false` only for Error objects + * `true` only for Ok objects */ - readonly ok: false; + readonly ok: true; /** - * The error value + * The success value */ - readonly error: E; + readonly value: V; } } diff --git a/packages/core/src/Result/Error.spec.ts b/packages/core/src/Result/Error.spec.ts index 440994396b..d4500d24cc 100644 --- a/packages/core/src/Result/Error.spec.ts +++ b/packages/core/src/Result/Error.spec.ts @@ -1,15 +1,17 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { Error } from './Error.js'; +import { describe, expect, it } from 'vitest'; + import type { Result } from '../Result.js'; +import { Error } from './Error.js'; + describe(Error, () => { it('should return a new object', () => { - expect(Error('anyValue')).toEqual({ ok: false, error: 'anyValue' }); + expect(Error('anyValue')).toEqual({ error: 'anyValue', ok: false }); }); it('should return void result when value is omitted', () => { const result = Error(); - expect(result).toEqual({ ok: false, error: undefined }); + expect(result).toEqual({ error: undefined, ok: false }); assertType>(true); }); }); diff --git a/packages/core/src/Result/Error.ts b/packages/core/src/Result/Error.ts index a2d8619ea7..ff730834c0 100644 --- a/packages/core/src/Result/Error.ts +++ b/packages/core/src/Result/Error.ts @@ -12,7 +12,6 @@ import type { Result } from '../Result.js'; * @param resultError the failure value */ export function Error(): Result; - /** * * @example @@ -23,7 +22,7 @@ export function Error(): Result; export function Error(resultError: E): Result; export function Error(resultError?: unknown): Result { return { - ok: false, error: resultError, + ok: false, }; } diff --git a/packages/core/src/Result/Ok.spec.ts b/packages/core/src/Result/Ok.spec.ts index b655c48f1e..69241dd43c 100644 --- a/packages/core/src/Result/Ok.spec.ts +++ b/packages/core/src/Result/Ok.spec.ts @@ -1,8 +1,10 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { Ok } from './Ok.js'; +import { describe, expect, it } from 'vitest'; + import type { Result } from '../Result.js'; +import { Ok } from './Ok.js'; + describe(Ok, () => { it('should return a new object', () => { expect(Ok('anyValue')).toEqual({ ok: true, value: 'anyValue' }); diff --git a/packages/core/src/Result/andThen.spec.ts b/packages/core/src/Result/andThen.spec.ts index 15a9fe0bba..dc7df2db35 100644 --- a/packages/core/src/Result/andThen.spec.ts +++ b/packages/core/src/Result/andThen.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Result } from '../Result.js'; import { andThen } from './andThen.js'; import { Error } from './Error.js'; diff --git a/packages/core/src/Result/andThen.ts b/packages/core/src/Result/andThen.ts index b717e7be6b..77fdb84d52 100644 --- a/packages/core/src/Result/andThen.ts +++ b/packages/core/src/Result/andThen.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { isOk } from './isOk.js'; /** diff --git a/packages/core/src/Result/get.spec.ts b/packages/core/src/Result/get.spec.ts index 185ab10121..208baabef0 100644 --- a/packages/core/src/Result/get.spec.ts +++ b/packages/core/src/Result/get.spec.ts @@ -1,10 +1,11 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { get } from './get.js'; -import { Error } from './Error.js'; +import { describe, expect, it } from 'vitest'; + import { Option } from '../Option.js'; -import { Ok } from './Ok.js'; import { Result } from '../Result.js'; +import { Error } from './Error.js'; +import { get } from './get.js'; +import { Ok } from './Ok.js'; describe(get, () => { it('should return undefined for Error', () => { @@ -18,7 +19,8 @@ describe(get, () => { assertType(true); const anyResult: Result<'anyValue', 'anyError'> = Ok('anyValue'); - // eslint-disable-next-line ts/no-unused-vars + + // eslint-disable-next-line unused-imports/no-unused-vars const optValue = get(anyResult); assertType(true); }); diff --git a/packages/core/src/Result/get.ts b/packages/core/src/Result/get.ts index 49cad858b9..a27171a473 100644 --- a/packages/core/src/Result/get.ts +++ b/packages/core/src/Result/get.ts @@ -1,5 +1,6 @@ import type { Option } from '../Option.js'; import type { Result } from '../Result.js'; + import { isError } from './isError.js'; /** diff --git a/packages/core/src/Result/getError.spec.ts b/packages/core/src/Result/getError.spec.ts index 97c71d0398..defc02f6c2 100644 --- a/packages/core/src/Result/getError.spec.ts +++ b/packages/core/src/Result/getError.spec.ts @@ -1,10 +1,11 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { getError } from './getError.js'; -import { Ok } from './Ok.js'; +import { describe, expect, it } from 'vitest'; + import { Option } from '../Option.js'; -import { Error } from './Error.js'; import { Result } from '../Result.js'; +import { Error } from './Error.js'; +import { getError } from './getError.js'; +import { Ok } from './Ok.js'; describe(getError, () => { const anyValue = 'anyValue' as const; @@ -21,8 +22,9 @@ describe(getError, () => { assertType(true); const anyResult: Result<'anyValue', 'anyError'> = Ok('anyValue'); - // eslint-disable-next-line ts/no-unused-vars + + // eslint-disable-next-line unused-imports/no-unused-vars const optError = getError(anyResult); - assertType(true); + assertType(true); }); }); diff --git a/packages/core/src/Result/getError.ts b/packages/core/src/Result/getError.ts index a3fa9b6562..42c77ba94e 100644 --- a/packages/core/src/Result/getError.ts +++ b/packages/core/src/Result/getError.ts @@ -1,5 +1,6 @@ import type { Option } from '../Option.js'; import type { Result } from '../Result.js'; + import { isError } from './isError.js'; /** diff --git a/packages/core/src/Result/getOrElse.spec.ts b/packages/core/src/Result/getOrElse.spec.ts index cef82a9763..cabb27fc34 100644 --- a/packages/core/src/Result/getOrElse.spec.ts +++ b/packages/core/src/Result/getOrElse.spec.ts @@ -1,8 +1,9 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { getOrElse } from './getOrElse.js'; -import { Error } from './Error.js'; +import { describe, expect, it } from 'vitest'; + import { Result } from '../Result.js'; +import { Error } from './Error.js'; +import { getOrElse } from './getOrElse.js'; import { Ok } from './Ok.js'; describe(getOrElse, () => { @@ -11,7 +12,7 @@ describe(getOrElse, () => { it('should return defaultValue for Error', () => { const returnValue = getOrElse(Error(anyError) as Result, () => 1); expect(returnValue).toEqual(1); - assertType(true); + assertType(true); }); it('should return value for Ok', () => { expect(getOrElse(Ok(anyValue), () => 1)).toBe(anyValue); diff --git a/packages/core/src/Result/getOrElse.ts b/packages/core/src/Result/getOrElse.ts index b770abb1f1..e0371eb2a4 100644 --- a/packages/core/src/Result/getOrElse.ts +++ b/packages/core/src/Result/getOrElse.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { isOk } from './isOk.js'; /** diff --git a/packages/core/src/Result/getOrThrow.spec.ts b/packages/core/src/Result/getOrThrow.spec.ts index 53d2bfd30a..0fe986d819 100644 --- a/packages/core/src/Result/getOrThrow.spec.ts +++ b/packages/core/src/Result/getOrThrow.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { getOrThrow } from './getOrThrow.js'; +import { describe, expect, it } from 'vitest'; + import { Error } from './Error.js'; +import { getOrThrow } from './getOrThrow.js'; import { Ok } from './Ok.js'; describe('.getOrThrow', () => { diff --git a/packages/core/src/Result/getOrThrow.ts b/packages/core/src/Result/getOrThrow.ts index 14311b9a8c..eb54c3ac91 100644 --- a/packages/core/src/Result/getOrThrow.ts +++ b/packages/core/src/Result/getOrThrow.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { isOk } from './isOk.js'; /** diff --git a/packages/core/src/Result/hasInstance.spec.ts b/packages/core/src/Result/hasInstance.spec.ts index 301d5bffb9..623378be07 100644 --- a/packages/core/src/Result/hasInstance.spec.ts +++ b/packages/core/src/Result/hasInstance.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + +import { Error } from './Error.js'; import { hasInstance } from './hasInstance.js'; import { Ok } from './Ok.js'; -import { Error } from './Error.js'; describe(hasInstance, () => { const anyValue = 'anyValue'; diff --git a/packages/core/src/Result/hasInstance.ts b/packages/core/src/Result/hasInstance.ts index 31d1fbe7ca..5ffd8a0f09 100644 --- a/packages/core/src/Result/hasInstance.ts +++ b/packages/core/src/Result/hasInstance.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { Error } from './Error.js'; import { Ok } from './Ok.js'; diff --git a/packages/core/src/Result/isError.spec.ts b/packages/core/src/Result/isError.spec.ts index 18b61a096f..86fb01b853 100644 --- a/packages/core/src/Result/isError.spec.ts +++ b/packages/core/src/Result/isError.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + +import { Error } from './Error.js'; import { isError } from './isError.js'; import { Ok } from './Ok.js'; -import { Error } from './Error.js'; describe(isError, () => { it('should return true for Result.Ok() object', () => { diff --git a/packages/core/src/Result/isError.ts b/packages/core/src/Result/isError.ts index d5c6883ac2..583ed743ee 100644 --- a/packages/core/src/Result/isError.ts +++ b/packages/core/src/Result/isError.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { isOk } from './isOk.js'; /** diff --git a/packages/core/src/Result/isOk.spec.ts b/packages/core/src/Result/isOk.spec.ts index 5d13523f47..a0ab852d45 100644 --- a/packages/core/src/Result/isOk.spec.ts +++ b/packages/core/src/Result/isOk.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + +import { Error } from './Error.js'; import { isOk } from './isOk.js'; import { Ok } from './Ok.js'; -import { Error } from './Error.js'; describe(isOk, () => { it('should return true for Ok() object', () => { diff --git a/packages/core/src/Result/map.spec.ts b/packages/core/src/Result/map.spec.ts index 8189e773a7..ddf4ed0f5e 100644 --- a/packages/core/src/Result/map.spec.ts +++ b/packages/core/src/Result/map.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + +import { Error } from './Error.js'; import { map } from './map.js'; import { Ok } from './Ok.js'; -import { Error } from './Error.js'; describe(map, () => { it('should return true for Ok() object', () => { diff --git a/packages/core/src/Result/map.ts b/packages/core/src/Result/map.ts index 940adc0298..3d36633cf8 100644 --- a/packages/core/src/Result/map.ts +++ b/packages/core/src/Result/map.ts @@ -1,6 +1,7 @@ import type { Result } from '../Result.js'; -import { Ok } from './Ok.js'; + import { isOk } from './isOk.js'; +import { Ok } from './Ok.js'; /** * Maps a `Result` to `Result` by applying a function to a contained {@link Result.Ok} value, leaving a {@link Result.Error} value untouched. diff --git a/packages/core/src/Result/mapError.spec.ts b/packages/core/src/Result/mapError.spec.ts index 8451a596ed..1013f497a5 100644 --- a/packages/core/src/Result/mapError.spec.ts +++ b/packages/core/src/Result/mapError.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + +import { Error } from './Error.js'; import { mapError } from './mapError.js'; import { Ok } from './Ok.js'; -import { Error } from './Error.js'; describe(mapError, () => { it('should return true for Ok() object', () => { diff --git a/packages/core/src/Result/mapError.ts b/packages/core/src/Result/mapError.ts index cb541b47b8..a9c7456f4e 100644 --- a/packages/core/src/Result/mapError.ts +++ b/packages/core/src/Result/mapError.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { Error } from './Error.js'; import { isOk } from './isOk.js'; diff --git a/packages/core/src/Result/orElse.spec.ts b/packages/core/src/Result/orElse.spec.ts index ccd84a2c3d..cb72b7ecb6 100644 --- a/packages/core/src/Result/orElse.spec.ts +++ b/packages/core/src/Result/orElse.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, it } from 'vitest'; + import { Result } from '../Result.js'; +import { Error } from './Error.js'; import { Ok } from './Ok.js'; import { orElse } from './orElse.js'; -import { Error } from './Error.js'; describe(orElse, () => { const handleError = (message: string): Result => Ok(`${message}_handled`); diff --git a/packages/core/src/Result/orElse.ts b/packages/core/src/Result/orElse.ts index 8555fa7781..4809dee07f 100644 --- a/packages/core/src/Result/orElse.ts +++ b/packages/core/src/Result/orElse.ts @@ -1,4 +1,5 @@ import type { Result } from '../Result.js'; + import { isOk } from './isOk.js'; /** diff --git a/packages/core/src/Result/tryCall.spec.ts b/packages/core/src/Result/tryCall.spec.ts index b748977597..ddd25e226b 100644 --- a/packages/core/src/Result/tryCall.spec.ts +++ b/packages/core/src/Result/tryCall.spec.ts @@ -1,16 +1,17 @@ import { describe, expect, it, vi } from 'vitest'; -import { tryCall } from './tryCall.js'; -import { Ok } from './Ok.js'; + import { Error } from './Error.js'; +import { Ok } from './Ok.js'; +import { tryCall } from './tryCall.js'; describe(tryCall, () => { class TestError extends globalThis.Error { + override name = 'TestError'; + constructor() { super(); this.name = 'TestError'; } - - override name = 'TestError'; } describe('sync', () => { it('should return Ok(block()) when nothing is thrown', () => { diff --git a/packages/core/src/Result/tryCall.ts b/packages/core/src/Result/tryCall.ts index e58d13aa94..de875e2cd2 100644 --- a/packages/core/src/Result/tryCall.ts +++ b/packages/core/src/Result/tryCall.ts @@ -1,7 +1,9 @@ import { isPromise } from '@w5s/async/dist/isPromise.js'; + import type { Result } from '../Result.js'; -import { Ok } from './Ok.js'; + import { Error } from './Error.js'; +import { Ok } from './Ok.js'; type NonPromise = Exclude>; @@ -27,7 +29,7 @@ type NonPromise = Exclude>; */ export function tryCall(block: () => Promise, onError: (error: unknown) => Promise): Promise>; export function tryCall(block: () => NonPromise, onError: (error: unknown) => NonPromise): Result; -export function tryCall(block: () => V | Promise, onError: (error: unknown) => E | Promise) { +export function tryCall(block: () => Promise | V, onError: (error: unknown) => E | Promise) { try { const returnValue = block(); if (isPromise(returnValue)) { diff --git a/packages/core/src/String.spec.ts b/packages/core/src/String.spec.ts index d95eb8c5fa..5546287e52 100644 --- a/packages/core/src/String.spec.ts +++ b/packages/core/src/String.spec.ts @@ -1,22 +1,23 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { String } from './String.js'; -import { of } from './String/of.js'; import { at } from './String/at.js'; -import { isEmpty } from './String/isEmpty.js'; -import { size } from './String/size.js'; -import { includes } from './String/includes.js'; -import { startsWith } from './String/startsWith.js'; -import { endsWith } from './String/endsWith.js'; import { concat } from './String/concat.js'; -import { split } from './String/split.js'; -import { join } from './String/join.js'; +import { endsWith } from './String/endsWith.js'; +import { includes } from './String/includes.js'; import { indexOf } from './String/indexOf.js'; +import { isEmpty } from './String/isEmpty.js'; +import { join } from './String/join.js'; import { lastIndexOf } from './String/lastIndexOf.js'; -import { StringComparable } from './String/StringComparable.js'; -import { Type } from './Type.js'; +import { of } from './String/of.js'; import { padEnd } from './String/padEnd.js'; import { padStart } from './String/padStart.js'; +import { size } from './String/size.js'; +import { split } from './String/split.js'; +import { startsWith } from './String/startsWith.js'; +import { StringComparable } from './String/StringComparable.js'; import { truncate } from './String/truncate.js'; +import { Type } from './Type.js'; describe('String', () => { it('is an alias to functions', () => { diff --git a/packages/core/src/String.ts b/packages/core/src/String.ts index 8f629402b8..4f6fe7b654 100644 --- a/packages/core/src/String.ts +++ b/packages/core/src/String.ts @@ -1,20 +1,20 @@ -import { string as StringType } from './Type/string.js'; -import { of } from './String/of.js'; import { at } from './String/at.js'; -import { isEmpty } from './String/isEmpty.js'; -import { StringComparable } from './String/StringComparable.js'; -import { size } from './String/size.js'; -import { includes } from './String/includes.js'; -import { startsWith } from './String/startsWith.js'; -import { endsWith } from './String/endsWith.js'; import { concat } from './String/concat.js'; -import { split } from './String/split.js'; -import { join } from './String/join.js'; +import { endsWith } from './String/endsWith.js'; +import { includes } from './String/includes.js'; import { indexOf } from './String/indexOf.js'; +import { isEmpty } from './String/isEmpty.js'; +import { join } from './String/join.js'; import { lastIndexOf } from './String/lastIndexOf.js'; +import { of } from './String/of.js'; import { padEnd } from './String/padEnd.js'; import { padStart } from './String/padStart.js'; +import { size } from './String/size.js'; +import { split } from './String/split.js'; +import { startsWith } from './String/startsWith.js'; +import { StringComparable } from './String/StringComparable.js'; import { truncate } from './String/truncate.js'; +import { string as StringType } from './Type/string.js'; /** * A collection of functions to manipulate `string` diff --git a/packages/core/src/String/StringComparable.spec.ts b/packages/core/src/String/StringComparable.spec.ts index 856a261125..61806917fa 100644 --- a/packages/core/src/String/StringComparable.spec.ts +++ b/packages/core/src/String/StringComparable.spec.ts @@ -1,13 +1,14 @@ import { describe } from 'vitest'; + import { describeComparable } from '../Testing.js'; import { StringComparable } from './StringComparable.js'; describe('StringComparable', () => { describeComparable(StringComparable, { - ordered: () => ['a', 'b', 'c'], equivalent: () => [ ['', ''], ['ab', 'ab'], ], + ordered: () => ['a', 'b', 'c'], }); }); diff --git a/packages/core/src/String/at.spec.ts b/packages/core/src/String/at.spec.ts index 2f41c9e7ac..bc2c5210f0 100644 --- a/packages/core/src/String/at.spec.ts +++ b/packages/core/src/String/at.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { at } from './at.js'; +import { describe, expect, it } from 'vitest'; + import { Option } from '../Option.js'; +import { at } from './at.js'; describe(at, () => { it('should return Option.None when index is not defined', () => { diff --git a/packages/core/src/String/compare.ts b/packages/core/src/String/compare.ts index efd1da7934..09bada9266 100644 --- a/packages/core/src/String/compare.ts +++ b/packages/core/src/String/compare.ts @@ -1,4 +1,5 @@ import type { Order } from '../Order.js'; + import { primitive } from '../Order/primitive.js'; export const compare: Order = primitive; diff --git a/packages/core/src/String/concat.spec.ts b/packages/core/src/String/concat.spec.ts index aacf73a1c4..c9d36b5357 100644 --- a/packages/core/src/String/concat.spec.ts +++ b/packages/core/src/String/concat.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { concat } from './concat.js'; describe(concat, () => { diff --git a/packages/core/src/String/endsWith.spec.ts b/packages/core/src/String/endsWith.spec.ts index b3ff4df4a6..9f65674f87 100644 --- a/packages/core/src/String/endsWith.spec.ts +++ b/packages/core/src/String/endsWith.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { endsWith } from './endsWith.js'; describe(endsWith, () => { diff --git a/packages/core/src/String/includes.spec.ts b/packages/core/src/String/includes.spec.ts index 72da67f866..15dd4dcdd1 100644 --- a/packages/core/src/String/includes.spec.ts +++ b/packages/core/src/String/includes.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { includes } from './includes.js'; describe(includes, () => { diff --git a/packages/core/src/String/indexOf.spec.ts b/packages/core/src/String/indexOf.spec.ts index da59824d9f..33d19a4adb 100644 --- a/packages/core/src/String/indexOf.spec.ts +++ b/packages/core/src/String/indexOf.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { indexOf } from './indexOf.js'; + import { Option } from '../Option.js'; +import { indexOf } from './indexOf.js'; describe(indexOf, () => { it('should return index of element', () => { diff --git a/packages/core/src/String/isEmpty.spec.ts b/packages/core/src/String/isEmpty.spec.ts index c79210e6a1..eda967020e 100644 --- a/packages/core/src/String/isEmpty.spec.ts +++ b/packages/core/src/String/isEmpty.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { isEmpty } from './isEmpty.js'; describe(isEmpty, () => { diff --git a/packages/core/src/String/join.spec.ts b/packages/core/src/String/join.spec.ts index 82ebc73583..51f0145a9d 100644 --- a/packages/core/src/String/join.spec.ts +++ b/packages/core/src/String/join.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { join } from './join.js'; describe(join, () => { diff --git a/packages/core/src/String/lastIndexOf.spec.ts b/packages/core/src/String/lastIndexOf.spec.ts index 171572956e..c03b6d8cb7 100644 --- a/packages/core/src/String/lastIndexOf.spec.ts +++ b/packages/core/src/String/lastIndexOf.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { lastIndexOf } from './lastIndexOf.js'; + import { Option } from '../Option.js'; +import { lastIndexOf } from './lastIndexOf.js'; describe(lastIndexOf, () => { it('should return index of element', () => { diff --git a/packages/core/src/String/of.spec.ts b/packages/core/src/String/of.spec.ts index 85f3792fdf..5cfd51b678 100644 --- a/packages/core/src/String/of.spec.ts +++ b/packages/core/src/String/of.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; describe(of, () => { diff --git a/packages/core/src/String/padEnd.spec.ts b/packages/core/src/String/padEnd.spec.ts index 1b1b369b27..d1569d6f31 100644 --- a/packages/core/src/String/padEnd.spec.ts +++ b/packages/core/src/String/padEnd.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { padEnd } from './padEnd.js'; describe(padEnd, () => { diff --git a/packages/core/src/String/padStart.spec.ts b/packages/core/src/String/padStart.spec.ts index b339059707..c23e08db82 100644 --- a/packages/core/src/String/padStart.spec.ts +++ b/packages/core/src/String/padStart.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { padStart } from './padStart.js'; describe(padStart, () => { diff --git a/packages/core/src/String/size.spec.ts b/packages/core/src/String/size.spec.ts index a4d951088e..ea0b85cc3d 100644 --- a/packages/core/src/String/size.spec.ts +++ b/packages/core/src/String/size.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { split } from './split.js'; describe(split, () => { diff --git a/packages/core/src/String/split.spec.ts b/packages/core/src/String/split.spec.ts index 2722a9c7c2..9dfe327fc7 100644 --- a/packages/core/src/String/split.spec.ts +++ b/packages/core/src/String/split.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { size } from './size.js'; describe(size, () => { diff --git a/packages/core/src/String/split.ts b/packages/core/src/String/split.ts index 913d99cc7b..47251f1baa 100644 --- a/packages/core/src/String/split.ts +++ b/packages/core/src/String/split.ts @@ -12,7 +12,7 @@ */ export function split( self: string, - separator: string | RegExp | { [Symbol.split](string: string, limit?: number): string[] }, + separator: RegExp | string | { [Symbol.split](string: string, limit?: number): Array }, limit?: number, ): Array { return self.split( diff --git a/packages/core/src/String/startsWith.spec.ts b/packages/core/src/String/startsWith.spec.ts index 88d956a475..b08a2d719d 100644 --- a/packages/core/src/String/startsWith.spec.ts +++ b/packages/core/src/String/startsWith.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { startsWith } from './startsWith.js'; describe(startsWith, () => { diff --git a/packages/core/src/String/truncate.spec.ts b/packages/core/src/String/truncate.spec.ts index 69a88697ae..34ed0aaa07 100644 --- a/packages/core/src/String/truncate.spec.ts +++ b/packages/core/src/String/truncate.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { truncate } from './truncate.js'; describe(truncate, () => { @@ -7,14 +8,14 @@ describe(truncate, () => { expect(truncate('', { maxLength: 1 })).toBe(''); }); it('keeps original string if it is shorter than the length', () => { - expect(truncate('abc', { maxLength: 3, ellipsis: '...' })).toBe('abc'); + expect(truncate('abc', { ellipsis: '...', maxLength: 3 })).toBe('abc'); }); it('handles length', () => { - expect(truncate('abc', { maxLength: 1, ellipsis: '...' })).toBe('...'); - expect(truncate('abc', { maxLength: 2, ellipsis: '...' })).toBe('...'); + expect(truncate('abc', { ellipsis: '...', maxLength: 1 })).toBe('...'); + expect(truncate('abc', { ellipsis: '...', maxLength: 2 })).toBe('...'); }); it('handles custom ellipsis', () => { - expect(truncate('abc', { maxLength: 1, ellipsis: 'XX' })).toBe('XX'); + expect(truncate('abc', { ellipsis: 'XX', maxLength: 1 })).toBe('XX'); }); it('truncates string to specified length', () => { expect(truncate('Hello World', { maxLength: 4 })).toBe('H...'); diff --git a/packages/core/src/String/truncate.ts b/packages/core/src/String/truncate.ts index e071736a38..f56d376f48 100644 --- a/packages/core/src/String/truncate.ts +++ b/packages/core/src/String/truncate.ts @@ -35,7 +35,7 @@ truncate.defaultOptions = { } satisfies truncate.Options; export namespace truncate { - export type Options = { + export interface Options { /** * A string to append at the end of the truncated string if it is shorter than the `maxLength` */ @@ -45,5 +45,5 @@ export namespace truncate { * The desired length of the output string */ maxLength?: number; - }; + } } diff --git a/packages/core/src/Struct.spec.ts b/packages/core/src/Struct.spec.ts index c6c3b89e91..79d740250d 100644 --- a/packages/core/src/Struct.spec.ts +++ b/packages/core/src/Struct.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; import { inspect } from 'node:util'; -import { Struct } from './Struct.js'; +import { describe, expect, it } from 'vitest'; + import { Callable } from './Callable.js'; +import { Struct } from './Struct.js'; describe('Struct', () => { describe(Struct.define, () => { diff --git a/packages/core/src/Struct.ts b/packages/core/src/Struct.ts index b04a740261..0dd25d612d 100644 --- a/packages/core/src/Struct.ts +++ b/packages/core/src/Struct.ts @@ -1,10 +1,12 @@ import type { PartialKeys } from '@w5s/core-type'; + import type { AsString } from './AsString.js'; -import { Struct as StructImpl } from './Struct/Struct.js'; +import type { Symbol } from './Symbol.js'; +import type { Type } from './Type.js'; + import { Callable } from './Callable.js'; +import { Struct as StructImpl } from './Struct/Struct.js'; import { define as defineType } from './Type/define.js'; -import type { Type } from './Type.js'; -import type { Symbol } from './Symbol.js'; const type = '_' as const; @@ -35,11 +37,6 @@ export type Struct< * @namespace */ export const Struct = { - /** - * The type property discriminator - */ - type, - /** * Return a new Struct from `properties`. * Struct adds debugging / inspecting abilities @@ -96,16 +93,23 @@ export const Struct = { ...module, }); }, -}; -export namespace Struct { /** - * Extract all parameters to create a new Struct + * The type property discriminator */ - export type Parameters = Omit; + type, +}; + +export namespace Struct { + export interface DefineParameters> extends PartialKeys< + Type.Parameters, + 'hasInstance' + > { + typeName: Model[Struct.type]; + } export interface Module - extends Type.Module, Callable<(properties: Parameters) => Model> { + extends Callable<(properties: Parameters) => Model>, Type.Module { /** * Construct a new model * @@ -130,14 +134,12 @@ export namespace Struct { readonly typeName: Model[Struct.type]; } - export type type = typeof type; + export type ModuleParameter = AsString & Pick, Symbol.inspect>; - export type ModuleParameter = Pick, Symbol.inspect> & AsString; + /** + * Extract all parameters to create a new Struct + */ + export type Parameters = Omit; - export interface DefineParameters> extends PartialKeys< - Type.Parameters, - 'hasInstance' - > { - typeName: Model[Struct.type]; - } + export type type = typeof type; } diff --git a/packages/core/src/Struct/Struct.spec.ts b/packages/core/src/Struct/Struct.spec.ts index 4bd56e475f..8f4a7c3446 100644 --- a/packages/core/src/Struct/Struct.spec.ts +++ b/packages/core/src/Struct/Struct.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect, vi } from 'vitest'; import { inspect } from 'node:util'; -import { Struct } from './Struct.js'; -import { Type } from '../Type.js'; +import { describe, expect, it, vi } from 'vitest'; + import { Symbol } from '../Symbol.js'; +import { Type } from '../Type.js'; +import { Struct } from './Struct.js'; describe(Struct, () => { const defaultProperties = { - typeName: 'Foo', hasInstance: vi.fn(), + typeName: 'Foo', }; describe(Struct.create, () => { it('returns a new instance', () => { @@ -27,7 +28,7 @@ describe(Struct, () => { }); it('always have _ tag first', () => { const Foo = Type.define<{ _: string; foo: boolean }>(defaultProperties); - const instance = Struct.create(Foo, { foo: true, _: 'Toto' }); + const instance = Struct.create(Foo, { _: 'Toto', foo: true }); expect(inspect(instance)).toBe(`{ _: 'Toto', foo: true }`); }); it('returns a custom representation when specified', () => { diff --git a/packages/core/src/Struct/Struct.ts b/packages/core/src/Struct/Struct.ts index 2260ece198..5185c1ebb4 100644 --- a/packages/core/src/Struct/Struct.ts +++ b/packages/core/src/Struct/Struct.ts @@ -1,7 +1,8 @@ -import { compare } from '../String/compare.js'; import type { Struct as TStruct } from '../Struct.js'; import type { InspectFunction, InspectOptions } from '../Type.js'; +import { compare } from '../String/compare.js'; + const { Object: { assign }, @@ -17,16 +18,16 @@ const defaultSort = (left: string | symbol, right: string | symbol) => export const Struct = class Object { // Important : we name Object so it is shown as anonymous object in snapshot. - static create(mod: TStruct.ModuleParameter, properties: T): T { - return assign(new Struct(mod), properties); - } - #module: TStruct.ModuleParameter; protected constructor(mod: TStruct.ModuleParameter) { this.#module = mod; } + static create(mod: TStruct.ModuleParameter, properties: T): T { + return assign(new Struct(mod), properties); + } + /** * Return an inspect representation * diff --git a/packages/core/src/Symbol.spec.ts b/packages/core/src/Symbol.spec.ts index 55898935b3..0100eefc0b 100644 --- a/packages/core/src/Symbol.spec.ts +++ b/packages/core/src/Symbol.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Symbol } from './Symbol.js'; const GlobalSymbol = globalThis.Symbol; diff --git a/packages/core/src/Symbol.ts b/packages/core/src/Symbol.ts index 1bdd040d2b..56aff1ccb1 100644 --- a/packages/core/src/Symbol.ts +++ b/packages/core/src/Symbol.ts @@ -20,9 +20,9 @@ const run = '__run__' as const; // GlobalSymbol.for('w5s.run') as any; */ export const Symbol = { /** - * A method that returns the default iterator for an object. Called by the semantics of the for-of statement. + * A method that is used to asynchronously release resources held by an object. Called by the semantics of the await using statement. */ - iterator: __symbolAlias('iterator') as SymbolConstructor['iterator'], + asyncDispose: __symbolAlias('asyncDispose') as SymbolConstructor['asyncDispose'], /** * A method that returns the default async iterator for an object. Called by the semantics of the for-await-of statement. @@ -30,110 +30,110 @@ export const Symbol = { asyncIterator: __symbolAlias('asyncIterator') as SymbolConstructor['asyncIterator'], /** - * A method that determines if a constructor object recognizes an object as one of the constructor’s instances. Called by the semantics of the instanceof operator. + * Call signature */ - hasInstance: __symbolAlias('hasInstance') as SymbolConstructor['hasInstance'], + call, /** - * A Boolean value that if true indicates that an object should flatten to its array elements by Array.prototype.concat. + * Decode property symbol + * + * @see {@link Codec} */ - isConcatSpreadable: __symbolAlias('isConcatSpreadable') as SymbolConstructor['isConcatSpreadable'], + decode, /** - * A regular expression method that matches the regular expression against a string. Called by the String.prototype.match method. + * A method that is used to release resources held by an object. Called by the semantics of the using statement. */ - match: __symbolAlias('match') as SymbolConstructor['match'], + dispose: __symbolAlias('dispose') as SymbolConstructor['dispose'], /** - * A regular expression method that matches the regular expression against a string. Called by the String.prototype.matchAll method. + * Encode property symbol + * + * @see {@link Codec} */ - matchAll: __symbolAlias('matchAll') as SymbolConstructor['matchAll'], + encode, /** - * A regular expression method that replaces matched substrings of a string. Called by the String.prototype.replace method. + * Enum keys */ - replace: __symbolAlias('replace') as SymbolConstructor['replace'], + enumKeys, /** - * A regular expression method that replaces matched substrings of a string. Called by the String.prototype.replace method. + * A method that determines if a constructor object recognizes an object as one of the constructor’s instances. Called by the semantics of the instanceof operator. */ - search: __symbolAlias('search') as SymbolConstructor['search'], + hasInstance: __symbolAlias('hasInstance') as SymbolConstructor['hasInstance'], /** - * A function valued property that is the constructor function that is used to create derived objects. + * NodeJS Inspect callback */ - species: __symbolAlias('species') as SymbolConstructor['species'], + inspect, /** - * A regular expression method that splits a string at the indices that match the regular expression. Called by the String.prototype.split method. + * A Boolean value that if true indicates that an object should flatten to its array elements by Array.prototype.concat. */ - split: __symbolAlias('split') as SymbolConstructor['split'], + isConcatSpreadable: __symbolAlias('isConcatSpreadable') as SymbolConstructor['isConcatSpreadable'], /** - * A String value that is used in the creation of the default string description of an object. Called by the built-in method Object.prototype.toString. + * A method that returns the default iterator for an object. Called by the semantics of the for-of statement. */ - toStringTag: __symbolAlias('toStringTag') as SymbolConstructor['toStringTag'], + iterator: __symbolAlias('iterator') as SymbolConstructor['iterator'], /** - * A method that converts an object to a corresponding primitive value. Called by the ToPrimitive abstract operation. + * A regular expression method that matches the regular expression against a string. Called by the String.prototype.match method. */ - toPrimitive: __symbolAlias('toPrimitive') as SymbolConstructor['toPrimitive'], + match: __symbolAlias('match') as SymbolConstructor['match'], /** - * An Object whose truthy properties are properties that are excluded from the 'with' environment bindings of the associated objects. + * A regular expression method that matches the regular expression against a string. Called by the String.prototype.matchAll method. */ - unscopables: __symbolAlias('unscopables') as SymbolConstructor['unscopables'], + matchAll: __symbolAlias('matchAll') as SymbolConstructor['matchAll'], /** - * A method that is used to release resources held by an object. Called by the semantics of the using statement. + * A regular expression method that replaces matched substrings of a string. Called by the String.prototype.replace method. */ - dispose: __symbolAlias('dispose') as SymbolConstructor['dispose'], + replace: __symbolAlias('replace') as SymbolConstructor['replace'], /** - * A method that is used to asynchronously release resources held by an object. Called by the semantics of the await using statement. + * Task run effect */ - asyncDispose: __symbolAlias('asyncDispose') as SymbolConstructor['asyncDispose'], + run, /** - * Call signature + * Schema property symbol + * + * @see {@link Codec} */ - call, + schema, /** - * NodeJS Inspect callback + * A regular expression method that replaces matched substrings of a string. Called by the String.prototype.replace method. */ - inspect, + search: __symbolAlias('search') as SymbolConstructor['search'], /** - * Encode property symbol - * - * @see {@link Codec} + * A function valued property that is the constructor function that is used to create derived objects. */ - encode, + species: __symbolAlias('species') as SymbolConstructor['species'], /** - * Decode property symbol - * - * @see {@link Codec} + * A regular expression method that splits a string at the indices that match the regular expression. Called by the String.prototype.split method. */ - decode, + split: __symbolAlias('split') as SymbolConstructor['split'], /** - * Schema property symbol - * - * @see {@link Codec} + * A method that converts an object to a corresponding primitive value. Called by the ToPrimitive abstract operation. */ - schema, + toPrimitive: __symbolAlias('toPrimitive') as SymbolConstructor['toPrimitive'], /** - * Enum keys + * A String value that is used in the creation of the default string description of an object. Called by the built-in method Object.prototype.toString. */ - enumKeys, + toStringTag: __symbolAlias('toStringTag') as SymbolConstructor['toStringTag'], /** - * Task run effect + * An Object whose truthy properties are properties that are excluded from the 'with' environment bindings of the associated objects. */ - run, + unscopables: __symbolAlias('unscopables') as SymbolConstructor['unscopables'], }; /** @@ -141,30 +141,30 @@ export const Symbol = { * */ export namespace Symbol { - export type iterator = typeof Symbol.iterator; + export type asyncDispose = typeof Symbol.asyncDispose; export type asyncIterator = typeof Symbol.asyncIterator; + // W5S symbols + export type call = typeof Symbol.call; + export type decode = typeof Symbol.decode; + export type dispose = typeof Symbol.dispose; + export type encode = typeof Symbol.encode; + export type enumKeys = typeof Symbol.enumKeys; export type hasInstance = typeof Symbol.hasInstance; + export type inspect = typeof Symbol.inspect; export type isConcatSpreadable = typeof Symbol.isConcatSpreadable; + export type iterator = typeof Symbol.iterator; export type match = typeof Symbol.match; export type matchAll = typeof Symbol.matchAll; export type replace = typeof Symbol.replace; + export type run = typeof Symbol.run; + + // NodeJS + + export type schema = typeof Symbol.schema; export type search = typeof Symbol.search; export type species = typeof Symbol.species; export type split = typeof Symbol.split; - export type toStringTag = typeof Symbol.toStringTag; export type toPrimitive = typeof Symbol.toPrimitive; + export type toStringTag = typeof Symbol.toStringTag; export type unscopables = typeof Symbol.unscopables; - export type dispose = typeof Symbol.dispose; - export type asyncDispose = typeof Symbol.asyncDispose; - - // NodeJS - - // W5S symbols - export type call = typeof Symbol.call; - export type inspect = typeof Symbol.inspect; - export type encode = typeof Symbol.encode; - export type decode = typeof Symbol.decode; - export type schema = typeof Symbol.schema; - export type enumKeys = typeof Symbol.enumKeys; - export type run = typeof Symbol.run; } diff --git a/packages/core/src/Tag.spec.ts b/packages/core/src/Tag.spec.ts index a625490ae0..d5dc0514f8 100644 --- a/packages/core/src/Tag.spec.ts +++ b/packages/core/src/Tag.spec.ts @@ -1,12 +1,13 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Tag } from './Tag.js'; import { define } from './Tag/define.js'; describe('Tag', () => { type PositiveNumber = number & Tag<'Positive'>; const PositiveNumber = Tag.define({ - typeName: 'PositiveNumber', hasInstance: (value) => typeof value === 'number' && value > 0, + typeName: 'PositiveNumber', }); it('is an alias to functions', () => { expect(Tag).toEqual({ diff --git a/packages/core/src/Tag.ts b/packages/core/src/Tag.ts index b5011161fa..fa2813e8f5 100644 --- a/packages/core/src/Tag.ts +++ b/packages/core/src/Tag.ts @@ -1,8 +1,10 @@ import type { Tag as CoreTypeTag } from '@w5s/core-type'; + import type { Callable } from './Callable.js'; -import { define } from './Tag/define.js'; import type { Type } from './Type.js'; +import { define } from './Tag/define.js'; + /** * Alias of {@link @w5s/core-type!Tag} * @@ -16,9 +18,7 @@ export const Tag = { define, }; export namespace Tag { - export interface Parameters extends Type.Parameters {} - - export interface Module extends Type.Module, Callable<(value: From) => To> { + export interface Module extends Callable<(value: From) => To>, Type.Module { /** * Convert an underlying type to a tagged type * Alias to `wrap(value)` @@ -28,19 +28,21 @@ export namespace Tag { (value: From): To; /** - * Convert an underlying type to a tagged type + * Convert a tagged value to the underlying type * * @category Type * @param value */ - wrap(value: From): To; + unwrap(value: To): From; /** - * Convert a tagged value to the underlying type + * Convert an underlying type to a tagged type * * @category Type * @param value */ - unwrap(value: To): From; + wrap(value: From): To; } + + export interface Parameters extends Type.Parameters {} } diff --git a/packages/core/src/Tag/define.spec.ts b/packages/core/src/Tag/define.spec.ts index e66afe1833..da7019bea0 100644 --- a/packages/core/src/Tag/define.spec.ts +++ b/packages/core/src/Tag/define.spec.ts @@ -1,23 +1,25 @@ import { describe, expect, it } from 'vitest'; -import { describeType } from '../Testing.js'; + +import type { Tag } from '../Tag.js'; + +import { Callable } from '../Callable.js'; import { Codec } from '../Codec.js'; import { CodecError } from '../CodecError.js'; import { Result } from '../Result.js'; -import type { Tag } from '../Tag.js'; +import { describeType } from '../Testing.js'; import { define } from './define.js'; -import { Callable } from '../Callable.js'; describe(define, () => { type PositiveNumber = number & Tag<'Positive'>; const PositiveNumber = define({ - typeName: 'PositiveNumber', hasInstance: (value) => typeof value === 'number' && value > 0, + typeName: 'PositiveNumber', }); describeType(PositiveNumber, () => ({ - typeName: 'PositiveNumber', instances: [1 as PositiveNumber, 1000 as PositiveNumber], notInstances: [0, -1, -1000], + typeName: 'PositiveNumber', })); describe('#()', () => { it('returns identity', () => { @@ -62,11 +64,11 @@ describe(define, () => { expect(Codec.decode(PositiveNumber, 1)).toEqual(Result.Ok(1)); expect(Codec.decode(PositiveNumber, 'invalid_value')).toEqual( Result.Error( - new CodecError({ message: 'Cannot decode "invalid_value" as PositiveNumber', input: 'invalid_value' }), + new CodecError({ input: 'invalid_value', message: 'Cannot decode "invalid_value" as PositiveNumber' }), ), ); expect(Codec.decode(PositiveNumber, undefined)).toEqual( - Result.Error(new CodecError({ message: 'Cannot decode undefined as PositiveNumber', input: undefined })), + Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as PositiveNumber' })), ); }); }); @@ -76,11 +78,11 @@ describe(define, () => { }); it('is overridable', () => { const PositiveNumberWithSchema = define({ - typeName: 'PositiveNumber', - hasInstance: (value) => typeof value === 'number' && value > 0, __schema__: () => ({ type: 'number', }), + hasInstance: (value) => typeof value === 'number' && value > 0, + typeName: 'PositiveNumber', }); expect(Codec.schema(PositiveNumberWithSchema)).toEqual({ type: 'number' }); }); diff --git a/packages/core/src/Tag/define.ts b/packages/core/src/Tag/define.ts index 294a9b5e52..3912ee43e2 100644 --- a/packages/core/src/Tag/define.ts +++ b/packages/core/src/Tag/define.ts @@ -1,5 +1,6 @@ -import { Callable } from '../Callable.js'; import type { Tag } from '../Tag.js'; + +import { Callable } from '../Callable.js'; import { define as defineType } from '../Type/define.js'; import { ensure as ensureType } from '../Type/ensure.js'; @@ -29,8 +30,8 @@ export function define(parameters: Tag.Parameters): T } return Callable({ - wrap, unwrap, + wrap, ...TagType, [Callable.symbol]: (value: From) => wrap(value), }); diff --git a/packages/core/src/Testing.spec.ts b/packages/core/src/Testing.spec.ts index cd7becda31..ea4cc82e7b 100644 --- a/packages/core/src/Testing.spec.ts +++ b/packages/core/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('Testing', () => { diff --git a/packages/core/src/Testing.ts b/packages/core/src/Testing.ts index 47d10ca955..b5112f598e 100644 --- a/packages/core/src/Testing.ts +++ b/packages/core/src/Testing.ts @@ -14,8 +14,8 @@ export * from './Testing/describeEqual.js'; export * from './Testing/describeIndexable.js'; export * from './Testing/describeMultiply.js'; export * from './Testing/describeNegate.js'; -export * from './Testing/describeNumeric.js'; export * from './Testing/describeNot.js'; +export * from './Testing/describeNumeric.js'; export * from './Testing/describePower.js'; export * from './Testing/describeRemainder.js'; export * from './Testing/describeSigned.js'; diff --git a/packages/core/src/Testing/defaultTestingLibrary.ts b/packages/core/src/Testing/defaultTestingLibrary.ts index e186cabfdc..506324001a 100644 --- a/packages/core/src/Testing/defaultTestingLibrary.ts +++ b/packages/core/src/Testing/defaultTestingLibrary.ts @@ -1,4 +1,5 @@ import type { TestingLibrary } from '@w5s/core-type'; + import { panic } from '@w5s/error'; const tryImport = async (path: string): Promise => { diff --git a/packages/core/src/Testing/describeAdd.ts b/packages/core/src/Testing/describeAdd.ts index 74372c65af..3d86a9ff32 100644 --- a/packages/core/src/Testing/describeAdd.ts +++ b/packages/core/src/Testing/describeAdd.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Add} trait * @@ -22,7 +23,7 @@ export function describeAdd( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '+'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeAsString.ts b/packages/core/src/Testing/describeAsString.ts index 840055ba8d..85fe2e69ea 100644 --- a/packages/core/src/Testing/describeAsString.ts +++ b/packages/core/src/Testing/describeAsString.ts @@ -1,7 +1,8 @@ import type { AsString } from '../AsString.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#AsString} interface * @@ -36,7 +37,7 @@ export function describeAsString>( testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { const { asString = true, String = true } = withTest; - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; if (asString) { describe('asString', () => { it.each(properties(subject))('satisfies asString($0) == $1', (instance, string) => { diff --git a/packages/core/src/Testing/describeBounded.ts b/packages/core/src/Testing/describeBounded.ts index 94dc02ba05..6635ae51de 100644 --- a/packages/core/src/Testing/describeBounded.ts +++ b/packages/core/src/Testing/describeBounded.ts @@ -1,7 +1,8 @@ import type { Bounded } from '../Bounded.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Bounded} trait * @@ -22,7 +23,7 @@ export function describeBounded( snapshot: Bounded, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; describe('minValue', () => { it('is a specific value', () => { expect(subject.minValue).toEqual(snapshot.minValue); diff --git a/packages/core/src/Testing/describeCheckedAdd.ts b/packages/core/src/Testing/describeCheckedAdd.ts index dbad7747f7..05572c4bf0 100644 --- a/packages/core/src/Testing/describeCheckedAdd.ts +++ b/packages/core/src/Testing/describeCheckedAdd.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; +import type { TestingLibrary } from './type.js'; + import { Option } from '../Option.js'; import { defaultTestingLibrary } from './defaultTestingLibrary.js'; -import type { TestingLibrary } from './type.js'; /** * Create a spec for {@link @w5s/core#Numeric.CheckedAdd} trait @@ -23,7 +24,7 @@ export function describeCheckedAdd( cases: Array<{ call: [L, R]; returns: Option }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '+?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCheckedDivide.ts b/packages/core/src/Testing/describeCheckedDivide.ts index 6cfa38ebdf..41f3f0a92f 100644 --- a/packages/core/src/Testing/describeCheckedDivide.ts +++ b/packages/core/src/Testing/describeCheckedDivide.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.CheckedDivide} trait * @@ -22,7 +23,7 @@ export function describeCheckedDivide( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '/?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCheckedMultiply.ts b/packages/core/src/Testing/describeCheckedMultiply.ts index e1cbeebc5f..327ad6baa0 100644 --- a/packages/core/src/Testing/describeCheckedMultiply.ts +++ b/packages/core/src/Testing/describeCheckedMultiply.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; +import type { TestingLibrary } from './type.js'; + import { Option } from '../Option.js'; import { defaultTestingLibrary } from './defaultTestingLibrary.js'; -import type { TestingLibrary } from './type.js'; /** * Create a spec for {@link @w5s/core#Numeric.CheckedMultiply} trait @@ -22,7 +23,7 @@ export function describeCheckedMultiply( cases: Array<{ call: [L, R]; returns: Option }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '*?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCheckedPower.ts b/packages/core/src/Testing/describeCheckedPower.ts index 7d53daea91..9aca0bba61 100644 --- a/packages/core/src/Testing/describeCheckedPower.ts +++ b/packages/core/src/Testing/describeCheckedPower.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.CheckedPower} trait * @@ -22,7 +23,7 @@ export function describeCheckedPower( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '**?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCheckedRemainder.ts b/packages/core/src/Testing/describeCheckedRemainder.ts index 804a0e669d..caa8dd99cf 100644 --- a/packages/core/src/Testing/describeCheckedRemainder.ts +++ b/packages/core/src/Testing/describeCheckedRemainder.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.CheckedRemainder} trait * @@ -22,7 +23,7 @@ export function describeCheckedRemainder( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '%?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCheckedSubtract.ts b/packages/core/src/Testing/describeCheckedSubtract.ts index 098f5cdd8c..201b604d01 100644 --- a/packages/core/src/Testing/describeCheckedSubtract.ts +++ b/packages/core/src/Testing/describeCheckedSubtract.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; +import type { TestingLibrary } from './type.js'; + import { Option } from '../Option.js'; import { defaultTestingLibrary } from './defaultTestingLibrary.js'; -import type { TestingLibrary } from './type.js'; /** * Create a spec for {@link @w5s/core#Numeric.CheckedSubtract} trait @@ -23,7 +24,7 @@ export function describeCheckedSubtract( cases: Array<{ call: [L, R]; returns: Option }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '-?'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeCodec.spec.ts b/packages/core/src/Testing/describeCodec.spec.ts index 777a66d9f4..7b3925c124 100644 --- a/packages/core/src/Testing/describeCodec.spec.ts +++ b/packages/core/src/Testing/describeCodec.spec.ts @@ -1,34 +1,36 @@ import { describe } from 'vitest'; + import type { Codec } from '../Codec.js'; + import { CodecError } from '../CodecError.js'; -import { describeCodec } from './describeCodec.js'; import { Result } from '../Result.js'; import { Symbol } from '../Symbol.js'; +import { describeCodec } from './describeCodec.js'; describe('describeCodec', () => { const StringCodec: Codec = { - [Symbol.encode]: (value) => value, [Symbol.decode]: (value) => typeof value === 'string' ? Result.Ok(value) : Result.Error( new CodecError({ - message: 'test error', input: value, + message: 'test error', }), ), + [Symbol.encode]: (value) => value, [Symbol.schema]: () => ({ type: 'string' }), }; describeCodec(StringCodec, () => ({ - encode: [ - ['a', 'a'], - ['', ''], - ], decode: [ ['a', Result.Ok('a')], [1, Result.Error(new CodecError({ input: 1, message: 'test error' }))], ], + encode: [ + ['a', 'a'], + ['', ''], + ], schema: { type: 'string', }, diff --git a/packages/core/src/Testing/describeCodec.ts b/packages/core/src/Testing/describeCodec.ts index 9aa2223967..f79041dc0d 100644 --- a/packages/core/src/Testing/describeCodec.ts +++ b/packages/core/src/Testing/describeCodec.ts @@ -1,8 +1,9 @@ -import { Codec } from '../Codec.js'; import type { Result } from '../Result.js'; +import type { TestingLibrary } from './type.js'; + +import { Codec } from '../Codec.js'; import { Symbol } from '../Symbol.js'; import { defaultTestingLibrary } from './defaultTestingLibrary.js'; -import type { TestingLibrary } from './type.js'; /** * Create a spec for Codec behavior @@ -36,21 +37,21 @@ export function describeCodec>( }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const data = properties(subject); (data.decode.length === 0 ? describe.todo : describe)(Symbol.decode, () => { - it.each(data.decode.map(([input, expected]) => ({ input, expected })))( + it.each(data.decode.map(([input, expected]) => ({ expected, input })))( '($input) == $expected', - ({ input, expected }) => { + ({ expected, input }) => { expect(Codec.decode(subject, input)).toEqual(expected); }, ); }); (data.encode.length === 0 ? describe.todo : describe)(Symbol.encode, () => { - it.each(data.encode.map(([input, expected]) => ({ input, expected })))( + it.each(data.encode.map(([input, expected]) => ({ expected, input })))( '($input) == $expected', - ({ input, expected }) => { + ({ expected, input }) => { expect(Codec.encode(subject, input)).toEqual(expected); }, ); diff --git a/packages/core/src/Testing/describeComparable.spec.ts b/packages/core/src/Testing/describeComparable.spec.ts index b610201d30..eeac1540ef 100644 --- a/packages/core/src/Testing/describeComparable.spec.ts +++ b/packages/core/src/Testing/describeComparable.spec.ts @@ -1,4 +1,5 @@ import { describe } from 'vitest'; + import { Comparable } from '../Comparable.js'; import { describeComparable } from './describeComparable.js'; @@ -8,11 +9,11 @@ describe('describeComparable', () => { }); describeComparable(NumberEqual, { - ordered: () => [-1, 0, 1], equivalent: () => [ [0, 0], [1, 1], [1.1, 1.1], ], + ordered: () => [-1, 0, 1], }); }); diff --git a/packages/core/src/Testing/describeComparable.ts b/packages/core/src/Testing/describeComparable.ts index 3d740bbedb..6c9f779cfa 100644 --- a/packages/core/src/Testing/describeComparable.ts +++ b/packages/core/src/Testing/describeComparable.ts @@ -1,7 +1,8 @@ import type { ComparableInterface } from '../Comparable.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for Comparable behavior * @@ -26,12 +27,12 @@ import type { TestingLibrary } from './type.js'; export function describeComparable( subject: ComparableInterface, properties: { - ordered: () => T[]; - equivalent: () => [T, T][]; + equivalent: () => Array<[T, T]>; + ordered: () => Array; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const { equivalent: equivalentDefault, ordered } = properties; const equivalent = () => equivalentDefault().map(([left, right]) => ({ left, right })); const inferiorData = () => { diff --git a/packages/core/src/Testing/describeDivide.ts b/packages/core/src/Testing/describeDivide.ts index f4229fa3a9..4d1792ad9b 100644 --- a/packages/core/src/Testing/describeDivide.ts +++ b/packages/core/src/Testing/describeDivide.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Divide} trait * @@ -21,7 +22,7 @@ export function describeDivide( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '/'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeEqual.spec.ts b/packages/core/src/Testing/describeEqual.spec.ts index 37d202f515..db322a0d00 100644 --- a/packages/core/src/Testing/describeEqual.spec.ts +++ b/packages/core/src/Testing/describeEqual.spec.ts @@ -1,4 +1,5 @@ import { describe } from 'vitest'; + import { Equal } from '../Equal.js'; import { describeEqual } from './describeEqual.js'; @@ -8,16 +9,16 @@ describe('describeEqual', () => { }); describeEqual(NumberEqual, { + different: () => [ + [1, -1], + [0.1, 0], + [NaN, NaN], + ], equivalent: () => [ [-1, -1], [0, 0], [1, 1], [1.1, 1.1], ], - different: () => [ - [1, -1], - [0.1, 0], - [NaN, NaN], - ], }); }); diff --git a/packages/core/src/Testing/describeEqual.ts b/packages/core/src/Testing/describeEqual.ts index 4f904d6a48..6d738b01f4 100644 --- a/packages/core/src/Testing/describeEqual.ts +++ b/packages/core/src/Testing/describeEqual.ts @@ -1,17 +1,18 @@ import type { EqualsInterface } from '../Equal.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + export function describeEqual( subject: EqualsInterface, properties: { - equivalent: () => [T, T][]; - different: () => [T, T][]; + different: () => Array<[T, T]>; + equivalent: () => Array<[T, T]>; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; - const { equivalent: equivalentDefault, different: differentDefault } = properties; + const { describe, expect, it } = testingLibrary; + const { different: differentDefault, equivalent: equivalentDefault } = properties; const equivalent = () => equivalentDefault().map(([left, right]) => ({ left, right })); const different = () => differentDefault().map(([left, right]) => ({ left, right })); diff --git a/packages/core/src/Testing/describeIndexable.ts b/packages/core/src/Testing/describeIndexable.ts index 11f31ea8fb..57407ae67e 100644 --- a/packages/core/src/Testing/describeIndexable.ts +++ b/packages/core/src/Testing/describeIndexable.ts @@ -1,7 +1,8 @@ import type { Indexable } from '../Indexable.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Indexable} trait * @@ -31,49 +32,49 @@ import type { TestingLibrary } from './type.js'; * @param cases.index * @param testingLibrary Optional testing library to use. Automatically detects if not provided. */ -export function describeIndexable( +export function describeIndexable( subject: Indexable, cases: { index: Array<[index: Index, value: V]>; - rangeSize?: Array<[start: V, end: V, expected: Index]>; range: Array<[start: V, end: V, expected: Array]>; + rangeSize?: Array<[start: V, end: V, expected: Index]>; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; - const at = cases.index.map(([index, expected]) => ({ index, expected })); - const indexOf = cases.index.map(([expected, value]) => ({ value, expected })); + const { describe, expect, it } = testingLibrary; + const at = cases.index.map(([index, expected]) => ({ expected, index })); + const indexOf = cases.index.map(([expected, value]) => ({ expected, value })); const rangeSize = - cases.rangeSize?.map(([start, end, expected]) => ({ start, end, expected })) ?? + cases.rangeSize?.map(([start, end, expected]) => ({ end, expected, start })) ?? cases.range.map(([start, end, expected]) => ({ - start, end, expected: subject.indexType === 'bigint' ? BigInt(expected.length) : (expected.length as Index), + start, })); - const range = cases.range.map(([start, end, expected]) => ({ start, end, expected })); + const range = cases.range.map(([start, end, expected]) => ({ end, expected, start })); // at (at.length === 0 ? describe.todo : describe)('at', () => { - it.each(at)('satisfies at($index) == $expected', ({ index, expected }) => { + it.each(at)('satisfies at($index) == $expected', ({ expected, index }) => { const value = subject.at(index); expect(value).toEqual(expected); }); }); // indexOf (indexOf.length === 0 ? describe.todo : describe)('indexOf', () => { - it.each(indexOf)('satisfies indexOf($value) == $expected', ({ value, expected }) => { + it.each(indexOf)('satisfies indexOf($value) == $expected', ({ expected, value }) => { const index = subject.indexOf(value); expect(index).toBe(expected); }); }); (rangeSize.length === 0 ? describe.todo : describe)('rangeSize', () => { - it.each(rangeSize)('satisfies rangeSize($start, $end) == $expected', ({ start, end, expected }) => { + it.each(rangeSize)('satisfies rangeSize($start, $end) == $expected', ({ end, expected, start }) => { const size = subject.rangeSize(start, end); expect(size).toBe(expected); }); }); (range.length === 0 ? describe.todo : describe)('range', () => { - it.each(range)('satisfies range($start, $end) == $expected', ({ start, end, expected }) => { + it.each(range)('satisfies range($start, $end) == $expected', ({ end, expected, start }) => { const array = [...subject.range(start, end)]; expect(array).toEqual(expected); }); diff --git a/packages/core/src/Testing/describeMultiply.ts b/packages/core/src/Testing/describeMultiply.ts index b4fafed688..a327e7d42c 100644 --- a/packages/core/src/Testing/describeMultiply.ts +++ b/packages/core/src/Testing/describeMultiply.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Multiply} trait * @@ -22,7 +23,7 @@ export function describeMultiply( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '*'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeNegate.ts b/packages/core/src/Testing/describeNegate.ts index f7c147687c..cadc3c3a8a 100644 --- a/packages/core/src/Testing/describeNegate.ts +++ b/packages/core/src/Testing/describeNegate.ts @@ -1,8 +1,9 @@ import type { EqualsInterface } from '../Equal.js'; import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link Numeric.Negate} interface * @@ -24,13 +25,13 @@ import type { TestingLibrary } from './type.js'; * @param testingLibrary Optional testing library to use. Automatically detects if not provided. */ export function describeNegate( - subject: Numeric.Negate & EqualsInterface, + subject: EqualsInterface & Numeric.Negate, properties: { values: () => Array<[base: T, negated: T]>; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const values = properties.values(); const describeIfValue = values.length === 0 ? describe.todo : describe; describeIfValue('negate', () => { diff --git a/packages/core/src/Testing/describeNot.ts b/packages/core/src/Testing/describeNot.ts index 44c8007a43..fc63f01c4e 100644 --- a/packages/core/src/Testing/describeNot.ts +++ b/packages/core/src/Testing/describeNot.ts @@ -1,7 +1,8 @@ import type { Not } from '../Not.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core!Not} interface * @@ -25,7 +26,7 @@ export function describeNot( cases: () => Array<[value: T, negation: T]>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; (cases().length === 0 ? describe.todo : describe)('not', () => { it.each(cases())('satisfies not($0) == $1', (left, right) => { expect(subject.not(left)).toEqual(right); diff --git a/packages/core/src/Testing/describeNumeric.ts b/packages/core/src/Testing/describeNumeric.ts index 7cb26c4e70..a02fe5ec53 100644 --- a/packages/core/src/Testing/describeNumeric.ts +++ b/packages/core/src/Testing/describeNumeric.ts @@ -1,20 +1,22 @@ import type { TestingLibrary } from '@w5s/core-type'; + +import type { ComparableInterface } from '../Comparable.js'; +import type { EqualsInterface } from '../Equal.js'; import type { Numeric } from '../Numeric.js'; + import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import { describeAdd } from './describeAdd.js'; -import { describeZero } from './describeZero.js'; import { describeComparable } from './describeComparable.js'; -import type { ComparableInterface } from '../Comparable.js'; import { describeMultiply } from './describeMultiply.js'; -import { describeSubtract } from './describeSubtract.js'; import { describeSigned } from './describeSigned.js'; -import type { EqualsInterface } from '../Equal.js'; +import { describeSubtract } from './describeSubtract.js'; +import { describeZero } from './describeZero.js'; export function describeNumeric( - subject: Numeric.Numeric & ComparableInterface & EqualsInterface, + subject: ComparableInterface & EqualsInterface & Numeric.Numeric, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { zero, one, negate } = subject; + const { negate, one, zero } = subject; const minusOne = () => negate(one()); describeAdd( @@ -31,9 +33,9 @@ export function describeNumeric( subject, { values: () => [ - { value: zero(), type: 'zero', sign: zero(), abs: zero() }, - { value: one(), type: 'positive', sign: one(), abs: one() }, - { value: minusOne(), type: 'negative', sign: minusOne(), abs: one() }, + { abs: zero(), sign: zero(), type: 'zero', value: zero() }, + { abs: one(), sign: one(), type: 'positive', value: one() }, + { abs: one(), sign: minusOne(), type: 'negative', value: minusOne() }, ], }, testingLibrary, @@ -61,12 +63,12 @@ export function describeNumeric( describeComparable( subject, { - ordered: () => [minusOne(), zero(), one()], equivalent: () => [ [one(), one()], [zero(), zero()], [minusOne(), minusOne()], ], + ordered: () => [minusOne(), zero(), one()], }, testingLibrary, ); diff --git a/packages/core/src/Testing/describePower.ts b/packages/core/src/Testing/describePower.ts index e935889c80..4fc4ede40a 100644 --- a/packages/core/src/Testing/describePower.ts +++ b/packages/core/src/Testing/describePower.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Power} trait * @@ -22,7 +23,7 @@ export function describePower( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '**'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeRemainder.ts b/packages/core/src/Testing/describeRemainder.ts index 36182d48fe..ee1327c584 100644 --- a/packages/core/src/Testing/describeRemainder.ts +++ b/packages/core/src/Testing/describeRemainder.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Remainder} trait * @@ -23,7 +24,7 @@ export function describeRemainder( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '%'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeSigned.ts b/packages/core/src/Testing/describeSigned.ts index 16b260eac0..30051d5f3a 100644 --- a/packages/core/src/Testing/describeSigned.ts +++ b/packages/core/src/Testing/describeSigned.ts @@ -1,8 +1,9 @@ import type { EqualsInterface } from '../Equal.js'; import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for Numeric.Signed behavior * @@ -26,15 +27,13 @@ import type { TestingLibrary } from './type.js'; * @param testingLibrary Optional testing library to use. Automatically detects if not provided. */ export function describeSigned( - subject: Numeric.Signed & EqualsInterface, + subject: EqualsInterface & Numeric.Signed, properties: { values: () => Array<{ - value: T; - /** - * Expected type for isNegative / isPositive + * Expected abs value */ - type: 'negative' | 'zero' | 'positive'; + abs: T; /** * Expected sign value @@ -42,14 +41,16 @@ export function describeSigned( sign: T; /** - * Expected abs value + * Expected type for isNegative / isPositive */ - abs: T; + type: 'negative' | 'positive' | 'zero'; + + value: T; }>; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const describeIfValue = properties.values().length === 0 ? describe.todo : describe; describeIfValue('abs', () => { @@ -63,7 +64,7 @@ export function describeSigned( }); }); describeIfValue('isPositive', () => { - it.each(properties.values().map(({ type, value }) => ({ value, expected: type === 'positive' })))( + it.each(properties.values().map(({ type, value }) => ({ expected: type === 'positive', value })))( 'satisfies isPositive($value) == $expected', ({ expected, value }) => { expect(subject.isPositive(value)).toBe(expected); @@ -71,7 +72,7 @@ export function describeSigned( ); }); describeIfValue('isNegative', () => { - it.each(properties.values().map(({ type, value }) => ({ value, expected: type === 'negative' })))( + it.each(properties.values().map(({ type, value }) => ({ expected: type === 'negative', value })))( 'satisfies isNegative($value) == $expected', ({ expected, value }) => { expect(subject.isNegative(value)).toBe(expected); diff --git a/packages/core/src/Testing/describeSubtract.ts b/packages/core/src/Testing/describeSubtract.ts index a1d3a4dab6..38e25a4b9d 100644 --- a/packages/core/src/Testing/describeSubtract.ts +++ b/packages/core/src/Testing/describeSubtract.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link @w5s/core#Numeric.Subtract} trait * @@ -22,7 +23,7 @@ export function describeSubtract( cases: Array<{ call: [L, R]; returns: Ret }>, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const op = '-'; (cases.length === 0 ? describe.todo : describe)(op, () => { it.each(cases)(`satisfies ['${op}']($call.0, $call.1) == $returns`, ({ call, returns }) => { diff --git a/packages/core/src/Testing/describeType.spec.ts b/packages/core/src/Testing/describeType.spec.ts index 74fdea52de..61eecb47cd 100644 --- a/packages/core/src/Testing/describeType.spec.ts +++ b/packages/core/src/Testing/describeType.spec.ts @@ -1,19 +1,21 @@ import { describe } from 'vitest'; + import type { Type } from '../Type.js'; + import { describeType } from './describeType.js'; describe('describeType', () => { const StringType: Type = { - typeName: 'String', - hasInstance: (value): value is string => typeof value === 'string', - asInstance: (value) => (typeof value === 'string' ? value : undefined), __inspect__: undefined, + asInstance: (value) => (typeof value === 'string' ? value : undefined), + hasInstance: (value): value is string => typeof value === 'string', + typeName: 'String', }; describeType(StringType, () => ({ - typeName: 'String', instances: ['', 'a', 'hello world !'], - notInstances: [null, undefined, 1, {}, new String('')], + + typeName: 'String', })); }); diff --git a/packages/core/src/Testing/describeType.ts b/packages/core/src/Testing/describeType.ts index 0510f23fdf..f2ca419f3a 100644 --- a/packages/core/src/Testing/describeType.ts +++ b/packages/core/src/Testing/describeType.ts @@ -1,8 +1,10 @@ import { inspect } from 'node:util'; + import type { Type } from '../Type.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * @example * ```typescript @@ -23,25 +25,25 @@ import type { TestingLibrary } from './type.js'; export function describeType>( subject: S, properties: (subject: S) => { - typeName: string; + inspect?: Array<[instance: S extends Type ? T : never, expected: string]>; instances: Array ? T : never>; notInstances: Array; - inspect?: Array<[instance: S extends Type ? T : never, expected: string]>; + typeName: string; }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; const { - typeName, + inspect: inspectDefault = [], instances: instancesDefault, notInstances: notInstancesDefault, - inspect: inspectDefault = [], + typeName, } = properties(subject); const instances = () => instancesDefault.map((instance) => ({ instance })); const notInstances = () => notInstancesDefault.map((instance) => ({ instance })); const fromData = [ - ...instancesDefault.map((_) => ({ value: _, expected: _ })), - ...notInstancesDefault.map((_) => ({ value: _, expected: undefined })), + ...instancesDefault.map((_) => ({ expected: _, value: _ })), + ...notInstancesDefault.map((_) => ({ expected: undefined, value: _ })), ]; describe('typeName', () => { @@ -60,7 +62,7 @@ export function describeType>( }); (fromData.length === 0 ? describe.todo : describe)('asInstance', () => { - it.each(fromData)('($value) returns $expected', ({ value, expected }) => { + it.each(fromData)('($value) returns $expected', ({ expected, value }) => { expect(subject.asInstance(value)).toEqual(expected); }); }); diff --git a/packages/core/src/Testing/describeZero.ts b/packages/core/src/Testing/describeZero.ts index 8d726bd41a..14410dd6c2 100644 --- a/packages/core/src/Testing/describeZero.ts +++ b/packages/core/src/Testing/describeZero.ts @@ -1,7 +1,8 @@ import type { Numeric } from '../Numeric.js'; -import { defaultTestingLibrary } from './defaultTestingLibrary.js'; import type { TestingLibrary } from './type.js'; +import { defaultTestingLibrary } from './defaultTestingLibrary.js'; + /** * Create a spec for {@link Zero} interface * @@ -26,7 +27,7 @@ export function describeZero( }, testingLibrary: TestingLibrary = defaultTestingLibrary(), ) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; describe('isZero', () => { it('satisfies isZero(zero()) == true', () => { diff --git a/packages/core/src/Testing/withOrder.ts b/packages/core/src/Testing/withOrder.ts index 43a4ece84d..8d6f357bac 100644 --- a/packages/core/src/Testing/withOrder.ts +++ b/packages/core/src/Testing/withOrder.ts @@ -1,4 +1,5 @@ import type { ExpectFunction } from '@w5s/core-type'; + import type { Order } from '../Order.js'; export interface ExpectOrder { diff --git a/packages/core/src/Type.spec.ts b/packages/core/src/Type.spec.ts index 33dcf486c8..c74b3a5ca0 100644 --- a/packages/core/src/Type.spec.ts +++ b/packages/core/src/Type.spec.ts @@ -1,84 +1,86 @@ -import { describe, expect, it } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + +import type { Int as TInt } from './Int.js'; +import type { Option as TOption } from './Option.js'; + +import { Codec } from './Codec.js'; +import { Enum } from './Enum.js'; +import { Tag } from './Tag.js'; import { Type } from './Type.js'; -import { define } from './Type/define.js'; import { Array } from './Type/Array.js'; -import { string } from './Type/string.js'; -import { number } from './Type/number.js'; -import { boolean } from './Type/boolean.js'; import { bigint } from './Type/bigint.js'; +import { boolean } from './Type/boolean.js'; +import { Char } from './Type/Char.js'; +import { constant } from './Type/constant.js'; +import { define } from './Type/define.js'; +import { ensure } from './Type/ensure.js'; import { Int } from './Type/Int.js'; -import { Option } from './Type/Option.js'; +import { number } from './Type/number.js'; import { TObject } from './Type/Object.js'; -import { Codec } from './Codec.js'; -import { Tag } from './Tag.js'; -import { Enum } from './Enum.js'; -import type { Int as TInt } from './Int.js'; -import type { Option as TOption } from './Option.js'; -import { ensure } from './Type/ensure.js'; -import { union } from './Type/union.js'; -import { constant } from './Type/constant.js'; +import { Option } from './Type/Option.js'; +import { Ordering } from './Type/Ordering.js'; +import { Record } from './Type/Record.js'; +import { RegExp } from './Type/RegExp.js'; +import { string } from './Type/string.js'; import { Tuple } from './Type/Tuple.js'; +import { union } from './Type/union.js'; import { unknown } from './Type/unknown.js'; -import { UUID } from './Type/UUID.js'; -import { Record } from './Type/Record.js'; import { URL } from './Type/URL.js'; -import { Char } from './Type/Char.js'; -import { RegExp } from './Type/RegExp.js'; -import { Ordering } from './Type/Ordering.js'; +import { UUID } from './Type/UUID.js'; describe('Type', () => { it('is an alias to functions', () => { expect(Type).toEqual({ - union, - constant, - define, - ensure, Array, bigint, boolean, Char, + constant, + define, + ensure, Int, number, - unknown, - string, - Record, Object: TObject, Option, Ordering, - Tuple, + Record, RegExp, - UUID, + string, + Tuple, + union, + unknown, URL, + UUID, }); }); - (() => { + { const Group = Type.Object({ name: Type.string, }); interface Group extends Codec.TypeOf {} const Gender = Enum.define({ - Male: 'male', Female: 'female', + Male: 'male', }); type PersonId = string & Tag<'PersonId'>; const PersonId = Tag.define({ - typeName: 'PersonId', hasInstance(anyValue) { return typeof anyValue === 'string'; }, + typeName: 'PersonId', }); const Person = Type.Object({ - id: PersonId, - name: Type.string, - description: Type.Option(Type.string), age: Type.Int, + description: Type.Option(Type.string), gender: Gender, groups: Type.Array(Group), + id: PersonId, + name: Type.string, // created: dateISO, // updated: dateISO, }); @@ -87,15 +89,15 @@ describe('Type', () => { assertType< Person, { - id: PersonId; - name: string; - description: TOption; age: TInt; - gender: 'male' | 'female'; + description: TOption; + gender: 'female' | 'male'; groups: ReadonlyArray; + id: PersonId; + name: string; // created: Date; // updated: Date; } >(true); - })(); + } }); diff --git a/packages/core/src/Type.ts b/packages/core/src/Type.ts index 2b953cdfde..2668a5b328 100644 --- a/packages/core/src/Type.ts +++ b/packages/core/src/Type.ts @@ -1,28 +1,30 @@ import type { PartialKeys } from '@w5s/core-type'; + +import type { AsString } from './AsString.js'; import type { Codec } from './Codec.js'; +import type { Option } from './Option.js'; +import type { Symbol } from './Symbol.js'; + +import { Array } from './Type/Array.js'; +import { bigint } from './Type/bigint.js'; +import { boolean } from './Type/boolean.js'; +import { Char } from './Type/Char.js'; +import { constant } from './Type/constant.js'; import { define } from './Type/define.js'; -import { string } from './Type/string.js'; +import { ensure } from './Type/ensure.js'; +import { Int } from './Type/Int.js'; import { number } from './Type/number.js'; -import { boolean } from './Type/boolean.js'; -import { bigint } from './Type/bigint.js'; import { TObject } from './Type/Object.js'; import { Option as TOption } from './Type/Option.js'; -import { Int } from './Type/Int.js'; -import { Array } from './Type/Array.js'; -import { ensure } from './Type/ensure.js'; -import type { Option } from './Option.js'; -import { union } from './Type/union.js'; -import { constant } from './Type/constant.js'; +import { Ordering } from './Type/Ordering.js'; +import { Record } from './Type/Record.js'; +import { RegExp } from './Type/RegExp.js'; +import { string } from './Type/string.js'; import { Tuple } from './Type/Tuple.js'; +import { union } from './Type/union.js'; import { unknown } from './Type/unknown.js'; -import { UUID } from './Type/UUID.js'; -import { Record } from './Type/Record.js'; import { URL } from './Type/URL.js'; -import { Char } from './Type/Char.js'; -import { RegExp } from './Type/RegExp.js'; -import { Ordering } from './Type/Ordering.js'; -import type { AsString } from './AsString.js'; -import type { Symbol } from './Symbol.js'; +import { UUID } from './Type/UUID.js'; export type InspectFunction = (anyValue: unknown, options: InspectOptions) => string; @@ -33,116 +35,116 @@ export type InspectOptions = globalThis.Record; */ export interface Type { /** - * Type string representation + * When defined, returns a custom string representation. + * To be useful, it should be bound to a prototype (ex: {@link Struct}) * * @example * ```typescript - * StringType.typeName // 'String' - * Int.typeName // 'Int' - * Person.typeName // 'Person' + * import { inspect } from 'node:util'; + * + * interface Foo { + * foo: boolean; + * } + * const Foo = Struct.define({ + * typeName: 'Foo', + * __inspect__: (self) => `Foo { ${String(self.foo)} }`, + * }); + * const myStruct = Struct.create(Foo, { foo: true });// 'Foo { true }' + * inspect(myStruct);// 'Foo { true }' * ``` * @category Type + * @param anyValue */ - typeName: string; + [Symbol.inspect]: Option<(anyValue: T, depth: number, options: InspectOptions, inspect: InspectFunction) => string>; /** - * Return `true` if the given value is an instance of the class. + * Try to convert anyValue to enum value or else returns `Option.None` * * @example * ```typescript * const StringType: Type; - * StringType.hasInstance('foo'); // true - * StringType.hasInstance(42); // false + * StringType.asInstance('foo'); // Option.Some('foo') + * StringType.asInstance(12); // Option.None * ``` - * * @category Type * @param anyValue */ - hasInstance(this: void, anyValue: unknown): anyValue is T; + asInstance(this: void, anyValue: unknown): Option; /** - * Try to convert anyValue to enum value or else returns `Option.None` + * Return `true` if the given value is an instance of the class. * * @example * ```typescript * const StringType: Type; - * StringType.asInstance('foo'); // Option.Some('foo') - * StringType.asInstance(12); // Option.None + * StringType.hasInstance('foo'); // true + * StringType.hasInstance(42); // false * ``` + * * @category Type * @param anyValue */ - asInstance(this: void, anyValue: unknown): Option; + hasInstance(this: void, anyValue: unknown): anyValue is T; /** - * When defined, returns a custom string representation. - * To be useful, it should be bound to a prototype (ex: {@link Struct}) + * Type string representation * * @example * ```typescript - * import { inspect } from 'node:util'; - * - * interface Foo { - * foo: boolean; - * } - * const Foo = Struct.define({ - * typeName: 'Foo', - * __inspect__: (self) => `Foo { ${String(self.foo)} }`, - * }); - * const myStruct = Struct.create(Foo, { foo: true });// 'Foo { true }' - * inspect(myStruct);// 'Foo { true }' + * StringType.typeName // 'String' + * Int.typeName // 'Int' + * Person.typeName // 'Person' * ``` * @category Type - * @param anyValue */ - [Symbol.inspect]: Option<(anyValue: T, depth: number, options: InspectOptions, inspect: InspectFunction) => string>; + typeName: string; } /** * @namespace */ export const Type = { - union, - constant, - define, - ensure, Array, - Char, bigint, boolean, + Char, + constant, + define, + ensure, Int, number, Object: TObject, Option: TOption, Ordering, Record, + RegExp, string, Tuple, + union, unknown, - RegExp, - UUID, URL, + UUID, }; export namespace Type { /** - * Extract the type of object from its module + * Type module interface */ - export type TypeOf = V extends Type ? T : never; + export interface Module extends AsString, Codec, Type {} /** * Type module constructor parameters */ export interface Parameters extends - PartialKeys, 'hasInstance'>, 'asInstance' | Symbol.inspect>, Partial>, - Partial> { + Partial>, + PartialKeys, 'hasInstance'>, 'asInstance' | Symbol.inspect> { hasInstance: (value: unknown) => boolean; } /** - * Type module interface + * Extract the type of object from its module */ - export interface Module extends Type, Codec, AsString {} + export type TypeOf = V extends Type ? T : never; } diff --git a/packages/core/src/Type/Array.spec.ts b/packages/core/src/Type/Array.spec.ts index 34903cfd08..49500877c9 100644 --- a/packages/core/src/Type/Array.spec.ts +++ b/packages/core/src/Type/Array.spec.ts @@ -1,27 +1,28 @@ import { describe } from 'vitest'; -import { Array } from './Array.js'; -import { describeCodec, describeType } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; -import { define } from './define.js'; +import { Result } from '../Result.js'; import { Symbol } from '../Symbol.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { Array } from './Array.js'; +import { define } from './define.js'; describe(Array, () => { const subject = Array; const AnyType = define({ - typeName: 'AnyType', hasInstance: (_) => typeof _ === 'string', - [Symbol.encode]: (_) => `_${_}`, - [Symbol.decode]: (input, { ok, error }) => + [Symbol.decode]: (input, { error, ok }) => typeof input === 'string' && input[0] === '_' ? ok(input.slice(1)) : error(input, 'UnderscoreString'), - [Symbol.schema]: () => ({ type: 'any', format: 'custom_underscore' }), + [Symbol.encode]: (_) => `_${_}`, + [Symbol.schema]: () => ({ format: 'custom_underscore', type: 'any' }), + typeName: 'AnyType', }); describeType(subject(AnyType), () => ({ - typeName: 'Array', instances: [[], ['']], notInstances: [null, 1, [1]], + typeName: 'Array', })); describeCodec(subject(AnyType), () => ({ decode: [ @@ -30,8 +31,8 @@ describe(Array, () => { ['a', '_b', '_c'], Result.Error( new CodecError({ - message: 'Cannot decode "a" as UnderscoreString', input: 'a', + message: 'Cannot decode "a" as UnderscoreString', }), ), ], @@ -42,6 +43,6 @@ describe(Array, () => { ['_a', '_b', '_c'], ], ], - schema: { type: 'array', item: { type: 'any', format: 'custom_underscore' } }, + schema: { item: { format: 'custom_underscore', type: 'any' }, type: 'array' }, })); }); diff --git a/packages/core/src/Type/Array.ts b/packages/core/src/Type/Array.ts index 03dd2277f3..c54ac569c4 100644 --- a/packages/core/src/Type/Array.ts +++ b/packages/core/src/Type/Array.ts @@ -1,9 +1,11 @@ import type { Array as CoreArray } from '@w5s/core-type'; + +import type { Type } from '../Type.js'; + import { decode } from '../Codec/decode.js'; import { schema } from '../Codec/schema.js'; import { isOk } from '../Result/isOk.js'; import { Symbol } from '../Symbol.js'; -import type { Type } from '../Type.js'; import { define } from './define.js'; const { isArray } = globalThis.Array; @@ -26,18 +28,16 @@ export type Array = CoreArray; */ export function Array(Item: Type.Module): Type.Module> { return define({ - typeName: `Array<${Item.typeName}>`, hasInstance: (anyValue): anyValue is Array => - isArray(anyValue) && anyValue.every(Item.hasInstance), - [Symbol.encode]: (input) => input.map(Item[Symbol.encode]), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (!isArray(input)) { return error(input, 'Array'); } const values = []; + // eslint-disable-next-line ts/prefer-for-of for (let index = 0; index < input.length; index += 1) { const result = decode(Item, input[index]); if (!isOk(result)) { @@ -47,6 +47,8 @@ export function Array(Item: Type.Module): Type.Module> { } return ok(values); }, - [Symbol.schema]: () => ({ type: 'array', item: schema(Item) }), + [Symbol.encode]: (input) => input.map(Item[Symbol.encode]), + [Symbol.schema]: () => ({ item: schema(Item), type: 'array' }), + typeName: `Array<${Item.typeName}>`, }); } diff --git a/packages/core/src/Type/Char.spec.ts b/packages/core/src/Type/Char.spec.ts index 2e294775f1..b0292c23be 100644 --- a/packages/core/src/Type/Char.spec.ts +++ b/packages/core/src/Type/Char.spec.ts @@ -1,28 +1,29 @@ import { describe } from 'vitest'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; import { describeCodec, describeType } from '../Testing.js'; import { Char } from './Char.js'; describe(Char, () => { describeType(Char, () => ({ - typeName: 'Char', instances: [Char('a'), Char('b')], notInstances: [null, undefined, 'ab', 2], + typeName: 'Char', })); describeCodec(Char, () => ({ decode: [ ['a', Result.Ok(Char('a'))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as Char', input: null }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as Char' }))], ], encode: [ [Char('a'), 'a'], [Char('A'), 'A'], ], schema: { - type: 'string', - minLength: 1, maxLength: 1, + minLength: 1, + type: 'string', }, })); }); diff --git a/packages/core/src/Type/Char.ts b/packages/core/src/Type/Char.ts index c118ffd598..c973433048 100644 --- a/packages/core/src/Type/Char.ts +++ b/packages/core/src/Type/Char.ts @@ -1,5 +1,6 @@ -import { Symbol } from '../Symbol.js'; import type { Tag } from '../Tag.js'; + +import { Symbol } from '../Symbol.js'; import { define } from '../Tag/define.js'; export type Char = string & Tag<'Char'>; @@ -10,11 +11,11 @@ export type Char = string & Tag<'Char'>; * @namespace */ export const Char = define({ - typeName: 'Char', hasInstance: (anyValue) => typeof anyValue === 'string' && anyValue.length === 1, [Symbol.schema]: () => ({ - type: 'string', - minLength: 1, maxLength: 1, + minLength: 1, + type: 'string', }), + typeName: 'Char', }); diff --git a/packages/core/src/Type/Int.spec.ts b/packages/core/src/Type/Int.spec.ts index d7af0b391d..5e4b2a2bc0 100644 --- a/packages/core/src/Type/Int.spec.ts +++ b/packages/core/src/Type/Int.spec.ts @@ -1,20 +1,21 @@ import { describe } from 'vitest'; -import { Int } from './Int.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { Int } from './Int.js'; describe('Int', () => { describeType(Int, () => ({ - typeName: 'Int', instances: [Int(0), Int(1), Int(2), Int(-1), Int(Number.MIN_SAFE_INTEGER), Int(Number.MAX_SAFE_INTEGER)], notInstances: ['1', 1.1, undefined, Number.MIN_SAFE_INTEGER - 1, Number.MAX_SAFE_INTEGER + 1, NaN, Infinity], + typeName: 'Int', })); describeCodec(Int, () => ({ decode: [ [1, Result.Ok(Int(1))], - [1.1, Result.Error(new CodecError({ message: 'Cannot decode 1.1 as Int', input: 1.1 }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as Int', input: null }))], + [1.1, Result.Error(new CodecError({ input: 1.1, message: 'Cannot decode 1.1 as Int' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as Int' }))], ], encode: [ [Int(0), 0], diff --git a/packages/core/src/Type/Int.ts b/packages/core/src/Type/Int.ts index 74f0eeca2d..96dd5f316f 100644 --- a/packages/core/src/Type/Int.ts +++ b/packages/core/src/Type/Int.ts @@ -1,4 +1,5 @@ import type { Int as CoreInt } from '@w5s/core-type'; + import { Symbol } from '../Symbol.js'; import { define } from '../Tag/define.js'; @@ -15,9 +16,9 @@ export type Int = CoreInt; * @namespace */ export const Int = define({ - typeName: 'Int', hasInstance: (anyValue) => Number.isSafeInteger(anyValue), [Symbol.schema]: () => ({ type: 'integer', }), + typeName: 'Int', }); diff --git a/packages/core/src/Type/Object.spec.ts b/packages/core/src/Type/Object.spec.ts index 6c6cd50bd9..51c16d0f22 100644 --- a/packages/core/src/Type/Object.spec.ts +++ b/packages/core/src/Type/Object.spec.ts @@ -1,6 +1,7 @@ import { describe } from 'vitest'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; import { describeCodec, describeType } from '../Testing.js'; import { define } from './define.js'; import { TObject } from './Object.js'; @@ -8,50 +9,50 @@ import { TObject } from './Object.js'; describe(TObject, () => { const subject = TObject; const AnyType = define({ - typeName: 'AnyType', - hasInstance: (_) => typeof _ === 'string', - __encode__: (_) => `_${_}`, - __decode__: (input, { ok, error }) => + __decode__: (input, { error, ok }) => typeof input === 'string' && input[0] === '_' ? ok(input.slice(1)) : error(input, 'UnderscoreString'), - __schema__: () => ({ type: 'any', format: 'custom_underscore' }), + __encode__: (_) => `_${_}`, + __schema__: () => ({ format: 'custom_underscore', type: 'any' }), + hasInstance: (_) => typeof _ === 'string', + typeName: 'AnyType', }); - describeType(subject({ foo: AnyType, bar: AnyType }, 'FooType'), () => ({ + describeType(subject({ bar: AnyType, foo: AnyType }, 'FooType'), () => ({ + instances: [{ bar: 'bar_value', foo: 'foo_value' }], + notInstances: [null, 1, '', {}, { foo: 'foo_value' }, { bar: 2, foo: 1 }], typeName: 'FooType', - instances: [{ foo: 'foo_value', bar: 'bar_value' }], - notInstances: [null, 1, '', {}, { foo: 'foo_value' }, { foo: 1, bar: 2 }], })); - describeCodec(subject({ foo: AnyType, bar: AnyType }), () => ({ + describeCodec(subject({ bar: AnyType, foo: AnyType }), () => ({ decode: [ - [{ foo: '_a', bar: '_b' }, Result.Ok({ foo: 'a', bar: 'b' })], + [{ bar: '_b', foo: '_a' }, Result.Ok({ bar: 'b', foo: 'a' })], [ - { foo: 'a' }, + { bar: '_b', foo: 'a' }, Result.Error( new CodecError({ - message: 'Cannot decode "a" as UnderscoreString', input: 'a', + message: 'Cannot decode "a" as UnderscoreString', }), ), ], ], encode: [ [ - { foo: 'a', bar: 'b' }, - { foo: '_a', bar: '_b' }, + { bar: 'b', foo: 'a' }, + { bar: '_b', foo: '_a' }, ], ], schema: { - type: 'object', - required: [], properties: { - foo: { - type: 'any', - format: 'custom_underscore', - }, bar: { + format: 'custom_underscore', type: 'any', + }, + foo: { format: 'custom_underscore', + type: 'any', }, }, + required: [], + type: 'object', }, })); }); diff --git a/packages/core/src/Type/Object.ts b/packages/core/src/Type/Object.ts index 9f0289e14b..4f678ffe5a 100644 --- a/packages/core/src/Type/Object.ts +++ b/packages/core/src/Type/Object.ts @@ -1,11 +1,12 @@ -import { encode } from '../Codec/encode.js'; +import type { JSONValue } from '../JSON.js'; +import type { Type } from '../Type.js'; + import { decode } from '../Codec/decode.js'; +import { encode } from '../Codec/encode.js'; import { schema } from '../Codec/schema.js'; -import type { JSONValue } from '../JSON.js'; import { isOk } from '../Result/isOk.js'; -import type { Type } from '../Type.js'; -import { define } from './define.js'; import { Symbol } from '../Symbol.js'; +import { define } from './define.js'; /** * Returns a new Type for `P`. @@ -32,7 +33,6 @@ export function TObject( const propertyNames = globalThis.Object.keys(Properties); const propertyNameCount = propertyNames.length; return define({ - typeName: typeName ?? 'Object', hasInstance: (anyValue): anyValue is Record => { if (typeof anyValue === 'object' && anyValue !== null) { for (let index = 0; index < propertyNameCount; index += 1) { @@ -45,18 +45,7 @@ export function TObject( } return false; }, - [Symbol.encode]: (input) => { - const returnValue: Record = {}; - - for (let index = 0; index < propertyNameCount; index += 1) { - const propertyName = propertyNames[index]!; - - returnValue[propertyName] = encode(Properties[propertyName]!, input[propertyName]); - } - - return returnValue; - }, - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (input == null || typeof input !== 'object') { return error(input, 'object'); } @@ -72,6 +61,17 @@ export function TObject( } return ok(returnValue); }, + [Symbol.encode]: (input) => { + const returnValue: Record = {}; + + for (let index = 0; index < propertyNameCount; index += 1) { + const propertyName = propertyNames[index]!; + + returnValue[propertyName] = encode(Properties[propertyName]!, input[propertyName]); + } + + return returnValue; + }, [Symbol.schema]: () => propertyNames.reduce( (acc, propertyName) => { @@ -80,11 +80,12 @@ export function TObject( return acc; }, { - type: 'object', - // eslint-disable-next-line ts/consistent-type-assertions + properties: {} as Record, - required: [] as string[], + required: [] as Array, + type: 'object', }, ) as JSONValue, + typeName: typeName ?? 'Object', }); } diff --git a/packages/core/src/Type/Option.spec.ts b/packages/core/src/Type/Option.spec.ts index 19f17a7f62..21d2ec2903 100644 --- a/packages/core/src/Type/Option.spec.ts +++ b/packages/core/src/Type/Option.spec.ts @@ -1,26 +1,27 @@ import { describe } from 'vitest'; -import { Option } from './Option.js'; + +import { None } from '../Option/None.js'; import { Result } from '../Result.js'; +import { Symbol } from '../Symbol.js'; import { describeCodec, describeType } from '../Testing.js'; -import { None } from '../Option/None.js'; import { define } from './define.js'; -import { Symbol } from '../Symbol.js'; +import { Option } from './Option.js'; describe(Option, () => { const subject = Option; const AnyType = define({ - typeName: 'AnyType', hasInstance: (_) => typeof _ === 'string', - [Symbol.encode]: (_) => `_${_}`, - [Symbol.decode]: (input, { ok, error }) => + [Symbol.decode]: (input, { error, ok }) => typeof input === 'string' && input[0] === '_' ? ok(input.slice(1)) : error(input, 'UnderscoreString'), - [Symbol.schema]: () => ({ type: 'any', format: 'custom_underscore' }), + [Symbol.encode]: (_) => `_${_}`, + [Symbol.schema]: () => ({ format: 'custom_underscore', type: 'any' }), + typeName: 'AnyType', }); describeType(subject(AnyType), () => ({ - typeName: 'Option', instances: [undefined, ''], notInstances: [null, 1], + typeName: 'Option', })); describeCodec(subject(AnyType), () => ({ decode: [ @@ -34,6 +35,6 @@ describe(Option, () => { ['', '_'], ['abc', '_abc'], ], - schema: { type: 'any', format: 'custom_underscore' }, + schema: { format: 'custom_underscore', type: 'any' }, })); }); diff --git a/packages/core/src/Type/Option.ts b/packages/core/src/Type/Option.ts index ad02879e96..dd98d62496 100644 --- a/packages/core/src/Type/Option.ts +++ b/packages/core/src/Type/Option.ts @@ -1,10 +1,11 @@ -import { encode } from '../Codec/encode.js'; -import { decode } from '../Codec/decode.js'; -import { schema } from '../Codec/schema.js'; import type { Option as OptionType } from '../Option.js'; import type { Type } from '../Type.js'; -import { define } from './define.js'; + +import { decode } from '../Codec/decode.js'; +import { encode } from '../Codec/encode.js'; +import { schema } from '../Codec/schema.js'; import { Symbol } from '../Symbol.js'; +import { define } from './define.js'; /** * Return a new optional type from `Value` @@ -16,10 +17,10 @@ import { Symbol } from '../Symbol.js'; */ export function Option(Value: Type.Module): Type.Module> { return define({ - typeName: `Option<${Value.typeName}>`, hasInstance: (anyValue): anyValue is OptionType => anyValue === undefined || Value.hasInstance(anyValue), - [Symbol.encode]: (input) => (input == null ? null : encode(Value, input)), [Symbol.decode]: (input, { ok }) => (input == null ? ok(undefined) : decode(Value, input)), + [Symbol.encode]: (input) => (input == null ? null : encode(Value, input)), [Symbol.schema]: () => schema(Value), + typeName: `Option<${Value.typeName}>`, }); } diff --git a/packages/core/src/Type/Ordering.spec.ts b/packages/core/src/Type/Ordering.spec.ts index d5378f1f33..1c878e32e5 100644 --- a/packages/core/src/Type/Ordering.spec.ts +++ b/packages/core/src/Type/Ordering.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; -import { Ordering } from './Ordering.js'; +import { describe, expect, it } from 'vitest'; + import { Enum } from '../Enum.js'; +import { Ordering } from './Ordering.js'; describe('Ordering', () => { it('should have a typeName property', () => { expect(Ordering.typeName).toBe('Ordering'); }); it('should have the correct values for Less, Equal, and Greater', () => { - expect(Enum.values(Ordering)).toMatchInlineSnapshot(` + expect(Enum.values(Ordering).toSorted((left, right) => left - right)).toMatchInlineSnapshot(` [ -1, 0, diff --git a/packages/core/src/Type/Ordering.ts b/packages/core/src/Type/Ordering.ts index fa588a24a2..24ef95c807 100644 --- a/packages/core/src/Type/Ordering.ts +++ b/packages/core/src/Type/Ordering.ts @@ -1,17 +1,11 @@ import type { Enum } from '../Enum.js'; + import { define } from '../Enum/define.js'; /** * An Ordering is the result of a comparison between two values. */ export const Ordering = define({ - typeName: 'Ordering', - - /** - * An ordering where a compared value is less than another. - */ - Less: -1, - /** * An ordering where a compared value is equal to another. */ @@ -21,5 +15,12 @@ export const Ordering = define({ * An ordering where a compared value is greater than another. */ Greater: 1, + + /** + * An ordering where a compared value is less than another. + */ + Less: -1, + + typeName: 'Ordering', }); export type Ordering = Enum.ValueOf; diff --git a/packages/core/src/Type/Record.spec.ts b/packages/core/src/Type/Record.spec.ts index 769dba550d..8af63925db 100644 --- a/packages/core/src/Type/Record.spec.ts +++ b/packages/core/src/Type/Record.spec.ts @@ -1,11 +1,13 @@ import { describe } from 'vitest'; -import { Record } from './Record.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + +import type { Type } from '../Type.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; import { bigint } from './bigint.js'; +import { Record } from './Record.js'; import { string } from './string.js'; -import type { Type } from '../Type.js'; describe(Record, () => { const subject = Record; @@ -14,20 +16,20 @@ describe(Record, () => { type TestRecord = Type.TypeOf; describeType(TestRecord, () => ({ - typeName: 'Record', - instances: [{ foo: 1n, bar: 2n }, { key: 1n, value: 3n }, {}] as TestRecord[], + instances: [{ bar: 2n, foo: 1n }, { key: 1n, value: 3n }, {}] as Array, notInstances: [null, 1, [1]], + typeName: 'Record', })); describeCodec(TestRecord, () => ({ decode: [ [{}, Result.Ok({})], - [{ foo: '1n', bar: '2n' }, Result.Ok({ foo: 1n, bar: 2n })], + [{ bar: '2n', foo: '1n' }, Result.Ok({ bar: 2n, foo: 1n })], [ ['a', '1'], Result.Error( new CodecError({ - message: 'Cannot decode a,1 as Record', input: ['a', '1'], + message: 'Cannot decode a,1 as Record', }), ), ], @@ -35,8 +37,8 @@ describe(Record, () => { encode: [ [{}, {}], [ - { foo: 1n, bar: 2n }, - { foo: '1n', bar: '2n' }, + { bar: 2n, foo: 1n }, + { bar: '2n', foo: '1n' }, ], ], schema: { type: 'object' }, diff --git a/packages/core/src/Type/Record.ts b/packages/core/src/Type/Record.ts index cb5eb32852..928e1c4e57 100644 --- a/packages/core/src/Type/Record.ts +++ b/packages/core/src/Type/Record.ts @@ -1,36 +1,28 @@ import type { Type } from '../Type.js'; -import { define } from './define.js'; -import { encode } from '../Codec/encode.js'; + import { decode } from '../Codec/decode.js'; +import { encode } from '../Codec/encode.js'; import { Symbol } from '../Symbol.js'; - -export type RecordKey = string | symbol; +import { define } from './define.js'; /** * A Record is an immutable mapping `{ [string]: value }` */ export type Record = Readonly>; +export type RecordKey = string | symbol; + export function Record, Value extends Type.Module>( Key: Key, Value: Value, ): Type.Module, Type.TypeOf>> { const typeName = `Record<${Key.typeName},${Value.typeName}>`; return define({ - typeName, hasInstance: (anyValue): boolean => typeof anyValue === 'object' && anyValue !== null ? Object.entries(anyValue).every(([key, value]) => Value.hasInstance(value) && Key.hasInstance(key)) : false, - [Symbol.encode]: (input) => { - const returnValue: globalThis.Record = {}; - for (const [key, value] of Object.entries(input)) { - returnValue[String(encode(Key, key))] = encode(Value, value); - } - - return returnValue; - }, - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input !== 'object' || input === null) { return error(input, typeName); } @@ -47,8 +39,17 @@ export function Record, Value extends Type.Module, Type.TypeOf>); }, + [Symbol.encode]: (input) => { + const returnValue: globalThis.Record = {}; + for (const [key, value] of Object.entries(input)) { + returnValue[String(encode(Key, key))] = encode(Value, value); + } + + return returnValue; + }, [Symbol.schema]: () => ({ type: 'object', }), + typeName, }); } diff --git a/packages/core/src/Type/RegExp.spec.ts b/packages/core/src/Type/RegExp.spec.ts index c5a5970c5e..82c5e466cc 100644 --- a/packages/core/src/Type/RegExp.spec.ts +++ b/packages/core/src/Type/RegExp.spec.ts @@ -1,29 +1,30 @@ -import { describe, it, expect } from 'vitest'; -import { RegExp } from './RegExp.js'; -import { describeCodec, describeType } from '../Testing.js'; -import { Result } from '../Result.js'; +import { describe, expect, it } from 'vitest'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { RegExp } from './RegExp.js'; describe('RegExp', () => { describeType(RegExp, () => ({ - typeName: 'RegExp', instances: [/abc/], notInstances: ['anything', null, undefined], + typeName: 'RegExp', })); describeCodec(RegExp, () => ({ - encode: [ - [new globalThis.RegExp(''), '/(?:)/'], - [/[a-z][A-Z]/, '/[a-z][A-Z]/'], - ], decode: [ ['', Result.Ok(/(?:)/)], ['[a-z][A-Z]', Result.Ok(/[a-z][A-Z]/)], ['/[a-z][A-Z]/', Result.Ok(/[a-z][A-Z]/)], ['/[a-z]{2}/gi', Result.Ok(/[a-z]{2}/gi)], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as RegExp', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as RegExp', input: null }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as RegExp' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as RegExp' }))], + ], + encode: [ + [new globalThis.RegExp(''), '/(?:)/'], + [/[a-z][A-Z]/, '/[a-z][A-Z]/'], ], - schema: { type: 'string', format: 'regex' }, + schema: { format: 'regex', type: 'string' }, })); describe(RegExp.parse, () => { it('should parse a regexp string', () => { diff --git a/packages/core/src/Type/RegExp.ts b/packages/core/src/Type/RegExp.ts index 208d83a7e4..226402132b 100644 --- a/packages/core/src/Type/RegExp.ts +++ b/packages/core/src/Type/RegExp.ts @@ -1,4 +1,5 @@ import type { Option } from '../Option.js'; + import { Symbol } from '../Symbol.js'; import { define } from './define.js'; @@ -24,10 +25,8 @@ function parse(expression: string): Option { */ export const RegExp = { ...define({ - typeName: 'RegExp', hasInstance: (anyValue) => Object.prototype.toString.call(anyValue) === '[object RegExp]', - [Symbol.encode]: (input) => `${input.toString()}`, - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string') { const result = parse(input); if (result != null) { @@ -36,7 +35,9 @@ export const RegExp = { } return error(input, 'RegExp'); }, - [Symbol.schema]: () => ({ type: 'string', format: 'regex' }), + [Symbol.encode]: (input) => `${input.toString()}`, + [Symbol.schema]: () => ({ format: 'regex', type: 'string' }), + typeName: 'RegExp', }), /** diff --git a/packages/core/src/Type/Tuple.spec.ts b/packages/core/src/Type/Tuple.spec.ts index d3a1da9bb4..f077a13100 100644 --- a/packages/core/src/Type/Tuple.spec.ts +++ b/packages/core/src/Type/Tuple.spec.ts @@ -1,18 +1,19 @@ import { describe } from 'vitest'; -import { Tuple } from './Tuple.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; import { bigint } from './bigint.js'; import { string } from './string.js'; +import { Tuple } from './Tuple.js'; describe(Tuple, () => { const subject = Tuple; describeType(subject(string, bigint), () => ({ - typeName: '[string,bigint]', instances: [['toto', 1n] as const, ['', 2n] as const], notInstances: [null, 1, [1]], + typeName: '[string,bigint]', })); describeCodec(subject(string, bigint), () => ({ decode: [ @@ -21,8 +22,8 @@ describe(Tuple, () => { ['a', '1'], Result.Error( new CodecError({ - message: 'Cannot decode a,1 as [string,bigint]', input: ['a', '1'], + message: 'Cannot decode a,1 as [string,bigint]', }), ), ], @@ -33,6 +34,6 @@ describe(Tuple, () => { ['a', '1n'], ], ], - schema: { type: 'array', items: [{ type: 'string' }, { type: 'string', format: 'bigint' }] }, + schema: { items: [{ type: 'string' }, { format: 'bigint', type: 'string' }], type: 'array' }, })); }); diff --git a/packages/core/src/Type/Tuple.ts b/packages/core/src/Type/Tuple.ts index 283ce8649a..97444b4b25 100644 --- a/packages/core/src/Type/Tuple.ts +++ b/packages/core/src/Type/Tuple.ts @@ -1,9 +1,10 @@ import type { Type } from '../Type.js'; -import { define } from './define.js'; -import { encode } from '../Codec/encode.js'; + import { decode } from '../Codec/decode.js'; +import { encode } from '../Codec/encode.js'; import { schema } from '../Codec/schema.js'; import { Symbol } from '../Symbol.js'; +import { define } from './define.js'; const { isArray } = globalThis.Array; @@ -12,11 +13,9 @@ export function Tuple>>( ): Type.Module<{ readonly [K in keyof C]: Type.TypeOf }> { const typeName = `[${items.map((item) => item.typeName).join(',')}]`; return define({ - typeName, hasInstance: (anyValue): boolean => isArray(anyValue) && items.every((item, itemIndex) => item.hasInstance(anyValue[itemIndex])), - [Symbol.encode]: (input) => items.map((item, itemIndex) => encode(item, input[itemIndex])), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (!Array.isArray(input)) { return error(input, typeName); } @@ -36,9 +35,11 @@ export function Tuple>>( returnValue, ); }, + [Symbol.encode]: (input) => items.map((item, itemIndex) => encode(item, input[itemIndex])), [Symbol.schema]: () => ({ - type: 'array', items: items.map(schema), + type: 'array', }), + typeName, }); } diff --git a/packages/core/src/Type/URL.spec.ts b/packages/core/src/Type/URL.spec.ts index 4ecd67491e..553fb75363 100644 --- a/packages/core/src/Type/URL.spec.ts +++ b/packages/core/src/Type/URL.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { Result } from '@w5s/core'; +import { describe } from 'vitest'; + import { CodecError } from '../CodecError.js'; import { describeCodec, describeType } from '../Testing.js'; import { URL } from './URL.js'; @@ -8,9 +9,9 @@ describe('URL', () => { const anyValidURL = 'http://localhost:3000/my/path?get=1' as URL; describeType(URL, () => ({ - typeName: 'URL', instances: [anyValidURL], notInstances: [null, ''], + typeName: 'URL', })); describeCodec(URL, () => ({ decode: [ @@ -19,8 +20,8 @@ describe('URL', () => { '', Result.Error( new CodecError({ - message: 'Cannot decode "" as URL', input: '', + message: 'Cannot decode "" as URL', }), ), ], @@ -28,16 +29,16 @@ describe('URL', () => { null, Result.Error( new CodecError({ - message: 'Cannot decode null as URL', input: null, + message: 'Cannot decode null as URL', }), ), ], ], encode: [[anyValidURL, anyValidURL]], schema: { - type: 'string', format: 'url', + type: 'string', }, })); }); diff --git a/packages/core/src/Type/URL.ts b/packages/core/src/Type/URL.ts index 869afe2732..8cdff3f4b1 100644 --- a/packages/core/src/Type/URL.ts +++ b/packages/core/src/Type/URL.ts @@ -1,5 +1,6 @@ -import { Symbol } from '../Symbol.js'; import type { Tag } from '../Tag.js'; + +import { Symbol } from '../Symbol.js'; import { define } from '../Tag/define.js'; /** @@ -13,7 +14,6 @@ export type URL = string & Tag<'URL'>; * @namespace */ export const URL = define({ - typeName: 'URL', hasInstance: (anyValue) => { if (typeof anyValue === 'string') { try { @@ -24,7 +24,8 @@ export const URL = define({ return false; }, [Symbol.schema]: () => ({ - type: 'string', format: 'url', + type: 'string', }), + typeName: 'URL', }); diff --git a/packages/core/src/Type/UUID.spec.ts b/packages/core/src/Type/UUID.spec.ts index 42840483eb..af62af8941 100644 --- a/packages/core/src/Type/UUID.spec.ts +++ b/packages/core/src/Type/UUID.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { Result } from '@w5s/core'; +import { describe } from 'vitest'; + import { CodecError } from '../CodecError.js'; import { describeCodec, describeType } from '../Testing.js'; import { UUID } from './UUID.js'; @@ -8,9 +9,9 @@ describe('UUID', () => { const anyValidUUID = '1c19548b-7cac-4222-b722-dc38f2870669' as UUID; describeType(UUID, () => ({ - typeName: 'UUID', instances: [anyValidUUID], notInstances: [null, anyValidUUID.slice(1)], + typeName: 'UUID', })); describeCodec(UUID, () => ({ decode: [ @@ -19,16 +20,16 @@ describe('UUID', () => { null, Result.Error( new CodecError({ - message: 'Cannot decode null as UUID', input: null, + message: 'Cannot decode null as UUID', }), ), ], ], encode: [[anyValidUUID, anyValidUUID]], schema: { - type: 'string', format: 'uuid', + type: 'string', }, })); }); diff --git a/packages/core/src/Type/UUID.ts b/packages/core/src/Type/UUID.ts index cbae82933b..dd84130dd0 100644 --- a/packages/core/src/Type/UUID.ts +++ b/packages/core/src/Type/UUID.ts @@ -1,13 +1,14 @@ -import { Symbol } from '../Symbol.js'; import type { Tag } from '../Tag.js'; -import { define } from '../Tag/define.js'; -export type UUIDString = `${string}-${string}-${string}-${string}-${string}`; +import { Symbol } from '../Symbol.js'; +import { define } from '../Tag/define.js'; /** * UUID string type */ -export type UUID = UUIDString & Tag<'UUID'>; +export type UUID = Tag<'UUID'> & UUIDString; + +export type UUIDString = `${string}-${string}-${string}-${string}-${string}`; const uuidRegexp = /^[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}$/i; @@ -17,10 +18,10 @@ const uuidRegexp = /^[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{ * @namespace */ export const UUID = define({ - typeName: 'UUID', hasInstance: (anyValue) => typeof anyValue === 'string' && uuidRegexp.test(anyValue), [Symbol.schema]: () => ({ - type: 'string', format: 'uuid', + type: 'string', }), + typeName: 'UUID', }); diff --git a/packages/core/src/Type/bigint.spec.ts b/packages/core/src/Type/bigint.spec.ts index dfe09a30f3..7c638c0430 100644 --- a/packages/core/src/Type/bigint.spec.ts +++ b/packages/core/src/Type/bigint.spec.ts @@ -1,28 +1,29 @@ import { describe } from 'vitest'; -import { bigint } from './bigint.js'; -import { describeCodec, describeType } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { bigint } from './bigint.js'; describe('bigint', () => { describeType(bigint, () => ({ - typeName: 'bigint', instances: [1n, 0n], notInstances: ['anything', null, undefined, bigint.hasInstance], + typeName: 'bigint', })); describeCodec(bigint, () => ({ - encode: [ - [0n, '0n'], - [1n, '1n'], - ], decode: [ ['1n', Result.Ok(1n)], ['-2n', Result.Ok(-2n)], - ['2', Result.Error(new CodecError({ message: 'Cannot decode "2" as bigint', input: '2' }))], - ['2.1n', Result.Error(new CodecError({ message: 'Cannot decode "2.1n" as bigint', input: '2.1n' }))], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as bigint', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as bigint', input: null }))], + ['2', Result.Error(new CodecError({ input: '2', message: 'Cannot decode "2" as bigint' }))], + ['2.1n', Result.Error(new CodecError({ input: '2.1n', message: 'Cannot decode "2.1n" as bigint' }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as bigint' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as bigint' }))], + ], + encode: [ + [0n, '0n'], + [1n, '1n'], ], - schema: { type: 'string', format: 'bigint' }, + schema: { format: 'bigint', type: 'string' }, })); }); diff --git a/packages/core/src/Type/bigint.ts b/packages/core/src/Type/bigint.ts index 3fe36dd2a0..08d4e0bd2d 100644 --- a/packages/core/src/Type/bigint.ts +++ b/packages/core/src/Type/bigint.ts @@ -7,10 +7,8 @@ import { define } from './define.js'; * @namespace */ export const bigint = define({ - typeName: 'bigint', hasInstance: (anyValue) => typeof anyValue === 'bigint', - [Symbol.encode]: (input) => `${input.toString(10)}n`, - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string' && input.endsWith('n')) { try { return ok(BigInt(input.slice(0, -1))); @@ -20,5 +18,7 @@ export const bigint = define({ } return error(input, 'bigint'); }, - [Symbol.schema]: () => ({ type: 'string', format: 'bigint' }), + [Symbol.encode]: (input) => `${input.toString(10)}n`, + [Symbol.schema]: () => ({ format: 'bigint', type: 'string' }), + typeName: 'bigint', }); diff --git a/packages/core/src/Type/boolean.spec.ts b/packages/core/src/Type/boolean.spec.ts index b4a42a6046..084d627bea 100644 --- a/packages/core/src/Type/boolean.spec.ts +++ b/packages/core/src/Type/boolean.spec.ts @@ -1,25 +1,26 @@ import { describe } from 'vitest'; -import { boolean } from './boolean.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { boolean } from './boolean.js'; describe('boolean', () => { describeType(boolean, () => ({ - typeName: 'boolean', instances: [true, false], notInstances: ['', null, undefined], + typeName: 'boolean', })); describeCodec(boolean, () => ({ - encode: [ - [true, true], - [false, false], - ], decode: [ [true, Result.Ok(true)], [false, Result.Ok(false)], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as boolean', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as boolean', input: null }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as boolean' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as boolean' }))], + ], + encode: [ + [true, true], + [false, false], ], schema: { type: 'boolean' }, })); diff --git a/packages/core/src/Type/boolean.ts b/packages/core/src/Type/boolean.ts index 717208cbca..8cc225eafe 100644 --- a/packages/core/src/Type/boolean.ts +++ b/packages/core/src/Type/boolean.ts @@ -7,7 +7,7 @@ import { define } from './define.js'; * @namespace */ export const boolean = define({ - typeName: 'boolean', hasInstance: (anyValue) => typeof anyValue === 'boolean', [Symbol.schema]: () => ({ type: 'boolean' }), + typeName: 'boolean', }); diff --git a/packages/core/src/Type/constant.spec.ts b/packages/core/src/Type/constant.spec.ts index 8021417103..7226a8277d 100644 --- a/packages/core/src/Type/constant.spec.ts +++ b/packages/core/src/Type/constant.spec.ts @@ -1,16 +1,17 @@ import { describe } from 'vitest'; -import { constant } from './constant.js'; -import { describeCodec, describeType } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { constant } from './constant.js'; describe(constant, () => { const subject = constant; describeType(subject('anyValue'), () => ({ - typeName: 'anyValue', instances: ['anyValue' as const], notInstances: [null, 1, [1], ''], + typeName: 'anyValue', })); describeCodec(subject('anyValue'), () => ({ decode: [ @@ -19,8 +20,8 @@ describe(constant, () => { 'otherValue', Result.Error( new CodecError({ - message: 'Cannot decode "otherValue" as anyValue', input: 'otherValue', + message: 'Cannot decode "otherValue" as anyValue', }), ), ], @@ -38,8 +39,8 @@ describe(constant, () => { 'otherValue', Result.Error( new CodecError({ - message: 'Cannot decode "otherValue" as Symbol(anySymbol)', input: 'otherValue', + message: 'Cannot decode "otherValue" as Symbol(anySymbol)', }), ), ], @@ -56,8 +57,8 @@ describe(constant, () => { undefined, Result.Error( new CodecError({ - message: 'Cannot decode undefined as undefined', input: undefined, + message: 'Cannot decode undefined as undefined', }), ), ], diff --git a/packages/core/src/Type/constant.ts b/packages/core/src/Type/constant.ts index db30cfd560..4ca6d0731e 100644 --- a/packages/core/src/Type/constant.ts +++ b/packages/core/src/Type/constant.ts @@ -1,7 +1,9 @@ import type { JSONPrimitive, Primitive } from '@w5s/core-type'; + import type { Type } from '../Type.js'; -import { define } from './define.js'; + import { Symbol } from '../Symbol.js'; +import { define } from './define.js'; /** * A type for constant `value`. An encoded value can be specified as second argument. @@ -18,7 +20,7 @@ import { Symbol } from '../Symbol.js'; * @param value the decoded constant value * @param encodedValue the encoded value (required only for non JSON representable values) */ -export function constant( +export function constant( value: Value, encodedValue?: JSONPrimitive, ): Type.Module; @@ -33,8 +35,9 @@ export function constant( const typeName = String(value); const resolvedEncodedValue = (encodedValue === undefined ? value : encodedValue) as unknown as JSONPrimitive; return define({ - typeName, hasInstance: (anyValue): boolean => anyValue === value, + [Symbol.decode]: (input, { error, ok }) => (input === resolvedEncodedValue ? ok(value) : error(input, typeName)), + [Symbol.encode]: () => resolvedEncodedValue, [Symbol.schema]: resolvedEncodedValue === null ? () => ({ @@ -43,7 +46,6 @@ export function constant( : () => ({ const: resolvedEncodedValue, }), - [Symbol.encode]: () => resolvedEncodedValue, - [Symbol.decode]: (input, { ok, error }) => (input === resolvedEncodedValue ? ok(value) : error(input, typeName)), + typeName, }); } diff --git a/packages/core/src/Type/define.spec.ts b/packages/core/src/Type/define.spec.ts index b87105ed14..0013551c09 100644 --- a/packages/core/src/Type/define.spec.ts +++ b/packages/core/src/Type/define.spec.ts @@ -1,16 +1,17 @@ import { describe, expect, it } from 'vitest'; -import { define } from './define.js'; + import { Codec } from '../Codec.js'; import { CodecError } from '../CodecError.js'; -import { Result } from '../Result.js'; import { Option } from '../Option.js'; +import { Result } from '../Result.js'; +import { define } from './define.js'; describe(define, () => { const inspect = (value: string) => `String(${value})`; const TestType = define({ - typeName: 'String', - hasInstance: (anyValue) => typeof anyValue === 'string', __inspect__: inspect, + hasInstance: (anyValue) => typeof anyValue === 'string', + typeName: 'String', }); describe('#typeName', () => { @@ -32,15 +33,15 @@ describe(define, () => { describe('#asString', () => { it('has default implementation', () => { const SomeType = define({ - typeName: 'Boolean', hasInstance: (anyValue) => typeof anyValue === 'boolean', + typeName: 'Boolean', }); expect(SomeType.asString(true)).toBe('true'); }); it('has default implementation for objects', () => { const SomeType = define<{}>({ - typeName: 'Foo', hasInstance: (anyValue) => typeof anyValue === 'object', + typeName: 'Foo', }); expect(SomeType.asString({})).toBe('[object Foo]'); }); @@ -82,10 +83,10 @@ describe(define, () => { it('returns a decoded value', () => { expect(Codec.decode(TestType, 'hello')).toEqual(Result.Ok('hello')); expect(Codec.decode(TestType, 1)).toEqual( - Result.Error(new CodecError({ message: 'Cannot decode 1 as String', input: 1 })), + Result.Error(new CodecError({ input: 1, message: 'Cannot decode 1 as String' })), ); expect(Codec.decode(TestType, undefined)).toEqual( - Result.Error(new CodecError({ message: 'Cannot decode undefined as String', input: undefined })), + Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as String' })), ); }); it('is overridable by parameters', () => { diff --git a/packages/core/src/Type/define.ts b/packages/core/src/Type/define.ts index d49890c09a..a4f4f841c8 100644 --- a/packages/core/src/Type/define.ts +++ b/packages/core/src/Type/define.ts @@ -19,24 +19,23 @@ import type { Type } from '../Type.js'; */ export function define(parameters: Type.Parameters): Type.Module { const hasInstance = parameters.hasInstance as Type['hasInstance']; + const { typeName } = parameters; const { - typeName, - __inspect__, + __decode__ = (value, { error, ok }) => (hasInstance(value) ? ok(value) : error(value, typeName)), __encode__ = (value) => value, - __decode__ = (value, { ok, error }) => (hasInstance(value) ? ok(value) : error(value, typeName)), + __inspect__, __schema__ = () => ({}), asInstance = (value) => (hasInstance(value) ? value : undefined), - asString = (self) => (typeof self === 'object' ? `[object ${typeName}]` : String(self)), } = parameters; return { - typeName, - hasInstance, - __inspect__, - __encode__, __decode__, + __encode__, + __inspect__, __schema__, asInstance, asString, + hasInstance, + typeName, }; } diff --git a/packages/core/src/Type/ensure.spec.ts b/packages/core/src/Type/ensure.spec.ts index a60a837ddc..ee5500bc12 100644 --- a/packages/core/src/Type/ensure.spec.ts +++ b/packages/core/src/Type/ensure.spec.ts @@ -1,11 +1,12 @@ import { describe, expect, it } from 'vitest'; -import { ensure } from './ensure.js'; + import { define } from './define.js'; +import { ensure } from './ensure.js'; describe('#ensure', () => { const TestType = define({ - typeName: 'String', hasInstance: (anyValue) => typeof anyValue === 'string', + typeName: 'String', }); it('throws an error only when not of type', () => { diff --git a/packages/core/src/Type/number.spec.ts b/packages/core/src/Type/number.spec.ts index e0079f566f..a93cb93677 100644 --- a/packages/core/src/Type/number.spec.ts +++ b/packages/core/src/Type/number.spec.ts @@ -1,25 +1,26 @@ import { describe } from 'vitest'; -import { number } from './number.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { number } from './number.js'; describe('Number', () => { describeType(number, () => ({ - typeName: 'number', instances: [1, 1], notInstances: ['', null, undefined], + typeName: 'number', })); describeCodec(number, () => ({ - encode: [ - [1, 1], - [0, 0], - ], decode: [ [1, Result.Ok(1)], [0, Result.Ok(0)], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as number', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as number', input: null }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as number' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as number' }))], + ], + encode: [ + [1, 1], + [0, 0], ], schema: { type: 'number' }, })); diff --git a/packages/core/src/Type/number.ts b/packages/core/src/Type/number.ts index b95c83e5ec..02de266328 100644 --- a/packages/core/src/Type/number.ts +++ b/packages/core/src/Type/number.ts @@ -7,7 +7,7 @@ import { define } from './define.js'; * @namespace */ export const number = define({ - typeName: 'number', hasInstance: (anyValue) => typeof anyValue === 'number', [Symbol.schema]: () => ({ type: 'number' }), + typeName: 'number', }); diff --git a/packages/core/src/Type/string.spec.ts b/packages/core/src/Type/string.spec.ts index c788f164a6..225d4bd13c 100644 --- a/packages/core/src/Type/string.spec.ts +++ b/packages/core/src/Type/string.spec.ts @@ -1,25 +1,26 @@ import { describe } from 'vitest'; -import { string } from './string.js'; -import { describeType, describeCodec } from '../Testing.js'; -import { Result } from '../Result.js'; + import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { string } from './string.js'; describe('string', () => { describeType(string, () => ({ - typeName: 'string', instances: ['', 'hello world'], notInstances: [0, null, undefined], + typeName: 'string', })); describeCodec(string, () => ({ - encode: [ - ['', ''], - ['true', 'true'], - ], decode: [ ['', Result.Ok('')], ['hello world', Result.Ok('hello world')], - [undefined, Result.Error(new CodecError({ message: 'Cannot decode undefined as string', input: undefined }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as string', input: null }))], + [undefined, Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as string' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as string' }))], + ], + encode: [ + ['', ''], + ['true', 'true'], ], schema: { type: 'string' }, })); diff --git a/packages/core/src/Type/string.ts b/packages/core/src/Type/string.ts index 0cbaf6577e..f4ace8bfec 100644 --- a/packages/core/src/Type/string.ts +++ b/packages/core/src/Type/string.ts @@ -7,7 +7,7 @@ import { define } from './define.js'; * @namespace */ export const string = define({ - typeName: 'string', hasInstance: (anyValue) => typeof anyValue === 'string', [Symbol.schema]: () => ({ type: 'string' }), + typeName: 'string', }); diff --git a/packages/core/src/Type/union.spec.ts b/packages/core/src/Type/union.spec.ts index 6c6540d383..9fd24ddace 100644 --- a/packages/core/src/Type/union.spec.ts +++ b/packages/core/src/Type/union.spec.ts @@ -1,11 +1,12 @@ import { describe } from 'vitest'; -import { union } from './union.js'; + +import { CodecError } from '../CodecError.js'; +import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { number } from './number.js'; import { TObject } from './Object.js'; import { string } from './string.js'; -import { number } from './number.js'; -import { describeCodec, describeType } from '../Testing.js'; -import { Result } from '../Result.js'; -import { CodecError } from '../CodecError.js'; +import { union } from './union.js'; describe(union, () => { const AType = TObject( @@ -20,16 +21,11 @@ describe(union, () => { const ABCType = union(AType, BCType); describeType(ABCType, () => ({ - typeName: 'AType|string|number', instances: [{ a: 'a_value' }, 1, 'a'], notInstances: [undefined, null, { a: 1 }], + typeName: 'AType|string|number', })); describeCodec(ABCType, () => ({ - encode: [ - [1, 1], - ['a', 'a'], - [{ a: 'va' }, { a: 'va' }], - ], decode: [ [1, Result.Ok(1)], ['a', Result.Ok('a')], @@ -37,14 +33,19 @@ describe(union, () => { [ { a: 1 }, Result.Error( - new CodecError({ message: 'Cannot decode [object Object] as AType|string|number', input: { a: 1 } }), + new CodecError({ input: { a: 1 }, message: 'Cannot decode [object Object] as AType|string|number' }), ), ], [ undefined, - Result.Error(new CodecError({ message: 'Cannot decode undefined as AType|string|number', input: undefined })), + Result.Error(new CodecError({ input: undefined, message: 'Cannot decode undefined as AType|string|number' })), ], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as AType|string|number', input: null }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as AType|string|number' }))], + ], + encode: [ + [1, 1], + ['a', 'a'], + [{ a: 'va' }, { a: 'va' }], ], schema: { anyOf: [ diff --git a/packages/core/src/Type/union.ts b/packages/core/src/Type/union.ts index 6ceeaeea63..cb0490c9df 100644 --- a/packages/core/src/Type/union.ts +++ b/packages/core/src/Type/union.ts @@ -1,7 +1,8 @@ import type { Type } from '../Type.js'; -import { define } from './define.js'; + import { schema } from '../Codec/schema.js'; import { Symbol } from '../Symbol.js'; +import { define } from './define.js'; /** * Return a union of all types @@ -16,7 +17,6 @@ export function union>>( ...types: Types ): Type.Module> { return define({ - typeName: types.map((type) => type.typeName).join('|'), hasInstance: (anyValue) => types.some((type) => type.hasInstance(anyValue)), [Symbol.schema]: () => ({ anyOf: types.flatMap((type) => { @@ -27,5 +27,6 @@ export function union>>( : typeSchema; }), }), + typeName: types.map((type) => type.typeName).join('|'), }); } diff --git a/packages/core/src/Type/unknown.spec.ts b/packages/core/src/Type/unknown.spec.ts index 4e2b73c9f9..65fb6bb079 100644 --- a/packages/core/src/Type/unknown.spec.ts +++ b/packages/core/src/Type/unknown.spec.ts @@ -1,26 +1,27 @@ import { describe } from 'vitest'; -import { unknown } from './unknown.js'; -import { describeType, describeCodec } from '../Testing.js'; + import { Result } from '../Result.js'; +import { describeCodec, describeType } from '../Testing.js'; +import { unknown } from './unknown.js'; describe('unknown', () => { describeType(unknown, () => ({ - typeName: 'unknown', instances: [0, null, undefined, 'hello world', {}, []], notInstances: [], + typeName: 'unknown', })); describeCodec(unknown, () => ({ - encode: [ - ['', ''], - [true, true], - [null, null], - ], decode: [ ['', Result.Ok('')], ['hello world', Result.Ok('hello world')], [undefined, Result.Ok(undefined)], [null, Result.Ok(null)], ], + encode: [ + ['', ''], + [true, true], + [null, null], + ], schema: { type: 'any' }, })); }); diff --git a/packages/core/src/Type/unknown.ts b/packages/core/src/Type/unknown.ts index e59ac1adf8..59e03a384f 100644 --- a/packages/core/src/Type/unknown.ts +++ b/packages/core/src/Type/unknown.ts @@ -5,11 +5,11 @@ import { define } from './define.js'; * Unknown (i.e. unsafe) type and codec */ export const unknown = define({ - typeName: 'unknown', hasInstance: (_value) => true, - [Symbol.encode]: (input) => input, [Symbol.decode]: (input, { ok }) => ok(input), + [Symbol.encode]: (input) => input, [Symbol.schema]: () => ({ type: 'any', }), + typeName: 'unknown', }); diff --git a/packages/core/src/identity.spec.ts b/packages/core/src/identity.spec.ts index 09b1d967e5..e6df0f3472 100644 --- a/packages/core/src/identity.spec.ts +++ b/packages/core/src/identity.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { identity } from './identity.js'; describe('identity', () => { diff --git a/packages/core/src/ignore.spec.ts b/packages/core/src/ignore.spec.ts index b6aa2aa8a4..49e2bf977b 100644 --- a/packages/core/src/ignore.spec.ts +++ b/packages/core/src/ignore.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + import { ignore } from './ignore.js'; describe('ignore', () => { diff --git a/packages/core/src/ignore.ts b/packages/core/src/ignore.ts index 29b49c7ce6..8fe2039b7f 100644 --- a/packages/core/src/ignore.ts +++ b/packages/core/src/ignore.ts @@ -1,5 +1,3 @@ -/* eslint-disable ts/no-unused-vars */ - /** * Always return `undefined` and ignore passed value. * @@ -16,4 +14,5 @@ * ``` * @param anyValue any value that should be ignored */ +// eslint-disable-next-line unused-imports/no-unused-vars export function ignore(anyValue: unknown): void {} diff --git a/packages/core/src/index.spec.ts b/packages/core/src/index.spec.ts index 5054b28a33..6771631ffb 100644 --- a/packages/core/src/index.spec.ts +++ b/packages/core/src/index.spec.ts @@ -1,5 +1,5 @@ -/* eslint-disable ts/no-unused-vars */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Std from './index.js'; describe('index', () => { @@ -12,9 +12,8 @@ describe('index', () => { 'Codec', 'CodecError', 'Comparable', - 'Struct', - 'Equal', 'Enum', + 'Equal', 'identity', 'ignore', 'Indexable', @@ -29,6 +28,7 @@ describe('index', () => { 'Ref', 'Result', 'String', + 'Struct', 'Symbol', 'Tag', 'Type', @@ -37,7 +37,9 @@ describe('index', () => { }); it('exports types', () => { + // eslint-disable-next-line unused-imports/no-unused-vars type Bounded = Std.Bounded; + // eslint-disable-next-line unused-imports/no-unused-vars type Numeric = Std.Numeric.Add; expect(true).toBe(true); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8cfe24d770..ed91f12677 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,8 +5,8 @@ export * from './Bounded.js'; export * from './Callable.js'; export * from './Char.js'; export * from './Codec.js'; -export * from './Comparable.js'; export * from './CodecError.js'; +export * from './Comparable.js'; export * from './Enum.js'; export * from './Equal.js'; export * from './identity.js'; diff --git a/packages/core/src/lazy.spec.ts b/packages/core/src/lazy.spec.ts index 3bec55c9bf..c1e56f910a 100644 --- a/packages/core/src/lazy.spec.ts +++ b/packages/core/src/lazy.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { lazy } from './lazy.js'; describe('lazy', () => { diff --git a/packages/core/src/omit.spec.ts b/packages/core/src/omit.spec.ts index 4b0c7596b9..b6cdfbc8cf 100644 --- a/packages/core/src/omit.spec.ts +++ b/packages/core/src/omit.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { omit } from './omit.js'; describe(omit, () => { it('returns a new object without specified keys', async () => { - const original = { foo: true, bar: true, baz: true }; + const original = { bar: true, baz: true, foo: true }; const omitted = omit(original, ['foo']); expect(omitted).toEqual({ bar: true, baz: true }); - expect(original).toEqual({ foo: true, bar: true, baz: true }); + expect(original).toEqual({ bar: true, baz: true, foo: true }); }); it('handles multiple keys', async () => { @@ -20,11 +21,11 @@ describe(omit, () => { it('handles symbol keys', async () => { const $symbol = Symbol('test'); - const original = { a: 1, [$symbol]: 2 }; + const original = { [$symbol]: 2, a: 1 }; const omitted = omit(original, [$symbol]); expect(omitted).toEqual({ a: 1 }); - expect(original).toEqual({ a: 1, [$symbol]: 2 }); + expect(original).toEqual({ [$symbol]: 2, a: 1 }); }); it("handles keys that don't exist in the object", async () => { diff --git a/packages/core/src/omit.ts b/packages/core/src/omit.ts index f6319d9a66..26dbfe1a59 100644 --- a/packages/core/src/omit.ts +++ b/packages/core/src/omit.ts @@ -12,7 +12,7 @@ * @param self the object * @param keys the keys to exclude */ -export function omit(self: Readonly, keys: readonly K[]): Omit { +export function omit(self: Readonly, keys: ReadonlyArray): Omit { const excludes = new Set(keys); const returnValue: object = {}; for (const [key, value] of Object.entries(self)) { diff --git a/packages/core/src/pick.spec.ts b/packages/core/src/pick.spec.ts index e2ec38f781..555611ca8b 100644 --- a/packages/core/src/pick.spec.ts +++ b/packages/core/src/pick.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { pick } from './pick.js'; describe(pick, () => { it('returns a new object without specified keys', async () => { - const original = { foo: true, bar: true, baz: true }; + const original = { bar: true, baz: true, foo: true }; const picked = pick(original, ['foo']); expect(picked).toEqual({ foo: true }); - expect(original).toEqual({ foo: true, bar: true, baz: true }); + expect(original).toEqual({ bar: true, baz: true, foo: true }); }); it('handles multiple keys', async () => { @@ -20,11 +21,11 @@ describe(pick, () => { it('handles symbol keys', async () => { const $symbol = Symbol('test'); - const original = { a: 1, [$symbol]: 2 }; + const original = { [$symbol]: 2, a: 1 }; const picked = pick(original, [$symbol]); expect(picked).toEqual({ [$symbol]: 2 }); - expect(original).toEqual({ a: 1, [$symbol]: 2 }); + expect(original).toEqual({ [$symbol]: 2, a: 1 }); }); it("handles keys that don't exist in the object", async () => { diff --git a/packages/core/src/pick.ts b/packages/core/src/pick.ts index 55e4b57ab6..3139b93cab 100644 --- a/packages/core/src/pick.ts +++ b/packages/core/src/pick.ts @@ -11,7 +11,7 @@ * @param self The object * @param keys The keys to pick in the new object. */ -export function pick(self: Readonly, keys: readonly K[]): Pick { +export function pick(self: Readonly, keys: ReadonlyArray): Pick { const returnValue: object = {}; for (const key of keys) { if (typeof key !== 'function' && key != null && Object.hasOwn(self, key)) { diff --git a/packages/database/README.md b/packages/database/README.md index 7d11e58519..08542e5ba5 100644 --- a/packages/database/README.md +++ b/packages/database/README.md @@ -18,7 +18,7 @@ npm install @w5s/database ```ts -import { sql, executeQuery, type Database } from '@w5s/database'; +import { type Database, executeQuery, sql } from '@w5s/database'; import { Task } from '@w5s/task'; interface User { @@ -35,8 +35,8 @@ export function getUserById(client: Database, id: User['id']) { export async function main(): Promise { const client: Database = { - databaseType: 'mysql', database: '', + databaseType: 'mysql', user: '', }; diff --git a/packages/database/example/.eslintrc.cjs b/packages/database/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/database/example/.eslintrc.cjs +++ b/packages/database/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/database/example/usage.ts b/packages/database/example/usage.ts index f28a9bd1d5..90e0dc04fd 100644 --- a/packages/database/example/usage.ts +++ b/packages/database/example/usage.ts @@ -1,4 +1,4 @@ -import { sql, executeQuery, type Database } from '@w5s/database'; +import { type Database, executeQuery, sql } from '@w5s/database'; import { Task } from '@w5s/task'; interface User { @@ -15,8 +15,8 @@ export function getUserById(client: Database, id: User['id']) { export async function main(): Promise { const client: Database = { - databaseType: 'mysql', database: '', + databaseType: 'mysql', user: '', }; diff --git a/packages/database/src/SQLDataType.spec.ts b/packages/database/src/SQLDataType.spec.ts index cadb851b3f..dd504d133e 100644 --- a/packages/database/src/SQLDataType.spec.ts +++ b/packages/database/src/SQLDataType.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { SQLDataType } from './SQLDataType.js'; describe('SQLDataType', () => { @@ -52,7 +53,7 @@ describe('SQLDataType', () => { }); describe('.BINARY', () => { it('should return a correct record', () => { - expect(SQLDataType.BINARY(2)).toEqual({ dataType: 'BINARY', byteLength: 2 }); + expect(SQLDataType.BINARY(2)).toEqual({ byteLength: 2, dataType: 'BINARY' }); }); it('should be correctly stringified', () => { expect(SQLDataType.format(SQLDataType.BINARY(2))).toEqual('BINARY(2)'); @@ -60,7 +61,7 @@ describe('SQLDataType', () => { }); describe('.VARBINARY', () => { it('should return a correct record', () => { - expect(SQLDataType.VARBINARY(2)).toEqual({ dataType: 'VARBINARY', byteLength: 2 }); + expect(SQLDataType.VARBINARY(2)).toEqual({ byteLength: 2, dataType: 'VARBINARY' }); }); it('should be correctly stringified', () => { expect(SQLDataType.format(SQLDataType.VARBINARY(2))).toEqual('VARBINARY(2)'); diff --git a/packages/database/src/SQLDataType.ts b/packages/database/src/SQLDataType.ts index 1b307593e6..59cf03530c 100644 --- a/packages/database/src/SQLDataType.ts +++ b/packages/database/src/SQLDataType.ts @@ -1,13 +1,36 @@ +export type SQLDataType = + | SQLDataType.BIGINT + | SQLDataType.BINARY + | SQLDataType.BLOB + | SQLDataType.BOOLEAN + | SQLDataType.CHAR + | SQLDataType.CLOB + | SQLDataType.DATE + | SQLDataType.DECIMAL + | SQLDataType.DOUBLE_PRECISION + | SQLDataType.FLOAT + | SQLDataType.INTEGER + | SQLDataType.INTERVAL + | SQLDataType.NCHAR + | SQLDataType.NUMERIC + | SQLDataType.NVARCHAR + | SQLDataType.REAL + | SQLDataType.SMALLINT + | SQLDataType.TIME + | SQLDataType.TIMESTAMP + | SQLDataType.VARBINARY + | SQLDataType.VARCHAR; type AnyObject = Record; -type EmptyObject = {}; type DataType = Readonly< - { + P & { /** * Data type identifier : CHAR, BINARY, etc */ dataType: T; - } & P + } >; +// eslint-disable-next-line ts/consistent-type-definitions +type EmptyObject = {}; function create(constructor: { dataType: T }, params: P): DataType { return { @@ -17,29 +40,6 @@ function create(constructor: { dataType: T }; } -export type SQLDataType = - | SQLDataType.CHAR - | SQLDataType.VARCHAR - | SQLDataType.NCHAR - | SQLDataType.NVARCHAR - | SQLDataType.CLOB - | SQLDataType.BOOLEAN - | SQLDataType.BINARY - | SQLDataType.VARBINARY - | SQLDataType.BLOB - | SQLDataType.INTEGER - | SQLDataType.SMALLINT - | SQLDataType.BIGINT - | SQLDataType.DECIMAL - | SQLDataType.NUMERIC - | SQLDataType.FLOAT - | SQLDataType.DOUBLE_PRECISION - | SQLDataType.REAL - | SQLDataType.DATE - | SQLDataType.TIME - | SQLDataType.TIMESTAMP - | SQLDataType.INTERVAL; - const CHAR = Object.assign((size: number) => create(CHAR, { size }), { dataType: 'CHAR', keys: ['size'], @@ -146,33 +146,29 @@ const INTERVAL = { } as const; const Modules = { - [BOOLEAN.dataType]: BOOLEAN, + [BIGINT.dataType]: BIGINT, + [BINARY.dataType]: BINARY, [BLOB.dataType]: BLOB, + [BOOLEAN.dataType]: BOOLEAN, + [CHAR.dataType]: CHAR, [CLOB.dataType]: CLOB, - [INTEGER.dataType]: INTEGER, - [SMALLINT.dataType]: SMALLINT, - [BIGINT.dataType]: BIGINT, - [REAL.dataType]: REAL, - [DOUBLE_PRECISION.dataType]: DOUBLE_PRECISION, [DATE.dataType]: DATE, - [TIME.dataType]: TIME, - [TIMESTAMP.dataType]: TIMESTAMP, + [DECIMAL.dataType]: DECIMAL, + [DOUBLE_PRECISION.dataType]: DOUBLE_PRECISION, + [FLOAT.dataType]: FLOAT, + [INTEGER.dataType]: INTEGER, [INTERVAL.dataType]: INTERVAL, - [CHAR.dataType]: CHAR, - [VARCHAR.dataType]: VARCHAR, [NCHAR.dataType]: NCHAR, - [NVARCHAR.dataType]: NVARCHAR, - [FLOAT.dataType]: FLOAT, - [DECIMAL.dataType]: DECIMAL, [NUMERIC.dataType]: NUMERIC, - [BINARY.dataType]: BINARY, + [NVARCHAR.dataType]: NVARCHAR, + [REAL.dataType]: REAL, + [SMALLINT.dataType]: SMALLINT, + [TIME.dataType]: TIME, + [TIMESTAMP.dataType]: TIMESTAMP, [VARBINARY.dataType]: VARBINARY, + [VARCHAR.dataType]: VARCHAR, }; -function isEmpty(anyValue: readonly unknown[]): anyValue is never[] { - return anyValue.length === 0; -} - /** * @example * ```typescript @@ -186,89 +182,96 @@ function format(data: SQLDataType): string { return `${data.dataType}${isEmpty(keys) ? '' : `(${keys.map((key) => (data as any)[key]).join(',')})`}`; } +function isEmpty(anyValue: ReadonlyArray): anyValue is Array { + return anyValue.length === 0; +} + /** * @namespace */ export const SQLDataType = { - CHAR, - VARCHAR, - NCHAR, - NVARCHAR, - CLOB, - BOOLEAN, + BIGINT, BINARY, - VARBINARY, BLOB, - INTEGER, - SMALLINT, - BIGINT, + BOOLEAN, + CHAR, + CLOB, + DATE, DECIMAL, - NUMERIC, + DOUBLE_PRECISION, FLOAT, + format, + INTEGER, + INTERVAL, + NCHAR, + NUMERIC, + NVARCHAR, REAL, - DOUBLE_PRECISION, - DATE, + SMALLINT, TIME, TIMESTAMP, - INTERVAL, - format, + VARBINARY, + VARCHAR, }; export namespace SQLDataType { - /** - * Character type - */ - export interface CHAR extends DataType {} + export interface BIGINT extends DataType {} /** - * Varying character type + * Binary types */ - export interface VARCHAR extends DataType {} + export interface BINARY extends DataType {} + + export interface BLOB extends DataType {} /** - * National Character type + * Boolean type */ - export interface NCHAR extends DataType {} + export interface BOOLEAN extends DataType {} /** - * National Character Varying type + * Character type */ - export interface NVARCHAR extends DataType {} + export interface CHAR extends DataType {} /** * Character Large Object type */ export interface CLOB extends DataType {} - /** - * Boolean type - */ - export interface BOOLEAN extends DataType {} - - /** - * Binary types - */ - export interface BINARY extends DataType {} + // + // Temporal + // + export interface DATE extends DataType {} - export interface VARBINARY extends DataType {} - export interface BLOB extends DataType {} + export interface DECIMAL extends DataType {} + export interface DOUBLE_PRECISION extends DataType {} // // Numeric types // + export interface FLOAT extends DataType {} export interface INTEGER extends DataType {} - export interface SMALLINT extends DataType {} - export interface BIGINT extends DataType {} - export interface DECIMAL extends DataType {} + export interface INTERVAL extends DataType {} + + /** + * National Character type + */ + export interface NCHAR extends DataType {} export interface NUMERIC extends DataType {} - export interface FLOAT extends DataType {} + + /** + * National Character Varying type + */ + export interface NVARCHAR extends DataType {} export interface REAL extends DataType {} - export interface DOUBLE_PRECISION extends DataType {} - // - // Temporal - // - export interface DATE extends DataType {} + export interface SMALLINT extends DataType {} export interface TIME extends DataType {} export interface TIMESTAMP extends DataType {} - export interface INTERVAL extends DataType {} + export interface VARBINARY extends DataType {} + + /** + * Varying character type + */ + export interface VARCHAR extends DataType {} } diff --git a/packages/database/src/SQLQuery.spec.ts b/packages/database/src/SQLQuery.spec.ts index 86c1b750de..79ba38a5e1 100644 --- a/packages/database/src/SQLQuery.spec.ts +++ b/packages/database/src/SQLQuery.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { SQLDataType } from './SQLDataType.js'; +import { describe, expect, it } from 'vitest'; + import { sql } from './sql.js'; +import { SQLDataType } from './SQLDataType.js'; import { SQLQuery } from './SQLQuery.js'; describe('SQLQuery', () => { @@ -9,11 +10,11 @@ describe('SQLQuery', () => { expect( SQLQuery.toSQLStatement( SQLQuery.AddColumn({ - tableName: 'anyTableName', - columnName: 'anyColumnName', columnAttributes: { type: SQLDataType.VARCHAR(255), }, + columnName: 'anyColumnName', + tableName: 'anyTableName', }), ), ).toEqual(sql`ALTER TABLE anyTableName ADD anyColumnName VARCHAR(255)`); @@ -21,7 +22,7 @@ describe('SQLQuery', () => { it('should correct statement for AddConstraint', () => { expect( - SQLQuery.toSQLStatement(SQLQuery.AddConstraint({ tableName: 'anyTableName', constraintName: 'anyConstraint' })), + SQLQuery.toSQLStatement(SQLQuery.AddConstraint({ constraintName: 'anyConstraint', tableName: 'anyTableName' })), ).toEqual(sql`ALTER TABLE anyTableName ADD CONSTRAINT anyConstraint`); }); it('should correct statement for CreateSchema', () => { @@ -33,14 +34,14 @@ describe('SQLQuery', () => { expect( SQLQuery.toSQLStatement( SQLQuery.CreateTable({ - tableName: 'anyTableName', tableAttributes: { - name: { type: SQLDataType.VARCHAR(255) }, description: { type: SQLDataType.VARCHAR(255) }, + name: { type: SQLDataType.VARCHAR(255) }, }, + tableName: 'anyTableName', }), ), - ).toEqual(sql`CREATE TABLE anyTableName (\n name VARCHAR(255),\n description VARCHAR(255)\n)`); + ).toEqual(sql`CREATE TABLE anyTableName (\n description VARCHAR(255),\n name VARCHAR(255)\n)`); }); it('should correct statement for DropSchema', () => { @@ -56,13 +57,13 @@ describe('SQLQuery', () => { it('should correct statement for RemoveConstraint', () => { expect( SQLQuery.toSQLStatement( - SQLQuery.RemoveConstraint({ tableName: 'anyTableName', constraintName: 'anyConstraint' }), + SQLQuery.RemoveConstraint({ constraintName: 'anyConstraint', tableName: 'anyTableName' }), ), ).toEqual(sql`ALTER TABLE anyTableName DROP CONSTRAINT anyConstraint`); }); it('should correct statement for RemoveColumn', () => { expect( - SQLQuery.toSQLStatement(SQLQuery.RemoveColumn({ tableName: 'anyTableName', columnName: 'anyColumn' })), + SQLQuery.toSQLStatement(SQLQuery.RemoveColumn({ columnName: 'anyColumn', tableName: 'anyTableName' })), ).toEqual(sql`ALTER TABLE anyTableName DROP COLUMN anyColumn`); }); }); diff --git a/packages/database/src/SQLQuery.ts b/packages/database/src/SQLQuery.ts index 875f56d0c5..7ef383790c 100644 --- a/packages/database/src/SQLQuery.ts +++ b/packages/database/src/SQLQuery.ts @@ -1,5 +1,6 @@ import { Struct } from '@w5s/core/dist/Struct.js'; import { assertNever } from '@w5s/error/dist/assertNever.js'; + import { sql, SQLStatement } from './sql.js'; import { SQLDataType } from './SQLDataType.js'; @@ -10,8 +11,8 @@ export type SQLQuery = | SQLQuery.CreateTable | SQLQuery.DropSchema | SQLQuery.DropTable - | SQLQuery.RemoveConstraint - | SQLQuery.RemoveColumn; + | SQLQuery.RemoveColumn + | SQLQuery.RemoveConstraint; const Order = Object.freeze({ Ascending: 'ASC', @@ -52,12 +53,12 @@ function toSQLStatement(query: SQLQuery): SQLStatement { case DropTable.typeName: { return sql`DROP TABLE ${identifier(query.tableName)}`; } - case RemoveConstraint.typeName: { - return alterTable(query.tableName, `DROP CONSTRAINT ${query.constraintName}`); - } case RemoveColumn.typeName: { return alterTable(query.tableName, `DROP COLUMN ${query.columnName}`); } + case RemoveConstraint.typeName: { + return alterTable(query.tableName, `DROP CONSTRAINT ${query.constraintName}`); + } default: { return assertNever(query); } @@ -68,42 +69,47 @@ function toSQLStatement(query: SQLQuery): SQLStatement { * @namespace */ export const SQLQuery = { - Order, AddColumn, AddConstraint, CreateSchema, CreateTable, DropSchema, DropTable, - RemoveConstraint, + Order, RemoveColumn, + RemoveConstraint, toSQLStatement, }; export namespace SQLQuery { - export type Order = 'ASC' | 'DESC'; - - export type OrderClause = string | Readonly<[string, Order]>; + export interface AddColumn extends Struct<{ + [Struct.type]: 'SQLAddColumn'; + columnAttributes: ColumnAttributes; + columnName: string; + tableName: string; + }> {} - type TriggerAction = 'CASCADE' | 'RESTRICT' | 'SET DEFAULT' | 'SET NULL' | 'NO ACTION'; + export interface AddConstraint extends Struct<{ + [Struct.type]: 'SQLAddConstraint'; + constraintName: string; + tableName: string; + }> {} - type ColumnReferencesOptions = { + export interface ColumnAttributes { /** - * Reference to another table + * Nullable column */ - tableName?: string; + allowNull?: boolean; /** - * Reference to a column + * Auto-incremented field */ - columnName?: string; - }; + autoIncrement?: boolean; - export interface ColumnAttributes { /** - * Nullable column + * Database comment */ - allowNull?: boolean; + comment?: string; /** * Default value @@ -111,61 +117,37 @@ export namespace SQLQuery { defaultValue?: any; /** - * Column type + * Trigger action when deleted */ - type: SQLDataType; + onDelete?: TriggerAction; /** - * Unique constraint on column + * Trigger action when updated */ - unique?: boolean | string | { name: string; message: string }; + onUpdate?: TriggerAction; /** * Primary key field */ primaryKey?: boolean; - /** - * Auto-incremented field - */ - autoIncrement?: boolean; - - /** - * Database comment - */ - comment?: string; - /** * An object with reference configurations */ references?: ColumnReferencesOptions; /** - * Trigger action when updated + * Column type */ - onUpdate?: TriggerAction; + type: SQLDataType; /** - * Trigger action when deleted + * Unique constraint on column */ - onDelete?: TriggerAction; + unique?: boolean | string | { message: string; name: string }; // values?: string[]; } - export interface TableAttributes extends Record {} - - export interface AddColumn extends Struct<{ - [Struct.type]: 'SQLAddColumn'; - tableName: string; - columnName: string; - columnAttributes: ColumnAttributes; - }> {} - - export interface AddConstraint extends Struct<{ - [Struct.type]: 'SQLAddConstraint'; - tableName: string; - constraintName: string; - }> {} export interface CreateSchema extends Struct<{ [Struct.type]: 'SQLCreateSchema'; @@ -174,10 +156,9 @@ export namespace SQLQuery { export interface CreateTable extends Struct<{ [Struct.type]: 'SQLCreateTable'; - tableName: string; tableAttributes: TableAttributes; + tableName: string; }> {} - export interface DropSchema extends Struct<{ [Struct.type]: 'SQLDropSchema'; schemaName: string; @@ -188,37 +169,57 @@ export namespace SQLQuery { tableName: string; }> {} - export interface RemoveConstraint extends Struct<{ - [Struct.type]: 'SQLRemoveConstraint'; - tableName: string; - constraintName: string; - }> {} + export type Order = 'ASC' | 'DESC'; + + export type OrderClause = Readonly<[string, Order]> | string; export interface RemoveColumn extends Struct<{ [Struct.type]: 'SQLRemoveColumn'; - tableName: string; columnName: string; + tableName: string; + }> {} + + export interface RemoveConstraint extends Struct<{ + [Struct.type]: 'SQLRemoveConstraint'; + constraintName: string; + tableName: string; }> {} + + export interface TableAttributes extends Record {} + + interface ColumnReferencesOptions { + /** + * Reference to a column + */ + columnName?: string; + + /** + * Reference to another table + */ + tableName?: string; + } + + type TriggerAction = 'CASCADE' | 'NO ACTION' | 'RESTRICT' | 'SET DEFAULT' | 'SET NULL'; } -function objectEntries(object: Record): Array<[string, V]> { - return Object.entries(object); +function alterTable(tableName: string, operation: string): SQLStatement { + return sql`ALTER TABLE ${sql.raw(tableName)} ${sql.raw(operation)}`; } -function stringifyDataType(data: SQLDataType): string { - return SQLDataType.format(data); +function objectEntries(object: Record): Array<[string, V]> { + return Object.entries(object); } function stringifyColumnAttributes(columnAttributes: SQLQuery.ColumnAttributes): string { return stringifyDataType(columnAttributes.type); } +function stringifyDataType(data: SQLDataType): string { + return SQLDataType.format(data); +} + function stringifyTableAttributes(tableAttributes: SQLQuery.TableAttributes): string { return objectEntries(tableAttributes) .map(([columnName, columnAttributes]) => `\n ${columnName} ${stringifyColumnAttributes(columnAttributes)}`) .join(','); } - -function alterTable(tableName: string, operation: string): SQLStatement { - return sql`ALTER TABLE ${sql.raw(tableName)} ${sql.raw(operation)}`; -} diff --git a/packages/database/src/configuration.spec.ts b/packages/database/src/configuration.spec.ts index 6139f8eb15..5a79fa8750 100644 --- a/packages/database/src/configuration.spec.ts +++ b/packages/database/src/configuration.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { configuration } from './configuration.js'; describe('configuration', () => { diff --git a/packages/database/src/configuration.ts b/packages/database/src/configuration.ts index 51a4e18c35..f48a1a2e33 100644 --- a/packages/database/src/configuration.ts +++ b/packages/database/src/configuration.ts @@ -1,4 +1,5 @@ import { useConfiguration } from '@w5s/application'; + import { meta } from './meta.js'; /** diff --git a/packages/database/src/driver.ts b/packages/database/src/driver.ts index 56df401478..6573d7ee88 100644 --- a/packages/database/src/driver.ts +++ b/packages/database/src/driver.ts @@ -1,7 +1,10 @@ -import type { TaskCanceler } from '@w5s/task'; import type { DatabaseDriverMap } from '@w5s/database'; +import type { TaskCanceler } from '@w5s/task'; + import { useState } from '@w5s/application'; + import type { SQLStatement } from './sql.js'; + import { DatabaseError } from './error.js'; import { meta } from './meta.js'; @@ -18,12 +21,6 @@ export const DatabaseDriver = { get(name: Name): DatabaseDriver.ModuleOf { return registry.current[name] ?? notFound(name); }, - set(name: Name, module: DatabaseDriver.ModuleOf): void { - registry.current = { - ...registry.current, - [name]: module, - }; - }, Make( adapter: Name, execute: (client: Client, sqlStatement: SQLStatement, cancelerRef: TaskCanceler) => Promise, @@ -36,6 +33,12 @@ export const DatabaseDriver = { }, }; }, + set(name: Name, module: DatabaseDriver.ModuleOf): void { + registry.current = { + ...registry.current, + [name]: module, + }; + }, }; export namespace DatabaseDriver { @@ -47,8 +50,8 @@ export namespace DatabaseDriver { handleError(cause: unknown): Promise; } - type ClientOf = DatabaseDriverMap[Name]; export type ModuleOf = Module>; + type ClientOf = DatabaseDriverMap[Name]; } export type Database = DatabaseDriverMap[keyof DatabaseDriverMap]; diff --git a/packages/database/src/driver/mock.spec.ts b/packages/database/src/driver/mock.spec.ts index 84e6e46858..d44bf1c463 100644 --- a/packages/database/src/driver/mock.spec.ts +++ b/packages/database/src/driver/mock.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { sql } from '../sql.js'; +import { describe, expect, it, vi } from 'vitest'; + import { DatabaseDriver } from '../driver.js'; +import { sql } from '../sql.js'; import { Mock } from './mock.js'; describe('Mock', () => { diff --git a/packages/database/src/driver/mock.ts b/packages/database/src/driver/mock.ts index 5105c81fe5..4ae6d59384 100644 --- a/packages/database/src/driver/mock.ts +++ b/packages/database/src/driver/mock.ts @@ -1,5 +1,6 @@ -import type { SQLStatement } from '../sql.js'; import type { AbstractDatabase } from '../client.js'; +import type { SQLStatement } from '../sql.js'; + import { DatabaseDriver } from '../driver.js'; export interface MockClient extends AbstractDatabase<'mock'> { diff --git a/packages/database/src/driver/mysql.spec.ts b/packages/database/src/driver/mysql.spec.ts index 379013c894..281feca59a 100644 --- a/packages/database/src/driver/mysql.spec.ts +++ b/packages/database/src/driver/mysql.spec.ts @@ -1,7 +1,9 @@ import type * as mysql from 'mysql'; -import { describe, it, expect, vi, type Mocked } from 'vitest'; -import { sql } from '../sql.js'; + +import { describe, expect, it, type Mocked, vi } from 'vitest'; + import { DatabaseDriver } from '../driver.js'; +import { sql } from '../sql.js'; import { MySQL } from './mysql.js'; describe('MySQL', () => { @@ -9,12 +11,12 @@ describe('MySQL', () => { const anyStatement = sql`SELECT author FROM books WHERE name=${'Toto'}`; const mockConnection = (connectionProperties?: any): Mocked => { const connection: Mocked = { + connect: vi.fn(), + end: vi.fn(), query: vi.fn( // @ts-ignore mock partial signature (_sql, _params, callback?) => callback(null, []), ), - connect: vi.fn(), - end: vi.fn(), ...connectionProperties, }; vi.spyOn(MySQL, 'createConnection').mockImplementation( diff --git a/packages/database/src/driver/mysql.ts b/packages/database/src/driver/mysql.ts index e151c47538..870dbbff25 100644 --- a/packages/database/src/driver/mysql.ts +++ b/packages/database/src/driver/mysql.ts @@ -1,19 +1,21 @@ -import { createConnection, type ConnectionConfig } from 'mysql'; -import { SQLStatement } from '../sql.js'; +import { type ConnectionConfig, createConnection } from 'mysql'; + import type { AbstractDatabase } from '../client.js'; + import { DatabaseDriver } from '../driver.js'; +import { SQLStatement } from '../sql.js'; + +export interface MySQLClient extends AbstractDatabase<'mysql'>, ConnectionConfig {} function mysqlSQLStatement(statement: SQLStatement) { return { + params: statement.values, sql: SQLStatement.format(statement, { formatValue: () => '?', }), - params: statement.values, }; } -export interface MySQLClient extends AbstractDatabase<'mysql'>, ConnectionConfig {} - export const MySQL = { createConnection, ...DatabaseDriver.Make('mysql', async (mysqlClient: MySQLClient, sqlStatement: SQLStatement): Promise => { @@ -22,7 +24,7 @@ export const MySQL = { try { connection.connect(); const queryResultPromise = new Promise((resolve, reject) => { - const { sql, params } = mysqlSQLStatement(sqlStatement); + const { params, sql } = mysqlSQLStatement(sqlStatement); connection.query(sql, params, (error, result) => (error == null ? resolve(result) : reject(error))); }); diff --git a/packages/database/src/driver/sqlite3.spec.ts b/packages/database/src/driver/sqlite3.spec.ts index 44aa868f91..cf027297e6 100644 --- a/packages/database/src/driver/sqlite3.spec.ts +++ b/packages/database/src/driver/sqlite3.spec.ts @@ -1,7 +1,9 @@ -import { describe, it, expect, vi, type Mocked } from 'vitest'; import type { Database } from 'sqlite3'; -import { sql } from '../sql.js'; + +import { describe, expect, it, type Mocked, vi } from 'vitest'; + import { DatabaseDriver } from '../driver.js'; +import { sql } from '../sql.js'; import { SQLite3 } from './sqlite3.js'; const mockDatabase = (): Mocked => { diff --git a/packages/database/src/driver/sqlite3.ts b/packages/database/src/driver/sqlite3.ts index 50edae3c3d..280a4b3dbc 100644 --- a/packages/database/src/driver/sqlite3.ts +++ b/packages/database/src/driver/sqlite3.ts @@ -1,27 +1,30 @@ -import { createRequire } from 'node:module'; import type { Database } from 'sqlite3'; -import { SQLStatement } from '../sql.js'; + +import { createRequire } from 'node:module'; + import type { AbstractDatabase } from '../client.js'; + import { DatabaseDriver } from '../driver.js'; +import { SQLStatement } from '../sql.js'; const require = createRequire(import.meta.url); -type SQLite3Module = { +export interface SQLite3Client extends AbstractDatabase<'sqlite3'> { + filename: string; +} + +interface SQLite3Module { Database: new (filename: string) => Database; -}; +} function sqlite3SQLStatement(statement: SQLStatement) { return { + params: statement.values, sql: SQLStatement.format(statement, { formatValue: () => '?', }).replace(/UNIX_TIMESTAMP\(\)/, "strftime('%s','now')"), - params: statement.values, }; } - -export interface SQLite3Client extends AbstractDatabase<'sqlite3'> { - filename: string; -} export const SQLite3 = { createDatabase(filename: string) { const { Database } = require('sqlite3') as SQLite3Module; @@ -30,7 +33,7 @@ export const SQLite3 = { ...DatabaseDriver.Make( 'sqlite3', async (sqlite3Client: SQLite3Client, sqlStatement: SQLStatement): Promise => { - const { sql, params } = sqlite3SQLStatement(sqlStatement); + const { params, sql } = sqlite3SQLStatement(sqlStatement); const database = SQLite3.createDatabase(sqlite3Client.filename); const queryResultPromise = new Promise((resolve, reject) => { database.all(sql, params, (error, result) => (error == null ? resolve(result) : reject(error))); diff --git a/packages/database/src/error.spec.ts b/packages/database/src/error.spec.ts index b2a33584bf..e1f6ebb0cd 100644 --- a/packages/database/src/error.spec.ts +++ b/packages/database/src/error.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; import { describeError } from '@w5s/error/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { DatabaseError } from './error.js'; describe('DatabaseError', () => { - describeError({ describe, it, expect })(DatabaseError, { + describeError({ describe, expect, it })(DatabaseError, { defaultParameters: () => ({}), - expectedName: 'DatabaseError', expectedDefaultMessage: 'An unknown error occurred with database', + expectedName: 'DatabaseError', }); }); diff --git a/packages/database/src/error.ts b/packages/database/src/error.ts index 7567e534fa..81db8e3d97 100644 --- a/packages/database/src/error.ts +++ b/packages/database/src/error.ts @@ -4,6 +4,6 @@ import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; * An error reported when the Database fails to perform an operation */ export class DatabaseError extends ErrorClass({ - errorName: 'DatabaseError', errorMessage: 'An unknown error occurred with database', + errorName: 'DatabaseError', }) {} diff --git a/packages/database/src/execute.spec.ts b/packages/database/src/execute.spec.ts index 911ac7b6fb..4b613d8717 100644 --- a/packages/database/src/execute.spec.ts +++ b/packages/database/src/execute.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { executeQuery } from './execute.js'; +import { describe, expect, it, vi } from 'vitest'; + import { DatabaseError } from './error.js'; +import { executeQuery } from './execute.js'; import { sql } from './sql.js'; import { SQLQuery } from './SQLQuery.js'; import './driver/all.js'; diff --git a/packages/database/src/execute.ts b/packages/database/src/execute.ts index 343f028339..39b12e4df3 100644 --- a/packages/database/src/execute.ts +++ b/packages/database/src/execute.ts @@ -1,9 +1,12 @@ import type { Task } from '@w5s/task'; + import { from } from '@w5s/task/dist/Task/from.js'; + +import type { DatabaseError } from './error.js'; + import { type Database, DatabaseDriver } from './driver.js'; import { SQLStatement } from './sql.js'; import { SQLQuery } from './SQLQuery.js'; -import type { DatabaseError } from './error.js'; /** * Execute the `sqlStatement` on an `client` @@ -21,10 +24,10 @@ import type { DatabaseError } from './error.js'; * @param client created with a database adapter `createEnvironment(environmentConfig)` function * @param sqlOrQuery SQL query object or a raw sql statement */ -export function executeQuery(client: Database, sqlOrQuery: SQLStatement | SQLQuery): Task { +export function executeQuery(client: Database, sqlOrQuery: SQLQuery | SQLStatement): Task { const driver = DatabaseDriver.get(client.databaseType); - return from(async ({ resolve, reject, canceler }) => { + return from(async ({ canceler, reject, resolve }) => { try { const sqlStatement = SQLStatement.hasInstance(sqlOrQuery) ? sqlOrQuery : SQLQuery.toSQLStatement(sqlOrQuery); const returnValue = await driver.execute(client, sqlStatement, canceler); diff --git a/packages/database/src/index.spec.ts b/packages/database/src/index.spec.ts index 311ec3fd30..7f09946674 100644 --- a/packages/database/src/index.spec.ts +++ b/packages/database/src/index.spec.ts @@ -1,20 +1,21 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { expect(new Set(Object.keys(Module))).toEqual( new Set([ - // List of all public exports - 'meta', 'configuration', - 'DatabaseError', 'DatabaseDriver', + 'DatabaseError', + 'executeQuery', + // List of all public exports + 'meta', + 'sql', 'SQLDataType', 'SQLQuery', 'SQLStatement', - 'sql', - 'executeQuery', ]), ); }); diff --git a/packages/database/src/index.ts b/packages/database/src/index.ts index 6d63a7a363..5ba41bf5be 100644 --- a/packages/database/src/index.ts +++ b/packages/database/src/index.ts @@ -3,12 +3,12 @@ import './driver/all.js'; // eslint-disable-next-line ts/no-empty-interface export interface DatabaseDriverMap {} -export * from './meta.js'; +export * from './client.js'; export * from './configuration.js'; export * from './driver.js'; -export * from './sql.js'; -export * from './client.js'; +export * from './error.js'; export * from './execute.js'; +export * from './meta.js'; +export * from './sql.js'; export * from './SQLDataType.js'; export * from './SQLQuery.js'; -export * from './error.js'; diff --git a/packages/database/src/sql.spec.ts b/packages/database/src/sql.spec.ts index 8a404e6211..8c30772aca 100644 --- a/packages/database/src/sql.spec.ts +++ b/packages/database/src/sql.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { sql, SQLStatement } from './sql.js'; describe('SQLStatement', () => { diff --git a/packages/database/src/sql.ts b/packages/database/src/sql.ts index 50a00f10e3..4ad0ab88f0 100644 --- a/packages/database/src/sql.ts +++ b/packages/database/src/sql.ts @@ -4,10 +4,10 @@ import { Struct } from '@w5s/core/dist/Struct.js'; const emptyStrings = Object.freeze(['']); const emptyArray = Object.freeze([]); -type SQLBuffer = { - strings: string[]; - values: unknown[]; -}; +interface SQLBuffer { + strings: Array; + values: Array; +} const SQLBuffer = (): SQLBuffer => ({ strings: [''], @@ -22,6 +22,7 @@ const append = ({ strings: targetStrings, values: targetValues }: SQLBuffer, { s targetStrings[stringsBufferIndex++] = strings[stringsIndex]!; } } + // eslint-disable-next-line ts/prefer-for-of for (let valuesIndex = 0; valuesIndex < values.length; valuesIndex++) { targetValues[valuesBufferIndex++] = values[valuesIndex]!; } @@ -29,6 +30,12 @@ const append = ({ strings: targetStrings, values: targetValues }: SQLBuffer, { s const SQLStatementType = Struct.define({ typeName: 'SQLStatement' }); +export interface SQLStatement extends Struct<{ + [Struct.type]: 'SQLStatement'; + strings: ReadonlyArray; + values: ReadonlyArray; +}> {} + function call({ strings = emptyStrings, values = emptyArray, @@ -42,9 +49,10 @@ function call({ }); } -function concat(...statements: SQLStatement[]): SQLStatement { +function concat(...statements: Array): SQLStatement { const buffer = SQLBuffer(); + // eslint-disable-next-line ts/prefer-for-of for (let statementIndex = 0; statementIndex < statements.length; statementIndex++) { append(buffer, statements[statementIndex]!); } @@ -68,12 +76,6 @@ function format( return returnValue; } -export interface SQLStatement extends Struct<{ - [Struct.type]: 'SQLStatement'; - strings: ReadonlyArray; - values: ReadonlyArray; -}> {} - /** * @namespace */ @@ -88,7 +90,7 @@ export namespace SQLStatement { export type Value = unknown; } -export function sql(strings: TemplateStringsArray, ...values: Array) { +export function sql(strings: TemplateStringsArray, ...values: Array) { const buffer = SQLBuffer(); buffer.strings[0] = strings[0]!; for (let stringIndex = 1; stringIndex < strings.length; stringIndex++) { diff --git a/packages/env/example/.eslintrc.cjs b/packages/env/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/env/example/.eslintrc.cjs +++ b/packages/env/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/env/src/Env.spec.ts b/packages/env/src/Env.spec.ts index b262a7f820..1846f19085 100644 --- a/packages/env/src/Env.spec.ts +++ b/packages/env/src/Env.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Env } from './Env.js'; describe('Env', () => { diff --git a/packages/env/src/Env.ts b/packages/env/src/Env.ts index 4b956ee8c4..7d848e7f43 100644 --- a/packages/env/src/Env.ts +++ b/packages/env/src/Env.ts @@ -1,16 +1,17 @@ import type { Option } from '@w5s/core'; + import { panic } from '@w5s/error/dist/panic.js'; const readImportMetaEnv = () => { try { - return (import.meta as { env?: Readonly<{ [key: string]: string }> }).env; + return (import.meta as { env?: Readonly> }).env; } catch { return undefined; } }; -const readProcessEnv = () => globalThis.process?.env as Option<{ [key: string]: string }>; +const readProcessEnv = () => globalThis.process?.env as Option>; -const createProxy = (properties: Option<{ [key: string]: string }>) => +const createProxy = (properties: Option>) => properties == null ? undefined : (Object.assign(Object.create(null), properties) as Env); const readEnv = (): Env => // NodeJS @@ -22,9 +23,7 @@ const readEnv = (): Env => /** * A dictionary of environment variables */ -export interface Env { - [key: string]: Option; -} +export type Env = Record>; /** * An object containing the environment variables diff --git a/packages/env/src/index.spec.ts b/packages/env/src/index.spec.ts index 00fde814cf..1b0199f53c 100644 --- a/packages/env/src/index.spec.ts +++ b/packages/env/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/error/README.md b/packages/error/README.md index 7c93f4cd9c..fd7ec3ab94 100644 --- a/packages/error/README.md +++ b/packages/error/README.md @@ -18,17 +18,17 @@ npm install @w5s/error ```ts -import { ErrorClass, Error, TypeError } from '@w5s/error'; +import { Error, ErrorClass, TypeError } from '@w5s/error'; export class MyError extends ErrorClass({ errorName: 'MyError' })<{ - foo: string; bar: boolean; + foo: string; }> {} const myError = new MyError({ - foo: 'this is foo', bar: true, cause: TypeError('this is the cause'), + foo: 'this is foo', }); console.log(myError instanceof Error); // true diff --git a/packages/error/example/.eslintrc.cjs b/packages/error/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/error/example/.eslintrc.cjs +++ b/packages/error/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/error/example/usage.ts b/packages/error/example/usage.ts index a1700d9a36..fa5fd6801a 100644 --- a/packages/error/example/usage.ts +++ b/packages/error/example/usage.ts @@ -1,14 +1,14 @@ -import { ErrorClass, Error, TypeError } from '@w5s/error'; +import { Error, ErrorClass, TypeError } from '@w5s/error'; export class MyError extends ErrorClass({ errorName: 'MyError' })<{ - foo: string; bar: boolean; + foo: string; }> {} const myError = new MyError({ - foo: 'this is foo', bar: true, cause: TypeError('this is the cause'), + foo: 'this is foo', }); console.log(myError instanceof Error); // true diff --git a/packages/error/src/AbortError.spec.ts b/packages/error/src/AbortError.spec.ts index b6e325f084..59058baa98 100644 --- a/packages/error/src/AbortError.spec.ts +++ b/packages/error/src/AbortError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { AbortError } from './AbortError.js'; import { describeError } from './Testing.js'; describe(AbortError, () => { - describeError({ describe, it, expect })(AbortError, { + describeError({ describe, expect, it })(AbortError, { defaultParameters: () => ({}), - expectedName: 'AbortError', expectedDefaultMessage: 'This operation was aborted', + expectedName: 'AbortError', }); }); diff --git a/packages/error/src/AbortError.ts b/packages/error/src/AbortError.ts index 08ae5c24dd..67a25897a6 100644 --- a/packages/error/src/AbortError.ts +++ b/packages/error/src/AbortError.ts @@ -5,6 +5,6 @@ import { ErrorClass } from './ErrorClass.js'; * */ export class AbortError extends ErrorClass({ - errorName: 'AbortError', errorMessage: 'This operation was aborted', + errorName: 'AbortError', }) {} diff --git a/packages/error/src/AggregateError.spec.ts b/packages/error/src/AggregateError.spec.ts index 22452b5503..3099b694a7 100644 --- a/packages/error/src/AggregateError.spec.ts +++ b/packages/error/src/AggregateError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { AggregateError } from './AggregateError.js'; describe(AggregateError, () => { diff --git a/packages/error/src/AggregateError.ts b/packages/error/src/AggregateError.ts index f2e7e2e024..d611d94ac2 100644 --- a/packages/error/src/AggregateError.ts +++ b/packages/error/src/AggregateError.ts @@ -16,13 +16,13 @@ * ``` */ // @ts-ignore Ignore duplicate -export declare class AggregateError> extends Error { - name: 'AggregateError'; - +export declare class AggregateError | Iterable> extends Error { /** * Array of error */ - errors: Errors extends any[] ? Array<[...Errors]> : Errors extends Iterable ? Array : never; + errors: Errors extends Array ? Array<[...Errors]> : Errors extends Iterable ? Array : never; + + name: 'AggregateError'; /** * AggregateError constructor diff --git a/packages/error/src/ArgumentError.spec.ts b/packages/error/src/ArgumentError.spec.ts index ca176e45bb..8299aaa540 100644 --- a/packages/error/src/ArgumentError.spec.ts +++ b/packages/error/src/ArgumentError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { ArgumentError } from './ArgumentError.js'; import { describeError } from './Testing.js'; describe('ArgumentError', () => { - describeError({ describe, it, expect })(ArgumentError, { + describeError({ describe, expect, it })(ArgumentError, { defaultParameters: () => ({}), - expectedName: 'ArgumentError', expectedDefaultMessage: 'Some arguments are invalid or missing', + expectedName: 'ArgumentError', }); }); diff --git a/packages/error/src/ArgumentError.ts b/packages/error/src/ArgumentError.ts index 2b7a00eef5..279dbf2aee 100644 --- a/packages/error/src/ArgumentError.ts +++ b/packages/error/src/ArgumentError.ts @@ -4,6 +4,6 @@ import { ErrorClass } from './ErrorClass.js'; * The ArgumentError object indicates an error that the program wrong argument is passed to a function */ export class ArgumentError extends ErrorClass({ - errorName: 'ArgumentError', errorMessage: 'Some arguments are invalid or missing', + errorName: 'ArgumentError', }) {} diff --git a/packages/error/src/CustomError.spec.ts b/packages/error/src/CustomError.spec.ts index dbe6720e93..cc2e5a9fd8 100644 --- a/packages/error/src/CustomError.spec.ts +++ b/packages/error/src/CustomError.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { CustomError } from './CustomError.js'; import { asString } from './CustomError/asString.js'; @@ -19,26 +20,26 @@ describe('CustomError', () => { it('should return Error with default properties', () => { expect(CustomError({ name: anyString })).toEqual( expect.objectContaining({ - message: '', cause: undefined, + message: '', }), ); }); it('should merge custom properties', () => { - expect(CustomError({ name: 'MockError', message: 'custom message', foo: true })).toEqual( + expect(CustomError({ foo: true, message: 'custom message', name: 'MockError' })).toEqual( expect.objectContaining({ - name: 'MockError', - message: 'custom message', foo: true, + message: 'custom message', + name: 'MockError', }), ); }); it('should keep original message', () => { const cause = new Error('CauseMessage'); - expect(CustomError({ name: anyString, message: 'OriginalMessage', cause })).toEqual( + expect(CustomError({ cause, message: 'OriginalMessage', name: anyString })).toEqual( expect.objectContaining({ - message: 'OriginalMessage', cause, + message: 'OriginalMessage', }), ); }); @@ -47,16 +48,16 @@ describe('CustomError', () => { it('returns instance of Error', () => { expect(new CustomError({ name: anyString })).toBeInstanceOf(Error); expect(new CustomError({ name: anyString })).toBeInstanceOf(CustomError); - expect(new CustomError({ name: anyString, foo: true })).toEqual(expect.objectContaining({ foo: true })); + expect(new CustomError({ foo: true, name: anyString })).toEqual(expect.objectContaining({ foo: true })); }); }); describe('#toString()', () => { it.each([ [CustomError({ name: 'CustomError' }), 'CustomError'], - [CustomError({ name: 'CustomError', message: 'CustomMessage' }), 'CustomError: CustomMessage'], + [CustomError({ message: 'CustomMessage', name: 'CustomError' }), 'CustomError: CustomMessage'], [ - CustomError({ name: 'CustomError', message: 'CustomMessage', cause: new Error('CauseMessage') }), + CustomError({ cause: new Error('CauseMessage'), message: 'CustomMessage', name: 'CustomError' }), [ // lines 'CustomError: CustomMessage', @@ -65,16 +66,16 @@ describe('CustomError', () => { ], [ CustomError({ - name: 'CustomError1', - message: 'Level 1', cause: CustomError({ - name: 'CustomError2', - message: 'Level 2', cause: CustomError({ - name: 'CustomError3', message: 'Level 3', + name: 'CustomError3', }), + message: 'Level 2', + name: 'CustomError2', }), + message: 'Level 1', + name: 'CustomError1', }), [ // lines @@ -94,9 +95,9 @@ describe('CustomError', () => { } const error = CustomError({ - name: 'CustomError', - message: 'CustomMessage', cause: new Error('CauseMessage'), + message: 'CustomMessage', + name: 'CustomError', }); const lines = error.stack.split('\n'); @@ -109,9 +110,9 @@ describe('CustomError', () => { it('forwards cause property', () => { const cause = new Error('CauseMessage'); const error = CustomError({ - name: 'CustomError', - message: 'CustomMessage', cause: new Error('CauseMessage'), + message: 'CustomMessage', + name: 'CustomError', }); expect(error.cause).toStrictEqual(cause); @@ -120,8 +121,8 @@ describe('CustomError', () => { describe('#message', () => { it('forwards cause property', () => { const error = CustomError({ - name: 'CustomError', message: 'CustomMessage', + name: 'CustomError', }); expect(error.message).toStrictEqual('CustomMessage'); diff --git a/packages/error/src/CustomError.ts b/packages/error/src/CustomError.ts index 26de843f69..f364fe491c 100644 --- a/packages/error/src/CustomError.ts +++ b/packages/error/src/CustomError.ts @@ -3,19 +3,15 @@ import { asString } from './CustomError/asString.js'; import { isError } from './isError.js'; -type CustomErrorRequiredProperties = { - name: string; -}; - /** * A Standard extendable error type */ export type CustomError = Readonly< - globalThis.Error & { + globalThis.Error & Properties & { /** - * Error name (used as tag) + * Optional `Error` that was thrown */ - name: Properties['name']; + cause: unknown; /** * Error message @@ -23,15 +19,15 @@ export type CustomError; interface CustomErrorConstructor /* extends ErrorConstructor */ { @@ -49,7 +45,6 @@ interface CustomErrorConstructor /* extends ErrorConstructor */ { * Call operator */ (properties: Properties): CustomError; - readonly prototype: CustomError; /** * Static method to convert an error to a string @@ -72,6 +67,12 @@ interface CustomErrorConstructor /* extends ErrorConstructor */ { this: Class, anyValue: unknown, ): anyValue is InstanceType; + + readonly prototype: CustomError; +} + +interface CustomErrorRequiredProperties { + name: string; } /** @@ -97,10 +98,11 @@ export const CustomError: CustomErrorConstructor = (() => { const captureStackTrace: CaptureStackTrace = (Error as any).captureStackTrace ?? ((_targetObject: object, _constructorOpt?: () => void) => {}); - function CustomError( + function CustomError( this: any, properties: Properties, ): CustomError { + // eslint-disable-next-line ts/consistent-indexed-object-style interface MutableError extends Error { [extra: string]: unknown; } @@ -122,16 +124,16 @@ export const CustomError: CustomErrorConstructor = (() => { } return objectAssign(CustomError, { + asString, errorName, hasInstance(anyValue: unknown): boolean { return isError(anyValue) && anyValue.name === this.errorName; }, - asString, prototype: objectAssign(objectCreate(Error.prototype), { + cause: undefined, constructor: CustomError, - name: errorName, message: '', - cause: undefined, + name: errorName, toString(this: Error) { return asString(this); }, diff --git a/packages/error/src/CustomError/asString.spec.ts b/packages/error/src/CustomError/asString.spec.ts index f69557be87..0b735c998a 100644 --- a/packages/error/src/CustomError/asString.spec.ts +++ b/packages/error/src/CustomError/asString.spec.ts @@ -1,15 +1,16 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { asString } from './asString.js'; describe(asString, () => { - const CustomError =

(properties: P) => + const CustomError =

(properties: P) => Object.assign(new Error(properties.message), properties); it.each([ [CustomError({ name: 'CustomError' }), 'CustomError'], - [CustomError({ name: 'CustomError', message: 'CustomMessage' }), 'CustomError: CustomMessage'], + [CustomError({ message: 'CustomMessage', name: 'CustomError' }), 'CustomError: CustomMessage'], [ - CustomError({ name: 'CustomError', message: 'CustomMessage', cause: new Error('CauseMessage') }), + CustomError({ cause: new Error('CauseMessage'), message: 'CustomMessage', name: 'CustomError' }), [ // lines 'CustomError: CustomMessage', @@ -18,16 +19,16 @@ describe(asString, () => { ], [ CustomError({ - name: 'CustomError1', - message: 'Level 1', cause: CustomError({ - name: 'CustomError2', - message: 'Level 2', cause: CustomError({ - name: 'CustomError3', message: 'Level 3', + name: 'CustomError3', }), + message: 'Level 2', + name: 'CustomError2', }), + message: 'Level 1', + name: 'CustomError1', }), [ // lines diff --git a/packages/error/src/Error.spec.ts b/packages/error/src/Error.spec.ts index 2053ed6287..f1051d4bb1 100644 --- a/packages/error/src/Error.spec.ts +++ b/packages/error/src/Error.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Error } from './Error.js'; describe(Error, () => { diff --git a/packages/error/src/Error.ts b/packages/error/src/Error.ts index ac799f6bbc..84064e73cb 100644 --- a/packages/error/src/Error.ts +++ b/packages/error/src/Error.ts @@ -13,9 +13,9 @@ import type { ErrorOptions } from './ErrorOptions.js'; // @ts-ignore Ignore duplicate export declare class Error { /** - * Error name + * Error cause */ - name: 'Error'; + cause?: unknown; /** * Error message @@ -23,14 +23,14 @@ export declare class Error { message: string; /** - * Error stack description (when supported) + * Error name */ - stack?: string; + name: 'Error'; /** - * Error cause + * Error stack description (when supported) */ - cause?: unknown; + stack?: string; /** * Error constructor diff --git a/packages/error/src/ErrorClass.ts b/packages/error/src/ErrorClass.ts index 59d1108706..5db53d37ae 100644 --- a/packages/error/src/ErrorClass.ts +++ b/packages/error/src/ErrorClass.ts @@ -1,75 +1,38 @@ import type { Pretty } from '@w5s/core-type'; -import { CustomError } from './CustomError.js'; -export type ErrorType = CustomError< - { - name: Name; - } & Properties ->; - -/** - * Return a new `Error` default factory - * See {@link ErrorClass} for additional properties added to the constructor - * - * @example - * ```typescript - * export class MyError extends ErrorClass({ - * errorName: 'MyError', - * // errorMessage: 'my message', - * })<{ - * foo: boolean; - * }> {}; - * - * const instance = MyError({ foo: true, message: 'hey!' }); // Error { name: 'MyError', message: 'hey!', foo: true } - * MyError.errorName === 'MyError' // true - * MyError.hasInstance(instance); // true - * ``` - * @param options the options for the new error type - */ -export function ErrorClass(options: ErrorClassOptions): ErrorClass { - const { errorName, errorMessage } = options; - class BaseError extends CustomError<{ name: Name }> { - static override errorName = errorName; - } - Object.assign(BaseError.prototype as any, { - name: errorName, - message: errorMessage, - }); - // @ts-ignore ensure types here and rely on testing - return BaseError; -} +import { CustomError } from './CustomError.js'; -export interface ErrorClassOptions { +export interface ErrorClass extends Pretty { /** * Error name */ - errorName: Name; + readonly errorName: Name; /** - * Default error message + * Error constructor */ - errorMessage?: string; + new = {}>( + ...properties: ErrorClassParameters + ): ErrorType; } -export interface ErrorClass extends Pretty { +export interface ErrorClassOptions { /** - * Error name + * Default error message */ - readonly errorName: Name; + errorMessage?: string; /** - * Error constructor + * Error name */ - new = {}>( - ...properties: ErrorClassParameters - ): ErrorType; + errorName: Name; } /** * Extract all parameters to create a new CustomError */ export type ErrorClassParameters = - RequiredKeysOf> extends never + RequiredKeysOf> extends never ? [properties?: ErrorClassProperties] : [properties: ErrorClassProperties]; @@ -78,19 +41,25 @@ export type ErrorClassParameters = */ export type ErrorClassProperties = Omit< Properties, - 'name' | 'stack' | 'message' | 'cause' + 'cause' | 'message' | 'name' | 'stack' > & { /** - * Optional message, if omitted default one will be used + * Optional cause */ - message?: string; + cause?: unknown; /** - * Optional cause + * Optional message, if omitted default one will be used */ - cause?: unknown; + message?: string; }; +export type ErrorType = CustomError< + Properties & { + name: Name; + } +>; + // TODO: move this to library type RequiredKeysOf = Exclude< { @@ -98,3 +67,35 @@ type RequiredKeysOf = Exclude< }[keyof T], undefined >; + +/** + * Return a new `Error` default factory + * See {@link ErrorClass} for additional properties added to the constructor + * + * @example + * ```typescript + * export class MyError extends ErrorClass({ + * errorName: 'MyError', + * // errorMessage: 'my message', + * })<{ + * foo: boolean; + * }> {}; + * + * const instance = MyError({ foo: true, message: 'hey!' }); // Error { name: 'MyError', message: 'hey!', foo: true } + * MyError.errorName === 'MyError' // true + * MyError.hasInstance(instance); // true + * ``` + * @param options the options for the new error type + */ +export function ErrorClass(options: ErrorClassOptions): ErrorClass { + const { errorMessage, errorName } = options; + class BaseError extends CustomError<{ name: Name }> { + static override errorName = errorName; + } + Object.assign(BaseError.prototype as any, { + message: errorMessage, + name: errorName, + }); + // @ts-ignore ensure types here and rely on testing + return BaseError; +} diff --git a/packages/error/src/EvalError.spec.ts b/packages/error/src/EvalError.spec.ts index 9d21ecdab7..2945a67791 100644 --- a/packages/error/src/EvalError.spec.ts +++ b/packages/error/src/EvalError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { EvalError } from './EvalError.js'; describe(EvalError, () => { diff --git a/packages/error/src/InvariantError.spec.ts b/packages/error/src/InvariantError.spec.ts index 435be8523b..42446a3885 100644 --- a/packages/error/src/InvariantError.spec.ts +++ b/packages/error/src/InvariantError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { InvariantError } from './InvariantError.js'; import { describeError } from './Testing.js'; describe('InvariantError', () => { - describeError({ describe, it, expect })(InvariantError, { + describeError({ describe, expect, it })(InvariantError, { defaultParameters: () => ({}), - expectedName: 'InvariantError', expectedDefaultMessage: 'An invariant error occurred', + expectedName: 'InvariantError', }); }); diff --git a/packages/error/src/InvariantError.ts b/packages/error/src/InvariantError.ts index 0fdbe9c02e..2790394a7f 100644 --- a/packages/error/src/InvariantError.ts +++ b/packages/error/src/InvariantError.ts @@ -8,6 +8,6 @@ import { ErrorClass } from './ErrorClass.js'; * */ export class InvariantError extends ErrorClass({ - errorName: 'InvariantError', errorMessage: 'An invariant error occurred', + errorName: 'InvariantError', }) {} diff --git a/packages/error/src/NotImplementedError.spec.ts b/packages/error/src/NotImplementedError.spec.ts index d6a118c7f0..e1c89612c0 100644 --- a/packages/error/src/NotImplementedError.spec.ts +++ b/packages/error/src/NotImplementedError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { NotImplementedError } from './NotImplementedError.js'; import { describeError } from './Testing.js'; describe(NotImplementedError, () => { - describeError({ describe, it, expect })(NotImplementedError, { + describeError({ describe, expect, it })(NotImplementedError, { defaultParameters: () => ({}), - expectedName: 'NotImplementedError', expectedDefaultMessage: 'Not implemented', + expectedName: 'NotImplementedError', }); }); diff --git a/packages/error/src/NotImplementedError.ts b/packages/error/src/NotImplementedError.ts index 162179cc78..473bb5b84c 100644 --- a/packages/error/src/NotImplementedError.ts +++ b/packages/error/src/NotImplementedError.ts @@ -11,6 +11,6 @@ import { ErrorClass } from './ErrorClass.js'; * ``` */ export class NotImplementedError extends ErrorClass({ - errorName: 'NotImplementedError', errorMessage: 'Not implemented', + errorName: 'NotImplementedError', }) {} diff --git a/packages/error/src/RangeError.spec.ts b/packages/error/src/RangeError.spec.ts index 550fb4ae33..798c7aa660 100644 --- a/packages/error/src/RangeError.spec.ts +++ b/packages/error/src/RangeError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RangeError } from './RangeError.js'; describe(RangeError, () => { diff --git a/packages/error/src/ReferenceError.spec.ts b/packages/error/src/ReferenceError.spec.ts index a2f8926ef6..ff600a2b85 100644 --- a/packages/error/src/ReferenceError.spec.ts +++ b/packages/error/src/ReferenceError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { ReferenceError } from './ReferenceError.js'; describe(ReferenceError, () => { diff --git a/packages/error/src/RuntimeError.spec.ts b/packages/error/src/RuntimeError.spec.ts index 61a3e800c1..c21433b654 100644 --- a/packages/error/src/RuntimeError.spec.ts +++ b/packages/error/src/RuntimeError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { RuntimeError } from './RuntimeError.js'; import { describeError } from './Testing.js'; describe(RuntimeError, () => { - describeError({ describe, it, expect })(RuntimeError, { + describeError({ describe, expect, it })(RuntimeError, { defaultParameters: () => ({}), - expectedName: 'RuntimeError', expectedDefaultMessage: 'An error occurred during program execution', + expectedName: 'RuntimeError', }); }); diff --git a/packages/error/src/RuntimeError.ts b/packages/error/src/RuntimeError.ts index d357a8eb6a..34fc1f33ce 100644 --- a/packages/error/src/RuntimeError.ts +++ b/packages/error/src/RuntimeError.ts @@ -4,6 +4,6 @@ import { ErrorClass } from './ErrorClass.js'; * The RuntimeError object indicates an error that an error occurred during the runtime of a program. */ export class RuntimeError extends ErrorClass({ - errorName: 'RuntimeError', errorMessage: 'An error occurred during program execution', + errorName: 'RuntimeError', }) {} diff --git a/packages/error/src/SyntaxError.spec.ts b/packages/error/src/SyntaxError.spec.ts index d89c0dadbd..921623f5c3 100644 --- a/packages/error/src/SyntaxError.spec.ts +++ b/packages/error/src/SyntaxError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { SyntaxError } from './SyntaxError.js'; describe(SyntaxError, () => { diff --git a/packages/error/src/Testing/describeError.ts b/packages/error/src/Testing/describeError.ts index 6b17ce8748..eb087574dc 100644 --- a/packages/error/src/Testing/describeError.ts +++ b/packages/error/src/Testing/describeError.ts @@ -14,21 +14,21 @@ import type { TestingLibrary } from '@w5s/core-type'; * @param testingLibrary Optional testing library to use. Automatically detects if not provided. */ export function describeError(testingLibrary: TestingLibrary) { - const { describe, it, expect } = testingLibrary; + const { describe, expect, it } = testingLibrary; return any>( subject: Constructor, spec: { defaultParameters: () => Constructor extends abstract new (properties: infer R) => any ? R : never; /** - * Expected error name + * Expected default message */ - expectedName: string; + expectedDefaultMessage: string; /** - * Expected default message + * Expected error name */ - expectedDefaultMessage: string; + expectedName: string; }, ) => { describe('errorName', () => { diff --git a/packages/error/src/TimeoutError.spec.ts b/packages/error/src/TimeoutError.spec.ts index 18372dd53f..305ddead88 100644 --- a/packages/error/src/TimeoutError.spec.ts +++ b/packages/error/src/TimeoutError.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; -import { TimeoutError } from './TimeoutError.js'; +import { describe, expect, it } from 'vitest'; + import { describeError } from './Testing.js'; +import { TimeoutError } from './TimeoutError.js'; describe('TimeoutError', () => { - describeError({ describe, it, expect })(TimeoutError, { + describeError({ describe, expect, it })(TimeoutError, { defaultParameters: () => ({}), - expectedName: 'TimeoutError', expectedDefaultMessage: 'Operation timed out', + expectedName: 'TimeoutError', }); }); diff --git a/packages/error/src/TimeoutError.ts b/packages/error/src/TimeoutError.ts index c7bcae15a6..c6a3575bb9 100644 --- a/packages/error/src/TimeoutError.ts +++ b/packages/error/src/TimeoutError.ts @@ -4,6 +4,6 @@ import { ErrorClass } from './ErrorClass.js'; * The TimeoutError object indicates an error that the operation took too much time and was canceled */ export class TimeoutError extends ErrorClass({ - errorName: 'TimeoutError', errorMessage: 'Operation timed out', + errorName: 'TimeoutError', }) {} diff --git a/packages/error/src/TypeError.spec.ts b/packages/error/src/TypeError.spec.ts index 3502ca61bb..a9091f0e22 100644 --- a/packages/error/src/TypeError.spec.ts +++ b/packages/error/src/TypeError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { TypeError } from './TypeError.js'; describe(TypeError, () => { diff --git a/packages/error/src/URIError.spec.ts b/packages/error/src/URIError.spec.ts index aeaf06b1d9..f89e19de8f 100644 --- a/packages/error/src/URIError.spec.ts +++ b/packages/error/src/URIError.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { URIError } from './URIError.js'; describe(URIError, () => { diff --git a/packages/error/src/assertNever.spec.ts b/packages/error/src/assertNever.spec.ts index 09a04dbf2a..263f1f96d4 100644 --- a/packages/error/src/assertNever.spec.ts +++ b/packages/error/src/assertNever.spec.ts @@ -1,5 +1,6 @@ -/* eslint-disable ts/no-unused-vars */ -import { describe, it, expect } from 'vitest'; +/* eslint-disable unused-imports/no-unused-vars */ +import { describe, it } from 'vitest'; + import { assertNever } from './assertNever.js'; describe('assertNever', () => { diff --git a/packages/error/src/index.spec.ts b/packages/error/src/index.spec.ts index 2eb18f51f0..53abe367fd 100644 --- a/packages/error/src/index.spec.ts +++ b/packages/error/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/error/src/index.ts b/packages/error/src/index.ts index d389b13e5d..2ab652d576 100644 --- a/packages/error/src/index.ts +++ b/packages/error/src/index.ts @@ -12,11 +12,11 @@ export * from './InvariantError.js'; export * from './isDOMException.js'; export * from './isError.js'; export * from './NotImplementedError.js'; +export * from './panic.js'; export * from './RangeError.js'; export * from './ReferenceError.js'; export * from './RuntimeError.js'; export * from './SyntaxError.js'; -export * from './panic.js'; export * from './TimeoutError.js'; export * from './TypeError.js'; export * from './URIError.js'; diff --git a/packages/error/src/invariant.spec.ts b/packages/error/src/invariant.spec.ts index f9c1151cd6..2ce7f209a3 100644 --- a/packages/error/src/invariant.spec.ts +++ b/packages/error/src/invariant.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { invariant } from './invariant.js'; import { InvariantError } from './InvariantError.js'; diff --git a/packages/error/src/invariant.ts b/packages/error/src/invariant.ts index 96fdd5268a..2ef0546b45 100644 --- a/packages/error/src/invariant.ts +++ b/packages/error/src/invariant.ts @@ -13,9 +13,9 @@ import { InvariantError } from './InvariantError.js'; * @param condition the predicate result * @param message an optional message for Error */ -export function invariant(condition: false, message?: string | null): never; -export function invariant(condition: boolean, message?: string | null): asserts condition; -export function invariant(condition: boolean, message?: string | null): asserts condition { +export function invariant(condition: false, message?: null | string): never; +export function invariant(condition: boolean, message?: null | string): asserts condition; +export function invariant(condition: boolean, message?: null | string): asserts condition { if (!condition) { throw new InvariantError({ message: message ?? '' }); } diff --git a/packages/error/src/isDOMException.spec.ts b/packages/error/src/isDOMException.spec.ts index 8975113262..9161f3facd 100644 --- a/packages/error/src/isDOMException.spec.ts +++ b/packages/error/src/isDOMException.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { isDOMException } from './isDOMException.js'; describe(isDOMException, () => { diff --git a/packages/error/src/isError.spec.ts b/packages/error/src/isError.spec.ts index b65f9a8df1..c6f38f0e1f 100644 --- a/packages/error/src/isError.spec.ts +++ b/packages/error/src/isError.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { runInNewContext } from 'node:vm'; +import { describe, expect, it } from 'vitest'; + import { isError } from './isError.js'; describe(isError, () => { @@ -24,8 +25,8 @@ describe(isError, () => { expect(isError(obj)).toBe(false); expect( isError({ - name: 'John', message: 'Hello', + name: 'John', stack: 'Some stack', }), ).toBe(false); diff --git a/packages/error/src/panic.spec.ts b/packages/error/src/panic.spec.ts index dd5eabbbaf..caf3dfb7fb 100644 --- a/packages/error/src/panic.spec.ts +++ b/packages/error/src/panic.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { panic } from './panic.js'; describe(panic, () => { diff --git a/packages/error/src/warning.spec.ts b/packages/error/src/warning.spec.ts index 6cfd214817..4916e3fe23 100644 --- a/packages/error/src/warning.spec.ts +++ b/packages/error/src/warning.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + import { warning } from './warning.js'; describe('warning', () => { diff --git a/packages/error/src/warning.ts b/packages/error/src/warning.ts index 2b910aa253..5cfc88b519 100644 --- a/packages/error/src/warning.ts +++ b/packages/error/src/warning.ts @@ -11,7 +11,7 @@ * @param condition the predicate result * @param message an optional message for Error */ -export function warning(condition: boolean, message?: string | null): void { +export function warning(condition: boolean, message?: null | string): void { if (!condition) { console.warn(`Warning: ${message ?? ''}`); } diff --git a/packages/global-storage/example/.eslintrc.cjs b/packages/global-storage/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/global-storage/example/.eslintrc.cjs +++ b/packages/global-storage/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/global-storage/src/index.spec.ts b/packages/global-storage/src/index.spec.ts index 5b4a5d92b8..21e341477f 100644 --- a/packages/global-storage/src/index.spec.ts +++ b/packages/global-storage/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { @@ -7,10 +8,10 @@ describe('index', () => { new Set([ // Public API '$storage', - 'meta', 'globalStorage', - 'useStorage', + 'meta', 'useGlobal', + 'useStorage', ]), ); }); diff --git a/packages/global-storage/src/index.ts b/packages/global-storage/src/index.ts index 4587216311..fdc71a68e2 100644 --- a/packages/global-storage/src/index.ts +++ b/packages/global-storage/src/index.ts @@ -1,6 +1,6 @@ export * from './$storage.js'; -export * from './Storage.js'; -export * from './meta.js'; export * from './globalStorage.js'; -export * from './useStorage.js'; +export * from './meta.js'; +export * from './Storage.js'; export * from './useGlobal.js'; +export * from './useStorage.js'; diff --git a/packages/global-storage/src/useGlobal.spec.ts b/packages/global-storage/src/useGlobal.spec.ts index a545fd9919..c173df4fab 100644 --- a/packages/global-storage/src/useGlobal.spec.ts +++ b/packages/global-storage/src/useGlobal.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { useGlobal } from './useGlobal.js'; describe(useGlobal, () => { diff --git a/packages/global-storage/src/useStorage.spec.ts b/packages/global-storage/src/useStorage.spec.ts index 7e450a61fc..0216ebfe48 100644 --- a/packages/global-storage/src/useStorage.spec.ts +++ b/packages/global-storage/src/useStorage.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { useStorage } from './useStorage.js'; + import { $storage } from './$storage.js'; +import { useStorage } from './useStorage.js'; describe(useStorage, () => { it('should be a map', () => { diff --git a/packages/global-storage/src/useStorage.ts b/packages/global-storage/src/useStorage.ts index 6a4edd9c29..18517f1567 100644 --- a/packages/global-storage/src/useStorage.ts +++ b/packages/global-storage/src/useStorage.ts @@ -1,6 +1,7 @@ -import { $storage } from './$storage.js'; import type { Storage } from './Storage.js'; +import { $storage } from './$storage.js'; + /** * Get or create a map object storage for `hostObject` * @@ -12,9 +13,7 @@ import type { Storage } from './Storage.js'; * @param hostObject the object hosting the storage */ export function useStorage(hostObject: object): Storage { - const target = hostObject as { - [P in string | symbol]: unknown; - }; + const target = hostObject as Record; return (target[$storage] as Storage | undefined) ?? (target[$storage] = new Map()); } diff --git a/packages/http/README.md b/packages/http/README.md index ec192839b4..3b4b4d156b 100644 --- a/packages/http/README.md +++ b/packages/http/README.md @@ -19,10 +19,10 @@ npm install @w5s/http ```ts -import { requestSend, HTTPError, ResponseParser, Client } from '@w5s/http'; import { Type } from '@w5s/core'; -import { Task } from '@w5s/task'; import { TimeoutError } from '@w5s/error'; +import { Client, HTTPError, requestSend, ResponseParser } from '@w5s/http'; +import { Task } from '@w5s/task'; const client = Client(); const getText = (id: number) => ({ diff --git a/packages/http/example/.eslintrc.cjs b/packages/http/example/.eslintrc.cjs index 7b08e8b9b3..f4abfcb015 100644 --- a/packages/http/example/.eslintrc.cjs +++ b/packages/http/example/.eslintrc.cjs @@ -3,8 +3,8 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', 'ts/no-floating-promises': 'off', }, }; diff --git a/packages/http/example/usage.ts b/packages/http/example/usage.ts index a1727da2ff..85b6caf8ab 100644 --- a/packages/http/example/usage.ts +++ b/packages/http/example/usage.ts @@ -1,7 +1,7 @@ -import { requestSend, HTTPError, ResponseParser, Client } from '@w5s/http'; import { Type } from '@w5s/core'; -import { Task } from '@w5s/task'; import { TimeoutError } from '@w5s/error'; +import { Client, HTTPError, requestSend, ResponseParser } from '@w5s/http'; +import { Task } from '@w5s/task'; const client = Client(); const getText = (id: number) => ({ diff --git a/packages/http/scripts/buildStatus.ts b/packages/http/scripts/buildStatus.ts index 88651b3e13..efa0ca0e30 100644 --- a/packages/http/scripts/buildStatus.ts +++ b/packages/http/scripts/buildStatus.ts @@ -1,33 +1,20 @@ -import { Type, Codec, Result, JSON } from '@w5s/core'; +import { Codec, JSON, Result, Type } from '@w5s/core'; import fs from 'node:fs/promises'; import path from 'node:path'; const eol = '\n'; const StatusDataComment = Type.Object({ - doc: Type.string, description: Type.string, + doc: Type.string, }); const StatusData = Type.Object({ code: Type.number, - phrase: Type.string, comment: StatusDataComment, isDeprecated: Type.Option(Type.boolean), + phrase: Type.string, }); const StatusArrayData = Type.Array(StatusData); -function outFile(file: string) { - return path.join('src', file); -} - -async function readStatusFile() { - const statusContent = await fs.readFile('resource/status.json'); - const statusDecoded = JSON.parse(String(statusContent)); - if (!statusDecoded.ok) { - return statusDecoded; - } - return Codec.decode(StatusArrayData, statusDecoded.value); -} - async function generateFiles() { const decodedResult = await readStatusFile(); if (!decodedResult.ok) { @@ -35,6 +22,7 @@ async function generateFiles() { } let statusAllContent = ''; statusAllContent += `import type { Int } from '@w5s/core/dist/Type/Int.js';${eol}`; + statusAllContent += `${eol}`; statusAllContent += `import { Status } from './Status.js';${eol}`; statusAllContent += `${eol}`; statusAllContent += decodedResult.value @@ -56,6 +44,23 @@ async function generateFiles() { return Result.Ok(); } +async function main() { + return Result.getOrThrow(await generateFiles()); +} + +function outFile(file: string) { + return path.join('src', file); +} + +async function readStatusFile() { + const statusContent = await fs.readFile('resource/status.json'); + const statusDecoded = JSON.parse(String(statusContent)); + if (!statusDecoded.ok) { + return statusDecoded; + } + return Codec.decode(StatusArrayData, statusDecoded.value); +} + function toConstant(str: string) { return str .replaceAll("'", ' ') @@ -65,8 +70,4 @@ function toConstant(str: string) { .join(''); } -async function main() { - return Result.getOrThrow(await generateFiles()); -} - await main(); diff --git a/packages/http/src/BodyReader.ts b/packages/http/src/BodyReader.ts index d1a16b1b09..a559383a53 100644 --- a/packages/http/src/BodyReader.ts +++ b/packages/http/src/BodyReader.ts @@ -1,33 +1,9 @@ import type { JSONValue, Option } from '@w5s/core'; -export type BodyReaderFormat = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; - -export type BodyReaderValue = F extends 'arrayBuffer' - ? ArrayBuffer - : F extends 'blob' - ? Blob - : F extends 'formData' - ? FormData - : F extends 'json' - ? JSONValue - : F extends 'stream' - ? Option - : F extends 'text' - ? string - : never; - /** * Represents an object that `BodyReader` */ export interface BodyReader { - /** - * Returns a promise of {@link ReadableStream} - * This is an internal method that should not be used directly - * - * @internal - */ - unsafeStream(): Option>; - /** * Returns a promise of {@link ArrayBuffer} * This is an internal method that should not be used directly @@ -60,6 +36,14 @@ export interface BodyReader { */ unsafeJSON(): Promise>; + /** + * Returns a promise of {@link ReadableStream} + * This is an internal method that should not be used directly + * + * @internal + */ + unsafeStream(): Option>; + /** * Returns a promise of `string` * This is an internal method that should not be used directly @@ -68,3 +52,19 @@ export interface BodyReader { */ unsafeText(): Promise>; } + +export type BodyReaderFormat = 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; + +export type BodyReaderValue = F extends 'arrayBuffer' + ? ArrayBuffer + : F extends 'blob' + ? Blob + : F extends 'formData' + ? FormData + : F extends 'json' + ? JSONValue + : F extends 'stream' + ? Option + : F extends 'text' + ? string + : never; diff --git a/packages/http/src/Client.spec.ts b/packages/http/src/Client.spec.ts index 0be53e57a5..841c2731b2 100644 --- a/packages/http/src/Client.spec.ts +++ b/packages/http/src/Client.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it } from 'vitest'; -import { TimeDuration } from '@w5s/time'; import { Option } from '@w5s/core'; import { Task } from '@w5s/task'; +import { TimeDuration } from '@w5s/time'; +import { describe, expect, it } from 'vitest'; + import { Client } from './Client.js'; describe(Client, () => { @@ -9,9 +10,9 @@ describe(Client, () => { const anyURL = 'https://localhost'; it('constructs a client', () => { expect(Client()).toEqual({ + fetch: globalThis.fetch, onRequest: Task.resolve, onResponse: Task.resolve, - fetch: globalThis.fetch, timeout: 'default', }); }); @@ -41,8 +42,8 @@ describe(Client, () => { timeout: anyDuration, }); const request = { - url: anyURL, timeout: 'default' as const, + url: anyURL, }; expect(Client.getRequestTimeoutDuration(client, request)).toBe(anyDuration); }); @@ -51,8 +52,8 @@ describe(Client, () => { timeout: 'none', }); const request = { - url: anyURL, timeout: 'none' as const, + url: anyURL, }; expect(Client.getRequestTimeoutDuration(client, request)).toBe(Option.None); }); @@ -61,8 +62,8 @@ describe(Client, () => { timeout: 'none', }); const request = { - url: anyURL, timeout: anyDuration, + url: anyURL, }; expect(Client.getRequestTimeoutDuration(client, request)).toBe(anyDuration); }); diff --git a/packages/http/src/Client.ts b/packages/http/src/Client.ts index f6e14c2d11..52e025da23 100644 --- a/packages/http/src/Client.ts +++ b/packages/http/src/Client.ts @@ -1,15 +1,22 @@ -import { invariant } from '@w5s/error/dist/invariant.js'; import type { Option } from '@w5s/core'; -import type { TimeDuration } from '@w5s/time'; import type { TaskLike } from '@w5s/task'; +import type { TimeDuration } from '@w5s/time'; + +import { invariant } from '@w5s/error/dist/invariant.js'; import { resolve } from '@w5s/task/dist/Task/resolve.js'; -import type { RequestTimeout } from './RequestTimeout.js'; -import type { Request } from './Request.js'; + +import type { BodyReader } from './BodyReader.js'; import type { HTTPError } from './HTTPError.js'; +import type { Request } from './Request.js'; +import type { RequestTimeout } from './RequestTimeout.js'; import type { Response } from './Response.js'; -import type { BodyReader } from './BodyReader.js'; export interface Client { + /** + * Fetch function. Default to `globalThis.fetch`. + */ + fetch: typeof globalThis.fetch; + /** * Wrap a request before sent * @@ -24,11 +31,6 @@ export interface Client { */ onResponse: (response: Response) => TaskLike, HTTPError>; - /** - * Fetch function. Default to `globalThis.fetch`. - */ - fetch: typeof globalThis.fetch; - /** * Response timeout setting */ @@ -41,11 +43,11 @@ export interface Client { */ export const Client = Object.assign( (parameters: Client.Options = {}): Client => { - const { timeout = 'default', fetch = getDefaultFetch(), onRequest = resolve, onResponse = resolve } = parameters; + const { fetch = getDefaultFetch(), onRequest = resolve, onResponse = resolve, timeout = 'default' } = parameters; return { + fetch, onRequest, onResponse, - fetch, timeout, }; }, @@ -55,21 +57,6 @@ export const Client = Object.assign( */ defaultTimeoutDuration: (30 * 1000) as TimeDuration, // 30 seconds - /** - * Returns the timeout duration in milliseconds for client - * - * @example - * ```typescript - * const client = Client(); - * const duration = Client.getTimeoutDuration(client); - * ``` - * @param client - */ - getTimeoutDuration(client: Client): Option { - const { timeout } = client; - return timeout === 'none' ? undefined : timeout === 'default' ? Client.defaultTimeoutDuration : timeout; - }, - /** * Returns the timeout duration in milliseconds for the request and client * @@ -89,6 +76,21 @@ export const Client = Object.assign( ? Client.getTimeoutDuration(client) : requestTimeout; }, + + /** + * Returns the timeout duration in milliseconds for client + * + * @example + * ```typescript + * const client = Client(); + * const duration = Client.getTimeoutDuration(client); + * ``` + * @param client + */ + getTimeoutDuration(client: Client): Option { + const { timeout } = client; + return timeout === 'none' ? undefined : timeout === 'default' ? Client.defaultTimeoutDuration : timeout; + }, }, ); diff --git a/packages/http/src/HTTPError.spec.ts b/packages/http/src/HTTPError.spec.ts index ce2b18a653..bd94e92f58 100644 --- a/packages/http/src/HTTPError.spec.ts +++ b/packages/http/src/HTTPError.spec.ts @@ -1,14 +1,15 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { HTTPError } from './HTTPError.js'; describe('HTTPError.InvalidURL', () => { it('should constructor new error', () => { - expect(new HTTPError.InvalidURL({ message: 'test', input: 'abc' })).toEqual( + expect(new HTTPError.InvalidURL({ input: 'abc', message: 'test' })).toEqual( expect.objectContaining({ + input: 'abc', + message: 'test', // _: 'DataError', name: 'HTTPInvalidURLError', - message: 'test', - input: 'abc', }), ); }); @@ -17,9 +18,9 @@ describe('HTTPError.NetworkError', () => { it('should constructor new error', () => { expect(new HTTPError.NetworkError({ message: 'test' })).toEqual( expect.objectContaining({ + message: 'test', // _: 'DataError', name: 'HTTPNetworkError', - message: 'test', }), ); }); @@ -28,9 +29,9 @@ describe('HTTPError.ParserError', () => { it('should constructor new error', () => { expect(new HTTPError.ParserError({ message: 'test' })).toEqual( expect.objectContaining({ + message: 'test', // _: 'DataError', name: 'HTTPParserError', - message: 'test', }), ); }); diff --git a/packages/http/src/HTTPError.ts b/packages/http/src/HTTPError.ts index dc08560929..4bd9c377e9 100644 --- a/packages/http/src/HTTPError.ts +++ b/packages/http/src/HTTPError.ts @@ -1,23 +1,24 @@ import type { TimeoutError } from '@w5s/error'; -import { NetworkError as NetworkErrorClass } from './HTTPError/NetworkError.js'; + import { InvalidURL as InvalidURLClass } from './HTTPError/InvalidURL.js'; +import { NetworkError as NetworkErrorClass } from './HTTPError/NetworkError.js'; import { ParserError as ParserErrorClass } from './HTTPError/ParserError.js'; /** * Union type of http client errors */ -export type HTTPError = HTTPError.NetworkError | HTTPError.InvalidURL | HTTPError.ParserError | TimeoutError; +export type HTTPError = HTTPError.InvalidURL | HTTPError.NetworkError | HTTPError.ParserError | TimeoutError; /** * @namespace */ export const HTTPError = { - NetworkError: NetworkErrorClass, InvalidURL: InvalidURLClass, + NetworkError: NetworkErrorClass, ParserError: ParserErrorClass, }; export namespace HTTPError { - export type NetworkError = NetworkErrorClass; export type InvalidURL = InvalidURLClass; + export type NetworkError = NetworkErrorClass; export type ParserError = ParserErrorClass; } diff --git a/packages/http/src/HTTPError/InvalidURL.ts b/packages/http/src/HTTPError/InvalidURL.ts index 8dbb17f1d4..4752155c64 100644 --- a/packages/http/src/HTTPError/InvalidURL.ts +++ b/packages/http/src/HTTPError/InvalidURL.ts @@ -4,6 +4,6 @@ import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; * An error when url passed is invalid */ export class InvalidURL extends ErrorClass({ - errorName: 'HTTPInvalidURLError', errorMessage: 'An invalid URL was provided', + errorName: 'HTTPInvalidURLError', })<{ input: string }> {} diff --git a/packages/http/src/HTTPError/NetworkError.ts b/packages/http/src/HTTPError/NetworkError.ts index 1c2e62b090..14d33ac73b 100644 --- a/packages/http/src/HTTPError/NetworkError.ts +++ b/packages/http/src/HTTPError/NetworkError.ts @@ -4,6 +4,6 @@ import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; * A network error when `fetch` fails */ export class NetworkError extends ErrorClass({ - errorName: 'HTTPNetworkError', errorMessage: 'Network error occurred', + errorName: 'HTTPNetworkError', }) {} diff --git a/packages/http/src/HTTPError/ParserError.ts b/packages/http/src/HTTPError/ParserError.ts index 691136f008..f68b1ae2ad 100644 --- a/packages/http/src/HTTPError/ParserError.ts +++ b/packages/http/src/HTTPError/ParserError.ts @@ -4,6 +4,6 @@ import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; * A parsing error when the body cannot be parsed */ export class ParserError extends ErrorClass({ - errorName: 'HTTPParserError', errorMessage: 'Cannot parse response body', + errorName: 'HTTPParserError', }) {} diff --git a/packages/http/src/Headers.spec.ts b/packages/http/src/Headers.spec.ts index 903df8c6bb..616c398096 100644 --- a/packages/http/src/Headers.spec.ts +++ b/packages/http/src/Headers.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + import { Headers } from './Headers.js'; -import { Headers as HeadersType } from './Headers/Headers.js'; import { empty } from './Headers/empty.js'; +import { Headers as HeadersType } from './Headers/Headers.js'; describe(Headers, () => { it('is an alias to functions', () => { diff --git a/packages/http/src/Headers.ts b/packages/http/src/Headers.ts index 2b8caf3719..fd4235453b 100644 --- a/packages/http/src/Headers.ts +++ b/packages/http/src/Headers.ts @@ -1,6 +1,7 @@ import { Callable } from '@w5s/core/dist/Callable.js'; -import { Headers as HeadersType } from './Headers/Headers.js'; + import { empty } from './Headers/empty.js'; +import { Headers as HeadersType } from './Headers/Headers.js'; /** * HTTP header record type @@ -26,11 +27,11 @@ export interface Headers extends HeadersType {} */ export const Headers = Callable({ ...HeadersType, - empty, [Callable.symbol]: (values: Iterable | Record): Headers => Symbol.iterator in values ? Object.fromEntries(values) : { ...values, }, + empty, }); diff --git a/packages/http/src/Headers/Headers.spec.ts b/packages/http/src/Headers/Headers.spec.ts index 87b65af788..2f7e2f0f18 100644 --- a/packages/http/src/Headers/Headers.spec.ts +++ b/packages/http/src/Headers/Headers.spec.ts @@ -1,21 +1,21 @@ -/* eslint-disable ts/consistent-type-assertions */ +import { CodecError, Result } from '@w5s/core'; +import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { describeType, describeCodec } from '@w5s/core/dist/Testing.js'; -import { Result, CodecError } from '@w5s/core'; + import { Headers } from './Headers.js'; describe('Headers', () => { describeType(Headers, () => ({ - typeName: 'Headers', instances: [{}, { 'Content-Type': 'application/json' } as Headers], notInstances: ['1', 1.1, undefined, { foo: 1 }], + typeName: 'Headers', })); describeCodec(Headers, () => ({ decode: [ [{}, Result.Ok({})], [{ foo: 'bar' }, Result.Ok({ foo: 'bar' })], - [1.1, Result.Error(new CodecError({ message: 'Cannot decode 1.1 as Record', input: 1.1 }))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as Record', input: null }))], + [1.1, Result.Error(new CodecError({ input: 1.1, message: 'Cannot decode 1.1 as Record' }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as Record' }))], ], encode: [[{ foo: 'bar' }, { foo: 'bar' }]], schema: { diff --git a/packages/http/src/Headers/Headers.ts b/packages/http/src/Headers/Headers.ts index a5d69e27a6..4589b295be 100644 --- a/packages/http/src/Headers/Headers.ts +++ b/packages/http/src/Headers/Headers.ts @@ -1,4 +1,5 @@ import type { Type } from '@w5s/core'; + import { Record } from '@w5s/core/dist/Type/Record.js'; import { string } from '@w5s/core/dist/Type/string.js'; diff --git a/packages/http/src/Headers/empty.spec.ts b/packages/http/src/Headers/empty.spec.ts index 2a017e73cf..891009755d 100644 --- a/packages/http/src/Headers/empty.spec.ts +++ b/packages/http/src/Headers/empty.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { empty } from './empty.js'; describe(empty, () => { diff --git a/packages/http/src/ReferrerPolicy.spec.ts b/packages/http/src/ReferrerPolicy.spec.ts index 82024dfb5a..f13025f7cb 100644 --- a/packages/http/src/ReferrerPolicy.spec.ts +++ b/packages/http/src/ReferrerPolicy.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { ReferrerPolicy } from './ReferrerPolicy.js'; describe('ReferrerPolicy', () => { diff --git a/packages/http/src/ReferrerPolicy.ts b/packages/http/src/ReferrerPolicy.ts index e471af68ea..b2968825d6 100644 --- a/packages/http/src/ReferrerPolicy.ts +++ b/packages/http/src/ReferrerPolicy.ts @@ -1,16 +1,17 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const ReferrerPolicy = define({ - typeName: 'ReferrerPolicy', Empty: '', NoReferrer: 'no-referrer', NoReferrerWhenDowngrade: 'no-referrer-when-downgrade', - SameOrigin: 'same-origin', Origin: 'origin', - StrictOrigin: 'strict-origin', OriginWhenCrossOrigin: 'origin-when-cross-origin', + SameOrigin: 'same-origin', + StrictOrigin: 'strict-origin', StrictOriginWhenCrossOrigin: 'strict-origin-when-cross-origin', + typeName: 'ReferrerPolicy', UnsafeURL: 'unsafe-url', }); diff --git a/packages/http/src/Request.ts b/packages/http/src/Request.ts index 09d45cd083..2ebc032da0 100644 --- a/packages/http/src/Request.ts +++ b/packages/http/src/Request.ts @@ -1,12 +1,13 @@ import type { Option } from '@w5s/core'; -import type { Method } from './Method.js'; + import type { Headers } from './Headers.js'; +import type { Method } from './Method.js'; +import type { ReferrerPolicy } from './ReferrerPolicy.js'; +import type { RequestCache } from './RequestCache.js'; import type { RequestCredentials } from './RequestCredentials.js'; import type { RequestDestination } from './RequestDestination.js'; -import type { RequestCache } from './RequestCache.js'; -import type { RequestRedirect } from './RequestRedirect.js'; -import type { ReferrerPolicy } from './ReferrerPolicy.js'; import type { RequestMode } from './RequestMode.js'; +import type { RequestRedirect } from './RequestRedirect.js'; import type { RequestTimeout } from './RequestTimeout.js'; import type { URL } from './URL.js'; @@ -18,6 +19,11 @@ import type { URL } from './URL.js'; export interface Request { // https://fetch.spec.whatwg.org/#requests + /** + * An optional BodyInit object to set request's body. + */ + readonly body?: Option; + /** * Indicates how the request will interact with the browser's cache to set request's cache. * @@ -32,15 +38,8 @@ export interface Request { * A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. */ readonly credentials?: RequestCredentials; - readonly destination?: RequestDestination; - /** - * Request URL - * - * @example - * 'https://foo.com' - */ - readonly url: URL; + readonly destination?: RequestDestination; /** * Request headers @@ -58,14 +57,9 @@ export interface Request { readonly integrity?: string; /** - * Indicates whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). - */ - readonly redirect?: RequestRedirect; - - /** - * Request referrer policy + * A boolean to set request's keepalive. */ - readonly referrerPolicy?: ReferrerPolicy; + readonly keepalive?: boolean; /** * Request Method @@ -74,38 +68,46 @@ export interface Request { */ readonly method?: Method; - /** - * A boolean to set request's keepalive. - */ - readonly keepalive?: boolean; - /** * Indicates whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. */ readonly mode?: RequestMode; /** - * An optional BodyInit object to set request's body. + * Indicates whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). */ - readonly body?: Option; + readonly redirect?: RequestRedirect; /** * A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. */ readonly referrer?: string; + /** + * Request referrer policy + */ + readonly referrerPolicy?: ReferrerPolicy; + + /** + * Request timeout setting + */ + readonly timeout?: RequestTimeout; + /** * An AbortSignal to set request's signal. */ // readonly signal?: Option; /** - * Can only be undefined. Used to disassociate request from any Window. + * Request URL + * + * @example + * 'https://foo.com' */ - readonly window?: undefined; + readonly url: URL; /** - * Request timeout setting + * Can only be undefined. Used to disassociate request from any Window. */ - readonly timeout?: RequestTimeout; + readonly window?: undefined; } diff --git a/packages/http/src/RequestCache.spec.ts b/packages/http/src/RequestCache.spec.ts index e489555314..d161a3f689 100644 --- a/packages/http/src/RequestCache.spec.ts +++ b/packages/http/src/RequestCache.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RequestCache } from './RequestCache.js'; describe('RequestCache', () => { diff --git a/packages/http/src/RequestCache.ts b/packages/http/src/RequestCache.ts index 2dfa6cee73..1d56739ca3 100644 --- a/packages/http/src/RequestCache.ts +++ b/packages/http/src/RequestCache.ts @@ -1,14 +1,15 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const RequestCache = define({ - typeName: 'RequestCache', Default: 'default', - NoStore: 'no-store', - Reload: 'reload', - NoCache: 'no-cache', ForceCache: 'force-cache', + NoCache: 'no-cache', + NoStore: 'no-store', OnlyIfCached: 'only-if-cached', + Reload: 'reload', + typeName: 'RequestCache', }); /** diff --git a/packages/http/src/RequestCredentials.spec.ts b/packages/http/src/RequestCredentials.spec.ts index 27c2e594f5..92754b78c6 100644 --- a/packages/http/src/RequestCredentials.spec.ts +++ b/packages/http/src/RequestCredentials.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RequestCredentials } from './RequestCredentials.js'; describe('RequestCredentials', () => { diff --git a/packages/http/src/RequestCredentials.ts b/packages/http/src/RequestCredentials.ts index 84080f0e6c..c2e9a29475 100644 --- a/packages/http/src/RequestCredentials.ts +++ b/packages/http/src/RequestCredentials.ts @@ -1,11 +1,12 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const RequestCredentials = define({ - typeName: 'RequestCredentials', Include: 'include', Omit: 'omit', SameOrigin: 'same-origin', + typeName: 'RequestCredentials', }); /** diff --git a/packages/http/src/RequestDestination.spec.ts b/packages/http/src/RequestDestination.spec.ts index 8b5521776a..6f7d5c51cf 100644 --- a/packages/http/src/RequestDestination.spec.ts +++ b/packages/http/src/RequestDestination.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RequestDestination } from './RequestDestination.js'; describe('RequestDestination', () => { diff --git a/packages/http/src/RequestDestination.ts b/packages/http/src/RequestDestination.ts index 34006df286..f3004e81d8 100644 --- a/packages/http/src/RequestDestination.ts +++ b/packages/http/src/RequestDestination.ts @@ -1,13 +1,13 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const RequestDestination = define({ - typeName: 'RequestDestination', - Empty: '', Audio: 'audio', AudioWorklet: 'audioworklet', Document: 'document', Embed: 'embed', + Empty: '', Font: 'font', Frame: 'frame', Iframe: 'iframe', @@ -20,6 +20,7 @@ export const RequestDestination = define({ SharedWorker: 'sharedworker', Style: 'style', Track: 'track', + typeName: 'RequestDestination', Video: 'video', Worker: 'worker', XSLT: 'xslt', diff --git a/packages/http/src/RequestMode.spec.ts b/packages/http/src/RequestMode.spec.ts index 9156733624..b5bdb14b68 100644 --- a/packages/http/src/RequestMode.spec.ts +++ b/packages/http/src/RequestMode.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RequestMode } from './RequestMode.js'; describe('RequestMode', () => { diff --git a/packages/http/src/RequestMode.ts b/packages/http/src/RequestMode.ts index 54aa000207..b115e1c41e 100644 --- a/packages/http/src/RequestMode.ts +++ b/packages/http/src/RequestMode.ts @@ -1,12 +1,13 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const RequestMode = define({ - typeName: 'RequestMode', - SameOrigin: 'same-origin', CORS: 'cors', Navigate: 'navigate', NoCORS: 'no-cors', + SameOrigin: 'same-origin', + typeName: 'RequestMode', }); /** diff --git a/packages/http/src/RequestRedirect.spec.ts b/packages/http/src/RequestRedirect.spec.ts index e83cdb456f..7f5a785573 100644 --- a/packages/http/src/RequestRedirect.spec.ts +++ b/packages/http/src/RequestRedirect.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { RequestRedirect } from './RequestRedirect.js'; describe('RequestRedirect', () => { diff --git a/packages/http/src/RequestRedirect.ts b/packages/http/src/RequestRedirect.ts index 1b480618fa..f46c4a7ddb 100644 --- a/packages/http/src/RequestRedirect.ts +++ b/packages/http/src/RequestRedirect.ts @@ -1,11 +1,12 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const RequestRedirect = define({ - typeName: 'RequestRedirect', - Follow: 'follow', Error: 'error', + Follow: 'follow', Manual: 'manual', + typeName: 'RequestRedirect', }); /** diff --git a/packages/http/src/RequestTimeout.ts b/packages/http/src/RequestTimeout.ts index 302e05527b..1afbfc4c2c 100644 --- a/packages/http/src/RequestTimeout.ts +++ b/packages/http/src/RequestTimeout.ts @@ -1,4 +1,5 @@ import type { Type } from '@w5s/core'; + import { constant } from '@w5s/core/dist/Type/constant.js'; import { union } from '@w5s/core/dist/Type/union.js'; import { TimeDuration } from '@w5s/time/dist/TimeDuration/TimeDuration.js'; diff --git a/packages/http/src/Response.spec.ts b/packages/http/src/Response.spec.ts index b75d7fd6bf..ade40a8fa2 100644 --- a/packages/http/src/Response.spec.ts +++ b/packages/http/src/Response.spec.ts @@ -1,7 +1,8 @@ import { describe, expect, it } from 'vitest'; + import { Response } from './Response.js'; -import { Status } from './Status.js'; import { from } from './Response/from.js'; +import { Status } from './Status.js'; describe(Response, () => { it('is an alias to functions', () => { @@ -14,18 +15,18 @@ describe(Response, () => { it('returns a new instance', () => { expect( Response({ - url: 'my/url', body: 'some body', status: Status.OK, + url: 'my/url', }), ).toEqual({ + body: 'some body', headers: {}, ok: true, - url: 'my/url', - status: Status.OK, - body: 'some body', redirected: false, + status: Status.OK, type: 'default', + url: 'my/url', }); }); }); diff --git a/packages/http/src/Response.ts b/packages/http/src/Response.ts index 33e949d236..0130c7c6da 100644 --- a/packages/http/src/Response.ts +++ b/packages/http/src/Response.ts @@ -1,29 +1,34 @@ -import { Callable } from '@w5s/core/dist/Callable.js'; import type { PartialKeys } from '@w5s/core-type'; + +import { Callable } from '@w5s/core/dist/Callable.js'; + +import type { Headers } from './Headers.js'; +import type { ResponseType } from './ResponseType.js'; import type { Status } from './Status.js'; import type { URL } from './URL.js'; -import type { ResponseType } from './ResponseType.js'; -import type { Headers } from './Headers.js'; + import { empty } from './Headers/empty.js'; import { from } from './Response/from.js'; export const Response = Callable({ - from, [Callable.symbol]: (parameters: Response.Parameters): Response => { - const { headers = empty(), ok = true, status, type = 'default', url, redirected = false, body } = parameters; + const { body, headers = empty(), ok = true, redirected = false, status, type = 'default', url } = parameters; return { + body, headers, ok, + redirected, status, type, url, - redirected, - body, }; }, + from, }); export interface Response { + readonly body: Body; + /** * The headers read-only property of the Response interface contains the Headers object associated with the response. * @@ -38,6 +43,13 @@ export interface Response { */ readonly ok: boolean; + /** + * The read-only redirected property of the {@link Response} interface indicates whether or not the response is the result of a request you made which was redirected. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Response/redirected + */ + readonly redirected: boolean; + /** * The read-only response {@link Status} * @@ -50,15 +62,7 @@ export interface Response { */ readonly type: ResponseType; readonly url: URL; - - /** - * The read-only redirected property of the {@link Response} interface indicates whether or not the response is the result of a request you made which was redirected. - * - * @see https://developer.mozilla.org/en-US/docs/Web/API/Response/redirected - */ - readonly redirected: boolean; - readonly body: Body; } export namespace Response { - export interface Parameters extends PartialKeys, 'ok' | 'redirected' | 'type' | 'headers'> {} + export interface Parameters extends PartialKeys, 'headers' | 'ok' | 'redirected' | 'type'> {} } diff --git a/packages/http/src/Response/from.ts b/packages/http/src/Response/from.ts index 6f439a4f8b..abe9f3434c 100644 --- a/packages/http/src/Response/from.ts +++ b/packages/http/src/Response/from.ts @@ -1,8 +1,9 @@ import type { Int } from '@w5s/core'; -import type { Response } from '../Response.js'; -import type { Status } from '../Status.js'; + import type { BodyReader } from '../BodyReader.js'; import type { Headers } from '../Headers.js'; +import type { Response } from '../Response.js'; +import type { Status } from '../Status.js'; /** * Returns a new {@link Response} object from {@link globalThis.Response} @@ -15,20 +16,24 @@ import type { Headers } from '../Headers.js'; */ export function from(originalResponse: globalThis.Response): Response { return { + body: responseBodyReader(originalResponse), headers: responseHeaders(originalResponse), ok: originalResponse.ok, + redirected: originalResponse.redirected, status: responseStatus(originalResponse), type: originalResponse.type, url: originalResponse.url, - redirected: originalResponse.redirected, - body: responseBodyReader(originalResponse), }; } -function responseStatus(response: globalThis.Response): Status { +function responseBodyReader(response: globalThis.Response): BodyReader { return { - statusCode: response.status as Int, - statusMessage: response.statusText, + unsafeArrayBuffer: () => response.arrayBuffer(), + unsafeBlob: () => response.blob(), + unsafeFormData: () => response.formData(), + unsafeJSON: () => response.json(), + unsafeStream: () => response.body ?? undefined, + unsafeText: () => response.text(), }; } @@ -42,13 +47,9 @@ function responseHeaders(response: globalThis.Response): Headers { return returnValue; } -function responseBodyReader(response: globalThis.Response): BodyReader { +function responseStatus(response: globalThis.Response): Status { return { - unsafeArrayBuffer: () => response.arrayBuffer(), - unsafeBlob: () => response.blob(), - unsafeFormData: () => response.formData(), - unsafeJSON: () => response.json(), - unsafeStream: () => response.body ?? undefined, - unsafeText: () => response.text(), + statusCode: response.status as Int, + statusMessage: response.statusText, }; } diff --git a/packages/http/src/ResponseParser.spec.ts b/packages/http/src/ResponseParser.spec.ts index 1117aa87f2..eb4d5c5078 100644 --- a/packages/http/src/ResponseParser.spec.ts +++ b/packages/http/src/ResponseParser.spec.ts @@ -1,11 +1,13 @@ import { CodecError, Type } from '@w5s/core'; import { Task } from '@w5s/task'; -import { describe, it, expect } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { ResponseParser } from './ResponseParser.js'; -import { HTTPError } from './HTTPError.js'; -import type { Response } from './Response.js'; +import { describe, expect, it } from 'vitest'; + import type { BodyReader, BodyReaderFormat } from './BodyReader.js'; +import type { Response } from './Response.js'; + +import { HTTPError } from './HTTPError.js'; +import { ResponseParser } from './ResponseParser.js'; import { FakeBodyReader } from './Testing.js'; const expectTask = withTask(expect); @@ -115,8 +117,8 @@ describe('ResponseParser', () => { ); await expectTask(parser(response)).toRejectAsync( new HTTPError.ParserError({ + cause: new CodecError({ input: true, message: 'Cannot decode true as string' }), message: 'Cannot parse response body', - cause: new CodecError({ message: 'Cannot decode true as string', input: true }), }), ); diff --git a/packages/http/src/ResponseParser.ts b/packages/http/src/ResponseParser.ts index 33e119c597..94b7439990 100644 --- a/packages/http/src/ResponseParser.ts +++ b/packages/http/src/ResponseParser.ts @@ -1,16 +1,24 @@ import type { Codec, JSONValue } from '@w5s/core'; import type { Task } from '@w5s/task'; -import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; -import { mapResult } from '@w5s/task/dist/Task/mapResult.js'; + import { decode } from '@w5s/core/dist/Codec/decode.js'; import { mapError } from '@w5s/core/dist/Result/mapError.js'; -import { HTTPError } from './HTTPError.js'; -import type { Response } from './Response.js'; +import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; +import { mapResult } from '@w5s/task/dist/Task/mapResult.js'; + import type { BodyReader } from './BodyReader.js'; +import type { Response } from './Response.js'; + +import { HTTPError } from './HTTPError.js'; + +/** + * A transformation function taking an {@link Response} as input + */ +export type ResponseParser = (response: Response) => Task; function from(fn: (response: Response) => Promise): ResponseParser { return (response) => - taskFrom(async ({ resolve, reject }) => { + taskFrom(async ({ reject, resolve }) => { try { resolve(await fn(response)); } catch (error: unknown) { @@ -23,13 +31,6 @@ function from(fn: (response: Response) => Promise): ResponsePa }); } -/** - * A transformation function taking an {@link Response} as input - */ -export interface ResponseParser { - (response: Response): Task; -} - /** * @namespace */ @@ -47,6 +48,19 @@ export const ResponseParser = { */ arrayBuffer: from((response) => response.body.unsafeArrayBuffer()), + /** + * Blob response parser + * + * @example + * ```typescript + * const request = requestSend({ + * url: 'http://localhost', + * }); + * const body = Task.andThen(request, HTTPParser.blob); // Task + * ``` + */ + blob: from((response) => response.body.unsafeBlob()), + /** * FormData response parser * @@ -86,19 +100,6 @@ export const ResponseParser = { ); }, - /** - * Blob response parser - * - * @example - * ```typescript - * const request = requestSend({ - * url: 'http://localhost', - * }); - * const body = Task.andThen(request, HTTPParser.blob); // Task - * ``` - */ - blob: from((response) => response.body.unsafeBlob()), - /** * Text response parser * diff --git a/packages/http/src/ResponseType.ts b/packages/http/src/ResponseType.ts index 5adbe4d5d9..7a1ce9052e 100644 --- a/packages/http/src/ResponseType.ts +++ b/packages/http/src/ResponseType.ts @@ -1,4 +1,5 @@ import type { Enum } from '@w5s/core'; + import { define } from '@w5s/core/dist/Enum/define.js'; export const ResponseType = define({ diff --git a/packages/http/src/Status.spec.ts b/packages/http/src/Status.spec.ts index 31b2e8c83a..b3c3d0fc4a 100644 --- a/packages/http/src/Status.spec.ts +++ b/packages/http/src/Status.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Status } from './Status.js'; import { StatusBounded } from './Status/StatusBounded.js'; import { StatusComparable } from './Status/StatusComparable.js'; @@ -13,10 +14,10 @@ describe('Status', () => { it('is a constructor', () => { expect(Status).toEqual( expect.objectContaining({ - hasInstance: expect.any(Function), - __schema__: expect.any(Function), - __encode__: expect.any(Function), __decode__: expect.any(Function), + __encode__: expect.any(Function), + __schema__: expect.any(Function), + hasInstance: expect.any(Function), }), ); }); diff --git a/packages/http/src/Status.ts b/packages/http/src/Status.ts index 506356a678..8dbe00198b 100644 --- a/packages/http/src/Status.ts +++ b/packages/http/src/Status.ts @@ -1,8 +1,9 @@ import { Callable } from '@w5s/core/dist/Callable.js'; + +import * as StatusAll from './Status/status.all.js'; import { Status as StatusType } from './Status/Status.js'; import { StatusBounded } from './Status/StatusBounded.js'; import { StatusComparable } from './Status/StatusComparable.js'; -import * as StatusAll from './Status/status.all.js'; import { StatusIndexable } from './Status/StatusIndexable.js'; /** diff --git a/packages/http/src/Status/Status.ts b/packages/http/src/Status/Status.ts index dd1b4d4f01..791a1d130a 100644 --- a/packages/http/src/Status/Status.ts +++ b/packages/http/src/Status/Status.ts @@ -1,4 +1,5 @@ import type { Type } from '@w5s/core'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { Int } from '@w5s/core/dist/Type/Int.js'; import { TObject } from '@w5s/core/dist/Type/Object.js'; diff --git a/packages/http/src/Status/StatusBounded.spec.ts b/packages/http/src/Status/StatusBounded.spec.ts index 7df3c8f8fe..43e58b0931 100644 --- a/packages/http/src/Status/StatusBounded.spec.ts +++ b/packages/http/src/Status/StatusBounded.spec.ts @@ -1,11 +1,12 @@ import { describeBounded } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { StatusBounded } from './StatusBounded.js'; + import { Continue, NetworkAuthenticationRequired } from './status.all.js'; +import { StatusBounded } from './StatusBounded.js'; describe('StatusBounded', () => { describeBounded(StatusBounded, { - minValue: Continue, maxValue: NetworkAuthenticationRequired, + minValue: Continue, }); }); diff --git a/packages/http/src/Status/StatusBounded.ts b/packages/http/src/Status/StatusBounded.ts index 07e7a07a78..b9e4e37d74 100644 --- a/packages/http/src/Status/StatusBounded.ts +++ b/packages/http/src/Status/StatusBounded.ts @@ -1,8 +1,10 @@ import type { Bounded } from '@w5s/core'; + import type { Status } from './Status.js'; + import { Continue, NetworkAuthenticationRequired } from './status.all.js'; export const StatusBounded: Bounded = { - minValue: Continue, maxValue: NetworkAuthenticationRequired, + minValue: Continue, }; diff --git a/packages/http/src/Status/StatusComparable.spec.ts b/packages/http/src/Status/StatusComparable.spec.ts index f8fb1ea0c7..b58d0cdfd8 100644 --- a/packages/http/src/Status/StatusComparable.spec.ts +++ b/packages/http/src/Status/StatusComparable.spec.ts @@ -1,15 +1,16 @@ -import { describe } from 'vitest'; -import { describeComparable } from '@w5s/core/dist/Testing.js'; import { Int } from '@w5s/core'; -import { StatusComparable } from './StatusComparable.js'; +import { describeComparable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Status } from './Status.js'; +import { StatusComparable } from './StatusComparable.js'; describe('StatusComparable', () => { describeComparable(StatusComparable, { - ordered: () => [Status(Int(100), 'z'), Status(Int(101), 'b'), Status(Int(500), 'a')], equivalent: () => [ [Status(Int(100), 'z'), Status(Int(100), 'z')], [Status(Int(100), 'z'), Status(Int(100), 'a')], ], + ordered: () => [Status(Int(100), 'z'), Status(Int(101), 'b'), Status(Int(500), 'a')], }); }); diff --git a/packages/http/src/Status/StatusComparable.ts b/packages/http/src/Status/StatusComparable.ts index fd37a1d90d..3feb8a472f 100644 --- a/packages/http/src/Status/StatusComparable.ts +++ b/packages/http/src/Status/StatusComparable.ts @@ -1,7 +1,9 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; -import { compare } from './compare.js'; + import type { Status } from './Status.js'; +import { compare } from './compare.js'; + export const StatusComparable = Comparable({ compare, }); diff --git a/packages/http/src/Status/StatusIndexable.spec.ts b/packages/http/src/Status/StatusIndexable.spec.ts index 1577163507..27dbddabc1 100644 --- a/packages/http/src/Status/StatusIndexable.spec.ts +++ b/packages/http/src/Status/StatusIndexable.spec.ts @@ -1,9 +1,10 @@ -import { describe } from 'vitest'; -import { describeIndexable } from '@w5s/core/dist/Testing.js'; import { Int } from '@w5s/core'; -import { StatusIndexable } from './StatusIndexable.js'; -import { Status } from './Status.js'; +import { describeIndexable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import * as StatusAll from './status.all.js'; +import { Status } from './Status.js'; +import { StatusIndexable } from './StatusIndexable.js'; describe('StatusIndexable', () => { describeIndexable(StatusIndexable, { @@ -11,7 +12,7 @@ describe('StatusIndexable', () => { [0, Status(Int(0), '')], [200, StatusAll.OK], ], - rangeSize: [], range: [], + rangeSize: [], }); }); diff --git a/packages/http/src/Status/StatusIndexable.ts b/packages/http/src/Status/StatusIndexable.ts index 6199d4b1ad..11700d30f3 100644 --- a/packages/http/src/Status/StatusIndexable.ts +++ b/packages/http/src/Status/StatusIndexable.ts @@ -1,8 +1,10 @@ -import { lazy } from '@w5s/core/dist/lazy.js'; import { Indexable } from '@w5s/core/dist/Indexable.js'; -import * as StatusAll from './status.all.js'; +import { lazy } from '@w5s/core/dist/lazy.js'; + import type { Status } from './Status.js'; +import * as StatusAll from './status.all.js'; + const indexByCode = lazy(() => { const returnValue = new Map(); for (const status of Object.values(StatusAll)) { @@ -12,7 +14,6 @@ const indexByCode = lazy(() => { }); export const StatusIndexable = Indexable({ - indexType: 'number', at(code) { return ( indexByCode().get(code) ?? { @@ -24,4 +25,5 @@ export const StatusIndexable = Indexable({ indexOf(status) { return status.statusCode; }, + indexType: 'number', }); diff --git a/packages/http/src/Status/compare.ts b/packages/http/src/Status/compare.ts index 4afa873db2..b1e0bcf7e5 100644 --- a/packages/http/src/Status/compare.ts +++ b/packages/http/src/Status/compare.ts @@ -1,5 +1,7 @@ -import { compare as compareNumber } from '@w5s/num/dist/Number/compare.js'; import type { Ordering } from '@w5s/core'; + +import { compare as compareNumber } from '@w5s/num/dist/Number/compare.js'; + import type { Status } from './Status.js'; export function compare(left: Status, right: Status): Ordering { diff --git a/packages/http/src/Status/status.all.ts b/packages/http/src/Status/status.all.ts index 8a328fd882..1ae009d034 100644 --- a/packages/http/src/Status/status.all.ts +++ b/packages/http/src/Status/status.all.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core/dist/Type/Int.js'; + import { Status } from './Status.js'; /** diff --git a/packages/http/src/Testing.spec.ts b/packages/http/src/Testing.spec.ts index 2fb53ce87c..e90e722d33 100644 --- a/packages/http/src/Testing.spec.ts +++ b/packages/http/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('index', () => { diff --git a/packages/http/src/Testing/FakeClient.ts b/packages/http/src/Testing/FakeClient.ts index adcadadf0c..68949c0e5b 100644 --- a/packages/http/src/Testing/FakeClient.ts +++ b/packages/http/src/Testing/FakeClient.ts @@ -1,4 +1,5 @@ import { Ref } from '@w5s/core/dist/Ref.js'; + import { Client } from '../Client.js'; export interface FakeClient extends Omit { diff --git a/packages/http/src/__snapshots__/ReferrerPolicy.spec.ts.snap b/packages/http/src/__snapshots__/ReferrerPolicy.spec.ts.snap index 806d62078a..22e9b8c4bd 100644 --- a/packages/http/src/__snapshots__/ReferrerPolicy.spec.ts.snap +++ b/packages/http/src/__snapshots__/ReferrerPolicy.spec.ts.snap @@ -17,10 +17,10 @@ exports[`ReferrerPolicy > is an enum 1`] = ` "Empty", "NoReferrer", "NoReferrerWhenDowngrade", - "SameOrigin", "Origin", - "StrictOrigin", "OriginWhenCrossOrigin", + "SameOrigin", + "StrictOrigin", "StrictOriginWhenCrossOrigin", "UnsafeURL", ], diff --git a/packages/http/src/__snapshots__/RequestCache.spec.ts.snap b/packages/http/src/__snapshots__/RequestCache.spec.ts.snap index bfc4d13190..40cccd8c7a 100644 --- a/packages/http/src/__snapshots__/RequestCache.spec.ts.snap +++ b/packages/http/src/__snapshots__/RequestCache.spec.ts.snap @@ -12,11 +12,11 @@ exports[`RequestCache > is an enum 1`] = ` "__encode__": [Function], "__enumKeys__": [ "Default", - "NoStore", - "Reload", - "NoCache", "ForceCache", + "NoCache", + "NoStore", "OnlyIfCached", + "Reload", ], "__inspect__": undefined, "__schema__": [Function], diff --git a/packages/http/src/__snapshots__/RequestDestination.spec.ts.snap b/packages/http/src/__snapshots__/RequestDestination.spec.ts.snap index 7cc31daa7f..f60059357f 100644 --- a/packages/http/src/__snapshots__/RequestDestination.spec.ts.snap +++ b/packages/http/src/__snapshots__/RequestDestination.spec.ts.snap @@ -25,11 +25,11 @@ exports[`RequestDestination > is an enum 1`] = ` "__decode__": [Function], "__encode__": [Function], "__enumKeys__": [ - "Empty", "Audio", "AudioWorklet", "Document", "Embed", + "Empty", "Font", "Frame", "Iframe", diff --git a/packages/http/src/__snapshots__/RequestMode.spec.ts.snap b/packages/http/src/__snapshots__/RequestMode.spec.ts.snap index e3c6393e3b..c84250c982 100644 --- a/packages/http/src/__snapshots__/RequestMode.spec.ts.snap +++ b/packages/http/src/__snapshots__/RequestMode.spec.ts.snap @@ -9,10 +9,10 @@ exports[`RequestMode > is an enum 1`] = ` "__decode__": [Function], "__encode__": [Function], "__enumKeys__": [ - "SameOrigin", "CORS", "Navigate", "NoCORS", + "SameOrigin", ], "__inspect__": undefined, "__schema__": [Function], diff --git a/packages/http/src/__snapshots__/RequestRedirect.spec.ts.snap b/packages/http/src/__snapshots__/RequestRedirect.spec.ts.snap index d46a10669d..4bb21e5c29 100644 --- a/packages/http/src/__snapshots__/RequestRedirect.spec.ts.snap +++ b/packages/http/src/__snapshots__/RequestRedirect.spec.ts.snap @@ -8,8 +8,8 @@ exports[`RequestRedirect > is an enum 1`] = ` "__decode__": [Function], "__encode__": [Function], "__enumKeys__": [ - "Follow", "Error", + "Follow", "Manual", ], "__inspect__": undefined, diff --git a/packages/http/src/index.spec.ts b/packages/http/src/index.spec.ts index c8787d678d..1814e820d5 100644 --- a/packages/http/src/index.spec.ts +++ b/packages/http/src/index.spec.ts @@ -1,23 +1,24 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Fetch from './index.js'; describe('index', () => { it('exports', () => { expect(new Set(Object.keys(Fetch))).toEqual( new Set([ - 'HTTPError', 'Client', + 'Headers', + 'HTTPError', 'ReferrerPolicy', 'RequestCache', 'RequestCredentials', 'RequestDestination', - 'Headers', 'RequestRedirect', 'requestSend', - 'Status', 'Response', 'ResponseParser', 'ResponseType', + 'Status', ]), ); }); diff --git a/packages/http/src/index.ts b/packages/http/src/index.ts index e4329c9e54..16ab13434b 100644 --- a/packages/http/src/index.ts +++ b/packages/http/src/index.ts @@ -1,14 +1,14 @@ +export * from './Client.js'; +export * from './Headers.js'; export * from './HTTPError.js'; -export * from './ResponseParser.js'; export * from './Method.js'; -export * from './Client.js'; export * from './ReferrerPolicy.js'; -export * from './Headers.js'; export * from './RequestCache.js'; export * from './RequestCredentials.js'; export * from './RequestDestination.js'; export * from './RequestRedirect.js'; export * from './requestSend.js'; -export * from './Status.js'; export * from './Response.js'; +export * from './ResponseParser.js'; export * from './ResponseType.js'; +export * from './Status.js'; diff --git a/packages/http/src/requestSend.spec.ts b/packages/http/src/requestSend.spec.ts index 427a20e470..39b21e7137 100644 --- a/packages/http/src/requestSend.spec.ts +++ b/packages/http/src/requestSend.spec.ts @@ -1,12 +1,13 @@ import { Int, Option } from '@w5s/core'; import { Task } from '@w5s/task'; -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { TimeDuration } from '@w5s/time'; import { timeout } from '@w5s/task-timeout'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { TimeDuration } from '@w5s/time'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { Client } from './Client.js'; import { HTTPError } from './HTTPError.js'; import { requestSend } from './requestSend.js'; -import { Client } from './Client.js'; import { Response } from './Response.js'; import { Status } from './Status.js'; @@ -24,24 +25,24 @@ describe(requestSend, () => { const anyURL = 'https://localhost'; const anyTask = expect.any(Object); const anyRequest = { - url: 'http://localhost#test', method: 'GET', + url: 'http://localhost#test', }; const anyResponse = new globalThis.Response(); const defer = (): { - resolve(value: V | PromiseLike): void; - reject(error: unknown): void; promise: Promise; + reject(error: unknown): void; + resolve(value: PromiseLike | V): void; } => { - const state: any = { resolve: (_: V) => undefined, reject: (_: unknown) => undefined }; + const state: any = { reject: (_: unknown) => undefined, resolve: (_: V) => undefined }; const promise = new Promise((resolve, reject) => { state.resolve = resolve; state.reject = reject; }); return { - resolve: (_) => state.resolve(_), - reject: (_) => state.reject(_), promise, + reject: (_) => state.reject(_), + resolve: (_) => state.resolve(_), }; }; const globalFetchMock = vi.fn(async () => anyResponse); @@ -52,12 +53,11 @@ describe(requestSend, () => { it('should call global fetch and send to parser', async () => { const url = 'http://localhost#test'; const task = requestSend(anyClient, { - url, method: 'GET', + url, }); await expectTask(task).toResolveAsync( Response({ - status: Status(Int(200), ''), body: { unsafeArrayBuffer: expect.any(Function), unsafeBlob: expect.any(Function), @@ -66,6 +66,7 @@ describe(requestSend, () => { unsafeStream: expect.any(Function), unsafeText: expect.any(Function), }, + status: Status(Int(200), ''), url: '', }), ); @@ -76,7 +77,7 @@ describe(requestSend, () => { url: 'http://www.exam ple.com', // invalid url }); await expectTask(task).toRejectAsync( - new HTTPError.InvalidURL({ message: 'Invalid URL', input: 'http://www.exam ple.com' }), + new HTTPError.InvalidURL({ input: 'http://www.exam ple.com', message: 'Invalid URL' }), ); }); it('should convert fetch error to NetworkError', async () => { @@ -127,23 +128,24 @@ describe(requestSend, () => { }); it('should use client#onRequest', async () => { const clientCustom = Client({ - onRequest: (request) => Task.resolve({ ...request, url: 'http://localhost#custom' }), fetch: globalFetchMock, + onRequest: (request) => Task.resolve({ ...request, url: 'http://localhost#custom' }), }); const request = { - url: 'http://localhost#test', method: 'GET', + url: 'http://localhost#test', }; const task = requestSend(clientCustom, request); await expectTask(task).toResolveAsync(expect.any(Object)); expect(globalFetchMock).toHaveBeenLastCalledWith('http://localhost#custom', { + body: null, method: 'GET', signal: expect.any(Object), - body: null, }); }); it('should use client#onResponse', async () => { const clientCustom = Client({ + fetch: globalFetchMock, onResponse: (response) => Task.resolve({ ...response, @@ -152,7 +154,6 @@ describe(requestSend, () => { bar: 'bar_value', }, }), - fetch: globalFetchMock, }); const mockResponse = new globalThis.Response(null, { headers: new globalThis.Headers({ @@ -164,8 +165,8 @@ describe(requestSend, () => { await expectTask(task).toResolveAsync( expect.objectContaining({ headers: { - foo: 'foo_value', bar: 'bar_value', + foo: 'foo_value', }, }), ); @@ -205,8 +206,8 @@ describe(requestSend, () => { timeout: 'default', }); requestSend(client, { - url: anyURL, timeout: 'none', + url: anyURL, }); expect(timeout).toHaveBeenLastCalledWith(anyTask, Option.None); }); @@ -215,8 +216,8 @@ describe(requestSend, () => { timeout: anyDuration, }); requestSend(client, { - url: anyURL, timeout: 'default', + url: anyURL, }); expect(timeout).toHaveBeenLastCalledWith(anyTask, anyDuration); }); @@ -235,8 +236,8 @@ describe(requestSend, () => { timeout: 'default', }); requestSend(client, { - url: anyURL, timeout: anyDuration, + url: anyURL, }); expect(timeout).toHaveBeenLastCalledWith(anyTask, anyDuration); }); diff --git a/packages/http/src/requestSend.ts b/packages/http/src/requestSend.ts index a6149c48d7..9284f7ea9b 100644 --- a/packages/http/src/requestSend.ts +++ b/packages/http/src/requestSend.ts @@ -1,12 +1,15 @@ import type { Task } from '@w5s/task'; -import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + import { timeout as taskTimeout } from '@w5s/task-timeout'; import { andThen as taskThen } from '@w5s/task/dist/Task/andThen.js'; -import { HTTPError } from './HTTPError.js'; -import type { Response } from './Response.js'; +import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + +import type { BodyReader } from './BodyReader.js'; import type { Request } from './Request.js'; +import type { Response } from './Response.js'; + import { Client } from './Client.js'; -import type { BodyReader } from './BodyReader.js'; +import { HTTPError } from './HTTPError.js'; import { from as responseFrom } from './Response/from.js'; /** @@ -29,12 +32,20 @@ export function requestSend(client: Client, requestObject: Request): Task, HTTPError> { const { fetch: fetchFn } = client; - return taskFrom(async ({ resolve, reject, canceler }) => { - // eslint-disable-next-line ts/no-unused-vars - const { url, body, window: _window, ...requestInfo } = requestObject; + return taskFrom(async ({ canceler, reject, resolve }) => { + const { body, url, window: _window, ...requestInfo } = requestObject; const controller = new AbortController(); canceler.onCancel = () => { controller.abort(); @@ -61,19 +72,10 @@ function requestSendImplementation(client: Client, requestObject: Request): Task await Promise.resolve(); reject( new HTTPError.InvalidURL({ - message: 'Invalid URL', input: url, + message: 'Invalid URL', }), ); } }); } - -function isValidURL(url: string): boolean { - try { - new globalThis.URL(url); - return true; - } catch { - return false; - } -} diff --git a/packages/iterable/example/.eslintrc.cjs b/packages/iterable/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/iterable/example/.eslintrc.cjs +++ b/packages/iterable/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/iterable/src/AsyncIterable.spec.ts b/packages/iterable/src/AsyncIterable.spec.ts index c0350788fe..8b2ad6add9 100644 --- a/packages/iterable/src/AsyncIterable.spec.ts +++ b/packages/iterable/src/AsyncIterable.spec.ts @@ -1,23 +1,24 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { AsyncIterable } from './AsyncIterable.js'; +import { chunks } from './AsyncIterable/chunks.js'; +import { concat } from './AsyncIterable/concat.js'; import { create } from './AsyncIterable/create.js'; +import { drop } from './AsyncIterable/drop.js'; import { empty } from './AsyncIterable/empty.js'; +import { every } from './AsyncIterable/every.js'; import { filter } from './AsyncIterable/filter.js'; +import { find } from './AsyncIterable/find.js'; +import { flatMap } from './AsyncIterable/flatMap.js'; import { generate } from './AsyncIterable/generate.js'; import { hasInstance } from './AsyncIterable/hasInstance.js'; import { map } from './AsyncIterable/map.js'; import { of } from './AsyncIterable/of.js'; import { reduce } from './AsyncIterable/reduce.js'; -import { zip } from './AsyncIterable/zip.js'; -import { every } from './AsyncIterable/every.js'; -import { some } from './AsyncIterable/some.js'; -import { flatMap } from './AsyncIterable/flatMap.js'; import { size } from './AsyncIterable/size.js'; -import { find } from './AsyncIterable/find.js'; -import { drop } from './AsyncIterable/drop.js'; +import { some } from './AsyncIterable/some.js'; import { take } from './AsyncIterable/take.js'; -import { chunks } from './AsyncIterable/chunks.js'; -import { concat } from './AsyncIterable/concat.js'; +import { zip } from './AsyncIterable/zip.js'; describe('AsyncIterable', () => { it('has alias to methods', () => { @@ -28,8 +29,8 @@ describe('AsyncIterable', () => { drop, empty, every, - find, filter, + find, flatMap, generate, hasInstance, diff --git a/packages/iterable/src/AsyncIterable.ts b/packages/iterable/src/AsyncIterable.ts index 6799896c71..9ccc239686 100644 --- a/packages/iterable/src/AsyncIterable.ts +++ b/packages/iterable/src/AsyncIterable.ts @@ -1,21 +1,21 @@ -import { of } from './AsyncIterable/of.js'; -import { filter } from './AsyncIterable/filter.js'; -import { map } from './AsyncIterable/map.js'; -import { zip } from './AsyncIterable/zip.js'; +import { chunks } from './AsyncIterable/chunks.js'; +import { concat } from './AsyncIterable/concat.js'; import { create } from './AsyncIterable/create.js'; -import { reduce } from './AsyncIterable/reduce.js'; -import { generate } from './AsyncIterable/generate.js'; -import { hasInstance } from './AsyncIterable/hasInstance.js'; +import { drop } from './AsyncIterable/drop.js'; import { empty } from './AsyncIterable/empty.js'; import { every } from './AsyncIterable/every.js'; -import { some } from './AsyncIterable/some.js'; +import { filter } from './AsyncIterable/filter.js'; +import { find } from './AsyncIterable/find.js'; import { flatMap } from './AsyncIterable/flatMap.js'; +import { generate } from './AsyncIterable/generate.js'; +import { hasInstance } from './AsyncIterable/hasInstance.js'; +import { map } from './AsyncIterable/map.js'; +import { of } from './AsyncIterable/of.js'; +import { reduce } from './AsyncIterable/reduce.js'; import { size } from './AsyncIterable/size.js'; -import { find } from './AsyncIterable/find.js'; -import { drop } from './AsyncIterable/drop.js'; +import { some } from './AsyncIterable/some.js'; import { take } from './AsyncIterable/take.js'; -import { chunks } from './AsyncIterable/chunks.js'; -import { concat } from './AsyncIterable/concat.js'; +import { zip } from './AsyncIterable/zip.js'; /** * @namespace diff --git a/packages/iterable/src/AsyncIterable/chunks.spec.ts b/packages/iterable/src/AsyncIterable/chunks.spec.ts index 97a6df634e..210da98552 100644 --- a/packages/iterable/src/AsyncIterable/chunks.spec.ts +++ b/packages/iterable/src/AsyncIterable/chunks.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { chunks } from './chunks.js'; + import { withAsyncIterable } from '../Testing.js'; +import { chunks } from './chunks.js'; import { from } from './from.js'; describe(chunks, () => { diff --git a/packages/iterable/src/AsyncIterable/concat.spec.ts b/packages/iterable/src/AsyncIterable/concat.spec.ts index 3f7acb7f7d..7b98688980 100644 --- a/packages/iterable/src/AsyncIterable/concat.spec.ts +++ b/packages/iterable/src/AsyncIterable/concat.spec.ts @@ -1,10 +1,11 @@ // packages/iterable/src/Iterable/chunks.spec.ts import { describe, expect, it } from 'vitest'; -import { concat } from './concat.js'; + import { withAsyncIterable } from '../Testing.js'; -import { of } from './of.js'; +import { concat } from './concat.js'; import { empty } from './empty.js'; +import { of } from './of.js'; describe(concat, () => { const expectIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/create.spec.ts b/packages/iterable/src/AsyncIterable/create.spec.ts index 2fd72fcf9d..188c1b421c 100644 --- a/packages/iterable/src/AsyncIterable/create.spec.ts +++ b/packages/iterable/src/AsyncIterable/create.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; import { Symbol } from '@w5s/core'; -import { create } from './create.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { create } from './create.js'; describe(create, () => { const expectAsyncIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/drop.spec.ts b/packages/iterable/src/AsyncIterable/drop.spec.ts index dcecbede53..a8c0e00487 100644 --- a/packages/iterable/src/AsyncIterable/drop.spec.ts +++ b/packages/iterable/src/AsyncIterable/drop.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { drop } from './drop.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { drop } from './drop.js'; import { of } from './of.js'; describe(drop, () => { diff --git a/packages/iterable/src/AsyncIterable/empty.spec.ts b/packages/iterable/src/AsyncIterable/empty.spec.ts index b159c4800e..6b47c989a2 100644 --- a/packages/iterable/src/AsyncIterable/empty.spec.ts +++ b/packages/iterable/src/AsyncIterable/empty.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { empty } from './empty.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { empty } from './empty.js'; describe(empty, () => { const expectAsyncIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/every.spec.ts b/packages/iterable/src/AsyncIterable/every.spec.ts index 448b6d50c5..cc977796f4 100644 --- a/packages/iterable/src/AsyncIterable/every.spec.ts +++ b/packages/iterable/src/AsyncIterable/every.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { of } from './of.js'; +import { describe, expect, it, vi } from 'vitest'; + import { every } from './every.js'; +import { of } from './of.js'; describe(every, () => { it('returns true when every elements satisfies the given predicate', async () => { diff --git a/packages/iterable/src/AsyncIterable/every.ts b/packages/iterable/src/AsyncIterable/every.ts index ec2baf80b4..5565824703 100644 --- a/packages/iterable/src/AsyncIterable/every.ts +++ b/packages/iterable/src/AsyncIterable/every.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/filter.spec.ts b/packages/iterable/src/AsyncIterable/filter.spec.ts index 7c2ce6d9b8..d2756db918 100644 --- a/packages/iterable/src/AsyncIterable/filter.spec.ts +++ b/packages/iterable/src/AsyncIterable/filter.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect, vi } from 'vitest'; import { Array } from '@w5s/collection'; -import { filter } from './filter.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { filter } from './filter.js'; import { of } from './of.js'; describe(filter, () => { diff --git a/packages/iterable/src/AsyncIterable/filter.ts b/packages/iterable/src/AsyncIterable/filter.ts index bb62ec6526..5a70af532d 100644 --- a/packages/iterable/src/AsyncIterable/filter.ts +++ b/packages/iterable/src/AsyncIterable/filter.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/find.spec.ts b/packages/iterable/src/AsyncIterable/find.spec.ts index 09feddefe9..7840345262 100644 --- a/packages/iterable/src/AsyncIterable/find.spec.ts +++ b/packages/iterable/src/AsyncIterable/find.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { find } from './find.js'; +import { describe, expect, it, vi } from 'vitest'; + import { create } from './create.js'; +import { find } from './find.js'; import { of } from './of.js'; describe(find, () => { diff --git a/packages/iterable/src/AsyncIterable/find.ts b/packages/iterable/src/AsyncIterable/find.ts index 0f065bfaa4..e43b31390a 100644 --- a/packages/iterable/src/AsyncIterable/find.ts +++ b/packages/iterable/src/AsyncIterable/find.ts @@ -1,5 +1,6 @@ -import type { Awaitable } from '@w5s/core-type'; import type { Option } from '@w5s/core'; +import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/flatMap.spec.ts b/packages/iterable/src/AsyncIterable/flatMap.spec.ts index 5ac6ebba0b..81c6b5b3d0 100644 --- a/packages/iterable/src/AsyncIterable/flatMap.spec.ts +++ b/packages/iterable/src/AsyncIterable/flatMap.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect, vi } from 'vitest'; import { Array } from '@w5s/collection'; -import { flatMap } from './flatMap.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { flatMap } from './flatMap.js'; import { of } from './of.js'; describe(flatMap, () => { diff --git a/packages/iterable/src/AsyncIterable/flatMap.ts b/packages/iterable/src/AsyncIterable/flatMap.ts index 0a56efe4fb..910bad8496 100644 --- a/packages/iterable/src/AsyncIterable/flatMap.ts +++ b/packages/iterable/src/AsyncIterable/flatMap.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/from.spec.ts b/packages/iterable/src/AsyncIterable/from.spec.ts index 0d81992d46..783ff2c0ed 100644 --- a/packages/iterable/src/AsyncIterable/from.spec.ts +++ b/packages/iterable/src/AsyncIterable/from.spec.ts @@ -1,8 +1,10 @@ -import { describe, it, expect } from 'vitest'; import type { Awaitable } from '@w5s/core-type'; -import { from } from './from.js'; -import { withAsyncIterable } from '../Testing.js'; + +import { describe, expect, it } from 'vitest'; + import { Iterable } from '../Iterable.js'; +import { withAsyncIterable } from '../Testing.js'; +import { from } from './from.js'; describe(from, () => { const expectIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/generate.spec.ts b/packages/iterable/src/AsyncIterable/generate.spec.ts index 3b50a5b5c7..4b396e9e6d 100644 --- a/packages/iterable/src/AsyncIterable/generate.spec.ts +++ b/packages/iterable/src/AsyncIterable/generate.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { generate } from './generate.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { generate } from './generate.js'; describe(generate, () => { const expectAsyncIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/generate.ts b/packages/iterable/src/AsyncIterable/generate.ts index 5c7db1bc36..2e257cd2ac 100644 --- a/packages/iterable/src/AsyncIterable/generate.ts +++ b/packages/iterable/src/AsyncIterable/generate.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import { empty } from './empty.js'; /** diff --git a/packages/iterable/src/AsyncIterable/hasInstance.spec.ts b/packages/iterable/src/AsyncIterable/hasInstance.spec.ts index cab11fc0f5..fede83defe 100644 --- a/packages/iterable/src/AsyncIterable/hasInstance.spec.ts +++ b/packages/iterable/src/AsyncIterable/hasInstance.spec.ts @@ -1,10 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { hasInstance } from './hasInstance.js'; describe(hasInstance, () => { it.each([ [{ [Symbol.iterator]: () => {} }, false], [{ [Symbol.iterator]: 'not_a_function' }, false], + // eslint-disable-next-line unicorn/no-invalid-well-known-symbol-methods [{ [Symbol.asyncIterator]: async () => {} }, true], [{ [Symbol.asyncIterator]: 'not_a_function' }, false], [[], false], diff --git a/packages/iterable/src/AsyncIterable/map.spec.ts b/packages/iterable/src/AsyncIterable/map.spec.ts index 1a9156547f..239ac260e3 100644 --- a/packages/iterable/src/AsyncIterable/map.spec.ts +++ b/packages/iterable/src/AsyncIterable/map.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect, vi } from 'vitest'; import { Array } from '@w5s/collection'; -import { map } from './map.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { map } from './map.js'; import { of } from './of.js'; describe(map, () => { diff --git a/packages/iterable/src/AsyncIterable/map.ts b/packages/iterable/src/AsyncIterable/map.ts index 60019098f0..10028f03f4 100644 --- a/packages/iterable/src/AsyncIterable/map.ts +++ b/packages/iterable/src/AsyncIterable/map.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/of.spec.ts b/packages/iterable/src/AsyncIterable/of.spec.ts index f1d363f192..a369285cf5 100644 --- a/packages/iterable/src/AsyncIterable/of.spec.ts +++ b/packages/iterable/src/AsyncIterable/of.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { of } from './of.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; +import { of } from './of.js'; describe(of, () => { const expectAsyncIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/of.ts b/packages/iterable/src/AsyncIterable/of.ts index 2ef7337a27..cffd12d65a 100644 --- a/packages/iterable/src/AsyncIterable/of.ts +++ b/packages/iterable/src/AsyncIterable/of.ts @@ -8,7 +8,7 @@ * @category Constructor * @param values The values of the iterable */ -export function of(...values: Value[]): AsyncIterable { +export function of(...values: Array): AsyncIterable { return { async* [Symbol.asyncIterator]() { for (const value of values) { diff --git a/packages/iterable/src/AsyncIterable/reduce.spec.ts b/packages/iterable/src/AsyncIterable/reduce.spec.ts index df69db9d28..4300d14152 100644 --- a/packages/iterable/src/AsyncIterable/reduce.spec.ts +++ b/packages/iterable/src/AsyncIterable/reduce.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { of } from './of.js'; import { reduce } from './reduce.js'; diff --git a/packages/iterable/src/AsyncIterable/reduce.ts b/packages/iterable/src/AsyncIterable/reduce.ts index a78654380e..b43110219c 100644 --- a/packages/iterable/src/AsyncIterable/reduce.ts +++ b/packages/iterable/src/AsyncIterable/reduce.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/size.spec.ts b/packages/iterable/src/AsyncIterable/size.spec.ts index 3f5bedecfb..0e1fd7c670 100644 --- a/packages/iterable/src/AsyncIterable/size.spec.ts +++ b/packages/iterable/src/AsyncIterable/size.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; import { size } from './size.js'; diff --git a/packages/iterable/src/AsyncIterable/size.ts b/packages/iterable/src/AsyncIterable/size.ts index a67c23fba9..325c51163e 100644 --- a/packages/iterable/src/AsyncIterable/size.ts +++ b/packages/iterable/src/AsyncIterable/size.ts @@ -1,7 +1,9 @@ import type { Int } from '@w5s/core'; -import { reduce } from './reduce.js'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; +import { reduce } from './reduce.js'; + const sum = (accumulator: Int) => (accumulator + 1) as Int; /** diff --git a/packages/iterable/src/AsyncIterable/some.spec.ts b/packages/iterable/src/AsyncIterable/some.spec.ts index 68281c0efe..c9e4e03656 100644 --- a/packages/iterable/src/AsyncIterable/some.spec.ts +++ b/packages/iterable/src/AsyncIterable/some.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { of } from './of.js'; import { some } from './some.js'; diff --git a/packages/iterable/src/AsyncIterable/some.ts b/packages/iterable/src/AsyncIterable/some.ts index 53007b81ca..b2d1998e49 100644 --- a/packages/iterable/src/AsyncIterable/some.ts +++ b/packages/iterable/src/AsyncIterable/some.ts @@ -1,5 +1,6 @@ import type { Int } from '@w5s/core'; import type { Awaitable } from '@w5s/core-type'; + import type { AsyncIterableLike } from '../AsyncIterableLike.js'; /** diff --git a/packages/iterable/src/AsyncIterable/take.spec.ts b/packages/iterable/src/AsyncIterable/take.spec.ts index fed7717878..e5ebe7b2eb 100644 --- a/packages/iterable/src/AsyncIterable/take.spec.ts +++ b/packages/iterable/src/AsyncIterable/take.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { take } from './take.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; import { of } from './of.js'; +import { take } from './take.js'; describe(take, () => { const expectIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/zip.spec.ts b/packages/iterable/src/AsyncIterable/zip.spec.ts index 4d9887e782..6726e5df7c 100644 --- a/packages/iterable/src/AsyncIterable/zip.spec.ts +++ b/packages/iterable/src/AsyncIterable/zip.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { zip } from './zip.js'; +import { describe, expect, it } from 'vitest'; + import { withAsyncIterable } from '../Testing.js'; import { of } from './of.js'; +import { zip } from './zip.js'; describe(zip, () => { const expectAsyncIterable = withAsyncIterable(expect); diff --git a/packages/iterable/src/AsyncIterable/zip.ts b/packages/iterable/src/AsyncIterable/zip.ts index 4e5e055a49..68b33ec65a 100644 --- a/packages/iterable/src/AsyncIterable/zip.ts +++ b/packages/iterable/src/AsyncIterable/zip.ts @@ -1,4 +1,5 @@ import type { AsyncIterableLike } from '../AsyncIterableLike.js'; + import { from } from './from.js'; /** diff --git a/packages/iterable/src/Iterable.spec.ts b/packages/iterable/src/Iterable.spec.ts index c7d4d168c9..2ef68c051f 100644 --- a/packages/iterable/src/Iterable.spec.ts +++ b/packages/iterable/src/Iterable.spec.ts @@ -1,24 +1,25 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Iterable } from './Iterable.js'; +import { chunks } from './Iterable/chunks.js'; +import { concat } from './Iterable/concat.js'; import { create } from './Iterable/create.js'; +import { drop } from './Iterable/drop.js'; import { empty } from './Iterable/empty.js'; +import { every } from './Iterable/every.js'; import { filter } from './Iterable/filter.js'; +import { find } from './Iterable/find.js'; +import { flatMap } from './Iterable/flatMap.js'; +import { from } from './Iterable/from.js'; import { generate } from './Iterable/generate.js'; import { hasInstance } from './Iterable/hasInstance.js'; import { map } from './Iterable/map.js'; import { of } from './Iterable/of.js'; import { reduce } from './Iterable/reduce.js'; -import { zip } from './Iterable/zip.js'; -import { every } from './Iterable/every.js'; -import { some } from './Iterable/some.js'; -import { flatMap } from './Iterable/flatMap.js'; import { size } from './Iterable/size.js'; -import { find } from './Iterable/find.js'; -import { drop } from './Iterable/drop.js'; +import { some } from './Iterable/some.js'; import { take } from './Iterable/take.js'; -import { chunks } from './Iterable/chunks.js'; -import { concat } from './Iterable/concat.js'; -import { from } from './Iterable/from.js'; +import { zip } from './Iterable/zip.js'; describe('Iterable', () => { it('has alias to methods', () => { diff --git a/packages/iterable/src/Iterable.ts b/packages/iterable/src/Iterable.ts index c97c333ac9..014f920f6f 100644 --- a/packages/iterable/src/Iterable.ts +++ b/packages/iterable/src/Iterable.ts @@ -1,22 +1,22 @@ -import { of } from './Iterable/of.js'; -import { filter } from './Iterable/filter.js'; -import { map } from './Iterable/map.js'; -import { zip } from './Iterable/zip.js'; +import { chunks } from './Iterable/chunks.js'; +import { concat } from './Iterable/concat.js'; import { create } from './Iterable/create.js'; -import { reduce } from './Iterable/reduce.js'; -import { generate } from './Iterable/generate.js'; -import { hasInstance } from './Iterable/hasInstance.js'; +import { drop } from './Iterable/drop.js'; import { empty } from './Iterable/empty.js'; -import { some } from './Iterable/some.js'; import { every } from './Iterable/every.js'; +import { filter } from './Iterable/filter.js'; +import { find } from './Iterable/find.js'; import { flatMap } from './Iterable/flatMap.js'; +import { from } from './Iterable/from.js'; +import { generate } from './Iterable/generate.js'; +import { hasInstance } from './Iterable/hasInstance.js'; +import { map } from './Iterable/map.js'; +import { of } from './Iterable/of.js'; +import { reduce } from './Iterable/reduce.js'; import { size } from './Iterable/size.js'; -import { find } from './Iterable/find.js'; -import { drop } from './Iterable/drop.js'; +import { some } from './Iterable/some.js'; import { take } from './Iterable/take.js'; -import { chunks } from './Iterable/chunks.js'; -import { concat } from './Iterable/concat.js'; -import { from } from './Iterable/from.js'; +import { zip } from './Iterable/zip.js'; /** * A collection of functions to manipulate Iterable diff --git a/packages/iterable/src/Iterable/chunks.spec.ts b/packages/iterable/src/Iterable/chunks.spec.ts index d6e8006438..14135faac4 100644 --- a/packages/iterable/src/Iterable/chunks.spec.ts +++ b/packages/iterable/src/Iterable/chunks.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { chunks } from './chunks.js'; + import { withIterable } from '../Testing.js'; +import { chunks } from './chunks.js'; describe(chunks, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/concat.spec.ts b/packages/iterable/src/Iterable/concat.spec.ts index 09ded89ffa..0af0b5e355 100644 --- a/packages/iterable/src/Iterable/concat.spec.ts +++ b/packages/iterable/src/Iterable/concat.spec.ts @@ -1,8 +1,9 @@ // packages/iterable/src/Iterable/chunks.spec.ts import { describe, expect, it } from 'vitest'; -import { concat } from './concat.js'; + import { withIterable } from '../Testing.js'; +import { concat } from './concat.js'; import { of } from './of.js'; describe(concat, () => { diff --git a/packages/iterable/src/Iterable/create.spec.ts b/packages/iterable/src/Iterable/create.spec.ts index 62cc533029..c9ceee10af 100644 --- a/packages/iterable/src/Iterable/create.spec.ts +++ b/packages/iterable/src/Iterable/create.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; import { Symbol } from '@w5s/core'; -import { create } from './create.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { create } from './create.js'; describe(create, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/drop.spec.ts b/packages/iterable/src/Iterable/drop.spec.ts index f0dd2f1737..d47ed8b2a4 100644 --- a/packages/iterable/src/Iterable/drop.spec.ts +++ b/packages/iterable/src/Iterable/drop.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { drop } from './drop.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { drop } from './drop.js'; import { of } from './of.js'; describe(drop, () => { diff --git a/packages/iterable/src/Iterable/empty.spec.ts b/packages/iterable/src/Iterable/empty.spec.ts index a5bff165ab..276328df18 100644 --- a/packages/iterable/src/Iterable/empty.spec.ts +++ b/packages/iterable/src/Iterable/empty.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { empty } from './empty.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { empty } from './empty.js'; describe(empty, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/every.spec.ts b/packages/iterable/src/Iterable/every.spec.ts index 8456f4afa2..8ffd842c5e 100644 --- a/packages/iterable/src/Iterable/every.spec.ts +++ b/packages/iterable/src/Iterable/every.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { of } from './of.js'; +import { describe, expect, it, vi } from 'vitest'; + import { every } from './every.js'; +import { of } from './of.js'; describe(every, () => { it('returns true when every elements satisfies the given predicate', () => { diff --git a/packages/iterable/src/Iterable/filter.spec.ts b/packages/iterable/src/Iterable/filter.spec.ts index 6d1f15c213..10696016b2 100644 --- a/packages/iterable/src/Iterable/filter.spec.ts +++ b/packages/iterable/src/Iterable/filter.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { filter } from './filter.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { filter } from './filter.js'; import { of } from './of.js'; describe(filter, () => { diff --git a/packages/iterable/src/Iterable/find.spec.ts b/packages/iterable/src/Iterable/find.spec.ts index 8f12f24807..bf10aa0910 100644 --- a/packages/iterable/src/Iterable/find.spec.ts +++ b/packages/iterable/src/Iterable/find.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { find } from './find.js'; +import { describe, expect, it, vi } from 'vitest'; + import { create } from './create.js'; +import { find } from './find.js'; import { of } from './of.js'; describe(find, () => { diff --git a/packages/iterable/src/Iterable/flatMap.spec.ts b/packages/iterable/src/Iterable/flatMap.spec.ts index b2ab3fdcb7..aecb34a581 100644 --- a/packages/iterable/src/Iterable/flatMap.spec.ts +++ b/packages/iterable/src/Iterable/flatMap.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { flatMap } from './flatMap.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { flatMap } from './flatMap.js'; import { of } from './of.js'; describe(flatMap, () => { diff --git a/packages/iterable/src/Iterable/from.spec.ts b/packages/iterable/src/Iterable/from.spec.ts index 26dbd50fa7..bc96ed4696 100644 --- a/packages/iterable/src/Iterable/from.spec.ts +++ b/packages/iterable/src/Iterable/from.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { from } from './from.js'; -import { withIterable } from '../Testing.js'; +import { describe, expect, it } from 'vitest'; + import { Iterable } from '../Iterable.js'; +import { withIterable } from '../Testing.js'; +import { from } from './from.js'; describe(from, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/from.ts b/packages/iterable/src/Iterable/from.ts index 8a72ed4ba8..556458a749 100644 --- a/packages/iterable/src/Iterable/from.ts +++ b/packages/iterable/src/Iterable/from.ts @@ -8,7 +8,7 @@ * @category Constructor * @param source */ -export function from(source: Iterable | (() => Iterator)): Iterable { +export function from(source: (() => Iterator) | Iterable): Iterable { const getIterator = typeof source === 'function' ? source : () => source[Symbol.iterator](); return { [Symbol.iterator]() { diff --git a/packages/iterable/src/Iterable/generate.spec.ts b/packages/iterable/src/Iterable/generate.spec.ts index 561313b55f..6c0ec9dfb9 100644 --- a/packages/iterable/src/Iterable/generate.spec.ts +++ b/packages/iterable/src/Iterable/generate.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { generate } from './generate.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { generate } from './generate.js'; describe(generate, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/generate.ts b/packages/iterable/src/Iterable/generate.ts index 73d8efe9a0..a2f954930b 100644 --- a/packages/iterable/src/Iterable/generate.ts +++ b/packages/iterable/src/Iterable/generate.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import { empty } from './empty.js'; /** diff --git a/packages/iterable/src/Iterable/hasInstance.spec.ts b/packages/iterable/src/Iterable/hasInstance.spec.ts index 5f97af262c..b12c3d5de7 100644 --- a/packages/iterable/src/Iterable/hasInstance.spec.ts +++ b/packages/iterable/src/Iterable/hasInstance.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { hasInstance } from './hasInstance.js'; describe(hasInstance, () => { diff --git a/packages/iterable/src/Iterable/map.spec.ts b/packages/iterable/src/Iterable/map.spec.ts index 9e488cd379..a9591658bd 100644 --- a/packages/iterable/src/Iterable/map.spec.ts +++ b/packages/iterable/src/Iterable/map.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; -import { map } from './map.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { map } from './map.js'; import { of } from './of.js'; describe(map, () => { diff --git a/packages/iterable/src/Iterable/of.spec.ts b/packages/iterable/src/Iterable/of.spec.ts index c8e3d57d8c..ab256c2fec 100644 --- a/packages/iterable/src/Iterable/of.spec.ts +++ b/packages/iterable/src/Iterable/of.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { of } from './of.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; +import { of } from './of.js'; describe(of, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/of.ts b/packages/iterable/src/Iterable/of.ts index 7ab49925be..96d573ecc8 100644 --- a/packages/iterable/src/Iterable/of.ts +++ b/packages/iterable/src/Iterable/of.ts @@ -8,7 +8,7 @@ * @category Constructor * @param values The values of the iterable */ -export function of(...values: Value[]): Iterable { +export function of(...values: Array): Iterable { return { [Symbol.iterator]: values[Symbol.iterator].bind(values), }; diff --git a/packages/iterable/src/Iterable/reduce.spec.ts b/packages/iterable/src/Iterable/reduce.spec.ts index fd2e9b5b1d..2280a6e9f4 100644 --- a/packages/iterable/src/Iterable/reduce.spec.ts +++ b/packages/iterable/src/Iterable/reduce.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { of } from './of.js'; import { reduce } from './reduce.js'; diff --git a/packages/iterable/src/Iterable/size.spec.ts b/packages/iterable/src/Iterable/size.spec.ts index f97ee03901..40868dd2d1 100644 --- a/packages/iterable/src/Iterable/size.spec.ts +++ b/packages/iterable/src/Iterable/size.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; import { size } from './size.js'; diff --git a/packages/iterable/src/Iterable/size.ts b/packages/iterable/src/Iterable/size.ts index 03e0cfba87..71646bb8d9 100644 --- a/packages/iterable/src/Iterable/size.ts +++ b/packages/iterable/src/Iterable/size.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import { reduce } from './reduce.js'; const sum = (accumulator: Int) => (accumulator + 1) as Int; diff --git a/packages/iterable/src/Iterable/some.spec.ts b/packages/iterable/src/Iterable/some.spec.ts index 7d91c8e83e..5f9a6f197d 100644 --- a/packages/iterable/src/Iterable/some.spec.ts +++ b/packages/iterable/src/Iterable/some.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { of } from './of.js'; import { some } from './some.js'; diff --git a/packages/iterable/src/Iterable/take.spec.ts b/packages/iterable/src/Iterable/take.spec.ts index 8920ca2740..5a630cafc6 100644 --- a/packages/iterable/src/Iterable/take.spec.ts +++ b/packages/iterable/src/Iterable/take.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { take } from './take.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; import { of } from './of.js'; +import { take } from './take.js'; describe(take, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Iterable/zip.spec.ts b/packages/iterable/src/Iterable/zip.spec.ts index 854cb0704d..ad6af47992 100644 --- a/packages/iterable/src/Iterable/zip.spec.ts +++ b/packages/iterable/src/Iterable/zip.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; -import { zip } from './zip.js'; +import { describe, expect, it } from 'vitest'; + import { withIterable } from '../Testing.js'; import { of } from './of.js'; +import { zip } from './zip.js'; describe(zip, () => { const expectIterable = withIterable(expect); diff --git a/packages/iterable/src/Testing/withAsyncIterable.ts b/packages/iterable/src/Testing/withAsyncIterable.ts index 2a779a3687..3d3316b278 100644 --- a/packages/iterable/src/Testing/withAsyncIterable.ts +++ b/packages/iterable/src/Testing/withAsyncIterable.ts @@ -1,33 +1,17 @@ import type { ExpectFunction } from '@w5s/core-type'; -async function arrayFromAsync(iterable: any, mapFn: any = (_: any) => _) { - const returnValue: globalThis.Array = []; - let index = 0; - - if (Symbol.asyncIterator in iterable) { - for await (const item of iterable) { - returnValue.push(await mapFn(item, index++)); - } - } else { - for (const item of iterable) { - returnValue.push(await mapFn(await item, index++)); - } - } - return returnValue; -} - export interface ExpectAsyncIterable { + /** + * Asserts that `[Symbol.iterator]()` always returns the same value + */ + toBeIdemPotent(): Promise; + /** * Asserts `[Symbol.iterator]()` emits the same values as `expected` * * @param expected */ toHaveValues(expected: Array): Promise; - - /** - * Asserts that `[Symbol.iterator]()` always returns the same value - */ - toBeIdemPotent(): Promise; } /** @@ -44,17 +28,33 @@ export interface ExpectAsyncIterable { */ export function withAsyncIterable(expectFn: ExpectFunction) { const create = (iterable: AsyncIterable, isNot: boolean): ExpectAsyncIterable => ({ - async toHaveValues(expected: Array) { - const expectValue = expectFn(arrayFromAsync(iterable)).resolves; - return (isNot ? expectValue.not : expectValue).toEqual(expected); - }, async toBeIdemPotent() { const expectValue = expectFn(arrayFromAsync(iterable)).resolves; return (isNot ? expectValue.not : expectValue).toEqual(await arrayFromAsync(iterable)); }, + async toHaveValues(expected: Array) { + const expectValue = expectFn(arrayFromAsync(iterable)).resolves; + return (isNot ? expectValue.not : expectValue).toEqual(expected); + }, }); return (iterable: AsyncIterable) => Object.assign(create(iterable, false), { not: create(iterable, true), }); } + +async function arrayFromAsync(iterable: any, mapFn: any = (_: any) => _) { + const returnValue: globalThis.Array = []; + let index = 0; + + if (Symbol.asyncIterator in iterable) { + for await (const item of iterable) { + returnValue.push(await mapFn(item, index++)); + } + } else { + for (const item of iterable) { + returnValue.push(await mapFn(await item, index++)); + } + } + return returnValue; +} diff --git a/packages/iterable/src/Testing/withIterable.ts b/packages/iterable/src/Testing/withIterable.ts index e16b0eb0ed..8606b057ea 100644 --- a/packages/iterable/src/Testing/withIterable.ts +++ b/packages/iterable/src/Testing/withIterable.ts @@ -1,17 +1,17 @@ import type { ExpectFunction } from '@w5s/core-type'; export interface ExpectIterable { + /** + * Asserts that `[Symbol.iterator]()` always returns the same value + */ + toBeIdemPotent(): void; + /** * Asserts `[Symbol.iterator]()` emits the same values as `expected` * * @param expected */ toHaveValues(expected: Array): void; - - /** - * Asserts that `[Symbol.iterator]()` always returns the same value - */ - toBeIdemPotent(): void; } /** @@ -28,14 +28,14 @@ export interface ExpectIterable { */ export function withIterable(expectFn: ExpectFunction) { const create = (iterable: Iterable, isNot: boolean): ExpectIterable => ({ - toHaveValues(expected: Array) { - const expectValue = expectFn([...iterable]); - (isNot ? expectValue.not : expectValue).toEqual(expected); - }, toBeIdemPotent() { const expectValue = expectFn([...iterable]); (isNot ? expectValue.not : expectValue).toEqual([...iterable]); }, + toHaveValues(expected: Array) { + const expectValue = expectFn([...iterable]); + (isNot ? expectValue.not : expectValue).toEqual(expected); + }, }); return (iterable: Iterable) => Object.assign(create(iterable, false), { diff --git a/packages/iterable/src/index.spec.ts b/packages/iterable/src/index.spec.ts index 31497aeaaa..3b6a983efb 100644 --- a/packages/iterable/src/index.spec.ts +++ b/packages/iterable/src/index.spec.ts @@ -1,12 +1,13 @@ import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('module public API', () => { it('should return correct values', () => { expect(Module).toEqual( expect.objectContaining({ - Iterable: expect.any(Object), AsyncIterable: expect.any(Object), + Iterable: expect.any(Object), }), ); }); diff --git a/packages/log/example/.eslintrc.cjs b/packages/log/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/log/example/.eslintrc.cjs +++ b/packages/log/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/log/src/Log.spec.ts b/packages/log/src/Log.spec.ts index 2e155643f6..3e8d2b611c 100644 --- a/packages/log/src/Log.spec.ts +++ b/packages/log/src/Log.spec.ts @@ -1,14 +1,15 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Log } from './Log.js'; -import { sendWith } from './Log/sendWith.js'; import { send } from './Log/send.js'; +import { sendWith } from './Log/sendWith.js'; describe('Log', () => { it('is an alias to functions', () => { expect(Log).toEqual( expect.objectContaining({ - sendWith, send, + sendWith, }), ); }); diff --git a/packages/log/src/Log.ts b/packages/log/src/Log.ts index c761d383a1..46941bc80e 100644 --- a/packages/log/src/Log.ts +++ b/packages/log/src/Log.ts @@ -7,6 +7,6 @@ import { sendWith } from './Log/sendWith.js'; * @namespace */ export const Log = { - sendWith, send, + sendWith, }; diff --git a/packages/log/src/Log/handle.spec.ts b/packages/log/src/Log/handle.spec.ts index 659c3beae2..cb90acd12b 100644 --- a/packages/log/src/Log/handle.spec.ts +++ b/packages/log/src/Log/handle.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; +import { Symbol } from '@w5s/core'; import { Task } from '@w5s/task'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { Symbol } from '@w5s/core'; -import { handle } from './handle.js'; +import { describe, expect, it, vi } from 'vitest'; + import { configuration } from '../configuration.js'; import { fakeLogRecord } from '../Testing.js'; +import { handle } from './handle.js'; describe(handle, () => { const expectTask = withTask(expect); diff --git a/packages/log/src/Log/handle.ts b/packages/log/src/Log/handle.ts index 8bc4f046df..b3fdb1431c 100644 --- a/packages/log/src/Log/handle.ts +++ b/packages/log/src/Log/handle.ts @@ -1,20 +1,23 @@ +import type { Task } from '@w5s/task'; + import { all as taskAll } from '@w5s/task/dist/Task/all.js'; -import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; import { andThen as taskThen } from '@w5s/task/dist/Task/andThen.js'; +import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; import { ignore as taskIgnore } from '@w5s/task/dist/Task/ignore.js'; -import type { Task } from '@w5s/task'; + import type { LogRecord } from '../LogRecord.js'; + import { configuration } from '../configuration.js'; +export function handle(logRecord: LogRecord): Task { + const tasks = getHandleTasks(logRecord); + const allTasks = taskThen(tasks, (_) => taskAll(_)); + return taskIgnore(allTasks); +} + function getHandleTasks(logRecord: LogRecord): Task>, never> { return taskFrom(({ resolve }) => { const handlerMap = configuration.get('handler'); resolve(Object.values(handlerMap).map((handler) => handler(logRecord))); }); } - -export function handle(logRecord: LogRecord): Task { - const tasks = getHandleTasks(logRecord); - const allTasks = taskThen(tasks, (_) => taskAll(_)); - return taskIgnore(allTasks); -} diff --git a/packages/log/src/Log/send.spec.ts b/packages/log/src/Log/send.spec.ts index 1162ff4a9e..aa3115e3ae 100644 --- a/packages/log/src/Log/send.spec.ts +++ b/packages/log/src/Log/send.spec.ts @@ -1,12 +1,13 @@ -import { describe, expect, it, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Task } from '@w5s/task'; -import { send } from './send.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { critical } from '../level.js'; -import { handle } from './handle.js'; -import { LogRecord } from '../LogRecord.js'; import { LogLevel } from '../LogLevel.js'; import { LogMessage } from '../LogMessage.js'; +import { LogRecord } from '../LogRecord.js'; +import { handle } from './handle.js'; +import { send } from './send.js'; vi.mock('./handle.js', async () => ({ handle: vi.fn(() => Task.resolve()), @@ -27,15 +28,15 @@ describe(send, () => { expectTask(send(message)).toResolveSync(undefined); expect(handle).toHaveBeenLastCalledWith( LogRecord({ - id: expect.any(String), - domain: '', - level: LogLevel.Critical, - message: LogMessage('Mock message ', { $ref: 'foo' }, ' ', { $ref: 'bar' }), + created: expect.any(Number), data: { - foo: { foo: true }, bar: 'bar_value', + foo: { foo: true }, }, - created: expect.any(Number), + domain: '', + id: expect.any(String), + level: LogLevel.Critical, + message: LogMessage('Mock message ', { $ref: 'foo' }, ' ', { $ref: 'bar' }), }), ); }); diff --git a/packages/log/src/Log/sendWith.spec.ts b/packages/log/src/Log/sendWith.spec.ts index 8c29296672..e8780fc4f3 100644 --- a/packages/log/src/Log/sendWith.spec.ts +++ b/packages/log/src/Log/sendWith.spec.ts @@ -1,12 +1,13 @@ -import { describe, expect, it, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Task } from '@w5s/task'; -import { sendWith } from './sendWith.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { critical } from '../level.js'; -import { handle } from './handle.js'; -import { LogRecord } from '../LogRecord.js'; import { LogLevel } from '../LogLevel.js'; import { LogMessage } from '../LogMessage.js'; +import { LogRecord } from '../LogRecord.js'; +import { handle } from './handle.js'; +import { sendWith } from './sendWith.js'; vi.mock('./handle.js', async () => ({ handle: vi.fn(() => Task.resolve()), @@ -28,15 +29,15 @@ describe(sendWith, () => { expectTask(send(message)).toResolveSync(undefined); expect(handle).toHaveBeenLastCalledWith( LogRecord({ - id: expect.any(String), - domain: 'MyComponent', - level: LogLevel.Critical, - message: LogMessage('Mock message ', { $ref: 'foo' }, ' ', { $ref: 'bar' }), + created: expect.any(Number), data: { - foo: { foo: true }, bar: 'bar_value', + foo: { foo: true }, }, - created: expect.any(Number), + domain: 'MyComponent', + id: expect.any(String), + level: LogLevel.Critical, + message: LogMessage('Mock message ', { $ref: 'foo' }, ' ', { $ref: 'bar' }), }), ); }); diff --git a/packages/log/src/Log/sendWith.ts b/packages/log/src/Log/sendWith.ts index 1005c3b847..c932db8c10 100644 --- a/packages/log/src/Log/sendWith.ts +++ b/packages/log/src/Log/sendWith.ts @@ -1,9 +1,12 @@ import type { Task } from '@w5s/task'; + import { andThen as taskThen } from '@w5s/task/dist/Task/andThen.js'; -import { randomUUID } from '@w5s/uuid'; import { now as timeNow } from '@w5s/time/dist/Time/now.js'; +import { randomUUID } from '@w5s/uuid'; + import type { LogLevelParameters } from '../level.js'; import type { LogRecord } from '../LogRecord.js'; + import { handle } from './handle.js'; export interface LogSendFunction { @@ -34,9 +37,9 @@ export function sendWith(domain: LogRecord['domain']): LogSendFunction { taskThen(timeNow(), (now) => { const initialRecord: LogRecord = { _: 'LogRecord', - id: uuid, - domain, created: now, + domain, + id: uuid, ...parameters, }; return handle(initialRecord); diff --git a/packages/log/src/LogHandler.spec.ts b/packages/log/src/LogHandler.spec.ts index 71a1d297e2..ebe5924b8a 100644 --- a/packages/log/src/LogHandler.spec.ts +++ b/packages/log/src/LogHandler.spec.ts @@ -1,14 +1,15 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { LogHandler } from './LogHandler.js'; -import { filter } from './LogHandler/filter.js'; import { Console } from './LogHandler/Console.js'; +import { filter } from './LogHandler/filter.js'; describe('LogHandler', () => { it('is an alias to functions', () => { expect(LogHandler).toEqual( expect.objectContaining({ - filter, Console, + filter, }), ); }); diff --git a/packages/log/src/LogHandler.ts b/packages/log/src/LogHandler.ts index 1613b9383d..f1a5336cdb 100644 --- a/packages/log/src/LogHandler.ts +++ b/packages/log/src/LogHandler.ts @@ -1,16 +1,16 @@ import type { Task } from '@w5s/task'; + import type { LogRecord } from './LogRecord.js'; + import { Console } from './LogHandler/Console.js'; import { filter } from './LogHandler/filter.js'; -export interface LogHandler { - (logRecord: LogRecord): Task; -} +export type LogHandler = (logRecord: LogRecord) => Task; /** * @namespace */ export const LogHandler = { - filter, Console, + filter, }; diff --git a/packages/log/src/LogHandler/Console.spec.ts b/packages/log/src/LogHandler/Console.spec.ts index 4ab9f6574d..0fbb13b05f 100644 --- a/packages/log/src/LogHandler/Console.spec.ts +++ b/packages/log/src/LogHandler/Console.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; import { Task } from '@w5s/task'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { LogLevel } from '../LogLevel.js'; import { LogMessage } from '../LogMessage.js'; import { fakeLogRecord } from '../Testing.js'; @@ -9,19 +10,19 @@ import { Console } from './Console.js'; describe(Console, () => { const fakeWebConsole = () => ({ debug: vi.fn(() => Task.resolve()), + error: vi.fn(() => Task.resolve()), info: vi.fn(() => Task.resolve()), + isWeb: vi.fn(() => true), log: vi.fn(() => Task.resolve()), warn: vi.fn(() => Task.resolve()), - error: vi.fn(() => Task.resolve()), - isWeb: vi.fn(() => true), }); const expectTask = withTask(expect); describe('[web]', () => { const console = fakeWebConsole(); const consoleHandler = Console({ - console, colors: false, + console, }); const defaultRecord = fakeLogRecord({ level: LogLevel.Debug, message: LogMessage('foobar') }); @@ -49,12 +50,12 @@ describe(Console, () => { expectTask( consoleHandler( fakeLogRecord({ - domain: 'myDomain', - level: LogLevel.Debug, - message: LogMessage('message=', { $ref: 'foo' }, '.'), data: { foo: 'bar', }, + domain: 'myDomain', + level: LogLevel.Debug, + message: LogMessage('message=', { $ref: 'foo' }, '.'), }), ), ).toResolveSync(undefined); @@ -71,11 +72,11 @@ describe(Console, () => { expectTask( consoleHandler( fakeLogRecord({ - level: LogLevel.Debug, - message: LogMessage('message=', { $ref: 'foo' }, '.'), data: { foo: 'bar', }, + level: LogLevel.Debug, + message: LogMessage('message=', { $ref: 'foo' }, '.'), }), ), ).toResolveSync(undefined); diff --git a/packages/log/src/LogHandler/Console.ts b/packages/log/src/LogHandler/Console.ts index d0bfcf79f5..4d41884d5b 100644 --- a/packages/log/src/LogHandler/Console.ts +++ b/packages/log/src/LogHandler/Console.ts @@ -1,12 +1,14 @@ -import { Console as defaultConsole, ANSICode } from '@w5s/console'; +import { ANSICode, Console as defaultConsole } from '@w5s/console'; import { format as timeAsString } from '@w5s/time/dist/Time/format.js'; + import type { LogHandler } from '../LogHandler.js'; -import { LogLevelAsString } from '../LogLevel/LogLevelAsString.js'; +import type { LogLevel } from '../LogLevel.js'; +import type { LogRecord } from '../LogRecord.js'; + import { LogLevelAsInt } from '../LogLevel/LogLevelAsInt.js'; +import { LogLevelAsString } from '../LogLevel/LogLevelAsString.js'; import { LogLevelValue } from '../LogLevel/LogLevelValue.js'; -import type { LogRecord } from '../LogRecord.js'; import { messageWithData } from '../LogRecord/messageWithData.js'; -import type { LogLevel } from '../LogLevel.js'; const red = ANSICode.color('red'); const yellow = ANSICode.color('yellow'); @@ -28,7 +30,7 @@ const formatLevelFor = (level: LogLevel) => const formatNoColor = (_: string): string => _; const defaultFormat: Exclude = (logRecord, { colors }) => { - const { domain, level, created } = logRecord; + const { created, domain, level } = logRecord; return [ (colors ? formatTime : formatNoColor)(timeAsString(created)), @@ -45,16 +47,16 @@ export interface ConsoleOptions { colors: boolean; /** - * Returns an array of arguments passed to the console.{log|warn|...}() function - * - * @param logRecord + * Custom console instance (default: Console) */ - format: (logRecord: LogRecord, options: ConsoleOptions) => [required: unknown, ...optionalParameters: unknown[]]; + console: Pick; /** - * Custom console instance (default: Console) + * Returns an array of arguments passed to the console.{log|warn|...}() function + * + * @param logRecord */ - console: Pick; + format: (logRecord: LogRecord, options: ConsoleOptions) => [required: unknown, ...optionalParameters: Array]; } /** @@ -71,12 +73,12 @@ export interface ConsoleOptions { export function Console(options: Partial = {}): LogHandler { const resolvedOptions = { colors: true, - format: defaultFormat, console: defaultConsole, + format: defaultFormat, ...options, }; - const { format, console } = resolvedOptions; - const consoleWrite = (level: LogLevel, args: [required: unknown, ...optionalParameters: unknown[]]) => + const { console, format } = resolvedOptions; + const consoleWrite = (level: LogLevel, args: [required: unknown, ...optionalParameters: Array]) => logLevelAsInt(level) >= logLevelAsInt(LogLevelValue.Error) ? console.error(...args) : logLevelAsInt(level) >= logLevelAsInt(LogLevelValue.Warn) diff --git a/packages/log/src/LogHandler/filter.spec.ts b/packages/log/src/LogHandler/filter.spec.ts index c29c11a672..211a0ded28 100644 --- a/packages/log/src/LogHandler/filter.spec.ts +++ b/packages/log/src/LogHandler/filter.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, vi } from 'vitest'; import { Task } from '@w5s/task'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { fakeLogRecord } from '../Testing.js'; import { filter } from './filter.js'; @@ -28,8 +29,8 @@ describe(filter, () => { ), ).toResolveSync(undefined); expect(handler).not.toHaveBeenLastCalledWith({ - id: '', category: 'foo', + id: '', }); }); }); diff --git a/packages/log/src/LogHandler/filter.ts b/packages/log/src/LogHandler/filter.ts index 230a1ddd07..86495da2ff 100644 --- a/packages/log/src/LogHandler/filter.ts +++ b/packages/log/src/LogHandler/filter.ts @@ -1,5 +1,7 @@ -import { resolve } from '@w5s/task/dist/Task/resolve.js'; import type { Task } from '@w5s/task'; + +import { resolve } from '@w5s/task/dist/Task/resolve.js'; + import type { LogHandler } from '../LogHandler.js'; import type { LogRecord } from '../LogRecord.js'; diff --git a/packages/log/src/LogLevel.spec.ts b/packages/log/src/LogLevel.spec.ts index 13f4dde1a4..2ce9232a52 100644 --- a/packages/log/src/LogLevel.spec.ts +++ b/packages/log/src/LogLevel.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { LogLevel } from './LogLevel.js'; +import { LogLevelAsInt } from './LogLevel/LogLevelAsInt.js'; +import { LogLevelAsString } from './LogLevel/LogLevelAsString.js'; import { LogLevelBounded } from './LogLevel/LogLevelBounded.js'; import { LogLevelComparable } from './LogLevel/LogLevelComparable.js'; import { LogLevelValue } from './LogLevel/LogLevelValue.js'; import { of } from './LogLevel/of.js'; -import { LogLevelAsString } from './LogLevel/LogLevelAsString.js'; -import { LogLevelAsInt } from './LogLevel/LogLevelAsInt.js'; describe('LogLevel', () => { it('is an alias to functions', () => { diff --git a/packages/log/src/LogLevel.ts b/packages/log/src/LogLevel.ts index 9fecf67c85..5a6ecf7b06 100644 --- a/packages/log/src/LogLevel.ts +++ b/packages/log/src/LogLevel.ts @@ -1,12 +1,13 @@ import { Callable } from '@w5s/core/dist/Callable.js'; + +import { from } from './LogLevel/from.js'; import { LogLevel as LogLevelType } from './LogLevel/LogLevel.js'; -import { LogLevelComparable } from './LogLevel/LogLevelComparable.js'; +import { LogLevelAsInt } from './LogLevel/LogLevelAsInt.js'; +import { LogLevelAsString } from './LogLevel/LogLevelAsString.js'; import { LogLevelBounded } from './LogLevel/LogLevelBounded.js'; +import { LogLevelComparable } from './LogLevel/LogLevelComparable.js'; import { LogLevelValue } from './LogLevel/LogLevelValue.js'; import { of } from './LogLevel/of.js'; -import { from } from './LogLevel/from.js'; -import { LogLevelAsString } from './LogLevel/LogLevelAsString.js'; -import { LogLevelAsInt } from './LogLevel/LogLevelAsInt.js'; export interface LogLevel extends LogLevelType {} @@ -21,7 +22,7 @@ export const LogLevel = Callable({ ...LogLevelBounded, ...LogLevelAsString, ...LogLevelAsInt, - of, - from, [Callable.symbol]: of, + from, + of, }); diff --git a/packages/log/src/LogLevel/LogLevel.spec.ts b/packages/log/src/LogLevel/LogLevel.spec.ts index de15e1d271..19fb72dbea 100644 --- a/packages/log/src/LogLevel/LogLevel.spec.ts +++ b/packages/log/src/LogLevel/LogLevel.spec.ts @@ -1,27 +1,28 @@ +import { CodecError, Int, Result } from '@w5s/core'; import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { CodecError, Int, Result } from '@w5s/core'; + import { LogLevel } from './LogLevel.js'; describe('LogLevel', () => { describeType(LogLevel, () => ({ - typeName: 'LogLevel', - instances: [LogLevel.create({ name: 'UberCritical', value: Int(60) })], - notInstances: [undefined], inspect: [ [LogLevel.create({ name: 'UberCritical', value: Int(60) }), 'UberCritical[60]'], [LogLevel.create({ name: 'Critical', value: Int(50) }), 'Critical[50]'], ], + instances: [LogLevel.create({ name: 'UberCritical', value: Int(60) })], + notInstances: [undefined], + typeName: 'LogLevel', })); describeCodec(LogLevel, () => ({ decode: [ ['UberCritical[60]', Result.Ok(LogLevel.create({ name: 'UberCritical', value: Int(60) }))], ['Critical[50]', Result.Ok(LogLevel.create({ name: 'Critical', value: Int(50) }))], - ['', Result.Error(new CodecError({ message: 'Cannot decode "" as LogLevel', input: '' }))], - ['[50]', Result.Error(new CodecError({ message: 'Cannot decode "[50]" as LogLevel', input: '[50]' }))], + ['', Result.Error(new CodecError({ input: '', message: 'Cannot decode "" as LogLevel' }))], + ['[50]', Result.Error(new CodecError({ input: '[50]', message: 'Cannot decode "[50]" as LogLevel' }))], [ 'Critical[abc]', - Result.Error(new CodecError({ message: 'Cannot decode "Critical[abc]" as LogLevel', input: 'Critical[abc]' })), + Result.Error(new CodecError({ input: 'Critical[abc]', message: 'Cannot decode "Critical[abc]" as LogLevel' })), ], ], encode: [ @@ -29,8 +30,8 @@ describe('LogLevel', () => { [LogLevel.create({ name: 'Critical', value: Int(50) }), 'Critical[50]'], ], schema: { - type: 'string', format: 'LogLevel', + type: 'string', }, })); }); diff --git a/packages/log/src/LogLevel/LogLevel.ts b/packages/log/src/LogLevel/LogLevel.ts index d87d89bcbc..73ecce469a 100644 --- a/packages/log/src/LogLevel/LogLevel.ts +++ b/packages/log/src/LogLevel/LogLevel.ts @@ -1,7 +1,9 @@ import type { Codec, Int } from '@w5s/core'; + import { Struct } from '@w5s/core/dist/Struct.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; import { parse as parseInt } from '@w5s/num/dist/Int/parse.js'; + import { LogLevelAsString } from './LogLevelAsString.js'; export interface LogLevel extends Struct<{ @@ -20,7 +22,7 @@ export interface LogLevel extends Struct<{ const typeName = 'LogLevel'; const encode = ({ name, value }: LogLevel) => `${name}[${value}]`; -const decode: Codec[Symbol.decode] = (input, { ok, error }) => { +const decode: Codec[Symbol.decode] = (input, { error, ok }) => { if (typeof input === 'string') { const match = input.match(/^(\w+)\[(\d+)]$/); if (match != null && match.length === 3) { @@ -37,13 +39,13 @@ const decode: Codec[Symbol.decode] = (input, { ok, error }) => { }; export const LogLevel = Struct.define({ - typeName, [Symbol.decode]: decode, [Symbol.encode]: encode, [Symbol.inspect]: encode, [Symbol.schema]: () => ({ - type: 'string', format: typeName, + type: 'string', }), + typeName, ...LogLevelAsString, }); diff --git a/packages/log/src/LogLevel/LogLevelAsInt.spec.ts b/packages/log/src/LogLevel/LogLevelAsInt.spec.ts index 896ad7e3ce..e26e8c349f 100644 --- a/packages/log/src/LogLevel/LogLevelAsInt.spec.ts +++ b/packages/log/src/LogLevel/LogLevelAsInt.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { LogLevelAsInt } from './LogLevelAsInt.js'; import { LogLevelValue } from './LogLevelValue.js'; diff --git a/packages/log/src/LogLevel/LogLevelAsInt.ts b/packages/log/src/LogLevel/LogLevelAsInt.ts index 2a7c9ae7b9..7d1c8a1694 100644 --- a/packages/log/src/LogLevel/LogLevelAsInt.ts +++ b/packages/log/src/LogLevel/LogLevelAsInt.ts @@ -1,4 +1,5 @@ import type { AsInt } from '@w5s/core'; + import type { LogLevel } from './LogLevel.js'; /** diff --git a/packages/log/src/LogLevel/LogLevelAsString.spec.ts b/packages/log/src/LogLevel/LogLevelAsString.spec.ts index fdcdd00c5c..87ec4752b8 100644 --- a/packages/log/src/LogLevel/LogLevelAsString.spec.ts +++ b/packages/log/src/LogLevel/LogLevelAsString.spec.ts @@ -1,6 +1,7 @@ -import { describe } from 'vitest'; import { Int } from '@w5s/core'; import { describeAsString } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { LogLevelAsString } from './LogLevelAsString.js'; import { of } from './of.js'; diff --git a/packages/log/src/LogLevel/LogLevelAsString.ts b/packages/log/src/LogLevel/LogLevelAsString.ts index ca7cf05157..04f014388e 100644 --- a/packages/log/src/LogLevel/LogLevelAsString.ts +++ b/packages/log/src/LogLevel/LogLevelAsString.ts @@ -1,4 +1,5 @@ import type { AsString } from '@w5s/core'; + import type { LogLevel } from './LogLevel.js'; export const LogLevelAsString: AsString = { diff --git a/packages/log/src/LogLevel/LogLevelBounded.spec.ts b/packages/log/src/LogLevel/LogLevelBounded.spec.ts index 709eea1e30..14796ce8b0 100644 --- a/packages/log/src/LogLevel/LogLevelBounded.spec.ts +++ b/packages/log/src/LogLevel/LogLevelBounded.spec.ts @@ -1,12 +1,13 @@ -import { describe } from 'vitest'; -import { describeBounded } from '@w5s/core/dist/Testing.js'; import { Int } from '@w5s/core'; +import { describeBounded } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { LogLevelBounded } from './LogLevelBounded.js'; import { of } from './of.js'; describe('LogLevelBounded', () => { describeBounded(LogLevelBounded, { - minValue: of('none', Int(0)), maxValue: of('critical', Int(50)), + minValue: of('none', Int(0)), }); }); diff --git a/packages/log/src/LogLevel/LogLevelBounded.ts b/packages/log/src/LogLevel/LogLevelBounded.ts index acaadd3320..06ea57e0db 100644 --- a/packages/log/src/LogLevel/LogLevelBounded.ts +++ b/packages/log/src/LogLevel/LogLevelBounded.ts @@ -1,8 +1,10 @@ import type { Bounded } from '@w5s/core'; -import { LogLevelValue } from './LogLevelValue.js'; + import type { LogLevel } from './LogLevel.js'; +import { LogLevelValue } from './LogLevelValue.js'; + export const LogLevelBounded: Bounded = { - minValue: LogLevelValue.None, maxValue: LogLevelValue.Critical, + minValue: LogLevelValue.None, }; diff --git a/packages/log/src/LogLevel/LogLevelComparable.spec.ts b/packages/log/src/LogLevel/LogLevelComparable.spec.ts index 7cb6353893..b4dfcf596b 100644 --- a/packages/log/src/LogLevel/LogLevelComparable.spec.ts +++ b/packages/log/src/LogLevel/LogLevelComparable.spec.ts @@ -1,15 +1,16 @@ -import { describe } from 'vitest'; -import { describeComparable } from '@w5s/core/dist/Testing.js'; import { Int } from '@w5s/core'; +import { describeComparable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { LogLevelComparable } from './LogLevelComparable.js'; import { of } from './of.js'; describe('LogLevelComparable', () => { describeComparable(LogLevelComparable, { - ordered: () => [of('One', Int(1)), of('Two', Int(2)), of('Three', Int(3))], equivalent: () => [ [of('One', Int(1)), of('One', Int(1))], [of('One', Int(1)), of('OneOther', Int(1))], ], + ordered: () => [of('One', Int(1)), of('Two', Int(2)), of('Three', Int(3))], }); }); diff --git a/packages/log/src/LogLevel/LogLevelComparable.ts b/packages/log/src/LogLevel/LogLevelComparable.ts index c378a0e75d..0c3ffc967d 100644 --- a/packages/log/src/LogLevel/LogLevelComparable.ts +++ b/packages/log/src/LogLevel/LogLevelComparable.ts @@ -1,4 +1,5 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import { compare } from './compare.js'; export const LogLevelComparable = Comparable({ diff --git a/packages/log/src/LogLevel/LogLevelValue.spec.ts b/packages/log/src/LogLevel/LogLevelValue.spec.ts index ff80ba89ef..611cc761dd 100644 --- a/packages/log/src/LogLevel/LogLevelValue.spec.ts +++ b/packages/log/src/LogLevel/LogLevelValue.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as LogLevelValue from './LogLevelValue.js'; describe('LogLevelValue', () => { diff --git a/packages/log/src/LogLevel/LogLevelValue.ts b/packages/log/src/LogLevel/LogLevelValue.ts index 2ddc94c03b..826bbc1884 100644 --- a/packages/log/src/LogLevel/LogLevelValue.ts +++ b/packages/log/src/LogLevel/LogLevelValue.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import { of } from './of.js'; const None = of('none', 0 as Int); @@ -32,12 +33,12 @@ const Debug = of('debug', 10 as Int); * @namespace */ export const LogLevelValue = { - None, Critical, + Debug, Error, - Warn, Info, - Debug, + None, + Warn, }; export type LogLevelValue = Lowercase; diff --git a/packages/log/src/LogLevel/compare.spec.ts b/packages/log/src/LogLevel/compare.spec.ts index 8b16b7e3ed..91328689bf 100644 --- a/packages/log/src/LogLevel/compare.spec.ts +++ b/packages/log/src/LogLevel/compare.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { compare } from './compare.js'; import { LogLevelValue } from './LogLevelValue.js'; diff --git a/packages/log/src/LogLevel/compare.ts b/packages/log/src/LogLevel/compare.ts index dc76819882..ec223a04d6 100644 --- a/packages/log/src/LogLevel/compare.ts +++ b/packages/log/src/LogLevel/compare.ts @@ -1,5 +1,7 @@ import type { Ordering } from '@w5s/core'; + import { compare as compareNumber } from '@w5s/num/dist/Number/compare.js'; + import type { LogLevel } from '../LogLevel.js'; export function compare(left: LogLevel, right: LogLevel): Ordering { diff --git a/packages/log/src/LogLevel/from.spec.ts b/packages/log/src/LogLevel/from.spec.ts index fc4e0a8918..4879c6bcfd 100644 --- a/packages/log/src/LogLevel/from.spec.ts +++ b/packages/log/src/LogLevel/from.spec.ts @@ -1,14 +1,15 @@ import { describe, expect, it } from 'vitest'; + import { from } from './from.js'; import { LogLevelValue } from './LogLevelValue.js'; describe(from, () => { it.each([ - { value: 'critical' as const, level: LogLevelValue.Critical }, - { value: 'error' as const, level: LogLevelValue.Error }, - { value: 'warn' as const, level: LogLevelValue.Warn }, - { value: 'info' as const, level: LogLevelValue.Info }, - { value: 'debug' as const, level: LogLevelValue.Debug }, + { level: LogLevelValue.Critical, value: 'critical' as const }, + { level: LogLevelValue.Error, value: 'error' as const }, + { level: LogLevelValue.Warn, value: 'warn' as const }, + { level: LogLevelValue.Info, value: 'info' as const }, + { level: LogLevelValue.Debug, value: 'debug' as const }, ])('returns a $value when given $level', ({ level, value }) => { expect(from(value)).toEqual(level); }); diff --git a/packages/log/src/LogLevel/of.spec.ts b/packages/log/src/LogLevel/of.spec.ts index b3af51eaba..9513911d1e 100644 --- a/packages/log/src/LogLevel/of.spec.ts +++ b/packages/log/src/LogLevel/of.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Int } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; describe(of, () => { diff --git a/packages/log/src/LogLevel/of.ts b/packages/log/src/LogLevel/of.ts index 1503f58b17..8ececead62 100644 --- a/packages/log/src/LogLevel/of.ts +++ b/packages/log/src/LogLevel/of.ts @@ -1,4 +1,5 @@ import type { Int } from '@w5s/core'; + import { LogLevel } from './LogLevel.js'; /** diff --git a/packages/log/src/LogMessage.spec.ts b/packages/log/src/LogMessage.spec.ts index a857fe0f6d..516a9937e0 100644 --- a/packages/log/src/LogMessage.spec.ts +++ b/packages/log/src/LogMessage.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { LogMessage, LogMessageRef } from './LogMessage.js'; describe(LogMessage, () => { diff --git a/packages/log/src/LogMessage.ts b/packages/log/src/LogMessage.ts index fe1948ee91..4f9c16efb8 100644 --- a/packages/log/src/LogMessage.ts +++ b/packages/log/src/LogMessage.ts @@ -1,9 +1,11 @@ import type { Type } from '@w5s/core'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { Array as TArray } from '@w5s/core/dist/Type/Array.js'; import { TObject } from '@w5s/core/dist/Type/Object.js'; import { string } from '@w5s/core/dist/Type/string.js'; import { union } from '@w5s/core/dist/Type/union.js'; + import { create } from './LogMessage/create.js'; import { of } from './LogMessage/of.js'; diff --git a/packages/log/src/LogMessage/create.spec.ts b/packages/log/src/LogMessage/create.spec.ts index 47b617f000..77ea0711ed 100644 --- a/packages/log/src/LogMessage/create.spec.ts +++ b/packages/log/src/LogMessage/create.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { create } from './create.js'; describe(create, () => { diff --git a/packages/log/src/LogMessage/create.ts b/packages/log/src/LogMessage/create.ts index db92f05c02..0f046f30fc 100644 --- a/packages/log/src/LogMessage/create.ts +++ b/packages/log/src/LogMessage/create.ts @@ -13,6 +13,7 @@ import type { LogMessage, LogMessageItem } from '../LogMessage.js'; export function create(parts: Array): LogMessage { const returnValue = []; let buffer = ''; + // eslint-disable-next-line ts/prefer-for-of for (let index = 0; index < parts.length; index += 1) { const value = parts[index]!; if (typeof value === 'string') { diff --git a/packages/log/src/LogMessage/of.spec.ts b/packages/log/src/LogMessage/of.spec.ts index f74cbadfad..5c6eb5b282 100644 --- a/packages/log/src/LogMessage/of.spec.ts +++ b/packages/log/src/LogMessage/of.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; describe(of, () => { diff --git a/packages/log/src/LogMessage/of.ts b/packages/log/src/LogMessage/of.ts index 95dc98ed15..c7b5b116df 100644 --- a/packages/log/src/LogMessage/of.ts +++ b/packages/log/src/LogMessage/of.ts @@ -1,4 +1,5 @@ import type { LogMessage, LogMessageItem } from '../LogMessage.js'; + import { create } from './create.js'; /** diff --git a/packages/log/src/LogRecord.spec.ts b/packages/log/src/LogRecord.spec.ts index 7a0d1e8858..dec6d856e2 100644 --- a/packages/log/src/LogRecord.spec.ts +++ b/packages/log/src/LogRecord.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect } from 'vitest'; import { Time } from '@w5s/time'; import { UUID } from '@w5s/uuid'; -import { LogRecord } from './LogRecord.js'; +import { describe, expect, it } from 'vitest'; + import { LogLevel } from './LogLevel.js'; import { LogMessage } from './LogMessage.js'; +import { LogRecord } from './LogRecord.js'; import { messageWithData } from './LogRecord/messageWithData.js'; describe('LogRecord', () => { @@ -11,21 +12,21 @@ describe('LogRecord', () => { it('should return a new message', () => { expect( LogRecord({ - id: UUID.empty(), + created: Time.of(1), + data: {}, domain: 'myDomain', + id: UUID.empty(), level: LogLevel.Warn, message: LogMessage.of('foo', 'bar', ''), - data: {}, - created: Time.of(1), }), ).toEqual({ _: 'LogRecord', - id: UUID.empty(), + created: 1, + data: {}, domain: 'myDomain', + id: UUID.empty(), level: LogLevel.Warn, message: ['foobar'], - data: {}, - created: 1, }); }); }); diff --git a/packages/log/src/LogRecord.ts b/packages/log/src/LogRecord.ts index 0cbfb0401d..93aed8ad43 100644 --- a/packages/log/src/LogRecord.ts +++ b/packages/log/src/LogRecord.ts @@ -1,5 +1,7 @@ import type { Struct } from '@w5s/core'; + import { Callable } from '@w5s/core/dist/Callable.js'; + import { LogRecord as LogRecordType } from './LogRecord/LogRecord.js'; import { messageWithData } from './LogRecord/messageWithData.js'; diff --git a/packages/log/src/LogRecord/LogRecord.ts b/packages/log/src/LogRecord/LogRecord.ts index 61153172d7..bb6a91a14e 100644 --- a/packages/log/src/LogRecord/LogRecord.ts +++ b/packages/log/src/LogRecord/LogRecord.ts @@ -1,45 +1,47 @@ -import { Time } from '@w5s/time/dist/Time/Time.js'; -import { UUID } from '@w5s/core/dist/Type/UUID.js'; -import { TObject } from '@w5s/core/dist/Type/Object.js'; +import type { Type } from '@w5s/core'; + import { constant } from '@w5s/core/dist/Type/constant.js'; -import { string } from '@w5s/core/dist/Type/string.js'; +import { TObject } from '@w5s/core/dist/Type/Object.js'; import { Record } from '@w5s/core/dist/Type/Record.js'; +import { string } from '@w5s/core/dist/Type/string.js'; import { unknown } from '@w5s/core/dist/Type/unknown.js'; -import type { Type } from '@w5s/core'; -import { LogMessage } from '../LogMessage.js'; +import { UUID } from '@w5s/core/dist/Type/UUID.js'; +import { Time } from '@w5s/time/dist/Time/Time.js'; + import { LogLevel } from '../LogLevel/LogLevel.js'; +import { LogMessage } from '../LogMessage.js'; export const LogRecord = TObject({ _: constant('LogRecord'), /** - * Event identifier + * Time when the record was created */ - id: UUID, + created: Time, /** - * The log domain (i.e. category) + * Additional data */ - domain: string, + data: Record(string, unknown), /** - * The log level + * The log domain (i.e. category) */ - level: LogLevel, + domain: string, /** - * Unformatted message + * Event identifier */ - message: LogMessage, + id: UUID, /** - * Time when the record was created + * The log level */ - created: Time, + level: LogLevel, /** - * Additional data + * Unformatted message */ - data: Record(string, unknown), + message: LogMessage, }); export interface LogRecord extends Type.TypeOf {} diff --git a/packages/log/src/LogRecord/messageWithData.spec.ts b/packages/log/src/LogRecord/messageWithData.spec.ts index 865fd5ee41..b1b1e8aa3c 100644 --- a/packages/log/src/LogRecord/messageWithData.spec.ts +++ b/packages/log/src/LogRecord/messageWithData.spec.ts @@ -1,15 +1,16 @@ -import { describe, it, expect } from 'vitest'; -import { messageWithData } from './messageWithData.js'; -import { fakeLogRecord } from '../Testing.js'; +import { describe, expect, it } from 'vitest'; + import { LogMessage } from '../LogMessage.js'; +import { fakeLogRecord } from '../Testing.js'; +import { messageWithData } from './messageWithData.js'; describe(messageWithData, () => { it('expands ref using data', () => { const record = fakeLogRecord({ - message: LogMessage('message', { $ref: 'foo' }), data: { foo: 'foo_value', }, + message: LogMessage('message', { $ref: 'foo' }), }); expect(messageWithData(record)).toEqual(['message', 'foo_value']); }); diff --git a/packages/log/src/Testing/fakeLogRecord.ts b/packages/log/src/Testing/fakeLogRecord.ts index 0ce601715a..88f0d74232 100644 --- a/packages/log/src/Testing/fakeLogRecord.ts +++ b/packages/log/src/Testing/fakeLogRecord.ts @@ -1,16 +1,17 @@ import { Time } from '@w5s/time'; import { UUID } from '@w5s/uuid'; -import { LogRecord } from '../LogRecord.js'; + import { LogLevel } from '../LogLevel.js'; import { LogMessage } from '../LogMessage.js'; +import { LogRecord } from '../LogRecord.js'; export const fakeLogRecord = (properties: Partial = {}): LogRecord => ({ _: 'LogRecord', - id: UUID.empty(), + created: Time(0), + data: {}, domain: '', + id: UUID.empty(), level: LogLevel.Debug, message: LogMessage.of('test'), - data: {}, - created: Time(0), ...properties, }); diff --git a/packages/log/src/configuration.spec.ts b/packages/log/src/configuration.spec.ts index 65d5ac62cd..c7a88ed631 100644 --- a/packages/log/src/configuration.spec.ts +++ b/packages/log/src/configuration.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { configuration } from './configuration.js'; describe('configuration', () => { diff --git a/packages/log/src/configuration.ts b/packages/log/src/configuration.ts index 4de5e63aaa..d084fc3c3c 100644 --- a/packages/log/src/configuration.ts +++ b/packages/log/src/configuration.ts @@ -1,7 +1,9 @@ import { useConfiguration } from '@w5s/application'; -import { meta } from './meta.js'; + import type { LogHandler } from './LogHandler.js'; +import { meta } from './meta.js'; + export interface Configuration { /** * A record of { handlerId: handler } diff --git a/packages/log/src/index.spec.ts b/packages/log/src/index.spec.ts index a6a5e89244..5325be2f14 100644 --- a/packages/log/src/index.spec.ts +++ b/packages/log/src/index.spec.ts @@ -1,26 +1,27 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { expect(new Set(Object.keys(Module))).toEqual( new Set([ - // List of all public exports - 'meta', 'configuration', + 'critical', + 'debug', + 'error', + 'info', + 'level', 'Log', + 'LogHandler', 'LogLevel', 'LogMessage', - 'LogMessageRef', 'LogMessageItem', + 'LogMessageRef', 'LogRecord', - 'LogHandler', - 'level', - 'critical', - 'error', + // List of all public exports + 'meta', 'warn', - 'info', - 'debug', ]), ); }); diff --git a/packages/log/src/index.ts b/packages/log/src/index.ts index 2be40c1922..827e013945 100644 --- a/packages/log/src/index.ts +++ b/packages/log/src/index.ts @@ -1,8 +1,8 @@ -export * from './meta.js'; export * from './configuration.js'; +export * from './level.js'; export * from './Log.js'; -export * from './LogLevel.js'; export * from './LogHandler.js'; +export * from './LogLevel.js'; export * from './LogMessage.js'; export * from './LogRecord.js'; -export * from './level.js'; +export * from './meta.js'; diff --git a/packages/log/src/level.spec.ts b/packages/log/src/level.spec.ts index 100bfb10b3..edbe5ccf89 100644 --- a/packages/log/src/level.spec.ts +++ b/packages/log/src/level.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { critical, debug, error, info, level, warn } from './level.js'; import { LogLevel } from './LogLevel.js'; import { LogMessage, LogMessageRef } from './LogMessage.js'; @@ -10,24 +11,24 @@ describe(level, () => { const message = level(LogLevel.Critical)`foo=${['foo', fooValue]},bar=${['bar', barValue]}`; expect(message).toEqual({ - level: LogLevel.Critical, - message: LogMessage('foo=', LogMessageRef('foo'), ',bar=', LogMessageRef('bar')), data: { bar: barValue, foo: fooValue, }, + level: LogLevel.Critical, + message: LogMessage('foo=', LogMessageRef('foo'), ',bar=', LogMessageRef('bar')), }); }); it('has .withData that adds more data', () => { const message = level(LogLevel.Critical).withData({ foo: 'foo_value' })`bar=${['bar', 'bar_value']}`; expect(message).toEqual({ - level: LogLevel.Critical, - message: LogMessage('bar=', LogMessageRef('bar')), data: { bar: 'bar_value', foo: 'foo_value', }, + level: LogLevel.Critical, + message: LogMessage('bar=', LogMessageRef('bar')), }); }); it('returns a factory from level value', () => { @@ -36,12 +37,12 @@ describe(level, () => { const message = level('critical')`foo=${['foo', fooValue]},bar=${['bar', barValue]}`; expect(message).toEqual({ - level: LogLevel.Critical, - message: LogMessage('foo=', LogMessageRef('foo'), ',bar=', LogMessageRef('bar')), data: { bar: barValue, foo: fooValue, }, + level: LogLevel.Critical, + message: LogMessage('foo=', LogMessageRef('foo'), ',bar=', LogMessageRef('bar')), }); }); }); diff --git a/packages/log/src/level.ts b/packages/log/src/level.ts index ccae5e541a..260b9845b1 100644 --- a/packages/log/src/level.ts +++ b/packages/log/src/level.ts @@ -1,26 +1,44 @@ import type { LogLevel } from './LogLevel.js'; +import type { LogLevelValue } from './LogLevel/LogLevelValue.js'; import type { LogMessageItem } from './LogMessage.js'; import type { LogRecord } from './LogRecord.js'; -import { create as logMessageCreate } from './LogMessage/create.js'; -import { from as logLevelFrom } from './LogLevel/from.js'; -import type { LogLevelValue } from './LogLevel/LogLevelValue.js'; - -type ReferenceInput = [string, unknown]; -export interface LogLevelParameters extends Pick {} +import { from as logLevelFrom } from './LogLevel/from.js'; +import { create as logMessageCreate } from './LogMessage/create.js'; export interface LogLevelFactory { ( strings: TemplateStringsArray, - ...referencesInput: Array + ...referencesInput: Array ): LogLevelParameters; withData(data: LogRecord['data']): LogLevelFactory; } +export interface LogLevelParameters extends Pick {} + +type ReferenceInput = [string, unknown]; + +/** + * Return a function that creates params to be used with a logger function + * + * @example + * ```typescript + * level(LogLevel.Debug)`debug message`;// { level: LogLevel.Debug, message: LogMessage('debug message'), ... } + * level('debug')`debug message`; // { level: LogLevel.Debug, message: LogMessage('debug message'), ... } + * level('debug')`foo=${['foo', 'foo_value']}`; // { ..., message: LogMessage('foo=', LogMessageRef('foo)), data: { foo: 'foo_value' } } + * level('debug').withData({ someData: true })`debug message`;// { level: LogLevel.Critical, message: LogMessage(...), data: { someData: true } } + * ``` + * @param logLevel the default message level + * @returns a new logger params factory + */ +export function level(logLevel: LogLevel | LogLevelValue): LogLevelFactory { + return levelWithData(typeof logLevel === 'string' ? logLevelFrom(logLevel) : logLevel, {}); +} + function levelWithData(logLevel: LogLevel, baseData: LogRecord['data']): LogLevelFactory { return Object.assign( - (strings: TemplateStringsArray, ...tokens: Array) => { - const message: LogMessageItem[] = [strings[0]!]; + (strings: TemplateStringsArray, ...tokens: Array) => { + const message: Array = [strings[0]!]; const data: Record = { ...baseData }; for (const [index, token] of tokens.entries()) { if (token != null) { @@ -36,9 +54,9 @@ function levelWithData(logLevel: LogLevel, baseData: LogRecord['data']): LogLeve } return { + data, level: logLevel, message: logMessageCreate(message), - data, }; }, { @@ -49,23 +67,6 @@ function levelWithData(logLevel: LogLevel, baseData: LogRecord['data']): LogLeve ); } -/** - * Return a function that creates params to be used with a logger function - * - * @example - * ```typescript - * level(LogLevel.Debug)`debug message`;// { level: LogLevel.Debug, message: LogMessage('debug message'), ... } - * level('debug')`debug message`; // { level: LogLevel.Debug, message: LogMessage('debug message'), ... } - * level('debug')`foo=${['foo', 'foo_value']}`; // { ..., message: LogMessage('foo=', LogMessageRef('foo)), data: { foo: 'foo_value' } } - * level('debug').withData({ someData: true })`debug message`;// { level: LogLevel.Critical, message: LogMessage(...), data: { someData: true } } - * ``` - * @param logLevel the default message level - * @returns a new logger params factory - */ -export function level(logLevel: LogLevelValue | LogLevel): LogLevelFactory { - return levelWithData(typeof logLevel === 'string' ? logLevelFrom(logLevel) : logLevel, {}); -} - /** * `Critical` string template * diff --git a/packages/money/README.md b/packages/money/README.md index 3becd1cdce..d48722ad4d 100644 --- a/packages/money/README.md +++ b/packages/money/README.md @@ -18,7 +18,7 @@ npm install @w5s/money ```ts -import { Money, EUR } from '@w5s/money'; +import { EUR, Money } from '@w5s/money'; export function main(): void { const price = EUR(10); diff --git a/packages/money/example/.eslintrc.cjs b/packages/money/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/money/example/.eslintrc.cjs +++ b/packages/money/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/money/example/usage.ts b/packages/money/example/usage.ts index 9500f36eea..e29760d238 100644 --- a/packages/money/example/usage.ts +++ b/packages/money/example/usage.ts @@ -1,4 +1,4 @@ -import { Money, EUR } from '@w5s/money'; +import { EUR, Money } from '@w5s/money'; export function main(): void { const price = EUR(10); diff --git a/packages/money/scripts/buildCurrencies.js b/packages/money/scripts/buildCurrencies.js index c7b435b49e..992d623942 100644 --- a/packages/money/scripts/buildCurrencies.js +++ b/packages/money/scripts/buildCurrencies.js @@ -1,18 +1,42 @@ +import currencyData from 'currencies.json'; import { writeFile } from 'node:fs/promises'; import path from 'node:path'; -import currencyData from 'currencies.json'; const EOL = '\n'; -function getTargetPath() { - return path.join('src', 'moneyFactory.all.ts'); +export async function main() { + const contents = buildContents(); + const targetPath = getTargetPath(); + await writeFile(targetPath, contents); +} + +function buildContents() { + return buildImports() + EOL + buildRegistry() + EOL + buildFactories() + EOL; +} + +function buildFactories() { + return currencyData.currencies + .map( + (currency) => ` +/** + * ${currency.name} money factory + * + * @example + * \`\`\`typescript + * const money = ${currency.code}('1.25');// Money({ currency: Currency({ code: '${currency.code}' }), amount: BigDecimal('1') }) + * \`\`\` + * @param amount The amount of money + */ +export const ${currency.code} = register('${currency.code}', ${currency.decimalDigits}, '${currency.name}', '${currency.namePlural}', ${currency.rounding}, '${currency.symbol}', '${currency.symbolNative}');`, + ) + .join(EOL); } function buildImports() { return `/* cSpell:disable */ import { Currency } from './Currency.js'; -import { factory as moneyFactory } from './Money/factory.js'; import { CurrencyRegistry } from './CurrencyRegistry.js'; +import { factory as moneyFactory } from './Money/factory.js'; `; } @@ -29,9 +53,9 @@ function buildRegistry() { CurrencyRegistry.add( Currency({ code, - precision: precision as Currency['precision'], name, namePlural, + precision: precision as Currency['precision'], rounding: rounding as Currency['rounding'], symbol, symbolNative, @@ -41,32 +65,8 @@ function buildRegistry() { };`; } -function buildFactories() { - return currencyData.currencies - .map( - (currency) => ` -/** - * ${currency.name} money factory - * - * @example - * \`\`\`typescript - * const money = ${currency.code}('1.25');// Money({ currency: Currency({ code: '${currency.code}' }), amount: BigDecimal('1') }) - * \`\`\` - * @param amount The amount of money - */ -export const ${currency.code} = register('${currency.code}', ${currency.decimalDigits}, '${currency.name}', '${currency.namePlural}', ${currency.rounding}, '${currency.symbol}', '${currency.symbolNative}');`, - ) - .join(EOL); -} - -function buildContents() { - return buildImports() + EOL + buildRegistry() + EOL + buildFactories() + EOL; -} - -export async function main() { - const contents = buildContents(); - const targetPath = getTargetPath(); - await writeFile(targetPath, contents); +function getTargetPath() { + return path.join('src', 'moneyFactory.all.ts'); } await main(); diff --git a/packages/money/src/Currency.spec.ts b/packages/money/src/Currency.spec.ts index 9c91350361..5c30129740 100644 --- a/packages/money/src/Currency.spec.ts +++ b/packages/money/src/Currency.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Currency } from './Currency.js'; import { CurrencyAsString } from './Currency/CurrencyAsString.js'; import { CurrencyComparable } from './Currency/CurrencyComparable.js'; diff --git a/packages/money/src/Currency.ts b/packages/money/src/Currency.ts index 3112166acf..4af26d0946 100644 --- a/packages/money/src/Currency.ts +++ b/packages/money/src/Currency.ts @@ -1,7 +1,8 @@ import { Callable } from '@w5s/core/dist/Callable.js'; -import { CurrencyComparable } from './Currency/CurrencyComparable.js'; + import { Currency as CurrencyType } from './Currency/Currency.js'; import { CurrencyAsString } from './Currency/CurrencyAsString.js'; +import { CurrencyComparable } from './Currency/CurrencyComparable.js'; export type Currency = CurrencyType; diff --git a/packages/money/src/Currency/Currency.spec.ts b/packages/money/src/Currency/Currency.spec.ts index d92e158822..6056a475fe 100644 --- a/packages/money/src/Currency/Currency.spec.ts +++ b/packages/money/src/Currency/Currency.spec.ts @@ -1,14 +1,15 @@ -import { describe, expect, it } from 'vitest'; import { Int } from '@w5s/core'; import { describeType } from '@w5s/core/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { Currency } from './Currency.js'; describe(Currency, () => { const anyProperties = { + code: 'EUR', name: 'Name', namePlural: 'Name plural', precision: Int(2), - code: 'EUR', rounding: Int(0), symbol: '$', symbolNative: '$', @@ -21,13 +22,13 @@ describe(Currency, () => { }; describeType(Currency, () => ({ - typeName: 'Currency', - instances: [Currency.create(anyProperties), { _: 'Currency' as const, ...anyProperties }], - notInstances: [], inspect: [ [Currency.create({ ...anyProperties, code: 'EUR' }), 'EUR'], [Currency.create({ ...anyProperties, code: 'USD' }), 'USD'], ], + instances: [Currency.create(anyProperties), { _: 'Currency' as const, ...anyProperties }], + notInstances: [], + typeName: 'Currency', })); it('should initialize Currency', () => { diff --git a/packages/money/src/Currency/Currency.ts b/packages/money/src/Currency/Currency.ts index 5755eb9a87..bd37fee63d 100644 --- a/packages/money/src/Currency/Currency.ts +++ b/packages/money/src/Currency/Currency.ts @@ -1,14 +1,23 @@ -import { Struct } from '@w5s/core/dist/Struct.js'; -import { Symbol, type Int } from '@w5s/core'; -import { Callable } from '@w5s/core/dist/Callable.js'; import type { PartialKeys } from '@w5s/core-type'; -import { defaultRounding } from './defaultRounding.js'; -import { defaultPrecision } from './defaultPrecision.js'; + +import { type Int, Symbol } from '@w5s/core'; +import { Callable } from '@w5s/core/dist/Callable.js'; +import { Struct } from '@w5s/core/dist/Struct.js'; + import { CurrencyAsString } from './CurrencyAsString.js'; +import { defaultPrecision } from './defaultPrecision.js'; +import { defaultRounding } from './defaultRounding.js'; export interface Currency extends Struct<{ [Struct.type]: 'Currency'; + /** + * Code ISO3 + * + * @example 'USD' + */ + code: string; + /** * Name */ @@ -19,13 +28,6 @@ export interface Currency extends Struct<{ */ namePlural: string; - /** - * Code ISO3 - * - * @example 'USD' - */ - code: string; - /** * Currency precision */ @@ -52,20 +54,20 @@ export interface Currency extends Struct<{ }> {} const CurrencyStruct = Struct.define({ - typeName: 'Currency', [Symbol.inspect]: CurrencyAsString.asString, + typeName: 'Currency', ...CurrencyAsString, }); export const Currency = Callable({ - defaultRounding, defaultPrecision, + defaultRounding, ...CurrencyStruct, [Callable.symbol]: (parameters: Currency.Parameters): Currency => CurrencyStruct.create({ - rounding: defaultRounding, - precision: defaultPrecision, namePlural: parameters.name, + precision: defaultPrecision, + rounding: defaultRounding, symbolNative: parameters.symbol, ...parameters, }), diff --git a/packages/money/src/Currency/CurrencyAsString.spec.ts b/packages/money/src/Currency/CurrencyAsString.spec.ts index f06e780bdf..f6c5339e0a 100644 --- a/packages/money/src/Currency/CurrencyAsString.spec.ts +++ b/packages/money/src/Currency/CurrencyAsString.spec.ts @@ -1,10 +1,11 @@ -import { describe } from 'vitest'; import { describeAsString } from '@w5s/core/dist/Testing.js'; -import { CurrencyAsString } from './CurrencyAsString.js'; +import { describe } from 'vitest'; + import { Currency } from './Currency.js'; +import { CurrencyAsString } from './CurrencyAsString.js'; describe('CurrencyAsString', () => { - const anyProperties = { code: 'ANY', symbol: '€', name: 'Any' }; + const anyProperties = { code: 'ANY', name: 'Any', symbol: '€' }; describeAsString(CurrencyAsString, () => [ [Currency({ ...anyProperties, code: 'EUR' }), 'EUR'], diff --git a/packages/money/src/Currency/CurrencyAsString.ts b/packages/money/src/Currency/CurrencyAsString.ts index 0266553e95..5114ef97dd 100644 --- a/packages/money/src/Currency/CurrencyAsString.ts +++ b/packages/money/src/Currency/CurrencyAsString.ts @@ -1,4 +1,5 @@ import type { AsString } from '@w5s/core'; + import type { Currency } from './Currency.js'; export const CurrencyAsString: AsString = { diff --git a/packages/money/src/Currency/CurrencyComparable.spec.ts b/packages/money/src/Currency/CurrencyComparable.spec.ts index aa63493b46..9aab468c1e 100644 --- a/packages/money/src/Currency/CurrencyComparable.spec.ts +++ b/packages/money/src/Currency/CurrencyComparable.spec.ts @@ -1,28 +1,29 @@ +import { Int } from '@w5s/core'; import { describeComparable } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { Int } from '@w5s/core'; + import { Currency } from './Currency.js'; import { CurrencyComparable } from './CurrencyComparable.js'; describe('CurrencyComparable', () => { const anyProperties = { + code: 'EUR', name: 'Name', namePlural: 'Name plural', precision: Int(2), - code: 'EUR', rounding: Int(0), symbol: '$', symbolNative: '$', }; describeComparable(CurrencyComparable, { + equivalent: () => [ + [Currency({ ...anyProperties, code: 'A' }), Currency({ ...anyProperties, code: 'A' })], + [Currency({ ...anyProperties, code: 'B' }), Currency({ ...anyProperties, code: 'B' })], + ], ordered: () => [ Currency({ ...anyProperties, code: 'A' }), Currency({ ...anyProperties, code: 'B' }), Currency({ ...anyProperties, code: 'C' }), ], - equivalent: () => [ - [Currency({ ...anyProperties, code: 'A' }), Currency({ ...anyProperties, code: 'A' })], - [Currency({ ...anyProperties, code: 'B' }), Currency({ ...anyProperties, code: 'B' })], - ], }); }); diff --git a/packages/money/src/Currency/CurrencyComparable.ts b/packages/money/src/Currency/CurrencyComparable.ts index b0a716de44..b0618cbf38 100644 --- a/packages/money/src/Currency/CurrencyComparable.ts +++ b/packages/money/src/Currency/CurrencyComparable.ts @@ -1,5 +1,7 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import type { Currency } from './Currency.js'; + import { compare } from './compare.js'; export const CurrencyComparable = Comparable({ diff --git a/packages/money/src/Currency/compare.ts b/packages/money/src/Currency/compare.ts index 91aaef8e25..6a455ab34d 100644 --- a/packages/money/src/Currency/compare.ts +++ b/packages/money/src/Currency/compare.ts @@ -1,5 +1,7 @@ -import { compare as compareString } from '@w5s/core/dist/String/compare.js'; import type { Ordering } from '@w5s/core'; + +import { compare as compareString } from '@w5s/core/dist/String/compare.js'; + import type { Currency } from './Currency.js'; export function compare(left: Currency, right: Currency): Ordering { diff --git a/packages/money/src/CurrencyRegistry.spec.ts b/packages/money/src/CurrencyRegistry.spec.ts index b46639e5aa..46db761d3e 100644 --- a/packages/money/src/CurrencyRegistry.spec.ts +++ b/packages/money/src/CurrencyRegistry.spec.ts @@ -1,9 +1,10 @@ import { describe, expect, it } from 'vitest'; + import { Currency } from './Currency.js'; import { CurrencyRegistry } from './CurrencyRegistry.js'; describe('CurrencyRegistry', () => { - const anyCurrency = Currency({ name: 'TEST', code: 'TEST', symbol: 'T' }); + const anyCurrency = Currency({ code: 'TEST', name: 'TEST', symbol: 'T' }); describe('.getByCode() / .add()', () => { it('should store data', () => { diff --git a/packages/money/src/CurrencyRegistry.ts b/packages/money/src/CurrencyRegistry.ts index 3bdfb77a65..d38b45de8f 100644 --- a/packages/money/src/CurrencyRegistry.ts +++ b/packages/money/src/CurrencyRegistry.ts @@ -1,6 +1,9 @@ import type { Option } from '@w5s/core'; -import { useState, type Meta } from '@w5s/application'; + +import { type Meta, useState } from '@w5s/application'; + import type { Currency } from './Currency/Currency.js'; + import { meta } from './meta.js'; export interface CurrencyRegistry { diff --git a/packages/money/src/Money.spec.ts b/packages/money/src/Money.spec.ts index c9f951c665..04d99dea62 100644 --- a/packages/money/src/Money.spec.ts +++ b/packages/money/src/Money.spec.ts @@ -1,10 +1,11 @@ import { describe, expect, it } from 'vitest'; + import { Money } from './Money.js'; -import { MoneyNegate } from './Money/MoneyNegate.js'; +import { MoneyAsString } from './Money/MoneyAsString.js'; import { MoneyComparable } from './Money/MoneyComparable.js'; -import { MoneyZero } from './Money/MoneyZero.js'; +import { MoneyNegate } from './Money/MoneyNegate.js'; import { MoneySigned } from './Money/MoneySigned.js'; -import { MoneyAsString } from './Money/MoneyAsString.js'; +import { MoneyZero } from './Money/MoneyZero.js'; describe('Money', () => { it('has defined shape', () => { diff --git a/packages/money/src/Money.ts b/packages/money/src/Money.ts index 6fa2e7c3b7..76e5dce200 100644 --- a/packages/money/src/Money.ts +++ b/packages/money/src/Money.ts @@ -1,14 +1,15 @@ import { Callable } from '@w5s/core/dist/Callable.js'; -import { MoneyComparable } from './Money/MoneyComparable.js'; -import { MoneyNumeric } from './Money/MoneyNumeric.js'; + +import { format } from './Money/format.js'; import { Money as MoneyType } from './Money/Money.js'; import { MoneyAsString } from './Money/MoneyAsString.js'; -import { format } from './Money/format.js'; -import { normalize } from './Money/normalize.js'; -import { parse } from './Money/parse.js'; +import { MoneyComparable } from './Money/MoneyComparable.js'; import { MoneyNegate } from './Money/MoneyNegate.js'; -import { MoneyZero } from './Money/MoneyZero.js'; +import { MoneyNumeric } from './Money/MoneyNumeric.js'; import { MoneySigned } from './Money/MoneySigned.js'; +import { MoneyZero } from './Money/MoneyZero.js'; +import { normalize } from './Money/normalize.js'; +import { parse } from './Money/parse.js'; export type Money = MoneyType; diff --git a/packages/money/src/Money/Money.spec.ts b/packages/money/src/Money/Money.spec.ts index 4de1c8c434..bec81ecf16 100644 --- a/packages/money/src/Money/Money.spec.ts +++ b/packages/money/src/Money/Money.spec.ts @@ -1,58 +1,59 @@ -import { describe, expect, it } from 'vitest'; import { BigDecimal } from '@w5s/bigdecimal'; -import { describeAsString, describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { CodecError, Result } from '@w5s/core'; -import { Money } from './Money.js'; +import { describeAsString, describeCodec, describeType } from '@w5s/core/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { Currency } from '../Currency/Currency.js'; import { CurrencyRegistry } from '../CurrencyRegistry.js'; +import { Money } from './Money.js'; describe(Money, () => { const anyCurrency = Currency({ - name: 'Any', code: 'ANY', + name: 'Any', symbol: 'A', }); const anyAmount = BigDecimal('1'); const EUR = CurrencyRegistry.getByCode('EUR')!; it('should initialize Money', () => { - expect(Money({ currency: anyCurrency, amount: anyAmount })).toMatchObject({ + expect(Money({ amount: anyAmount, currency: anyCurrency })).toMatchObject({ _: 'Money', - currency: anyCurrency, amount: anyAmount, + currency: anyCurrency, }); }); describeType(Money, () => ({ - typeName: 'Money', + inspect: [ + [Money({ amount: BigDecimal('1.1'), currency: anyCurrency }), '1.1ANY'], + [Money({ amount: BigDecimal('1.1'), currency: EUR }), '1.1EUR'], + ], instances: [ Money.create({ amount: BigDecimal('1.1'), currency: anyCurrency }), { _: 'Money' as const, amount: BigDecimal('1.1'), currency: anyCurrency }, ], notInstances: [], - inspect: [ - [Money({ amount: BigDecimal('1.1'), currency: anyCurrency }), '1.1ANY'], - [Money({ amount: BigDecimal('1.1'), currency: EUR }), '1.1EUR'], - ], + typeName: 'Money', })); describeCodec(Money, () => ({ decode: [ - ['1.1EUR', Result.Ok(Money({ currency: EUR, amount: BigDecimal('1.1') }))], - ['EUR', Result.Error(new CodecError({ message: 'Cannot decode "EUR" as Money', input: 'EUR' }))], - ['BLAH', Result.Error(new CodecError({ message: 'Cannot decode "BLAH" as Money', input: 'BLAH' }))], - [1, Result.Error(new CodecError({ message: 'Cannot decode 1 as Money', input: 1 }))], + ['1.1EUR', Result.Ok(Money({ amount: BigDecimal('1.1'), currency: EUR }))], + ['EUR', Result.Error(new CodecError({ input: 'EUR', message: 'Cannot decode "EUR" as Money' }))], + ['BLAH', Result.Error(new CodecError({ input: 'BLAH', message: 'Cannot decode "BLAH" as Money' }))], + [1, Result.Error(new CodecError({ input: 1, message: 'Cannot decode 1 as Money' }))], ], encode: [ - [Money({ currency: anyCurrency, amount: BigDecimal('0') }), '0ANY'], - [Money({ currency: anyCurrency, amount: BigDecimal('-1.1') }), '-1.1ANY'], + [Money({ amount: BigDecimal('0'), currency: anyCurrency }), '0ANY'], + [Money({ amount: BigDecimal('-1.1'), currency: anyCurrency }), '-1.1ANY'], ], schema: { - type: 'string', format: 'money', + type: 'string', }, })); describeAsString(Money, () => [ - [Money({ currency: anyCurrency, amount: BigDecimal('0') }), '0ANY'], - [Money({ currency: anyCurrency, amount: BigDecimal('-1.1') }), '-1.1ANY'], + [Money({ amount: BigDecimal('0'), currency: anyCurrency }), '0ANY'], + [Money({ amount: BigDecimal('-1.1'), currency: anyCurrency }), '-1.1ANY'], ]); }); diff --git a/packages/money/src/Money/Money.ts b/packages/money/src/Money/Money.ts index f6d6a1e6d8..ac7ca2c565 100644 --- a/packages/money/src/Money/Money.ts +++ b/packages/money/src/Money/Money.ts @@ -1,9 +1,12 @@ import type { BigDecimal } from '@w5s/bigdecimal'; + import { Struct } from '@w5s/core/dist/Struct.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; + import type { Currency } from '../Currency/Currency.js'; -import { parse } from './parse.js'; + import { MoneyAsString } from './MoneyAsString.js'; +import { parse } from './parse.js'; export interface Money extends Struct<{ [Struct.type]: 'Money'; @@ -19,9 +22,7 @@ export interface Money extends Struct<{ currency: Currency; }> {} export const Money = Struct.define({ - typeName: 'Money', - [Symbol.encode]: (input) => MoneyAsString.asString(input), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string') { const parseResult = parse(input); if (parseResult != null) { @@ -30,10 +31,12 @@ export const Money = Struct.define({ } return error(input, 'Money'); }, + [Symbol.encode]: (input) => MoneyAsString.asString(input), + [Symbol.inspect]: MoneyAsString.asString, [Symbol.schema]: () => ({ - type: 'string', format: 'money', + type: 'string', }), - [Symbol.inspect]: MoneyAsString.asString, + typeName: 'Money', ...MoneyAsString, }); diff --git a/packages/money/src/Money/MoneyAsString.spec.ts b/packages/money/src/Money/MoneyAsString.spec.ts index 8021b89471..231f2bbf9f 100644 --- a/packages/money/src/Money/MoneyAsString.spec.ts +++ b/packages/money/src/Money/MoneyAsString.spec.ts @@ -1,12 +1,13 @@ -import { describe } from 'vitest'; import { BigDecimal } from '@w5s/bigdecimal'; import { describeAsString } from '@w5s/core/dist/Testing.js'; -import { MoneyAsString } from './MoneyAsString.js'; -import { Money } from './Money.js'; +import { describe } from 'vitest'; + import { Currency } from '../Currency.js'; +import { Money } from './Money.js'; +import { MoneyAsString } from './MoneyAsString.js'; describe('MoneyAsString', () => { - const EUR = Currency({ code: 'EUR', symbol: '€', name: 'Euro' }); + const EUR = Currency({ code: 'EUR', name: 'Euro', symbol: '€' }); describeAsString(MoneyAsString, () => [ // cases diff --git a/packages/money/src/Money/MoneyAsString.ts b/packages/money/src/Money/MoneyAsString.ts index 71bf3f50a2..672ff6eb11 100644 --- a/packages/money/src/Money/MoneyAsString.ts +++ b/packages/money/src/Money/MoneyAsString.ts @@ -1,8 +1,11 @@ -import { BigDecimalAsString } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalAsString.js'; import type { AsString } from '@w5s/core'; -import { CurrencyAsString } from '../Currency/CurrencyAsString.js'; + +import { BigDecimalAsString } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalAsString.js'; + import type { Money } from './Money.js'; +import { CurrencyAsString } from '../Currency/CurrencyAsString.js'; + const bigDecimalAsString = BigDecimalAsString.asString; const currencyAsString = CurrencyAsString.asString; diff --git a/packages/money/src/Money/MoneyComparable.spec.ts b/packages/money/src/Money/MoneyComparable.spec.ts index 135115841c..d592ab2aff 100644 --- a/packages/money/src/Money/MoneyComparable.spec.ts +++ b/packages/money/src/Money/MoneyComparable.spec.ts @@ -1,28 +1,30 @@ +import { BigDecimal } from '@w5s/bigdecimal'; import { describeComparable } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { BigDecimal } from '@w5s/bigdecimal'; -import { MoneyComparable } from './MoneyComparable.js'; -import { Money } from './Money.js'; + import { Currency } from '../Currency.js'; +import { Money } from './Money.js'; +import { MoneyComparable } from './MoneyComparable.js'; describe('MoneyComparable', () => { const currencyEuro = Currency({ - name: 'Euro', code: 'EUR', + name: 'Euro', symbol: '€', }); const currencyDollar = Currency({ - name: 'Dollar', code: 'USD', + name: 'Dollar', symbol: '$', }); const _0 = BigDecimal('0'); const _1 = BigDecimal('1'); const _2 = BigDecimal('2'); - const EUR = (amount: BigDecimal) => Money({ currency: currencyEuro, amount }); - const USD = (amount: BigDecimal) => Money({ currency: currencyDollar, amount }); + const EUR = (amount: BigDecimal) => Money({ amount, currency: currencyEuro }); + const USD = (amount: BigDecimal) => Money({ amount, currency: currencyDollar }); describeComparable(MoneyComparable, { + equivalent: () => [[EUR(_1), EUR(_1)]], ordered: () => [ // Money({ currency: anyCurrency, amount: anyAmount }), EUR(_0), @@ -30,6 +32,5 @@ describe('MoneyComparable', () => { EUR(_2), USD(_1), ], - equivalent: () => [[EUR(_1), EUR(_1)]], }); }); diff --git a/packages/money/src/Money/MoneyComparable.ts b/packages/money/src/Money/MoneyComparable.ts index c0a9acfc99..3f4a8b0620 100644 --- a/packages/money/src/Money/MoneyComparable.ts +++ b/packages/money/src/Money/MoneyComparable.ts @@ -1,5 +1,7 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import type { Money } from './Money.js'; + import { compare } from './compare.js'; export const MoneyComparable = Comparable({ diff --git a/packages/money/src/Money/MoneyNegate.spec.ts b/packages/money/src/Money/MoneyNegate.spec.ts index 4b7ff9e177..73eb478ef0 100644 --- a/packages/money/src/Money/MoneyNegate.spec.ts +++ b/packages/money/src/Money/MoneyNegate.spec.ts @@ -1,8 +1,9 @@ -import { describe } from 'vitest'; import { describeNegate } from '@w5s/core/dist/Testing.js'; -import { MoneyNegate } from './MoneyNegate.js'; -import { MoneyComparable } from './MoneyComparable.js'; +import { describe } from 'vitest'; + import { ANY } from '../Testing.js'; +import { MoneyComparable } from './MoneyComparable.js'; +import { MoneyNegate } from './MoneyNegate.js'; describe('MoneyNegate', () => { describeNegate( diff --git a/packages/money/src/Money/MoneyNegate.ts b/packages/money/src/Money/MoneyNegate.ts index 380a1636f8..0ed6e1c86e 100644 --- a/packages/money/src/Money/MoneyNegate.ts +++ b/packages/money/src/Money/MoneyNegate.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import { BigDecimalNegate } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalNegate.js'; + import { Money } from './Money.js'; export const MoneyNegate: Numeric.Negate = { diff --git a/packages/money/src/Money/MoneyNumeric.spec.ts b/packages/money/src/Money/MoneyNumeric.spec.ts index d6804e8ca5..8ce7e73eb7 100644 --- a/packages/money/src/Money/MoneyNumeric.spec.ts +++ b/packages/money/src/Money/MoneyNumeric.spec.ts @@ -1,24 +1,25 @@ import { BigDecimal, type BigDecimalString } from '@w5s/bigdecimal'; -import { describe, it, expect } from 'vitest'; import { Result } from '@w5s/core'; import { ArgumentError } from '@w5s/error'; -import { Money } from './Money.js'; +import { describe, expect, it } from 'vitest'; + import { Currency } from '../Currency/Currency.js'; +import { Money } from './Money.js'; import { MoneyNumeric } from './MoneyNumeric.js'; describe('MoneyNumeric', () => { const currencyEuro = Currency({ - name: 'Euro', code: 'EUR', + name: 'Euro', symbol: '€', }); const currencyDollar = Currency({ - name: 'Dollar', code: 'USD', + name: 'Dollar', symbol: '$', }); const anyAmount = '1'; - const money = (currency: Currency, amount: BigDecimalString) => Money({ currency, amount: BigDecimal(amount) }); + const money = (currency: Currency, amount: BigDecimalString) => Money({ amount: BigDecimal(amount), currency }); const EUR = (amount: BigDecimalString) => money(currencyEuro, amount); const USD = (amount: BigDecimalString) => money(currencyDollar, amount); diff --git a/packages/money/src/Money/MoneyNumeric.ts b/packages/money/src/Money/MoneyNumeric.ts index 5fa6902b3b..6e5b762e62 100644 --- a/packages/money/src/Money/MoneyNumeric.ts +++ b/packages/money/src/Money/MoneyNumeric.ts @@ -1,9 +1,11 @@ +import type { BigDecimal } from '@w5s/bigdecimal'; import type { Result } from '@w5s/core'; -import { ArgumentError } from '@w5s/error/dist/ArgumentError.js'; -import { Ok } from '@w5s/core/dist/Result/Ok.js'; -import { Error } from '@w5s/core/dist/Result/Error.js'; + import { BigDecimalNumeric } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalNumeric.js'; -import type { BigDecimal } from '@w5s/bigdecimal'; +import { Error } from '@w5s/core/dist/Result/Error.js'; +import { Ok } from '@w5s/core/dist/Result/Ok.js'; +import { ArgumentError } from '@w5s/error/dist/ArgumentError.js'; + import { compare as currencyCompare } from '../Currency/compare.js'; import { Money } from './Money.js'; @@ -12,8 +14,8 @@ function createOperator(combineFn: (leftAmount: Money['amount'], rightAmount: Mo currencyCompare(left.currency, right.currency) === 0 ? Ok( Money({ - currency: left.currency, amount: combineFn(left.amount, right.amount), + currency: left.currency, }), ) : Error( @@ -24,6 +26,19 @@ function createOperator(combineFn: (leftAmount: Money['amount'], rightAmount: Mo } export const MoneyNumeric: { + /** + * Multiply operator + * + * @example + * ```typescript + * Money['*'](EUR(2), BigDecimal('2'));// EUR("4") + * ``` + * @category Numeric + * @param money money object + * @param multiplier multiplication factor + */ + '*'(money: Money, multiplier: BigDecimal): Money; + /** * Addition operator * @@ -51,25 +66,12 @@ export const MoneyNumeric: { * @param right Right operand money */ '-'(this: void, left: Money, right: Money): Result; - - /** - * Multiply operator - * - * @example - * ```typescript - * Money['*'](EUR(2), BigDecimal('2'));// EUR("4") - * ``` - * @category Numeric - * @param money money object - * @param multiplier multiplication factor - */ - '*'(money: Money, multiplier: BigDecimal): Money; } = { - '+': createOperator(BigDecimalNumeric['+']), - '-': createOperator(BigDecimalNumeric['-']), '*': (money, multiplier) => Money({ - currency: money.currency, amount: BigDecimalNumeric['*'](money.amount, multiplier), + currency: money.currency, }), + '+': createOperator(BigDecimalNumeric['+']), + '-': createOperator(BigDecimalNumeric['-']), }; diff --git a/packages/money/src/Money/MoneySigned.spec.ts b/packages/money/src/Money/MoneySigned.spec.ts index c48cda0644..e9e19008b5 100644 --- a/packages/money/src/Money/MoneySigned.spec.ts +++ b/packages/money/src/Money/MoneySigned.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { MoneySigned } from './MoneySigned.js'; +import { describe, expect, it } from 'vitest'; + import { ANY } from '../Testing.js'; +import { MoneySigned } from './MoneySigned.js'; describe('MoneySigned', () => { describe(MoneySigned.isPositive, () => { diff --git a/packages/money/src/Money/MoneySigned.ts b/packages/money/src/Money/MoneySigned.ts index 7a376e4b8f..56a3f9da01 100644 --- a/packages/money/src/Money/MoneySigned.ts +++ b/packages/money/src/Money/MoneySigned.ts @@ -1,26 +1,27 @@ import { BigDecimalSigned } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalSigned.js'; + import type { Money } from './Money.js'; -const { isPositive: bigDecimalIsPositive, isNegative: bigDecimalIsNegative } = BigDecimalSigned; +const { isNegative: bigDecimalIsNegative, isPositive: bigDecimalIsPositive } = BigDecimalSigned; interface MoneySigned { /** - * Returns true if the number is positive and false if the number is zero or negative. + * Returns true if the number is negative and false if the number is zero or positive. * * @category Numeric * @param self the numeric value */ - isPositive(this: void, self: Money): boolean; + isNegative(this: void, self: Money): boolean; /** - * Returns true if the number is negative and false if the number is zero or positive. + * Returns true if the number is positive and false if the number is zero or negative. * * @category Numeric * @param self the numeric value */ - isNegative(this: void, self: Money): boolean; + isPositive(this: void, self: Money): boolean; } export const MoneySigned: MoneySigned = { - isPositive: ({ amount }) => bigDecimalIsPositive(amount), isNegative: ({ amount }) => bigDecimalIsNegative(amount), + isPositive: ({ amount }) => bigDecimalIsPositive(amount), }; diff --git a/packages/money/src/Money/MoneyZero.spec.ts b/packages/money/src/Money/MoneyZero.spec.ts index a1641beec2..8be28c80d6 100644 --- a/packages/money/src/Money/MoneyZero.spec.ts +++ b/packages/money/src/Money/MoneyZero.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { MoneyZero } from './MoneyZero.js'; +import { describe, expect, it } from 'vitest'; + import { ANY } from '../Testing.js'; +import { MoneyZero } from './MoneyZero.js'; describe('MoneyZero', () => { describe(MoneyZero.isZero, () => { diff --git a/packages/money/src/Money/MoneyZero.ts b/packages/money/src/Money/MoneyZero.ts index e109919573..be2836e266 100644 --- a/packages/money/src/Money/MoneyZero.ts +++ b/packages/money/src/Money/MoneyZero.ts @@ -1,4 +1,5 @@ import { BigDecimalZero } from '@w5s/bigdecimal/dist/BigDecimal/BigDecimalZero.js'; + import type { Money } from './Money.js'; const { isZero: bigDecimalIsZero } = BigDecimalZero; diff --git a/packages/money/src/Money/compare.ts b/packages/money/src/Money/compare.ts index 38046d6988..b8f68a39ab 100644 --- a/packages/money/src/Money/compare.ts +++ b/packages/money/src/Money/compare.ts @@ -1,8 +1,11 @@ -import { compare as bigDecimalCompare } from '@w5s/bigdecimal/dist/BigDecimal/compare.js'; import type { Ordering } from '@w5s/core'; -import { compare as currencyCompare } from '../Currency/compare.js'; + +import { compare as bigDecimalCompare } from '@w5s/bigdecimal/dist/BigDecimal/compare.js'; + import type { Money } from './Money.js'; +import { compare as currencyCompare } from '../Currency/compare.js'; + export function compare(left: Money, right: Money): Ordering { const comparison = currencyCompare(left.currency, right.currency); return comparison === 0 ? bigDecimalCompare(left.amount, right.amount) : comparison; diff --git a/packages/money/src/Money/factory.spec.ts b/packages/money/src/Money/factory.spec.ts index 9c7a3dd240..9c333fc853 100644 --- a/packages/money/src/Money/factory.spec.ts +++ b/packages/money/src/Money/factory.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { Int } from '@w5s/core'; import { BigDecimal } from '@w5s/bigdecimal'; +import { Int } from '@w5s/core'; +import { beforeEach, describe, expect, it } from 'vitest'; + import { Currency } from '../Currency.js'; import { CurrencyRegistry } from '../CurrencyRegistry.js'; import { Money } from '../Money.js'; @@ -14,8 +15,8 @@ describe(factory, () => { registry = CurrencyRegistry(app); registry.add( Currency({ - name: 'test', code: TEST, + name: 'test', symbol: '#', }), ); @@ -29,9 +30,9 @@ describe(factory, () => { expect(currency).toEqual( Currency({ code: TEST, - precision: Int(2), name: 'test', namePlural: 'test', + precision: Int(2), rounding: Int(0), symbol: '#', symbolNative: '#', @@ -44,14 +45,14 @@ describe(factory, () => { }); const currency = Currency({ code: TEST, - precision: Int(2), name: 'test', namePlural: 'test', + precision: Int(2), rounding: Int(0), symbol: '#', symbolNative: '#', }); - expect(testFactory(BigDecimal('1'))).toEqual(Money({ currency, amount: BigDecimal('1') })); + expect(testFactory(BigDecimal('1'))).toEqual(Money({ amount: BigDecimal('1'), currency })); }); it('should return a new factory by string', () => { @@ -60,13 +61,13 @@ describe(factory, () => { }); const currency = Currency({ code: TEST, - precision: Int(2), name: 'test', namePlural: 'test', + precision: Int(2), rounding: Int(0), symbol: '#', symbolNative: '#', }); - expect(testFactory('1')).toEqual(Money({ currency, amount: BigDecimal('1') })); + expect(testFactory('1')).toEqual(Money({ amount: BigDecimal('1'), currency })); }); }); diff --git a/packages/money/src/Money/factory.ts b/packages/money/src/Money/factory.ts index 951490c1e0..276feaa052 100644 --- a/packages/money/src/Money/factory.ts +++ b/packages/money/src/Money/factory.ts @@ -1,7 +1,10 @@ -import { invariant } from '@w5s/error/dist/invariant.js'; -import { call as BigDecimal } from '@w5s/bigdecimal/dist/BigDecimal/call.js'; import type { BigDecimalString } from '@w5s/bigdecimal'; + +import { call as BigDecimal } from '@w5s/bigdecimal/dist/BigDecimal/call.js'; +import { invariant } from '@w5s/error/dist/invariant.js'; + import type { Currency } from '../Currency/Currency.js'; + import { CurrencyRegistry } from '../CurrencyRegistry.js'; import { Money } from './Money.js'; import { of } from './of.js'; @@ -14,6 +17,6 @@ export function factory( ) { const currency = (options?.registry ?? CurrencyRegistry).getByCode(currencyCode); invariant(currency != null, `${currencyCode} is not valid currency code`); - return (amount: Money['amount'] | BigDecimalString): Money => + return (amount: BigDecimalString | Money['amount']): Money => of(currency, typeof amount === 'string' ? BigDecimal(amount) : amount); } diff --git a/packages/money/src/Money/format.spec.ts b/packages/money/src/Money/format.spec.ts index 3c7c5e7ffb..1fe5241530 100644 --- a/packages/money/src/Money/format.spec.ts +++ b/packages/money/src/Money/format.spec.ts @@ -1,11 +1,12 @@ -import { describe, expect, it } from 'vitest'; import { BigDecimal } from '@w5s/bigdecimal'; +import { describe, expect, it } from 'vitest'; + +import { Currency } from '../Currency.js'; import { format } from './format.js'; import { Money } from './Money.js'; -import { Currency } from '../Currency.js'; describe(format, () => { - const anyCurrency = Currency({ code: 'EUR', symbol: '€', name: 'Euro' }); + const anyCurrency = Currency({ code: 'EUR', name: 'Euro', symbol: '€' }); it('should return the formatted money value', () => { const result = format(Money({ amount: BigDecimal('1.10'), currency: anyCurrency })); diff --git a/packages/money/src/Money/format.ts b/packages/money/src/Money/format.ts index 837f0fce79..8af8dea69a 100644 --- a/packages/money/src/Money/format.ts +++ b/packages/money/src/Money/format.ts @@ -1,4 +1,5 @@ import type { Money } from './Money.js'; + import { MoneyAsString } from './MoneyAsString.js'; /** diff --git a/packages/money/src/Money/normalize.spec.ts b/packages/money/src/Money/normalize.spec.ts index 27c41eb9e1..92b5e47b14 100644 --- a/packages/money/src/Money/normalize.spec.ts +++ b/packages/money/src/Money/normalize.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect } from 'vitest'; import { BigDecimal } from '@w5s/bigdecimal'; -import { normalize } from './normalize.js'; -import { Money } from './Money.js'; +import { describe, expect, it } from 'vitest'; + import { CurrencyRegistry } from '../CurrencyRegistry.js'; +import { Money } from './Money.js'; +import { normalize } from './normalize.js'; import '../moneyFactory.all.js'; describe(normalize, () => { diff --git a/packages/money/src/Money/normalize.ts b/packages/money/src/Money/normalize.ts index b6fc2aba54..e782eb5f03 100644 --- a/packages/money/src/Money/normalize.ts +++ b/packages/money/src/Money/normalize.ts @@ -1,6 +1,7 @@ import { normalize as bigDecimalNormalize } from '@w5s/bigdecimal/dist/BigDecimal/normalize.js'; -import { Money } from './Money.js'; + import { moneyMapAmount } from '../internal/moneyMapAmount.js'; +import { Money } from './Money.js'; /** * Normalizes a `BigDecimal` object to its simplest form. diff --git a/packages/money/src/Money/of.ts b/packages/money/src/Money/of.ts index f976520c04..1799024e98 100644 --- a/packages/money/src/Money/of.ts +++ b/packages/money/src/Money/of.ts @@ -1,7 +1,9 @@ import type { BigDecimal } from '@w5s/bigdecimal'; -import { Money } from './Money.js'; + import type { Currency } from '../Currency.js'; +import { Money } from './Money.js'; + export function of(currency: Currency, amount: BigDecimal): Money { return Money.create({ amount, currency }); } diff --git a/packages/money/src/Money/parse.spec.ts b/packages/money/src/Money/parse.spec.ts index fe89203ab1..f378d02575 100644 --- a/packages/money/src/Money/parse.spec.ts +++ b/packages/money/src/Money/parse.spec.ts @@ -1,9 +1,10 @@ -import { describe, expect, it } from 'vitest'; -import { Option } from '@w5s/core'; import { BigDecimal } from '@w5s/bigdecimal'; -import { parse } from './parse.js'; -import { Money } from './Money.js'; +import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { CurrencyRegistry } from '../CurrencyRegistry.js'; +import { Money } from './Money.js'; +import { parse } from './parse.js'; describe(parse, async () => { const EUR = CurrencyRegistry.getByCode('EUR')!; diff --git a/packages/money/src/Money/parse.ts b/packages/money/src/Money/parse.ts index c3474636bc..3fe1aee1e2 100644 --- a/packages/money/src/Money/parse.ts +++ b/packages/money/src/Money/parse.ts @@ -1,6 +1,9 @@ import type { Option } from '@w5s/core'; + import { parse as bigDecimalParse } from '@w5s/bigdecimal/dist/BigDecimal/parse.js'; + import type { Money } from './Money.js'; + import { CurrencyRegistry } from '../CurrencyRegistry.js'; import '../moneyFactory.all.js'; // Important : load well known currencies import { of } from './of.js'; diff --git a/packages/money/src/Testing.spec.ts b/packages/money/src/Testing.spec.ts index 394c96fc7f..73b949f8d2 100644 --- a/packages/money/src/Testing.spec.ts +++ b/packages/money/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('Testing', () => { diff --git a/packages/money/src/Testing/anyCurrency.ts b/packages/money/src/Testing/anyCurrency.ts index 2337371021..d5ccd592b9 100644 --- a/packages/money/src/Testing/anyCurrency.ts +++ b/packages/money/src/Testing/anyCurrency.ts @@ -5,8 +5,8 @@ import { CurrencyRegistry } from '../CurrencyRegistry.js'; * A stub currency for testing purposes. It has a unique code, symbol, and name. */ export const anyCurrency = Currency({ - name: 'Any Currency', code: 'ANY', + name: 'Any Currency', symbol: 'Ᾰ', }); diff --git a/packages/money/src/configuration.spec.ts b/packages/money/src/configuration.spec.ts index a3705f2c99..61ed5bb19a 100644 --- a/packages/money/src/configuration.spec.ts +++ b/packages/money/src/configuration.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { configuration } from './configuration.js'; describe('configuration', () => { diff --git a/packages/money/src/configuration.ts b/packages/money/src/configuration.ts index 98470ccd85..49723f4640 100644 --- a/packages/money/src/configuration.ts +++ b/packages/money/src/configuration.ts @@ -1,4 +1,5 @@ import { useConfiguration } from '@w5s/application'; + import { meta } from './meta.js'; /** diff --git a/packages/money/src/index.spec.ts b/packages/money/src/index.spec.ts index cdbf1df6a9..3170e5580c 100644 --- a/packages/money/src/index.spec.ts +++ b/packages/money/src/index.spec.ts @@ -1,15 +1,16 @@ -import { describe, expect, it } from 'vitest'; import currencyData from 'currencies.json'; -import * as Module from './index.js'; +import { describe, expect, it } from 'vitest'; + import { configuration } from './configuration.js'; +import * as Module from './index.js'; describe('module public API', () => { it('should return correct values', () => { expect(Module).toEqual( expect.objectContaining({ - meta: expect.any(Object), configuration, Currency: expect.any(Function), + meta: expect.any(Object), Money: expect.any(Function), }), ); diff --git a/packages/money/src/index.ts b/packages/money/src/index.ts index 7c51745599..e5b5d4eaa3 100644 --- a/packages/money/src/index.ts +++ b/packages/money/src/index.ts @@ -1,5 +1,5 @@ -export * from './meta.js'; export * from './configuration.js'; export * from './Currency.js'; +export * from './meta.js'; export * from './Money.js'; export * from './moneyFactory.all.js'; diff --git a/packages/money/src/internal/moneyMapAmount.ts b/packages/money/src/internal/moneyMapAmount.ts index 41f65e2d8c..cd24a93368 100644 --- a/packages/money/src/internal/moneyMapAmount.ts +++ b/packages/money/src/internal/moneyMapAmount.ts @@ -1,4 +1,5 @@ import type { Money } from '../Money/Money.js'; + import { of } from '../Money/of.js'; export function moneyMapAmount(self: Money, fn: (amount: Money['amount']) => Money['amount']): Money { diff --git a/packages/money/src/moneyFactory.all.spec.ts b/packages/money/src/moneyFactory.all.spec.ts index cbb8e84c6a..d63b00d304 100644 --- a/packages/money/src/moneyFactory.all.spec.ts +++ b/packages/money/src/moneyFactory.all.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import currencyData from 'currencies.json'; +import { describe, expect, it } from 'vitest'; + import * as MoneyFactory from './moneyFactory.all.js'; describe.each(['USD', 'EUR'] as const)('%s()', (factoryName) => { diff --git a/packages/money/src/moneyFactory.all.ts b/packages/money/src/moneyFactory.all.ts index 7ebaba82a6..d94869b0a0 100644 --- a/packages/money/src/moneyFactory.all.ts +++ b/packages/money/src/moneyFactory.all.ts @@ -1,7 +1,7 @@ /* cSpell:disable */ import { Currency } from './Currency.js'; -import { factory as moneyFactory } from './Money/factory.js'; import { CurrencyRegistry } from './CurrencyRegistry.js'; +import { factory as moneyFactory } from './Money/factory.js'; const register = ( code: Currency['code'], @@ -15,9 +15,9 @@ const register = ( CurrencyRegistry.add( Currency({ code, - precision: precision as Currency['precision'], name, namePlural, + precision: precision as Currency['precision'], rounding: rounding as Currency['rounding'], symbol, symbolNative, diff --git a/packages/num/example/.eslintrc.cjs b/packages/num/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/num/example/.eslintrc.cjs +++ b/packages/num/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/num/src/BigInt.spec.ts b/packages/num/src/BigInt.spec.ts index 9c52d78079..42a51e86a5 100644 --- a/packages/num/src/BigInt.spec.ts +++ b/packages/num/src/BigInt.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; import { Type } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { BigInt } from './BigInt.js'; -import { parse } from './BigInt/parse.js'; -import { format } from './BigInt/format.js'; import { BigIntComparable } from './BigInt/BigIntComparable.js'; -import { BigIntIntegral } from './BigInt/BigIntIntegral.js'; import { BigIntIndexable } from './BigInt/BigIntIndexable.js'; +import { BigIntIntegral } from './BigInt/BigIntIntegral.js'; +import { format } from './BigInt/format.js'; import { fromInt } from './BigInt/fromInt.js'; import { fromNumber } from './BigInt/fromNumber.js'; +import { parse } from './BigInt/parse.js'; describe('BigInt', () => { it('is an alias to functions', () => { @@ -17,10 +18,10 @@ describe('BigInt', () => { expect(BigInt).toEqual(expect.objectContaining(Type.bigint)); expect(BigInt).toEqual( expect.objectContaining({ - parse, format, fromInt, fromNumber, + parse, }), ); }); diff --git a/packages/num/src/BigInt.ts b/packages/num/src/BigInt.ts index 700f573aa7..f69f19cade 100644 --- a/packages/num/src/BigInt.ts +++ b/packages/num/src/BigInt.ts @@ -1,11 +1,12 @@ import { bigint as BigIntType } from '@w5s/core/dist/Type/bigint.js'; -import { parse } from './BigInt/parse.js'; -import { format } from './BigInt/format.js'; + import { BigIntComparable } from './BigInt/BigIntComparable.js'; -import { fromInt } from './BigInt/fromInt.js'; -import { fromNumber } from './BigInt/fromNumber.js'; import { BigIntIndexable } from './BigInt/BigIntIndexable.js'; import { BigIntIntegral } from './BigInt/BigIntIntegral.js'; +import { format } from './BigInt/format.js'; +import { fromInt } from './BigInt/fromInt.js'; +import { fromNumber } from './BigInt/fromNumber.js'; +import { parse } from './BigInt/parse.js'; /** * A collection of functions to manipulate `bigint` @@ -24,8 +25,8 @@ export const BigInt = { ...BigIntIndexable, ...BigIntType, ...BigIntIntegral, - parse, format, fromInt, fromNumber, + parse, }; diff --git a/packages/num/src/BigInt/BigIntComparable.spec.ts b/packages/num/src/BigInt/BigIntComparable.spec.ts index 6f40bef1f9..5b2e2eaedd 100644 --- a/packages/num/src/BigInt/BigIntComparable.spec.ts +++ b/packages/num/src/BigInt/BigIntComparable.spec.ts @@ -1,14 +1,15 @@ -import { describe } from 'vitest'; import { describeComparable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { BigIntComparable } from './BigIntComparable.js'; describe('BigIntComparable', () => { describeComparable(BigIntComparable, { - ordered: () => [-1n, 0, 1n], equivalent: () => [ [0n, 0n], [1n, 1n], [-2n, -2n], ], + ordered: () => [-1n, 0, 1n], }); }); diff --git a/packages/num/src/BigInt/BigIntComparable.ts b/packages/num/src/BigInt/BigIntComparable.ts index 280000f2d2..e861d26d5d 100644 --- a/packages/num/src/BigInt/BigIntComparable.ts +++ b/packages/num/src/BigInt/BigIntComparable.ts @@ -1,4 +1,5 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import { compare } from './compare.js'; export const BigIntComparable = Comparable({ diff --git a/packages/num/src/BigInt/BigIntIndexable.spec.ts b/packages/num/src/BigInt/BigIntIndexable.spec.ts index a4c7ab5eb3..5a179e46eb 100644 --- a/packages/num/src/BigInt/BigIntIndexable.spec.ts +++ b/packages/num/src/BigInt/BigIntIndexable.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeIndexable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { BigIntIndexable } from './BigIntIndexable.js'; describe('BigIntIndexable', () => { @@ -8,13 +9,13 @@ describe('BigIntIndexable', () => { [0n, 0n], [1n, 1n], ], - rangeSize: [ - [1n, 3n, 3n], - [1n, 4n, 4n], - ], range: [ [0n, 2n, [0n, 1n, 2n]], [1n, 4n, [1n, 2n, 3n, 4n]], ], + rangeSize: [ + [1n, 3n, 3n], + [1n, 4n, 4n], + ], }); }); diff --git a/packages/num/src/BigInt/BigIntIndexable.ts b/packages/num/src/BigInt/BigIntIndexable.ts index d766d60072..606e4df4bd 100644 --- a/packages/num/src/BigInt/BigIntIndexable.ts +++ b/packages/num/src/BigInt/BigIntIndexable.ts @@ -1,7 +1,7 @@ import { Indexable } from '@w5s/core/dist/Indexable.js'; export const BigIntIndexable: Indexable = Indexable({ - indexType: 'bigint', at: (index) => index, indexOf: (value) => value, + indexType: 'bigint', }); diff --git a/packages/num/src/BigInt/BigIntIntegral.spec.ts b/packages/num/src/BigInt/BigIntIntegral.spec.ts index 9142598423..b67d0fb4a1 100644 --- a/packages/num/src/BigInt/BigIntIntegral.spec.ts +++ b/packages/num/src/BigInt/BigIntIntegral.spec.ts @@ -1,4 +1,3 @@ -import { describe } from 'vitest'; import { describeAdd, describeMultiply, @@ -7,8 +6,10 @@ import { describeSubtract, describeZero, } from '@w5s/core/dist/Testing.js'; -import { BigIntIntegral } from './BigIntIntegral.js'; +import { describe } from 'vitest'; + import { BigIntComparable } from './BigIntComparable.js'; +import { BigIntIntegral } from './BigIntIntegral.js'; describe('BigIntIntegral', () => { const subject = { @@ -45,11 +46,11 @@ describe('BigIntIntegral', () => { // ]); describeSigned(subject, { values: () => [ - { value: -2n, type: 'negative', sign: -1n, abs: 2n }, - { value: -1n, type: 'negative', sign: -1n, abs: 1n }, - { value: 0n, type: 'zero', sign: 0n, abs: 0n }, - { value: 1n, type: 'positive', sign: 1n, abs: 1n }, - { value: 2n, type: 'positive', sign: 1n, abs: 2n }, + { abs: 2n, sign: -1n, type: 'negative', value: -2n }, + { abs: 1n, sign: -1n, type: 'negative', value: -1n }, + { abs: 0n, sign: 0n, type: 'zero', value: 0n }, + { abs: 1n, sign: 1n, type: 'positive', value: 1n }, + { abs: 2n, sign: 1n, type: 'positive', value: 2n }, ], }); }); diff --git a/packages/num/src/BigInt/BigIntIntegral.ts b/packages/num/src/BigInt/BigIntIntegral.ts index d442d115b6..591868ff15 100644 --- a/packages/num/src/BigInt/BigIntIntegral.ts +++ b/packages/num/src/BigInt/BigIntIntegral.ts @@ -1,25 +1,27 @@ import type { Numeric } from '@w5s/core/dist/Numeric.js'; + import type { Int } from '../Int.js'; + import { fromInt } from './fromInt.js'; export const BigIntIntegral: Numeric.Integral = { - fromInt, - 'asInt': (self) => Number(self) as Int, - 'negate': (self) => -self, - 'zero': () => 0n, - 'isZero': (self) => self === 0n, - 'one': () => 1n, - 'isOne': (self) => self === 1n, - 'abs': (value) => (value < 0n ? -value : value), - 'sign': (value) => (value < 0n ? -1n : value > 0n ? 1n : 0n), - 'isNegative': (self) => self < 0n, - 'isPositive': (self) => self > 0n, - + '%': (base, divider) => base % divider, + '*': (left, right) => left * right, '+': (left, right) => left + right, '-': (left, right) => left - right, - '*': (left, right) => left * right, // '**': (left, right) => left ** right, '/': (base, divider) => base / divider, - '%': (base, divider) => base % divider, '/%': (base, divider) => [base / divider, base % divider], + 'abs': (value) => (value < 0n ? -value : value), + 'asInt': (self) => Number(self) as Int, + fromInt, + 'isNegative': (self) => self < 0n, + 'isOne': (self) => self === 1n, + + 'isPositive': (self) => self > 0n, + 'isZero': (self) => self === 0n, + 'negate': (self) => -self, + 'one': () => 1n, + 'sign': (value) => (value < 0n ? -1n : value > 0n ? 1n : 0n), + 'zero': () => 0n, }; diff --git a/packages/num/src/BigInt/compare.ts b/packages/num/src/BigInt/compare.ts index d2fccae111..7944d1f7cd 100644 --- a/packages/num/src/BigInt/compare.ts +++ b/packages/num/src/BigInt/compare.ts @@ -1,4 +1,5 @@ -import { primitive } from '@w5s/core/dist/Order/primitive.js'; import type { Order } from '@w5s/core'; +import { primitive } from '@w5s/core/dist/Order/primitive.js'; + export const compare: Order = primitive; diff --git a/packages/num/src/BigInt/format.spec.ts b/packages/num/src/BigInt/format.spec.ts index 712b358c04..b80f04048a 100644 --- a/packages/num/src/BigInt/format.spec.ts +++ b/packages/num/src/BigInt/format.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { format } from './format.js'; describe(format, () => { diff --git a/packages/num/src/BigInt/fromInt.spec.ts b/packages/num/src/BigInt/fromInt.spec.ts index c28b6f0b1c..393ee9f020 100644 --- a/packages/num/src/BigInt/fromInt.spec.ts +++ b/packages/num/src/BigInt/fromInt.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { Int } from '../Int.js'; import { fromInt } from './fromInt.js'; diff --git a/packages/num/src/BigInt/fromNumber.spec.ts b/packages/num/src/BigInt/fromNumber.spec.ts index d1275a5a81..a00d0460ce 100644 --- a/packages/num/src/BigInt/fromNumber.spec.ts +++ b/packages/num/src/BigInt/fromNumber.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { fromNumber } from './fromNumber.js'; describe(fromNumber, () => { diff --git a/packages/num/src/BigInt/fromNumber.ts b/packages/num/src/BigInt/fromNumber.ts index c6cda3814e..5a0c8c175f 100644 --- a/packages/num/src/BigInt/fromNumber.ts +++ b/packages/num/src/BigInt/fromNumber.ts @@ -1,4 +1,5 @@ import type { Option } from '@w5s/core'; + import { fromNumber as intFromNumber } from '../Int/fromNumber.js'; /** diff --git a/packages/num/src/BigInt/parse.spec.ts b/packages/num/src/BigInt/parse.spec.ts index a93c6a394b..bf0d62b861 100644 --- a/packages/num/src/BigInt/parse.spec.ts +++ b/packages/num/src/BigInt/parse.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { parse } from './parse.js'; describe(parse, () => { diff --git a/packages/num/src/Int.spec.ts b/packages/num/src/Int.spec.ts index 9bd9d1f233..3a64dddf93 100644 --- a/packages/num/src/Int.spec.ts +++ b/packages/num/src/Int.spec.ts @@ -1,12 +1,13 @@ -import { describe, it, expect } from 'vitest'; -import { describeType, describeCodec, describeAsString } from '@w5s/core/dist/Testing.js'; import { CodecError, Result } from '@w5s/core'; +import { describeAsString, describeCodec, describeType } from '@w5s/core/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { Int } from './Int.js'; -import { parse } from './Int/parse.js'; import { format } from './Int/format.js'; -import { IntIntegral } from './Int/IntIntegral.js'; -import { IntIndexable } from './Int/IntIndexable.js'; import { IntBounded } from './Int/IntBounded.js'; +import { IntIndexable } from './Int/IntIndexable.js'; +import { IntIntegral } from './Int/IntIntegral.js'; +import { parse } from './Int/parse.js'; describe('Int', () => { const minValue = Number.MIN_SAFE_INTEGER; @@ -23,26 +24,26 @@ describe('Int', () => { ); expect(IntFunctions).toEqual( expect.objectContaining({ - zero: expect.any(Function), isZero: expect.any(Function), + zero: expect.any(Function), }), ); expect(IntFunctions).toEqual( expect.objectContaining({ - parse, format, + parse, }), ); }); describeType(Int, () => ({ - typeName: 'Int', instances: [0 as Int, 1 as Int, 2 as Int, -1 as Int, minValue as Int, maxValue as Int], notInstances: ['1', 1.1, undefined, minValue - 1, maxValue + 1], + typeName: 'Int', })); describeCodec(Int, () => ({ decode: [ [1, Result.Ok(Int(1))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as Int', input: null }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as Int' }))], ], encode: [ [Int(0), 0], diff --git a/packages/num/src/Int.ts b/packages/num/src/Int.ts index 29c31e192d..af0a2517df 100644 --- a/packages/num/src/Int.ts +++ b/packages/num/src/Int.ts @@ -1,13 +1,15 @@ -import { Int as IntType } from '@w5s/core/dist/Type/Int.js'; -import { Callable } from '@w5s/core/dist/Callable.js'; import type * as Core from '@w5s/core'; + +import { Callable } from '@w5s/core/dist/Callable.js'; +import { Int as IntType } from '@w5s/core/dist/Type/Int.js'; + import { format } from './Int/format.js'; -import { parse } from './Int/parse.js'; import { fromNumber } from './Int/fromNumber.js'; -import { IntIntegral } from './Int/IntIntegral.js'; -import { IntIndexable } from './Int/IntIndexable.js'; -import { IntComparable } from './Int/IntComparable.js'; import { IntBounded } from './Int/IntBounded.js'; +import { IntComparable } from './Int/IntComparable.js'; +import { IntIndexable } from './Int/IntIndexable.js'; +import { IntIntegral } from './Int/IntIntegral.js'; +import { parse } from './Int/parse.js'; /** * Integer value @@ -28,22 +30,22 @@ export const Int = Callable({ ...IntBounded, ...IntIndexable, format, - parse, fromNumber, + parse, }); export namespace Int { export interface Module extends - Core.Comparable, Core.Numeric.Add, + Core.Bounded, + Core.Numeric.CheckedDivide, + Core.Comparable, Core.Numeric.Multiply, - Core.Numeric.Remainder, - Core.Numeric.Subtract, + Core.Numeric.Negate, Core.Numeric.Power, - Core.Numeric.CheckedDivide, + Core.Numeric.Remainder, Core.Numeric.Signed, - Core.Numeric.Negate, - Core.Numeric.Zero, - Core.Bounded {} + Core.Numeric.Subtract, + Core.Numeric.Zero {} } diff --git a/packages/num/src/Int/IntBounded.spec.ts b/packages/num/src/Int/IntBounded.spec.ts index e87658be3a..dfd071ed95 100644 --- a/packages/num/src/Int/IntBounded.spec.ts +++ b/packages/num/src/Int/IntBounded.spec.ts @@ -1,10 +1,11 @@ -import { describe } from 'vitest'; import { describeBounded } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { IntBounded } from './IntBounded.js'; describe('IntBounded', () => { describeBounded(IntBounded, { - minValue: Number.MIN_SAFE_INTEGER, maxValue: Number.MAX_SAFE_INTEGER, + minValue: Number.MIN_SAFE_INTEGER, }); }); diff --git a/packages/num/src/Int/IntBounded.ts b/packages/num/src/Int/IntBounded.ts index 1b35ce7e19..d010a855ed 100644 --- a/packages/num/src/Int/IntBounded.ts +++ b/packages/num/src/Int/IntBounded.ts @@ -1,4 +1,5 @@ import type { Bounded } from '@w5s/core'; + import type { Int } from '../Int.js'; export const IntBounded: Bounded = { diff --git a/packages/num/src/Int/IntComparable.spec.ts b/packages/num/src/Int/IntComparable.spec.ts index beb1f88a88..f7c36ad9a5 100644 --- a/packages/num/src/Int/IntComparable.spec.ts +++ b/packages/num/src/Int/IntComparable.spec.ts @@ -1,15 +1,16 @@ -import { describe } from 'vitest'; import { describeComparable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Int } from '../Int.js'; import { IntComparable } from './IntComparable.js'; describe('IntComparable', () => { describeComparable(IntComparable, { - ordered: () => [Int(-1), Int(0), Int(1)], equivalent: () => [ [Int(0), Int(0)], [Int(1), Int(1)], [Int(-1), Int(-1)], ], + ordered: () => [Int(-1), Int(0), Int(1)], }); }); diff --git a/packages/num/src/Int/IntComparable.ts b/packages/num/src/Int/IntComparable.ts index 9481fed341..8f81be3cb2 100644 --- a/packages/num/src/Int/IntComparable.ts +++ b/packages/num/src/Int/IntComparable.ts @@ -1,5 +1,7 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; + import type { Int } from '../Int.js'; + import { compare } from './compare.js'; export const IntComparable = Comparable({ diff --git a/packages/num/src/Int/IntIndexable.spec.ts b/packages/num/src/Int/IntIndexable.spec.ts index 6a8b72354e..b1bed9c3c0 100644 --- a/packages/num/src/Int/IntIndexable.spec.ts +++ b/packages/num/src/Int/IntIndexable.spec.ts @@ -1,7 +1,8 @@ -import { describe } from 'vitest'; import { describeIndexable } from '@w5s/core/dist/Testing.js'; -import { IntIndexable } from './IntIndexable.js'; +import { describe } from 'vitest'; + import { Int } from '../Int.js'; +import { IntIndexable } from './IntIndexable.js'; describe('IntIndexable', () => { describeIndexable(IntIndexable, { diff --git a/packages/num/src/Int/IntIndexable.ts b/packages/num/src/Int/IntIndexable.ts index f95e32e12b..9533c9d499 100644 --- a/packages/num/src/Int/IntIndexable.ts +++ b/packages/num/src/Int/IntIndexable.ts @@ -1,8 +1,9 @@ import { Indexable } from '@w5s/core/dist/Indexable.js'; + import type { Int } from '../Int.js'; export const IntIndexable = Indexable({ - indexType: 'number', at: (index) => index, indexOf: (value) => value, + indexType: 'number', }); diff --git a/packages/num/src/Int/IntIntegral.spec.ts b/packages/num/src/Int/IntIntegral.spec.ts index 8fdf28c7c8..d470d8ae49 100644 --- a/packages/num/src/Int/IntIntegral.spec.ts +++ b/packages/num/src/Int/IntIntegral.spec.ts @@ -1,8 +1,9 @@ -import { describe } from 'vitest'; import { describeNegate, describeNumeric, describeSigned, describeZero } from '@w5s/core/dist/Testing.js'; -import { IntIntegral } from './IntIntegral.js'; +import { describe } from 'vitest'; + import { Int } from '../Int.js'; import { IntComparable } from './IntComparable.js'; +import { IntIntegral } from './IntIntegral.js'; describe('IntIntegral', () => { describeZero(IntIntegral, { @@ -22,11 +23,11 @@ describe('IntIntegral', () => { { ...IntComparable, ...IntIntegral }, { values: () => [ - { value: -2, type: 'negative', sign: -1, abs: 2 }, - { value: -1, type: 'negative', sign: -1, abs: 1 }, - { value: 0, type: 'zero', sign: 0, abs: 0 }, - { value: 1, type: 'positive', sign: 1, abs: 1 }, - { value: 2, type: 'positive', sign: 1, abs: 2 }, + { abs: 2, sign: -1, type: 'negative', value: -2 }, + { abs: 1, sign: -1, type: 'negative', value: -1 }, + { abs: 0, sign: 0, type: 'zero', value: 0 }, + { abs: 1, sign: 1, type: 'positive', value: 1 }, + { abs: 2, sign: 1, type: 'positive', value: 2 }, ], }, ); diff --git a/packages/num/src/Int/IntIntegral.ts b/packages/num/src/Int/IntIntegral.ts index 8032089007..658c99863e 100644 --- a/packages/num/src/Int/IntIntegral.ts +++ b/packages/num/src/Int/IntIntegral.ts @@ -1,5 +1,7 @@ import type { Integral } from '@w5s/core/dist/Numeric/Integral.js'; + import type { Int } from '../Int.js'; + import { fromNumber } from './fromNumber.js'; const unchecked = @@ -11,21 +13,21 @@ const quot = unchecked((base, divider) => base / divider); const mod = unchecked((base, divider) => base % divider); export const IntIntegral: Integral = { + '%': mod, + '*': unchecked((left, right) => left * right), '+': unchecked((left, right) => left + right), '-': unchecked((left, right) => left - right), - '*': unchecked((left, right) => left * right), - '%': mod, '/': quot, '/%': (base, divider) => [quot(base, divider), mod(base, divider)], - 'fromInt': (self) => self, + 'abs': Math.abs as Integral['abs'], 'asInt': (self) => self, - 'negate': (self) => -(self as number) as Int, - 'zero': () => 0 as Int, - 'isZero': (self) => self === 0, - 'one': () => 1 as Int, - 'isOne': (self) => self === 1, + 'fromInt': (self) => self, 'isNegative': (self) => self < 0, + 'isOne': (self) => self === 1, 'isPositive': (self) => self > 0, - 'abs': Math.abs as Integral['abs'], + 'isZero': (self) => self === 0, + 'negate': (self) => -(self as number) as Int, + 'one': () => 1 as Int, 'sign': Math.sign as Integral['sign'], + 'zero': () => 0 as Int, }; diff --git a/packages/num/src/Int/compare.ts b/packages/num/src/Int/compare.ts index 6f031096fb..17fb1d97e9 100644 --- a/packages/num/src/Int/compare.ts +++ b/packages/num/src/Int/compare.ts @@ -1,5 +1,7 @@ -import { primitive } from '@w5s/core/dist/Order/primitive.js'; import type { Order } from '@w5s/core'; + +import { primitive } from '@w5s/core/dist/Order/primitive.js'; + import type { Int } from '../Int.js'; export const compare: Order = primitive; diff --git a/packages/num/src/Int/format.spec.ts b/packages/num/src/Int/format.spec.ts index dd2354493e..11a61f2eae 100644 --- a/packages/num/src/Int/format.spec.ts +++ b/packages/num/src/Int/format.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { format } from './format.js'; + import { Int } from '../Int.js'; +import { format } from './format.js'; describe(format, () => { it('should return a valid string representation', () => { diff --git a/packages/num/src/Int/format.ts b/packages/num/src/Int/format.ts index 7aeab10e5e..904ff32302 100644 --- a/packages/num/src/Int/format.ts +++ b/packages/num/src/Int/format.ts @@ -1,4 +1,5 @@ import type { Radix36 } from '@w5s/core-type'; + import type { Int } from '../Int.js'; /** diff --git a/packages/num/src/Int/fromNumber.spec.ts b/packages/num/src/Int/fromNumber.spec.ts index 3ad56242c1..73885f7d42 100644 --- a/packages/num/src/Int/fromNumber.spec.ts +++ b/packages/num/src/Int/fromNumber.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { fromNumber } from './fromNumber.js'; describe(fromNumber, () => { - const { MIN_SAFE_INTEGER: minValue, MAX_SAFE_INTEGER: maxValue } = Number; + const { MAX_SAFE_INTEGER: maxValue, MIN_SAFE_INTEGER: minValue } = Number; it('should return identity for 0', () => { expect(fromNumber(0)).toBe(0); diff --git a/packages/num/src/Int/fromNumber.ts b/packages/num/src/Int/fromNumber.ts index 7a68a1a474..749c752518 100644 --- a/packages/num/src/Int/fromNumber.ts +++ b/packages/num/src/Int/fromNumber.ts @@ -1,4 +1,5 @@ import type { Option } from '@w5s/core'; + import type { Int } from '../Int.js'; /** diff --git a/packages/num/src/Int/parse.spec.ts b/packages/num/src/Int/parse.spec.ts index 6691da4487..17146a45d6 100644 --- a/packages/num/src/Int/parse.spec.ts +++ b/packages/num/src/Int/parse.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it } from 'vitest'; import { Option } from '@w5s/core'; -import { parse } from './parse.js'; +import { describe, expect, it } from 'vitest'; + import { IntBounded } from '../Int/IntBounded.js'; +import { parse } from './parse.js'; describe(parse, () => { it('should return a valid parsed integer when radix is omitted', () => { diff --git a/packages/num/src/Int/parse.ts b/packages/num/src/Int/parse.ts index b5769bf5fa..62c5d22273 100644 --- a/packages/num/src/Int/parse.ts +++ b/packages/num/src/Int/parse.ts @@ -1,6 +1,8 @@ -import type { Option } from '@w5s/core/dist/Option.js'; import type { Radix36 } from '@w5s/core-type'; +import type { Option } from '@w5s/core/dist/Option.js'; + import type { Int } from '../Int.js'; + import { fromNumber } from './fromNumber.js'; /** diff --git a/packages/num/src/Number.spec.ts b/packages/num/src/Number.spec.ts index 1bff381708..7bad0b8977 100644 --- a/packages/num/src/Number.spec.ts +++ b/packages/num/src/Number.spec.ts @@ -1,29 +1,30 @@ -import { describe, it, expect } from 'vitest'; import { Type } from '@w5s/core/dist/Type.js'; +import { describe, expect, it } from 'vitest'; + import { Number } from './Number.js'; -import { parse } from './Number/parse.js'; import { format } from './Number/format.js'; +import { parse } from './Number/parse.js'; import { NumberConversion } from './NumberConversion.js'; describe('Number', () => { it('is an alias to functions', () => { expect(Number).toEqual( expect.objectContaining({ - 'compare': expect.any(Function), - '==': expect.any(Function), - '+': expect.any(Function), - '*': expect.any(Function), '%': expect.any(Function), - '-': expect.any(Function), + '*': expect.any(Function), '**': expect.any(Function), + '+': expect.any(Function), + '-': expect.any(Function), + '==': expect.any(Function), + 'compare': expect.any(Function), }), ); expect(Number).toEqual( expect.objectContaining({ - sign: expect.any(Function), abs: expect.any(Function), isNegative: expect.any(Function), isPositive: expect.any(Function), + sign: expect.any(Function), }), ); expect(Number).toEqual(expect.objectContaining(NumberConversion.Bounded())); @@ -41,8 +42,8 @@ describe('Number', () => { expect(Number).toEqual(expect.objectContaining(Type.number)); expect(Number).toEqual( expect.objectContaining({ - parse, format, + parse, }), ); }); diff --git a/packages/num/src/Number.ts b/packages/num/src/Number.ts index 84e8cfad67..93ef3e9578 100644 --- a/packages/num/src/Number.ts +++ b/packages/num/src/Number.ts @@ -1,6 +1,7 @@ import { number as NumberType } from '@w5s/core/dist/Type/number.js'; -import { parse } from './Number/parse.js'; + import { format } from './Number/format.js'; +import { parse } from './Number/parse.js'; import { NumberConversion } from './NumberConversion.js'; /** @@ -18,6 +19,6 @@ import { NumberConversion } from './NumberConversion.js'; export const Number = { ...NumberType, ...NumberConversion(), - parse, format, + parse, }; diff --git a/packages/num/src/Number/compare.ts b/packages/num/src/Number/compare.ts index 924145362e..52c2f7a0f4 100644 --- a/packages/num/src/Number/compare.ts +++ b/packages/num/src/Number/compare.ts @@ -1,4 +1,5 @@ -import { primitive } from '@w5s/core/dist/Order/primitive.js'; import type { Order } from '@w5s/core'; +import { primitive } from '@w5s/core/dist/Order/primitive.js'; + export const compare: Order = primitive; diff --git a/packages/num/src/Number/format.spec.ts b/packages/num/src/Number/format.spec.ts index 7671436c69..e7f12bf478 100644 --- a/packages/num/src/Number/format.spec.ts +++ b/packages/num/src/Number/format.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { format } from './format.js'; describe(format, () => { diff --git a/packages/num/src/Number/parse.spec.ts b/packages/num/src/Number/parse.spec.ts index 0a2e0deb20..ef1983104d 100644 --- a/packages/num/src/Number/parse.spec.ts +++ b/packages/num/src/Number/parse.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Option } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { parse } from './parse.js'; describe(parse, () => { diff --git a/packages/num/src/NumberConversion.spec.ts b/packages/num/src/NumberConversion.spec.ts index 90ce9efc3d..ece1cdb7f9 100644 --- a/packages/num/src/NumberConversion.spec.ts +++ b/packages/num/src/NumberConversion.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { NumberConversion } from './NumberConversion.js'; import { Bounded } from './NumberConversion/Bounded.js'; import { Comparable } from './NumberConversion/Comparable.js'; @@ -29,13 +30,13 @@ describe('NumberConversion', () => { it('should create a default number conversion module', () => { expect(NumberConversion()).toEqual( expect.objectContaining({ - '+': expect.any(Function), '*': expect.any(Function), + '+': expect.any(Function), + 'compare': expect.any(Function), + 'maxValue': expect.any(Number), + 'minValue': expect.any(Number), 'negate': expect.any(Function), 'zero': expect.any(Function), - 'minValue': expect.any(Number), - 'maxValue': expect.any(Number), - 'compare': expect.any(Function), }), ); }); diff --git a/packages/num/src/NumberConversion.ts b/packages/num/src/NumberConversion.ts index bcd2f5a45b..991fc16ac4 100644 --- a/packages/num/src/NumberConversion.ts +++ b/packages/num/src/NumberConversion.ts @@ -1,6 +1,9 @@ import type * as Core from '@w5s/core'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; + +import { defaultConversion } from './internal/defaultConversion.js'; import { Add } from './NumberConversion/Add.js'; import { Bounded } from './NumberConversion/Bounded.js'; import { Comparable } from './NumberConversion/Comparable.js'; @@ -11,22 +14,21 @@ import { Remainder } from './NumberConversion/Remainder.js'; import { Signed } from './NumberConversion/Signed.js'; import { Subtract } from './NumberConversion/Subtract.js'; import { Zero } from './NumberConversion/Zero.js'; -import { defaultConversion } from './internal/defaultConversion.js'; export interface NumberConversion { /** - * Converts a number value to type T + * Converts a value of type T to a number * - * @param value A number value + * @param value A value of type T */ - fromNumber(this: void, value: number): T; + asNumber(this: void, value: T): number; /** - * Converts a value of type T to a number + * Converts a number value to type T * - * @param value A value of type T + * @param value A number value */ - asNumber(this: void, value: T): number; + fromNumber(this: void, value: number): T; } function call(): NumberConversion.Module; @@ -51,7 +53,6 @@ function call(BaseType?: NumberConversion): NumberConversion.Module { * @namespace */ export const NumberConversion = Callable({ - [Symbol.call]: call, Add, Bounded, Comparable, @@ -61,19 +62,20 @@ export const NumberConversion = Callable({ Remainder, Signed, Subtract, + [Symbol.call]: call, Zero, }); export namespace NumberConversion { export interface Module extends - Core.Comparable, Core.Numeric.Add, + Core.Bounded, + Core.Comparable, Core.Numeric.Multiply, - Core.Numeric.Remainder, - Core.Numeric.Subtract, + Core.Numeric.Negate, Core.Numeric.Power, + Core.Numeric.Remainder, Core.Numeric.Signed, - Core.Numeric.Negate, - Core.Numeric.Zero, - Core.Bounded {} + Core.Numeric.Subtract, + Core.Numeric.Zero {} } diff --git a/packages/num/src/NumberConversion/Add.spec.ts b/packages/num/src/NumberConversion/Add.spec.ts index fb1ab7625a..58813bcfc1 100644 --- a/packages/num/src/NumberConversion/Add.spec.ts +++ b/packages/num/src/NumberConversion/Add.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeAdd } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Add } from './Add.js'; diff --git a/packages/num/src/NumberConversion/Add.ts b/packages/num/src/NumberConversion/Add.ts index 1c7cbcc2bb..4230bdd237 100644 --- a/packages/num/src/NumberConversion/Add.ts +++ b/packages/num/src/NumberConversion/Add.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; import { uncheckedOperator } from '../internal/uncheckedOperator.js'; diff --git a/packages/num/src/NumberConversion/Bounded.spec.ts b/packages/num/src/NumberConversion/Bounded.spec.ts index cee82cfbf7..18d2f1f582 100644 --- a/packages/num/src/NumberConversion/Bounded.spec.ts +++ b/packages/num/src/NumberConversion/Bounded.spec.ts @@ -1,19 +1,20 @@ -import { describe } from 'vitest'; import { describeBounded } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Bounded } from './Bounded.js'; describe(Bounded, () => { describeBounded(Bounded(), { - minValue: Number.MIN_VALUE, maxValue: Number.MAX_VALUE, + minValue: Number.MIN_VALUE, }); describeBounded( Bounded({ fromNumber: (v) => ({ custom: true, value: v }), }), { - minValue: { custom: true, value: Number.MIN_VALUE }, maxValue: { custom: true, value: Number.MAX_VALUE }, + minValue: { custom: true, value: Number.MIN_VALUE }, }, ); }); diff --git a/packages/num/src/NumberConversion/Bounded.ts b/packages/num/src/NumberConversion/Bounded.ts index 84cae98139..c49cc754ee 100644 --- a/packages/num/src/NumberConversion/Bounded.ts +++ b/packages/num/src/NumberConversion/Bounded.ts @@ -1,5 +1,7 @@ import type { Bounded } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; /** diff --git a/packages/num/src/NumberConversion/Comparable.spec.ts b/packages/num/src/NumberConversion/Comparable.spec.ts index 5d1fc04d96..0a69e184a7 100644 --- a/packages/num/src/NumberConversion/Comparable.spec.ts +++ b/packages/num/src/NumberConversion/Comparable.spec.ts @@ -1,27 +1,23 @@ -import { describe } from 'vitest'; import { describeComparable } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Int } from '../Int.js'; import { Comparable } from './Comparable.js'; describe(Comparable, () => { describeComparable(Comparable(), { - ordered: () => [Int(-1), Int(0), Int(1)], equivalent: () => [ [Int(0), Int(0)], [Int(1), Int(1)], [Int(-1), Int(-1)], ], + ordered: () => [Int(-1), Int(0), Int(1)], }); describeComparable( Comparable({ asNumber: (v: { custom: true; value: number }) => v.value, }), { - ordered: () => [ - { custom: true, value: -1 }, - { custom: true, value: 0 }, - { custom: true, value: 1 }, - ], equivalent: () => [ [ { custom: true, value: 0 }, @@ -36,6 +32,11 @@ describe(Comparable, () => { { custom: true, value: -1 }, ], ], + ordered: () => [ + { custom: true, value: -1 }, + { custom: true, value: 0 }, + { custom: true, value: 1 }, + ], }, ); }); diff --git a/packages/num/src/NumberConversion/Comparable.ts b/packages/num/src/NumberConversion/Comparable.ts index 8c596ca4c0..4df3f3b99e 100644 --- a/packages/num/src/NumberConversion/Comparable.ts +++ b/packages/num/src/NumberConversion/Comparable.ts @@ -1,7 +1,9 @@ import { Comparable as CoreComparable } from '@w5s/core/dist/Comparable.js'; -import { compare } from '../Number/compare.js'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; +import { compare } from '../Number/compare.js'; export function Comparable(): CoreComparable; export function Comparable(BaseType: Pick, 'asNumber'>): CoreComparable; diff --git a/packages/num/src/NumberConversion/Multiply.spec.ts b/packages/num/src/NumberConversion/Multiply.spec.ts index 06cd7ada0c..45b2197737 100644 --- a/packages/num/src/NumberConversion/Multiply.spec.ts +++ b/packages/num/src/NumberConversion/Multiply.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeMultiply } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Multiply } from './Multiply.js'; diff --git a/packages/num/src/NumberConversion/Multiply.ts b/packages/num/src/NumberConversion/Multiply.ts index 7f3aa307c4..f459115539 100644 --- a/packages/num/src/NumberConversion/Multiply.ts +++ b/packages/num/src/NumberConversion/Multiply.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; import { uncheckedOperator } from '../internal/uncheckedOperator.js'; diff --git a/packages/num/src/NumberConversion/Negate.spec.ts b/packages/num/src/NumberConversion/Negate.spec.ts index 18a62f0d55..512bedc35d 100644 --- a/packages/num/src/NumberConversion/Negate.spec.ts +++ b/packages/num/src/NumberConversion/Negate.spec.ts @@ -1,7 +1,8 @@ -import { describe } from 'vitest'; import { describeNegate } from '@w5s/core/dist/Testing.js'; -import { Negate } from './Negate.js'; +import { describe } from 'vitest'; + import { Comparable } from './Comparable.js'; +import { Negate } from './Negate.js'; describe(Negate, () => { describeNegate( @@ -16,8 +17,8 @@ describe(Negate, () => { ); const CustomConversion = { - fromNumber: (v: number) => ({ custom: true, value: v }), asNumber: (v: { custom: true; value: number }) => v.value, + fromNumber: (v: number) => ({ custom: true, value: v }), }; describeNegate( { ...Negate(CustomConversion), ...Comparable(CustomConversion) }, diff --git a/packages/num/src/NumberConversion/Negate.ts b/packages/num/src/NumberConversion/Negate.ts index aaea916e52..9c0a670f2f 100644 --- a/packages/num/src/NumberConversion/Negate.ts +++ b/packages/num/src/NumberConversion/Negate.ts @@ -1,11 +1,13 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; export function Negate(): Numeric.Negate; export function Negate(BaseType: NumberConversion): Numeric.Negate; export function Negate(BaseType?: NumberConversion): Numeric.Negate { - const { fromNumber, asNumber } = BaseType ?? defaultConversion(); + const { asNumber, fromNumber } = BaseType ?? defaultConversion(); return { negate(self) { // @ts-ignore we know asNumber(self) is number diff --git a/packages/num/src/NumberConversion/Power.spec.ts b/packages/num/src/NumberConversion/Power.spec.ts index dfa0738e82..fa57a5559f 100644 --- a/packages/num/src/NumberConversion/Power.spec.ts +++ b/packages/num/src/NumberConversion/Power.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describePower } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Power } from './Power.js'; diff --git a/packages/num/src/NumberConversion/Power.ts b/packages/num/src/NumberConversion/Power.ts index ebe4328014..f7ee05a9ad 100644 --- a/packages/num/src/NumberConversion/Power.ts +++ b/packages/num/src/NumberConversion/Power.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; import { uncheckedOperator } from '../internal/uncheckedOperator.js'; diff --git a/packages/num/src/NumberConversion/Remainder.spec.ts b/packages/num/src/NumberConversion/Remainder.spec.ts index 34c2a9d18a..7e845e73e0 100644 --- a/packages/num/src/NumberConversion/Remainder.spec.ts +++ b/packages/num/src/NumberConversion/Remainder.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeRemainder } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Remainder } from './Remainder.js'; diff --git a/packages/num/src/NumberConversion/Remainder.ts b/packages/num/src/NumberConversion/Remainder.ts index 0b1efc1c26..cb8a0f5462 100644 --- a/packages/num/src/NumberConversion/Remainder.ts +++ b/packages/num/src/NumberConversion/Remainder.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; import { uncheckedOperator } from '../internal/uncheckedOperator.js'; diff --git a/packages/num/src/NumberConversion/Signed.spec.ts b/packages/num/src/NumberConversion/Signed.spec.ts index 19a9acc2bc..e03b9cc50a 100644 --- a/packages/num/src/NumberConversion/Signed.spec.ts +++ b/packages/num/src/NumberConversion/Signed.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeSigned } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Signed } from './Signed.js'; @@ -8,52 +9,52 @@ describe(Signed, () => { { ...NumberConversion.Comparable(), ...Signed() }, { values: () => [ - { value: -2, type: 'negative', sign: -1, abs: 2 }, - { value: -1, type: 'negative', sign: -1, abs: 1 }, - { value: 0, type: 'zero', sign: 0, abs: 0 }, - { value: 1, type: 'positive', sign: 1, abs: 1 }, - { value: 2, type: 'positive', sign: 1, abs: 2 }, + { abs: 2, sign: -1, type: 'negative', value: -2 }, + { abs: 1, sign: -1, type: 'negative', value: -1 }, + { abs: 0, sign: 0, type: 'zero', value: 0 }, + { abs: 1, sign: 1, type: 'positive', value: 1 }, + { abs: 2, sign: 1, type: 'positive', value: 2 }, ], }, ); const CustomConversion = { - fromNumber: (v: number) => ({ custom: true, value: v }), asNumber: (v: { custom: true; value: number }) => v.value, + fromNumber: (v: number) => ({ custom: true, value: v }), }; describeSigned( { ...NumberConversion.Comparable(CustomConversion), ...Signed(CustomConversion) }, { values: () => [ { - value: CustomConversion.fromNumber(-2), - type: 'negative', - sign: CustomConversion.fromNumber(-1), abs: CustomConversion.fromNumber(2), + sign: CustomConversion.fromNumber(-1), + type: 'negative', + value: CustomConversion.fromNumber(-2), }, { - value: CustomConversion.fromNumber(-1), - type: 'negative', - sign: CustomConversion.fromNumber(-1), abs: CustomConversion.fromNumber(1), + sign: CustomConversion.fromNumber(-1), + type: 'negative', + value: CustomConversion.fromNumber(-1), }, { - value: CustomConversion.fromNumber(0), - type: 'zero', - sign: CustomConversion.fromNumber(0), abs: CustomConversion.fromNumber(0), + sign: CustomConversion.fromNumber(0), + type: 'zero', + value: CustomConversion.fromNumber(0), }, { - value: CustomConversion.fromNumber(1), - type: 'positive', - sign: CustomConversion.fromNumber(1), abs: CustomConversion.fromNumber(1), + sign: CustomConversion.fromNumber(1), + type: 'positive', + value: CustomConversion.fromNumber(1), }, { - value: CustomConversion.fromNumber(2), - type: 'positive', - sign: CustomConversion.fromNumber(1), abs: CustomConversion.fromNumber(2), + sign: CustomConversion.fromNumber(1), + type: 'positive', + value: CustomConversion.fromNumber(2), }, ], }, diff --git a/packages/num/src/NumberConversion/Signed.ts b/packages/num/src/NumberConversion/Signed.ts index c91c421425..3113ab9b99 100644 --- a/packages/num/src/NumberConversion/Signed.ts +++ b/packages/num/src/NumberConversion/Signed.ts @@ -1,15 +1,17 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; export function Signed(): Numeric.Signed; export function Signed(BaseType: NumberConversion): Numeric.Signed; export function Signed(BaseType?: NumberConversion): Numeric.Signed { - const { fromNumber, asNumber } = BaseType ?? defaultConversion(); + const { asNumber, fromNumber } = BaseType ?? defaultConversion(); return { abs: (self) => fromNumber(Math.abs(asNumber(self))), - sign: (self) => fromNumber(Math.sign(asNumber(self))), isNegative: (self) => asNumber(self) < 0, isPositive: (self) => asNumber(self) > 0, + sign: (self) => fromNumber(Math.sign(asNumber(self))), }; } diff --git a/packages/num/src/NumberConversion/Subtract.spec.ts b/packages/num/src/NumberConversion/Subtract.spec.ts index c450014704..6cca5b1bc0 100644 --- a/packages/num/src/NumberConversion/Subtract.spec.ts +++ b/packages/num/src/NumberConversion/Subtract.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeSubtract } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { NumberConversion } from '../NumberConversion.js'; import { Subtract } from './Subtract.js'; diff --git a/packages/num/src/NumberConversion/Subtract.ts b/packages/num/src/NumberConversion/Subtract.ts index 65d1dcbbad..bde062be8f 100644 --- a/packages/num/src/NumberConversion/Subtract.ts +++ b/packages/num/src/NumberConversion/Subtract.ts @@ -1,5 +1,7 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; import { uncheckedOperator } from '../internal/uncheckedOperator.js'; diff --git a/packages/num/src/NumberConversion/Zero.spec.ts b/packages/num/src/NumberConversion/Zero.spec.ts index 216512b904..13976483f0 100644 --- a/packages/num/src/NumberConversion/Zero.spec.ts +++ b/packages/num/src/NumberConversion/Zero.spec.ts @@ -1,5 +1,6 @@ -import { describe } from 'vitest'; import { describeZero } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Zero } from './Zero.js'; describe(Zero, () => { @@ -7,8 +8,8 @@ describe(Zero, () => { nonZero: () => [1, 2, -1], }); const CustomConversion = { - fromNumber: (v: number) => ({ custom: true, value: v }), asNumber: (v: { custom: true; value: number }) => v.value, + fromNumber: (v: number) => ({ custom: true, value: v }), }; describeZero(Zero(CustomConversion), { nonZero: () => [ diff --git a/packages/num/src/NumberConversion/Zero.ts b/packages/num/src/NumberConversion/Zero.ts index efaebae644..c211301e83 100644 --- a/packages/num/src/NumberConversion/Zero.ts +++ b/packages/num/src/NumberConversion/Zero.ts @@ -1,13 +1,15 @@ import type { Numeric } from '@w5s/core'; + import type { NumberConversion } from '../NumberConversion.js'; + import { defaultConversion } from '../internal/defaultConversion.js'; export function Zero(): Numeric.Zero; export function Zero(BaseType: NumberConversion): Numeric.Zero; export function Zero(BaseType?: NumberConversion): Numeric.Zero { - const { fromNumber, asNumber } = BaseType ?? defaultConversion(); + const { asNumber, fromNumber } = BaseType ?? defaultConversion(); return { - zero: () => fromNumber(0), isZero: (self: T) => asNumber(self) === 0, + zero: () => fromNumber(0), }; } diff --git a/packages/num/src/RoundingMode.spec.ts b/packages/num/src/RoundingMode.spec.ts index 801ac47d20..fac692fcf6 100644 --- a/packages/num/src/RoundingMode.spec.ts +++ b/packages/num/src/RoundingMode.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, expectTypeOf } from 'vitest'; +import { describe, expect, expectTypeOf, it } from 'vitest'; + import { RoundingMode } from './RoundingMode.js'; describe('RoundingMode', () => { diff --git a/packages/num/src/RoundingMode.ts b/packages/num/src/RoundingMode.ts index 49733edb08..97ceaa0e15 100644 --- a/packages/num/src/RoundingMode.ts +++ b/packages/num/src/RoundingMode.ts @@ -1,7 +1,20 @@ import { Enum } from '@w5s/core'; export const RoundingMode = Enum.define({ - typeName: 'RoundingMode', + /** + * Towards +∞ + * + * @example + * 5.5 → 6.0 + * 2.5 → 3.0 + * 1.6 → 2.0 + * 1.1 → 2.0 + * -1.1 → -1.0 + * -1.6 → -1.0 + * -2.5 → -2.0 + * -5.5 → -5.0 + */ + Ceil: 'ceil', /** * Always round away from zero @@ -19,49 +32,49 @@ export const RoundingMode = Enum.define({ Expand: 'expand', /** - * Always round towards zero + * Towards -∞ * * @example * 5.5 → 5.0 * 2.5 → 2.0 * 1.6 → 1.0 * 1.1 → 1.0 - * -1.1 → -1.0 - * -1.6 → -1.0 - * -2.5 → -2.0 - * -5.5 → -5.0 + * -1.1 → -2.0 + * -1.6 → -2.0 + * -2.5 → -3.0 + * -5.5 → -6.0 */ - Trunc: 'trunc', + Floor: 'floor', /** - * Towards +∞ + * Round to ‘nearest neighbor’, or towards +∞ if ending decimal is 5 * * @example * 5.5 → 6.0 * 2.5 → 3.0 * 1.6 → 2.0 - * 1.1 → 2.0 + * 1.1 → 1.0 * -1.1 → -1.0 - * -1.6 → -1.0 + * -1.6 → -2.0 * -2.5 → -2.0 * -5.5 → -5.0 */ - Ceil: 'ceil', + HalfCeil: 'halfCeil', /** - * Towards -∞ + * Round to ‘nearest neighbor’, if equidistant, round towards nearest even digit * * @example - * 5.5 → 5.0 + * 5.5 → 6.0 * 2.5 → 2.0 - * 1.6 → 1.0 + * 1.6 → 2.0 * 1.1 → 1.0 - * -1.1 → -2.0 + * -1.1 → -1.0 * -1.6 → -2.0 - * -2.5 → -3.0 + * -2.5 → -2.0 * -5.5 → -6.0 */ - Floor: 'floor', + HalfEven: 'halfEven', /** * Round to ‘nearest neighbor’, or up if ending decimal is 5 @@ -79,7 +92,7 @@ export const RoundingMode = Enum.define({ HalfExpand: 'halfExpand', /** - * Round to ‘nearest neighbor’, or down if ending decimal is 5 + * Round to ‘nearest neighbor’, or towards -∞ if ending decimal is 5 * * @example * 5.5 → 5.0 @@ -88,32 +101,17 @@ export const RoundingMode = Enum.define({ * 1.1 → 1.0 * -1.1 → -1.0 * -1.6 → -2.0 - * -2.5 → -2.0 - * -5.5 → -5.0 - */ - HalfTrunc: 'halfTrunc', - - /** - * Round to ‘nearest neighbor’, if equidistant, round towards nearest even digit - * - * @example - * 5.5 → 6.0 - * 2.5 → 2.0 - * 1.6 → 2.0 - * 1.1 → 1.0 - * -1.1 → -1.0 - * -1.6 → -2.0 - * -2.5 → -2.0 + * -2.5 → -3.0 * -5.5 → -6.0 */ - HalfEven: 'halfEven', + HalfFloor: 'halfFloor', /** - * Round to ‘nearest neighbor’, or towards +∞ if ending decimal is 5 + * Round to ‘nearest neighbor’, or down if ending decimal is 5 * * @example - * 5.5 → 6.0 - * 2.5 → 3.0 + * 5.5 → 5.0 + * 2.5 → 2.0 * 1.6 → 2.0 * 1.1 → 1.0 * -1.1 → -1.0 @@ -121,21 +119,23 @@ export const RoundingMode = Enum.define({ * -2.5 → -2.0 * -5.5 → -5.0 */ - HalfCeil: 'halfCeil', + HalfTrunc: 'halfTrunc', /** - * Round to ‘nearest neighbor’, or towards -∞ if ending decimal is 5 + * Always round towards zero * * @example * 5.5 → 5.0 * 2.5 → 2.0 - * 1.6 → 2.0 + * 1.6 → 1.0 * 1.1 → 1.0 * -1.1 → -1.0 - * -1.6 → -2.0 - * -2.5 → -3.0 - * -5.5 → -6.0 + * -1.6 → -1.0 + * -2.5 → -2.0 + * -5.5 → -5.0 */ - HalfFloor: 'halfFloor', + Trunc: 'trunc', + + typeName: 'RoundingMode', }); export type RoundingMode = Enum.ValueOf; diff --git a/packages/num/src/__snapshots__/RoundingMode.spec.ts.snap b/packages/num/src/__snapshots__/RoundingMode.spec.ts.snap index e8be4a19d0..5e1dcf42c4 100644 --- a/packages/num/src/__snapshots__/RoundingMode.spec.ts.snap +++ b/packages/num/src/__snapshots__/RoundingMode.spec.ts.snap @@ -14,15 +14,15 @@ exports[`RoundingMode > has values 1`] = ` "__decode__": [Function], "__encode__": [Function], "__enumKeys__": [ - "Expand", - "Trunc", "Ceil", + "Expand", "Floor", - "HalfExpand", - "HalfTrunc", - "HalfEven", "HalfCeil", + "HalfEven", + "HalfExpand", "HalfFloor", + "HalfTrunc", + "Trunc", ], "__inspect__": undefined, "__schema__": [Function], diff --git a/packages/num/src/index.spec.ts b/packages/num/src/index.spec.ts index bb7d7cf7ea..433862121c 100644 --- a/packages/num/src/index.spec.ts +++ b/packages/num/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/num/src/internal/defaultConversion.ts b/packages/num/src/internal/defaultConversion.ts index 8e798cb338..7105275a3e 100644 --- a/packages/num/src/internal/defaultConversion.ts +++ b/packages/num/src/internal/defaultConversion.ts @@ -1,8 +1,8 @@ import type { NumberConversion } from '../NumberConversion.js'; const defaultConversionInstance: NumberConversion = { - fromNumber: (n: number) => n, asNumber: (n: number) => n, + fromNumber: (n: number) => n, }; export const defaultConversion = (): NumberConversion => defaultConversionInstance; diff --git a/packages/num/src/internal/uncheckedOperator.ts b/packages/num/src/internal/uncheckedOperator.ts index ce67f47f75..62caab9741 100644 --- a/packages/num/src/internal/uncheckedOperator.ts +++ b/packages/num/src/internal/uncheckedOperator.ts @@ -1,7 +1,7 @@ import type { NumberConversion } from '../NumberConversion.js'; export function uncheckedOperator(BaseType: NumberConversion) { - const { fromNumber, asNumber } = BaseType; + const { asNumber, fromNumber } = BaseType; return (fn: (left: number, right: number) => number) => (left: T, right: T): T => fromNumber(fn(asNumber(left), asNumber(right))); diff --git a/packages/object-id/example/.eslintrc.cjs b/packages/object-id/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/object-id/example/.eslintrc.cjs +++ b/packages/object-id/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/object-id/src/index.spec.ts b/packages/object-id/src/index.spec.ts index abfa4c6e09..c7f25098f5 100644 --- a/packages/object-id/src/index.spec.ts +++ b/packages/object-id/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/object-id/src/index.ts b/packages/object-id/src/index.ts index ec5885941b..a8381f5591 100644 --- a/packages/object-id/src/index.ts +++ b/packages/object-id/src/index.ts @@ -1,2 +1,2 @@ -export * from './objectId.js'; export * from './meta.js'; +export * from './objectId.js'; diff --git a/packages/object-id/src/internal/state.ts b/packages/object-id/src/internal/state.ts index 13bf4a10ad..774a5e5793 100644 --- a/packages/object-id/src/internal/state.ts +++ b/packages/object-id/src/internal/state.ts @@ -1,5 +1,7 @@ import { useGlobal } from '@w5s/global-storage'; + import type { ObjectId, ObjectIdParameter } from '../objectId.js'; + import { meta } from '../meta.js'; export interface ObjectIdState { diff --git a/packages/object-id/src/objectId.spec.ts b/packages/object-id/src/objectId.spec.ts index 5970c33a14..71d8598369 100644 --- a/packages/object-id/src/objectId.spec.ts +++ b/packages/object-id/src/objectId.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { objectId } from './objectId.js'; describe(objectId, () => { @@ -6,9 +7,9 @@ describe(objectId, () => { describe.each([ // Generator - { type: 'function', generate: (): object => ({ property: Math.random() }) }, - { type: 'symbol', generate: () => Symbol('foo') }, - { type: 'function', generate: () => function foo() {} }, + { generate: (): object => ({ property: Math.random() }), type: 'function' }, + { generate: () => Symbol('foo'), type: 'symbol' }, + { generate: () => function foo() {}, type: 'function' }, ])('with $function', ({ generate }) => { it('returns an integer value', () => { const value = generate(); diff --git a/packages/object-id/src/objectId.ts b/packages/object-id/src/objectId.ts index 1e8a297d1c..d17a7a7183 100644 --- a/packages/object-id/src/objectId.ts +++ b/packages/object-id/src/objectId.ts @@ -1,6 +1,12 @@ import type { ObjectLike, Tag } from '@w5s/core-type'; + import { state } from './internal/state.js'; +/** + * Type representing a unique object id + */ +export type ObjectId = number & Tag<'ObjectId'>; + /** * Type representing values that can have an {@link ObjectId} * @@ -8,11 +14,6 @@ import { state } from './internal/state.js'; */ export type ObjectIdParameter = ObjectLike; -/** - * Type representing a unique object id - */ -export type ObjectId = number & Tag<'ObjectId'>; - /** * Return a unique identifier for an object or function * diff --git a/packages/playground/src/Hash.spec.ts b/packages/playground/src/Hash.spec.ts index 196c20e9cf..c862848ae5 100644 --- a/packages/playground/src/Hash.spec.ts +++ b/packages/playground/src/Hash.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Int } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { Hash } from './Hash.js'; describe(`Hash`, () => { diff --git a/packages/playground/src/Hash.ts b/packages/playground/src/Hash.ts index b132da2b26..bf6807143a 100644 --- a/packages/playground/src/Hash.ts +++ b/packages/playground/src/Hash.ts @@ -9,10 +9,6 @@ const FALSE = 0x42_10_84_20 as Int; const UNDEFINED = 0x42_10_84_23 as Int; const NULL = 0x42_10_84_22 as Int; -function int32SMI(i32: number): Int { - return (((i32 >>> 1) & 0x40_00_00_00) | (i32 & 0xBF_FF_FF_FF)) as Int; -} - function hashNumber(value: number): Hash.Value { if (value !== value || value === Infinity) { return ZERO; @@ -49,6 +45,10 @@ function hashString(str: string): Hash.Value { return int32SMI(hashValue); } +function int32SMI(i32: number): Int { + return (((i32 >>> 1) & 0x40_00_00_00) | (i32 & 0xBF_FF_FF_FF)) as Int; +} + /** * @namespace */ @@ -79,7 +79,7 @@ export const Hash = { * @category Constructor * @param anyValue hashed value */ - from(anyValue: undefined | null | boolean | number | string): Hash.Value { + from(anyValue: boolean | null | number | string | undefined): Hash.Value { switch (typeof anyValue) { case 'boolean': { return anyValue ? TRUE : FALSE; @@ -87,12 +87,12 @@ export const Hash = { case 'number': { return hashNumber(anyValue); } - case 'undefined': { - return UNDEFINED; - } case 'string': { return hashString(anyValue); } + case 'undefined': { + return UNDEFINED; + } default: { if (anyValue === null) { return NULL; diff --git a/packages/playground/src/PartialFunction.ts b/packages/playground/src/PartialFunction.ts index d33d487956..593b705fc4 100644 --- a/packages/playground/src/PartialFunction.ts +++ b/packages/playground/src/PartialFunction.ts @@ -1,103 +1,99 @@ -type PartialApplyFunction

= (value: P) => R; - -export type PartialParameter = Parameters[0]; - +/* eslint-disable ts/unified-signatures */ export interface PartialFunctionLike { - readonly isDefinedAt: (anyValue: unknown) => anyValue is PartialParameter; readonly apply: F; + readonly isDefinedAt: (anyValue: unknown) => anyValue is PartialParameter; } +export type PartialParameter = Parameters[0]; + +type PartialApplyFunction

= (value: P) => R; + export class PartialFunction implements PartialFunctionLike { - readonly isDefinedAt: (anyValue: unknown) => anyValue is PartialParameter; readonly apply: F; + readonly isDefinedAt: (anyValue: unknown) => anyValue is PartialParameter; constructor(properties: PartialFunctionLike) { this.isDefinedAt = properties.isDefinedAt; this.apply = properties.apply; } - orElse(elseFn: PartialFunctionLike): PartialFunction { - return orElse(this, elseFn); - } - andThen>>( thenFn: FThen, ): PartialFunction<(parameter: PartialParameter) => ReturnType>; - /* eslint-disable ts/unified-signatures -- Keep explicit overloads for call-site inference */ andThen>>( thenFn: PartialFunctionLike, ): PartialFunction<(parameter: PartialParameter) => ReturnType>; - /* eslint-enable ts/unified-signatures */ andThen>>( - thenFn: PartialFunctionLike | FThen, + thenFn: FThen | PartialFunctionLike, ): PartialFunction<(parameter: PartialParameter) => ReturnType> { // @ts-ignore Typing is hard here return andThen(this, thenFn); } -} - -export function partial(properties: PartialFunctionLike): PartialFunction { - return new PartialFunction(properties); -} -export function orElse( - self: PartialFunctionLike, - elseFn: PartialFunctionLike, -): PartialFunction { - return partial({ - isDefinedAt: (value) => self.isDefinedAt(value) || elseFn.isDefinedAt(value), - // @ts-ignore Typing is hard here - - apply: (value) => (self.isDefinedAt(value) ? self.apply(value) : elseFn.apply(value)), - }); + orElse(elseFn: PartialFunctionLike): PartialFunction { + return orElse(this, elseFn); + } } export function andThen>>( self: PartialFunctionLike, thenFn: FThen, ): PartialFunction<(parameter: PartialParameter) => ReturnType>; -/* eslint-disable ts/unified-signatures -- Keep explicit overloads for call-site inference */ export function andThen>>( self: PartialFunctionLike, thenFn: PartialFunctionLike, ): PartialFunction<(parameter: PartialParameter) => ReturnType>; -/* eslint-enable ts/unified-signatures */ export function andThen>>( self: PartialFunctionLike, - thenFn: PartialFunctionLike | FThen, + thenFn: FThen | PartialFunctionLike, ): PartialFunction<(parameter: PartialParameter) => ReturnType> { - const { isDefinedAt, apply } = self; + const { apply, isDefinedAt } = self; const thenApply = typeof thenFn === 'function' ? thenFn : thenFn.apply; return partial({ + apply: (value: PartialParameter) => thenApply(apply(value)), + isDefinedAt, + }); +} - apply: (value: PartialParameter) => thenApply(apply(value)), +export function orElse( + self: PartialFunctionLike, + elseFn: PartialFunctionLike, +): PartialFunction { + return partial({ + // @ts-ignore Typing is hard here + apply: (value) => (self.isDefinedAt(value) ? self.apply(value) : elseFn.apply(value)), + isDefinedAt: (value) => self.isDefinedAt(value) || elseFn.isDefinedAt(value), }); } +export function partial(properties: PartialFunctionLike): PartialFunction { + return new PartialFunction(properties); +} + export const handleBoolean = partial({ - isDefinedAt: (value) => typeof value === 'boolean', apply: (_value: boolean) => 'bool' as const, + isDefinedAt: (value) => typeof value === 'boolean', }); export const handleNumber = partial({ - isDefinedAt: (value) => typeof value === 'number', apply: (_value: number) => 'bool' as const, + isDefinedAt: (value) => typeof value === 'number', }); export const handleBooleanOrNumber = handleBoolean // .orElse({ - isDefinedAt: (value) => typeof value === 'number', apply: (_value: number) => 'bool' as const, + isDefinedAt: (value) => typeof value === 'number', }) .orElse({ - isDefinedAt: (value) => typeof value === 'string', apply: (_value: string) => 'str' as const, + isDefinedAt: (value) => typeof value === 'string', }); export const isEven = partial({ - isDefinedAt: (value) => typeof value === 'number', apply: (value: number) => value % 2 === 0, + isDefinedAt: (value) => typeof value === 'number', }); export const processEven = isEven.andThen((_value: number) => 'bool' as const); diff --git a/packages/playground/src/Spread.ts b/packages/playground/src/Spread.ts index b88b815857..2f2bf06d47 100644 --- a/packages/playground/src/Spread.ts +++ b/packages/playground/src/Spread.ts @@ -14,12 +14,6 @@ // ? Spread> // : unknown; -type OptionalPropertyNames = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? K : never }[keyof T]; - -type SpreadProperties = { [P in K]: L[P] | Exclude }; - -type Id = T extends infer U ? { [K in keyof U]: U[K] } : never; - /** * Typing for `{ ...A, ...B }` * @@ -34,5 +28,11 @@ export type Spread = Id< Pick> & Pick>> & Pick, keyof L>> & - SpreadProperties & keyof L> + SpreadProperties> >; + +type Id = T extends infer U ? { [K in keyof U]: U[K] } : never; + +type OptionalPropertyNames = { [K in keyof T]-?: {} extends Record ? K : never }[keyof T]; + +type SpreadProperties = { [P in K]: Exclude | L[P] }; diff --git a/packages/playground/src/assign.spec.ts b/packages/playground/src/assign.spec.ts index 6a1aadffdb..54e2ab7746 100644 --- a/packages/playground/src/assign.spec.ts +++ b/packages/playground/src/assign.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { assign } from './assign.js'; describe('assign', () => { @@ -9,15 +10,15 @@ describe('assign', () => { expect(assign(anyObject, {})).toBe(anyObject); }); it('should return a new object when another object is passed', () => { - expect(assign({ unchanged: '', foo: true }, { foo: false })).toEqual({ unchanged: '', foo: false }); + expect(assign({ foo: true, unchanged: '' }, { foo: false })).toEqual({ foo: false, unchanged: '' }); }); it('should return identity when values are shallow equals', () => { - const object = { unchanged: '', foo: true }; + const object = { foo: true, unchanged: '' }; expect(assign(object, { foo: true })).toBe(object); }); // eslint-disable-next-line test/expect-expect it('should not allow adding property', () => { - const object = { unchanged: '', foo: true }; + const object = { foo: true, unchanged: '' }; // @ts-expect-error notAllowed is not present in object assign(object, { notAllowed: false }); }); diff --git a/packages/playground/src/assign.ts b/packages/playground/src/assign.ts index 88b7804100..1561a52b4a 100644 --- a/packages/playground/src/assign.ts +++ b/packages/playground/src/assign.ts @@ -14,7 +14,7 @@ import { extend } from './extend.js'; * @param source a base object * @param properties an extension object map */ -export function assign(source: T, properties: Partial | undefined | null): T { +export function assign(source: T, properties: null | Partial | undefined): T { // @ts-ignore extends has a different typing but does the same thing return extend(source, properties); } diff --git a/packages/playground/src/collection/Seq.spec.ts b/packages/playground/src/collection/Seq.spec.ts index 77e4d21b7f..ab01342fce 100644 --- a/packages/playground/src/collection/Seq.spec.ts +++ b/packages/playground/src/collection/Seq.spec.ts @@ -1,16 +1,17 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Seq } from './Seq.js'; -import { of } from './Seq/of.js'; import { from } from './Seq/from.js'; import { hasInstance } from './Seq/hasInstance.js'; +import { of } from './Seq/of.js'; describe('Seq', () => { it('has alias to methods', () => { expect(Seq).toEqual( expect.objectContaining({ - of, from, hasInstance, + of, }), ); }); diff --git a/packages/playground/src/collection/Seq.ts b/packages/playground/src/collection/Seq.ts index ea4546362b..903a159248 100644 --- a/packages/playground/src/collection/Seq.ts +++ b/packages/playground/src/collection/Seq.ts @@ -1,8 +1,10 @@ import { Callable } from '@w5s/core/dist/Callable.js'; + +import type { seqIterable } from './Seq/seqIterable.js'; + import { from } from './Seq/from.js'; -import { of } from './Seq/of.js'; import { hasInstance } from './Seq/hasInstance.js'; -import type { seqIterable } from './Seq/seqIterable.js'; +import { of } from './Seq/of.js'; export interface Seq extends Iterable { readonly [seqIterable]: Iterable; @@ -14,6 +16,6 @@ export interface Seq extends Iterable { export const Seq = Callable({ [Callable.symbol]: from, from, - of, hasInstance, + of, }); diff --git a/packages/playground/src/collection/Seq/Seq.ts b/packages/playground/src/collection/Seq/Seq.ts index 150894f1c3..a3938c0c84 100644 --- a/packages/playground/src/collection/Seq/Seq.ts +++ b/packages/playground/src/collection/Seq/Seq.ts @@ -1,4 +1,5 @@ import type { Seq as SeqInterface } from '../Seq.js'; + import { useSeqState } from '../internal/useSeqState.js'; import { seqIterable } from './seqIterable.js'; @@ -14,12 +15,12 @@ export class Seq implements SeqInterface { * [Symbol.iterator]() { const seqState = useSeqState(this[seqIterable]); - const { resolvedValues, currentIterator } = seqState; + const { currentIterator, resolvedValues } = seqState; yield* resolvedValues; if (currentIterator !== undefined) { while (true) { - const { value, done } = currentIterator.next(); + const { done, value } = currentIterator.next(); if (done) { seqState.currentIterator = undefined; diff --git a/packages/playground/src/collection/Seq/from.spec.ts b/packages/playground/src/collection/Seq/from.spec.ts index 0889614761..eb8f465615 100644 --- a/packages/playground/src/collection/Seq/from.spec.ts +++ b/packages/playground/src/collection/Seq/from.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { withIterable } from '@w5s/iterable/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { from } from './from.js'; describe(from, () => { diff --git a/packages/playground/src/collection/Seq/hasInstance.spec.ts b/packages/playground/src/collection/Seq/hasInstance.spec.ts index d77e858f54..e451e10f6f 100644 --- a/packages/playground/src/collection/Seq/hasInstance.spec.ts +++ b/packages/playground/src/collection/Seq/hasInstance.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Iterable } from '@w5s/iterable'; +import { describe, expect, it } from 'vitest'; + import { hasInstance } from './hasInstance.js'; import { of as Seq } from './of.js'; diff --git a/packages/playground/src/collection/Seq/hasInstance.ts b/packages/playground/src/collection/Seq/hasInstance.ts index 1ca21d8faf..895d483ca5 100644 --- a/packages/playground/src/collection/Seq/hasInstance.ts +++ b/packages/playground/src/collection/Seq/hasInstance.ts @@ -1,5 +1,7 @@ import { hasInstance as isIterable } from '@w5s/iterable/dist/Iterable/hasInstance.js'; + import type { Seq } from '../Seq.js'; + import { seqIterable } from './seqIterable.js'; /** diff --git a/packages/playground/src/collection/Seq/of.spec.ts b/packages/playground/src/collection/Seq/of.spec.ts index 12d7afe72c..9fdd92879f 100644 --- a/packages/playground/src/collection/Seq/of.spec.ts +++ b/packages/playground/src/collection/Seq/of.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { withIterable } from '@w5s/iterable/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { of } from './of.js'; describe(of, () => { diff --git a/packages/playground/src/collection/Seq/of.ts b/packages/playground/src/collection/Seq/of.ts index 4c3da7500f..434507d24a 100644 --- a/packages/playground/src/collection/Seq/of.ts +++ b/packages/playground/src/collection/Seq/of.ts @@ -1,4 +1,5 @@ import type { Seq } from '../Seq.js'; + import { from } from './from.js'; /** @@ -10,6 +11,6 @@ import { from } from './from.js'; * ``` * @param values values to be converted to a sequence */ -export function of(...values: T[]): Seq { +export function of(...values: Array): Seq { return from(values); } diff --git a/packages/playground/src/collection/internal/useSeqState.ts b/packages/playground/src/collection/internal/useSeqState.ts index 9fcd98fdd1..ea6c439032 100644 --- a/packages/playground/src/collection/internal/useSeqState.ts +++ b/packages/playground/src/collection/internal/useSeqState.ts @@ -3,10 +3,10 @@ const state = new WeakMap, ReturnType> /** * @internal */ -export type SeqState = { - resolvedValues: Array; +export interface SeqState { currentIterator: Iterator | undefined; -}; + resolvedValues: Array; +} /** * @param iterable @@ -16,8 +16,8 @@ export type SeqState = { export function useSeqState(iterable: Iterable): SeqState { if (typeof iterable === 'string') { return { - resolvedValues: [...iterable], currentIterator: undefined, + resolvedValues: [...iterable], }; } @@ -25,12 +25,12 @@ export function useSeqState(iterable: Iterable): SeqState { if (returnValue === undefined) { returnValue = Array.isArray(iterable) ? { - resolvedValues: iterable as Array, currentIterator: undefined, + resolvedValues: iterable as Array, } : { - resolvedValues: [], currentIterator: iterable[Symbol.iterator](), + resolvedValues: [], }; state.set(iterable, returnValue); } diff --git a/packages/playground/src/csv/CSVEncodeOptions.ts b/packages/playground/src/csv/CSVEncodeOptions.ts index 7b2298831e..9c06a4febc 100644 --- a/packages/playground/src/csv/CSVEncodeOptions.ts +++ b/packages/playground/src/csv/CSVEncodeOptions.ts @@ -1,4 +1,5 @@ import type { Option } from '@w5s/core'; + import { defaultCSVDecodeOptions } from './CSVDecodeOptions.js'; export interface CSVEncodeOptions { diff --git a/packages/playground/src/csv/CSVParseResult.ts b/packages/playground/src/csv/CSVParseResult.ts index b87e0fb0be..928e0adca6 100644 --- a/packages/playground/src/csv/CSVParseResult.ts +++ b/packages/playground/src/csv/CSVParseResult.ts @@ -1,6 +1,7 @@ import type { Result } from '@w5s/core'; -import type { CSVHeader, CSVNamedRecord, CSVRecord } from './CSVRecord.js'; + import type { CSVError } from './CSVError.js'; +import type { CSVHeader, CSVNamedRecord, CSVRecord } from './CSVRecord.js'; export interface CSVParseResult { csvHeader: CSVHeader; diff --git a/packages/playground/src/csv/CSVRecord.ts b/packages/playground/src/csv/CSVRecord.ts index 34efdfcf22..f84e323046 100644 --- a/packages/playground/src/csv/CSVRecord.ts +++ b/packages/playground/src/csv/CSVRecord.ts @@ -1,14 +1,12 @@ export type CSVField = string; -export type CSVRecord = ReadonlyArray; +export type CSVHeader = ReadonlyArray; export type CSVHeaderName = string; -export type CSVHeader = ReadonlyArray; +export type CSVNamedRecord = Readonly>; -export type CSVNamedRecord = { - readonly [name: CSVHeaderName]: CSVField; -}; +export type CSVRecord = ReadonlyArray; export const CSVNamedRecord = { fromCSVRecord(header: CSVHeader, record: CSVRecord): CSVNamedRecord { const length = Math.min(header.length, record.length); diff --git a/packages/playground/src/csv/decodeByName.spec.ts b/packages/playground/src/csv/decodeByName.spec.ts index 578a36efdc..a8c82f463c 100644 --- a/packages/playground/src/csv/decodeByName.spec.ts +++ b/packages/playground/src/csv/decodeByName.spec.ts @@ -1,9 +1,10 @@ -import { describe, expect, it } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Result } from '@w5s/core'; import { withAsyncIterable } from '@w5s/iterable/dist/Testing.js'; -import { decodeByName } from './decodeByName.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { CSVError } from './CSVError.js'; +import { decodeByName } from './decodeByName.js'; describe(decodeByName, () => { const expectTask = withTask(expect); @@ -37,7 +38,7 @@ describe(decodeByName, () => { }); it('should throw an error for missing header', async () => { - const input: string[] = []; + const input: Array = []; await expectTask(decodeByName(input)).toRejectAsync(new CSVError({ message: 'No header found' })); }); }); diff --git a/packages/playground/src/csv/decodeByName.ts b/packages/playground/src/csv/decodeByName.ts index fbded5ee7b..53e66866b8 100644 --- a/packages/playground/src/csv/decodeByName.ts +++ b/packages/playground/src/csv/decodeByName.ts @@ -1,16 +1,19 @@ -import { create as taskCreate } from '@w5s/task/dist/Task/create.js'; -import type { Task } from '@w5s/task'; -import { error } from '@w5s/task/dist/Task/error.js'; -import { ok } from '@w5s/task/dist/Task/ok.js'; import type { AsyncIterableLike } from '@w5s/iterable/dist/AsyncIterableLike.js'; -import { find as asyncIterableFind } from '@w5s/iterable/dist/AsyncIterable/find.js'; +import type { Task } from '@w5s/task'; + import { filter as asyncIterableFilter } from '@w5s/iterable/dist/AsyncIterable/filter.js'; +import { find as asyncIterableFind } from '@w5s/iterable/dist/AsyncIterable/find.js'; import { map as asyncIterableMap } from '@w5s/iterable/dist/AsyncIterable/map.js'; import { map as iterableMap } from '@w5s/iterable/dist/Iterable/map.js'; -import { CSVError } from './CSVError.js'; -import type { CSVNamedRecord } from './CSVRecord.js'; +import { create as taskCreate } from '@w5s/task/dist/Task/create.js'; +import { error } from '@w5s/task/dist/Task/error.js'; +import { ok } from '@w5s/task/dist/Task/ok.js'; + import type { CSVParseResult } from './CSVParseResult.js'; -import { defaultCSVDecodeOptions, type CSVDecodeOptions } from './CSVDecodeOptions.js'; +import type { CSVNamedRecord } from './CSVRecord.js'; + +import { type CSVDecodeOptions, defaultCSVDecodeOptions } from './CSVDecodeOptions.js'; +import { CSVError } from './CSVError.js'; import { readLines } from './readLines.js'; export function decodeByName( diff --git a/packages/playground/src/csv/encodeByName.ts b/packages/playground/src/csv/encodeByName.ts index 805b760200..e2a0c132b9 100644 --- a/packages/playground/src/csv/encodeByName.ts +++ b/packages/playground/src/csv/encodeByName.ts @@ -1,11 +1,14 @@ -import { create as taskCreate } from '@w5s/task/dist/Task/create.js'; -import type { Task } from '@w5s/task'; -import { ok } from '@w5s/task/dist/Task/ok.js'; import type { AsyncIterableLike } from '@w5s/iterable/dist/AsyncIterableLike.js'; +import type { Task } from '@w5s/task'; + import { map as asyncIterableMap } from '@w5s/iterable/dist/AsyncIterable/map.js'; -import { defaultCSVEncodeOptions, type CSVEncodeOptions } from './CSVEncodeOptions.js'; +import { create as taskCreate } from '@w5s/task/dist/Task/create.js'; +import { ok } from '@w5s/task/dist/Task/ok.js'; + import type { CSVNamedRecord } from './CSVRecord.js'; +import { type CSVEncodeOptions, defaultCSVEncodeOptions } from './CSVEncodeOptions.js'; + export function encodeByName( data: AsyncIterableLike, options: CSVEncodeOptions = defaultCSVEncodeOptions, diff --git a/packages/playground/src/csv/readLines.spec.ts b/packages/playground/src/csv/readLines.spec.ts index 77dac51995..3d5d811fcc 100644 --- a/packages/playground/src/csv/readLines.spec.ts +++ b/packages/playground/src/csv/readLines.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { withAsyncIterable } from '@w5s/iterable/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { decodeByName } from './decodeByName.js'; import { readLines } from './readLines.js'; diff --git a/packages/playground/src/date/Duration.spec.ts b/packages/playground/src/date/Duration.spec.ts index 8adc065835..d58a3cf3e1 100644 --- a/packages/playground/src/date/Duration.spec.ts +++ b/packages/playground/src/date/Duration.spec.ts @@ -1,23 +1,24 @@ -import { describeType, describeCodec } from '@w5s/core/dist/Testing.js'; -import { describe } from 'vitest'; import { CodecError, Int, Result } from '@w5s/core'; +import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { Duration } from './Duration.js'; describe('Duration', () => { describeType(Duration, () => ({ - typeName: 'Duration', instances: [ Duration({ - years: Int(1), - months: Int(2), - weeks: Int(3), days: Int(4), hours: Int(5), minutes: Int(6), + months: Int(2), seconds: 7, + weeks: Int(3), + years: Int(1), }), ], notInstances: ['1', 1.1, undefined, {}], + typeName: 'Duration', })); describeCodec(Duration, () => ({ decode: [ @@ -25,20 +26,20 @@ describe('Duration', () => { 'P2Y4M3W6DT14H30M20.42S', Result.Ok( Duration({ - years: Int(2), - months: Int(4), - weeks: Int(3), days: Int(6), hours: Int(14), minutes: Int(30), + months: Int(4), seconds: 20.42, + weeks: Int(3), + years: Int(2), }), ), ], // Invalid inputs ...['', 'P', 'PT'].map( (_) => - [_, Result.Error(new CodecError({ message: `Cannot decode "${_}" as Duration`, input: _ }))] as [ + [_, Result.Error(new CodecError({ input: _, message: `Cannot decode "${_}" as Duration` }))] as [ string, Result, ], @@ -46,15 +47,15 @@ describe('Duration', () => { ], encode: [ [ - Duration({ years: Int(1), months: Int(2), days: Int(3), hours: Int(4), minutes: Int(5), seconds: 6 }), + Duration({ days: Int(3), hours: Int(4), minutes: Int(5), months: Int(2), seconds: 6, years: Int(1) }), 'P1Y2M3DT4H5M6S', ], - [Duration({ years: Int(1), months: Int(2), days: Int(3) }), 'P1Y2M3D'], + [Duration({ days: Int(3), months: Int(2), years: Int(1) }), 'P1Y2M3D'], [Duration({ hours: Int(4), minutes: Int(5), seconds: 6.2 }), 'PT4H5M6.2S'], ], schema: { - type: 'string', format: 'duration', + type: 'string', }, })); }); diff --git a/packages/playground/src/date/Duration.ts b/packages/playground/src/date/Duration.ts index f00113568a..6260eb6ff3 100644 --- a/packages/playground/src/date/Duration.ts +++ b/packages/playground/src/date/Duration.ts @@ -1,9 +1,10 @@ import type { Codec, Int, Option } from '@w5s/core'; + +import { Callable } from '@w5s/core/dist/Callable.js'; import { Struct } from '@w5s/core/dist/Struct.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; -import { parse as parseNumber } from '@w5s/num/dist/Number/parse.js'; -import { Callable } from '@w5s/core/dist/Callable.js'; import { parse as parseInt } from '@w5s/num/dist/Int/parse.js'; +import { parse as parseNumber } from '@w5s/num/dist/Number/parse.js'; const numbers = String.raw`\d+`; const fractionalNumbers = String.raw`${numbers}(?:[\.,]${numbers})?`; @@ -54,48 +55,48 @@ function parse(expression: string): Option { // eslint-disable-next-line ts/no-use-before-define return DurationStruct.create({ - years, - months, - weeks, days, hours, minutes, + months, seconds, + weeks, + years, }); } const formatPart = (prefix: string, part: number) => (part === 0 ? '' : `${part}${prefix}`); const formatSection = (prefix: string, content: string) => (content.length === 0 ? '' : `${prefix}${content}`); -function format(duration: Duration): string { - return `P${formatPart('Y', duration.years)}${formatPart('M', duration.months)}${formatPart('D', duration.days)}${formatSection( - 'T', - `${formatPart('H', duration.hours)}${formatPart('M', duration.minutes)}${formatPart('S', duration.seconds)}`, - )}`; -} - export interface Duration extends Struct<{ _: 'Duration'; - years: Int; - months: Int; - weeks: Int; days: Int; hours: Int; minutes: Int; + months: Int; seconds: number; + weeks: Int; + years: Int; }> {} +function format(duration: Duration): string { + return `P${formatPart('Y', duration.years)}${formatPart('M', duration.months)}${formatPart('D', duration.days)}${formatSection( + 'T', + `${formatPart('H', duration.hours)}${formatPart('M', duration.minutes)}${formatPart('S', duration.seconds)}`, + )}`; +} + const DurationStruct = Struct.define({ typeName: 'Duration' }); const DurationCodec: Codec = { - [Symbol.encode]: (value) => format(value), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { const returnValue = typeof input === 'string' ? parse(input) : undefined; return returnValue === undefined ? error(input, 'Duration') : ok(returnValue); }, + [Symbol.encode]: (value) => format(value), [Symbol.schema]: () => ({ - type: 'string', format: 'duration', + type: 'string', }), }; @@ -107,12 +108,12 @@ export const Duration = Callable({ ...DurationCodec, [Callable.symbol]: (properties?: Partial>): Duration => Duration.create({ - years: properties?.years ?? (0 as Int), - months: properties?.months ?? (0 as Int), - weeks: properties?.weeks ?? (0 as Int), days: properties?.days ?? (0 as Int), hours: properties?.hours ?? (0 as Int), minutes: properties?.minutes ?? (0 as Int), + months: properties?.months ?? (0 as Int), seconds: properties?.seconds ?? 0, + weeks: properties?.weeks ?? (0 as Int), + years: properties?.years ?? (0 as Int), }), }); diff --git a/packages/playground/src/di/ContainerKey.spec.ts b/packages/playground/src/di/ContainerKey.spec.ts index dad9112a38..87a543674e 100644 --- a/packages/playground/src/di/ContainerKey.spec.ts +++ b/packages/playground/src/di/ContainerKey.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { ContainerKey } from './ContainerKey.js'; describe(ContainerKey, () => { @@ -6,8 +7,8 @@ describe(ContainerKey, () => { it('should be a symbol', () => { const provider = () => 'my_implementation'; expect(ContainerKey('test', provider)).toEqual({ - containerKey: 'test', containerDefaultProvider: provider, + containerKey: 'test', }); }); it('should have default provider if omitted', () => { diff --git a/packages/playground/src/di/ContainerKey.ts b/packages/playground/src/di/ContainerKey.ts index 5a2a7bc7b3..144a1b115e 100644 --- a/packages/playground/src/di/ContainerKey.ts +++ b/packages/playground/src/di/ContainerKey.ts @@ -1,4 +1,5 @@ import type { Option } from '@w5s/core'; + import type { ContainerProviderFunction } from './ContainerProviderFunction.js'; /** @@ -6,14 +7,14 @@ import type { ContainerProviderFunction } from './ContainerProviderFunction.js'; */ export interface ContainerKey { /** - * Injection symbol key + * Default implementation of the key */ - containerKey: Key; + containerDefaultProvider: ContainerProviderFunction<{}, Value>; /** - * Default implementation of the key + * Injection symbol key */ - containerDefaultProvider: ContainerProviderFunction<{}, Value>; + containerKey: Key; } export function ContainerKey(key: Key): ContainerKey>; export function ContainerKey( @@ -26,7 +27,7 @@ export function ContainerKey( ): ContainerKey { return { - containerKey: key, containerDefaultProvider: defaultProvider ?? (() => undefined), + containerKey: key, }; } diff --git a/packages/playground/src/di/ContainerProvider.ts b/packages/playground/src/di/ContainerProvider.ts index 31c6db355a..1bb4319afe 100644 --- a/packages/playground/src/di/ContainerProvider.ts +++ b/packages/playground/src/di/ContainerProvider.ts @@ -3,6 +3,4 @@ import type { ContainerProviderFunction } from './ContainerProviderFunction.js'; /** * A container of dependencies. */ -export type ContainerProvider = { - readonly [key in Key]: ContainerProviderFunction; -}; +export type ContainerProvider = Readonly>>; diff --git a/packages/playground/src/di/ContainerProviderFunction.ts b/packages/playground/src/di/ContainerProviderFunction.ts index 69044ed9a4..77f8927942 100644 --- a/packages/playground/src/di/ContainerProviderFunction.ts +++ b/packages/playground/src/di/ContainerProviderFunction.ts @@ -1,6 +1,4 @@ /** * A container provider */ -export interface ContainerProviderFunction { - (requirement: Requirement): Value; -} +export type ContainerProviderFunction = (requirement: Requirement) => Value; diff --git a/packages/playground/src/di/index.spec.ts b/packages/playground/src/di/index.spec.ts index 4d2b5c96ea..fb3fb7a7ef 100644 --- a/packages/playground/src/di/index.spec.ts +++ b/packages/playground/src/di/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/playground/src/di/index.ts b/packages/playground/src/di/index.ts index 3606a55521..f84e14f3a7 100644 --- a/packages/playground/src/di/index.ts +++ b/packages/playground/src/di/index.ts @@ -1,4 +1,4 @@ -export * from './ContainerProvider.js'; export * from './ContainerKey.js'; +export * from './ContainerProvider.js'; export * from './provide.js'; export * from './use.js'; diff --git a/packages/playground/src/di/provide.spec.ts b/packages/playground/src/di/provide.spec.ts index ad1e11e3a6..b4ea996d84 100644 --- a/packages/playground/src/di/provide.spec.ts +++ b/packages/playground/src/di/provide.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { provide } from './provide.js'; +import { describe, expect, it } from 'vitest'; + import { ContainerKey } from './ContainerKey.js'; +import { provide } from './provide.js'; describe(provide, () => { it('should add property to object', () => { diff --git a/packages/playground/src/di/provide.ts b/packages/playground/src/di/provide.ts index 21f55451f9..3eb3d1ccc5 100644 --- a/packages/playground/src/di/provide.ts +++ b/packages/playground/src/di/provide.ts @@ -1,6 +1,7 @@ import type { Option } from '@w5s/core'; -import type { ContainerProvider } from './ContainerProvider.js'; + import type { ContainerKey } from './ContainerKey.js'; +import type { ContainerProvider } from './ContainerProvider.js'; import type { ContainerProviderFunction } from './ContainerProviderFunction.js'; /** diff --git a/packages/playground/src/di/use.spec.ts b/packages/playground/src/di/use.spec.ts index 87d0a6415c..82ee06ec37 100644 --- a/packages/playground/src/di/use.spec.ts +++ b/packages/playground/src/di/use.spec.ts @@ -1,9 +1,11 @@ -import { describe, it, expect } from 'vitest'; -import { ContainerKey } from './ContainerKey.js'; -import { use } from './use.js'; -import { provide } from './provide.js'; +import { describe, expect, it } from 'vitest'; + import type { ContainerProvider } from './ContainerProvider.js'; + import { pipe } from '../pipe.js'; +import { ContainerKey } from './ContainerKey.js'; +import { provide } from './provide.js'; +import { use } from './use.js'; describe(use, () => { interface ServiceA { diff --git a/packages/playground/src/di/use.ts b/packages/playground/src/di/use.ts index 669e6c5c37..d722fe9ad7 100644 --- a/packages/playground/src/di/use.ts +++ b/packages/playground/src/di/use.ts @@ -1,6 +1,7 @@ import type { Option } from '@w5s/core'; -import type { ContainerProvider } from './ContainerProvider.js'; + import type { ContainerKey } from './ContainerKey.js'; +import type { ContainerProvider } from './ContainerProvider.js'; import type { ContainerProviderFunction } from './ContainerProviderFunction.js'; const $cache: unique symbol = Symbol('use.cache'); @@ -9,9 +10,35 @@ interface Cacheable { [$cache]: use.Cache; } +/** + * Return the container value + * + * @example + * ```typescript + * interface SomeServiceInterface { ... } + * const SomeService = ContainerKey<'SomeService', SomeServiceInterface>('SomeService'); + * const appContext: AppContext = // ... + * + * const someService = use(appContext, SomeService);// typeof someService == SomeServiceInterface + * ``` + * @param appContext the app context container + * @param key the injection key + */ +export function use( + appContext: Partial>>, + key: ContainerKey>, +): Value; +export function use( + appContext: ContainerProvider, + key: ContainerKey, +): Value; +export function use(appContext: any, key: any) { + return cacheGet(appContext, cacheFor(appContext), key); +} + function cacheFor(appContext: object): use.Cache { // @ts-ignore we know what we are doing - const cache = appContext[use.cache] as use.Cache | undefined; + const cache = appContext[use.cache] as undefined | use.Cache; if (cache === undefined || cache.appContext !== appContext) { const cacheNew = { appContext }; @@ -21,7 +48,6 @@ function cacheFor(appContext: object): use.Cache { } return cache; } - function cacheGet( appContext: Partial>>, cache: use.Cache, @@ -33,47 +59,21 @@ function cacheGet( const value: Value = cache[containerKey] ?? (cache[containerKey] = getProvider(appContext, key)(appContext)); return value; } - function getProvider( appContext: ContainerProvider, - { containerKey, containerDefaultProvider }: ContainerKey, + { containerDefaultProvider, containerKey }: ContainerKey, ): ContainerProviderFunction { return appContext[containerKey] ?? containerDefaultProvider; } - -/** - * Return the container value - * - * @example - * ```typescript - * interface SomeServiceInterface { ... } - * const SomeService = ContainerKey<'SomeService', SomeServiceInterface>('SomeService'); - * const appContext: AppContext = // ... - * - * const someService = use(appContext, SomeService);// typeof someService == SomeServiceInterface - * ``` - * @param appContext the app context container - * @param key the injection key - */ -export function use( - appContext: Partial>>, - key: ContainerKey>, -): Value; -export function use( - appContext: ContainerProvider, - key: ContainerKey, -): Value; -export function use(appContext: any, key: any) { - return cacheGet(appContext, cacheFor(appContext), key); -} use.cache = $cache; export namespace use { export interface Cache { + [key: symbol]: any; + /** * The app context */ appContext: object; - [key: symbol]: any; } } diff --git a/packages/playground/src/extend.spec.ts b/packages/playground/src/extend.spec.ts index c81476248e..5d5a665ce7 100644 --- a/packages/playground/src/extend.spec.ts +++ b/packages/playground/src/extend.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + import { extend } from './extend.js'; describe('extend', () => { @@ -10,16 +11,16 @@ describe('extend', () => { expect(extend(anyObject, {})).toBe(anyObject); }); it('should return identity when values are shallow equals', () => { - const object = { unchanged: '', foo: true }; + const object = { foo: true, unchanged: '' }; expect(extend(object, { foo: true })).toBe(object); }); it('should return a new object when another object is passed', () => { - const result = extend({ unchanged: '', override: true }, { override: 'false', newProperty: false }); + const result = extend({ override: true, unchanged: '' }, { newProperty: false, override: 'false' }); expect(result).toEqual({ - unchanged: '', - override: 'false', newProperty: false, + override: 'false', + unchanged: '', }); - assertType(true); + assertType(true); }); }); diff --git a/packages/playground/src/fiber/Fiber/resume.ts b/packages/playground/src/fiber/Fiber/resume.ts index e0b48efadf..efe04e4cd9 100644 --- a/packages/playground/src/fiber/Fiber/resume.ts +++ b/packages/playground/src/fiber/Fiber/resume.ts @@ -1,6 +1,7 @@ -import { toFiberId } from '../internal/toFiberId.js'; import type { FiberIdLike } from '../FiberIdLike.js'; + import { scheduler } from '../internal/scheduler.js'; +import { toFiberId } from '../internal/toFiberId.js'; /** * Resume a previously suspended fiber execution diff --git a/packages/playground/src/fiber/Fiber/run.spec.ts b/packages/playground/src/fiber/Fiber/run.spec.ts index a463d6e61a..3cb67628c1 100644 --- a/packages/playground/src/fiber/Fiber/run.spec.ts +++ b/packages/playground/src/fiber/Fiber/run.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + import { run } from './run.js'; describe(run, () => { const createTracer = () => { - const stack: string[] = []; + const stack: Array = []; return Object.assign( (name: string) => { diff --git a/packages/playground/src/fiber/Fiber/run.ts b/packages/playground/src/fiber/Fiber/run.ts index e5c9cd02eb..7c2b516158 100644 --- a/packages/playground/src/fiber/Fiber/run.ts +++ b/packages/playground/src/fiber/Fiber/run.ts @@ -1,5 +1,6 @@ import type { FiberCallback } from '../FiberCallback.js'; import type { FiberResult } from '../FiberResult.js'; + import { scheduler } from '../internal/scheduler.js'; /** diff --git a/packages/playground/src/fiber/Fiber/suspend.spec.ts b/packages/playground/src/fiber/Fiber/suspend.spec.ts index 9c1956e584..a7ded93923 100644 --- a/packages/playground/src/fiber/Fiber/suspend.spec.ts +++ b/packages/playground/src/fiber/Fiber/suspend.spec.ts @@ -1,12 +1,13 @@ /* eslint-disable ts/no-use-before-define */ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + +import { resume } from './resume.js'; import { run } from './run.js'; import { suspend } from './suspend.js'; -import { resume } from './resume.js'; describe(suspend, () => { it('should run a generator function', async () => { - const stack: string[] = []; + const stack: Array = []; const trace = (name: string) => { stack.push(name); return name; diff --git a/packages/playground/src/fiber/Fiber/suspend.ts b/packages/playground/src/fiber/Fiber/suspend.ts index b5378798ec..3896ad9f17 100644 --- a/packages/playground/src/fiber/Fiber/suspend.ts +++ b/packages/playground/src/fiber/Fiber/suspend.ts @@ -1,6 +1,7 @@ -import { toFiberId } from '../internal/toFiberId.js'; import type { FiberIdLike } from '../FiberIdLike.js'; + import { scheduler } from '../internal/scheduler.js'; +import { toFiberId } from '../internal/toFiberId.js'; /** * Suspend temporarily a fiber execution diff --git a/packages/playground/src/fiber/Fiber/terminate.spec.ts b/packages/playground/src/fiber/Fiber/terminate.spec.ts index 2e3731d1dc..f5e6186f0c 100644 --- a/packages/playground/src/fiber/Fiber/terminate.spec.ts +++ b/packages/playground/src/fiber/Fiber/terminate.spec.ts @@ -1,11 +1,12 @@ -import { describe, it, expect } from 'vitest'; import { defer } from '@w5s/async'; +import { describe, expect, it } from 'vitest'; + import { run } from './run.js'; import { terminate } from './terminate.js'; describe(terminate, () => { it('should run a generator function', async () => { - const stack: string[] = []; + const stack: Array = []; const trace = (name: string) => { stack.push(name); return name; diff --git a/packages/playground/src/fiber/Fiber/terminate.ts b/packages/playground/src/fiber/Fiber/terminate.ts index 03e3bc83e2..047ae13760 100644 --- a/packages/playground/src/fiber/Fiber/terminate.ts +++ b/packages/playground/src/fiber/Fiber/terminate.ts @@ -1,6 +1,7 @@ -import { toFiberId } from '../internal/toFiberId.js'; import type { FiberIdLike } from '../FiberIdLike.js'; + import { scheduler } from '../internal/scheduler.js'; +import { toFiberId } from '../internal/toFiberId.js'; /** * Terminate a fiber diff --git a/packages/playground/src/fiber/FiberId.ts b/packages/playground/src/fiber/FiberId.ts index 2938e25101..6f950a471e 100644 --- a/packages/playground/src/fiber/FiberId.ts +++ b/packages/playground/src/fiber/FiberId.ts @@ -11,6 +11,6 @@ export type FiberId = number & Tag<'FiberId'>; * @namespace */ export const FiberId = Tag.define({ - typeName: 'FiberId', hasInstance: (value) => typeof value === 'number', + typeName: 'FiberId', }); diff --git a/packages/playground/src/fiber/Scheduler/Scheduler.ts b/packages/playground/src/fiber/Scheduler/Scheduler.ts index ae02c2e0a0..fd428218fc 100644 --- a/packages/playground/src/fiber/Scheduler/Scheduler.ts +++ b/packages/playground/src/fiber/Scheduler/Scheduler.ts @@ -1,9 +1,12 @@ import type { Option } from '@w5s/core'; + import { defer } from '@w5s/async/dist/defer.js'; -import { FiberId } from '../FiberId.js'; -import type { SchedulerFiberState } from './SchedulerFiberState.js'; + import type { FiberCallback } from '../FiberCallback.js'; import type { FiberResult } from '../FiberResult.js'; +import type { SchedulerFiberState } from './SchedulerFiberState.js'; + +import { FiberId } from '../FiberId.js'; import { cancelScheduledCallback, requestScheduledCallback, @@ -13,22 +16,9 @@ import { export class Scheduler { #currentId = FiberId(1); - #fiber: Map = new Map(); + #fiber = new Map(); #timerId: Option; - spawn(callback: FiberCallback): FiberResult { - const id = this.nextId(); - const deferred = defer(); - this.#fiber.set(id, { - id, - callback, - running: false, - generator: undefined, - deferred, - }); - return { id, promise: deferred.promise }; - } - resume(id: FiberId): void { this.modifyState(id, (state) => state.running @@ -40,6 +30,19 @@ export class Scheduler { ); } + spawn(callback: FiberCallback): FiberResult { + const id = this.nextId(); + const deferred = defer(); + this.#fiber.set(id, { + callback, + deferred, + generator: undefined, + id, + running: false, + }); + return { id, promise: deferred.promise }; + } + suspend(id: FiberId): void { this.modifyState(id, (state) => state.running @@ -59,6 +62,16 @@ export class Scheduler { return false; } + protected generator(fiber: SchedulerFiberState) { + const { callback } = fiber; + let { generator } = fiber; + if (generator === undefined) { + generator = callback(); + this.modifyState(fiber.id, (state) => ({ ...state, generator })); + } + return generator; + } + protected getCycleDeadline() { return 12; } @@ -80,12 +93,6 @@ export class Scheduler { return false; } - protected onStateChange(previous: SchedulerFiberState, next: SchedulerFiberState): void { - if (previous.running !== next.running) { - this.scheduleNext(); - } - } - protected nextId(): FiberId { const currentId = this.#currentId; // @ts-ignore we know what we are doing @@ -93,17 +100,6 @@ export class Scheduler { return currentId; } - protected scheduleNext() { - const countActive = this.#fiber.size; - if (countActive > 0) { - if (this.#timerId === undefined) { - this.#timerId = requestScheduledCallback(this.onCycle, this.getCycleDeadline()); - } - } else if (this.#timerId !== undefined) { - cancelScheduledCallback(this.#timerId); - } - } - protected onCycle: ScheduledRequestCallback = (deadline) => { // Clear timer this.#timerId = undefined; @@ -129,14 +125,15 @@ export class Scheduler { this.scheduleNext(); }; - protected generator(fiber: SchedulerFiberState) { - const { callback } = fiber; - let { generator } = fiber; - if (generator === undefined) { - generator = callback(); - this.modifyState(fiber.id, (state) => ({ ...state, generator })); + protected onStateChange(previous: SchedulerFiberState, next: SchedulerFiberState): void { + if (previous.running !== next.running) { + this.scheduleNext(); } - return generator; + } + + protected reject(fiber: SchedulerFiberState, error: any): void { + this.#fiber.delete(fiber.id); + fiber.deferred.reject(error); } protected resolve(fiber: SchedulerFiberState, value: any): void { @@ -144,8 +141,14 @@ export class Scheduler { fiber.deferred.resolve(value); } - protected reject(fiber: SchedulerFiberState, error: any): void { - this.#fiber.delete(fiber.id); - fiber.deferred.reject(error); + protected scheduleNext() { + const countActive = this.#fiber.size; + if (countActive > 0) { + if (this.#timerId === undefined) { + this.#timerId = requestScheduledCallback(this.onCycle, this.getCycleDeadline()); + } + } else if (this.#timerId !== undefined) { + cancelScheduledCallback(this.#timerId); + } } } diff --git a/packages/playground/src/fiber/Scheduler/SchedulerFiberState.ts b/packages/playground/src/fiber/Scheduler/SchedulerFiberState.ts index a2a7dd01c7..52d49e3ba0 100644 --- a/packages/playground/src/fiber/Scheduler/SchedulerFiberState.ts +++ b/packages/playground/src/fiber/Scheduler/SchedulerFiberState.ts @@ -1,11 +1,12 @@ import type { Option } from '@w5s/core'; -import type { FiberId } from '../FiberId.js'; + import type { FiberCallback } from '../FiberCallback.js'; +import type { FiberId } from '../FiberId.js'; export interface SchedulerFiberState { - readonly id: FiberId; readonly callback: FiberCallback; - readonly running: boolean; - readonly generator: Option; readonly deferred: PromiseWithResolvers; + readonly generator: Option; + readonly id: FiberId; + readonly running: boolean; } diff --git a/packages/playground/src/fiber/index.spec.ts b/packages/playground/src/fiber/index.spec.ts index d577a51526..df31e9c5f4 100644 --- a/packages/playground/src/fiber/index.spec.ts +++ b/packages/playground/src/fiber/index.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { expect(new Set(Object.keys(Module))).toEqual( new Set([ + 'Fiber', // All keys 'FiberId', - 'Fiber', ]), ); }); diff --git a/packages/playground/src/fiber/index.ts b/packages/playground/src/fiber/index.ts index 1a040f7f74..dcc8b5094e 100644 --- a/packages/playground/src/fiber/index.ts +++ b/packages/playground/src/fiber/index.ts @@ -1,4 +1,4 @@ -export * from './FiberId.js'; export * from './Fiber.js'; -export type * from './FiberIdLike.js'; export type * from './FiberCallback.js'; +export * from './FiberId.js'; +export type * from './FiberIdLike.js'; diff --git a/packages/playground/src/fiber/internal/requestScheduledCallback.ts b/packages/playground/src/fiber/internal/requestScheduledCallback.ts index 79c448da46..e53decb903 100644 --- a/packages/playground/src/fiber/internal/requestScheduledCallback.ts +++ b/packages/playground/src/fiber/internal/requestScheduledCallback.ts @@ -1,7 +1,8 @@ -import { setImmediate } from '@w5s/async/dist/setImmediate.js'; -import { clearImmediate } from '@w5s/async/dist/clearImmediate.js'; import type { ImmediateId } from '@w5s/async'; +import { clearImmediate } from '@w5s/async/dist/clearImmediate.js'; +import { setImmediate } from '@w5s/async/dist/setImmediate.js'; + const performanceNow = globalThis.performance == null ? () => Date.now() : () => performance.now(); /** @@ -11,12 +12,14 @@ export interface ScheduledDeadline { timeRemaining(): number; } -export interface ScheduledRequestCallback { - (api: ScheduledDeadline): void; -} +export type ScheduledRequestCallback = (api: ScheduledDeadline) => void; export type ScheduledRequestId = ImmediateId; +export function cancelScheduledCallback(id: ScheduledRequestId): void { + return clearImmediate(id); +} + export function requestScheduledCallback(callback: ScheduledRequestCallback, deadlineMs: number): ScheduledRequestId { return setImmediate(() => { const startTime = performanceNow(); @@ -28,7 +31,3 @@ export function requestScheduledCallback(callback: ScheduledRequestCallback, dea }); }) as unknown as ScheduledRequestId; } - -export function cancelScheduledCallback(id: ScheduledRequestId): void { - return clearImmediate(id); -} diff --git a/packages/playground/src/fiber/internal/scheduler.spec.ts b/packages/playground/src/fiber/internal/scheduler.spec.ts index 60204c2fda..a1a0984fe0 100644 --- a/packages/playground/src/fiber/internal/scheduler.spec.ts +++ b/packages/playground/src/fiber/internal/scheduler.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { scheduler } from './scheduler.js'; +import { describe, expect, it } from 'vitest'; + import { Scheduler as SchedulerImpl } from '../Scheduler/Scheduler.js'; +import { scheduler } from './scheduler.js'; describe('Scheduler', () => { it('is an instance of SchedulerImpl', () => { diff --git a/packages/playground/src/initializer-example/initializers/init1.ts b/packages/playground/src/initializer-example/initializers/init1.ts index 214c6a3a34..727aa5b267 100644 --- a/packages/playground/src/initializer-example/initializers/init1.ts +++ b/packages/playground/src/initializer-example/initializers/init1.ts @@ -1,6 +1,7 @@ -import { Initializer } from '../../initializer/index.js'; import type { AppContext } from '../AppContext.js'; +import { Initializer } from '../../initializer/index.js'; + export default Initializer(import.meta.url, async (_: AppContext) => { console.log('init1'); }); diff --git a/packages/playground/src/initializer-example/initializers/init2.ts b/packages/playground/src/initializer-example/initializers/init2.ts index d32fd5c0cd..63bcc7bba0 100644 --- a/packages/playground/src/initializer-example/initializers/init2.ts +++ b/packages/playground/src/initializer-example/initializers/init2.ts @@ -1,6 +1,7 @@ -import { Initializer } from '../../initializer/index.js'; import type { AppContext } from '../AppContext.js'; +import { Initializer } from '../../initializer/index.js'; + export default Initializer(import.meta.url, async (_: AppContext) => { console.log('init2'); }); diff --git a/packages/playground/src/initializer-example/main.ts b/packages/playground/src/initializer-example/main.ts index 0c8d95dc5b..4c1bf9a0a0 100644 --- a/packages/playground/src/initializer-example/main.ts +++ b/packages/playground/src/initializer-example/main.ts @@ -1,6 +1,7 @@ -import { startAll } from '../initializer/index.js'; import type { AppContext } from './AppContext.js'; +import { startAll } from '../initializer/index.js'; + export async function main3() { const appContext: AppContext = { foo: true }; const result = await startAll(appContext, [ diff --git a/packages/playground/src/initializer/InitializerStatus.spec.ts b/packages/playground/src/initializer/InitializerStatus.spec.ts index 0115e61946..efdda1be26 100644 --- a/packages/playground/src/initializer/InitializerStatus.spec.ts +++ b/packages/playground/src/initializer/InitializerStatus.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { InitializerStatus } from './InitializerStatus.js'; describe('InitializerStatus', () => { diff --git a/packages/playground/src/initializer/InitializerStatus.ts b/packages/playground/src/initializer/InitializerStatus.ts index 73e4b67da6..3c372af06d 100644 --- a/packages/playground/src/initializer/InitializerStatus.ts +++ b/packages/playground/src/initializer/InitializerStatus.ts @@ -4,9 +4,9 @@ import type { ValueOf } from '@w5s/core-type'; * Initializer status */ export const InitializerStatus = { - Stopped: 'stopped', - Starting: 'starting', - Ready: 'ready', Crashed: 'crashed', + Ready: 'ready', + Starting: 'starting', + Stopped: 'stopped', } as const; export type InitializerStatus = ValueOf; diff --git a/packages/playground/src/initializer/internal/state.ts b/packages/playground/src/initializer/internal/state.ts index b2e8e14287..a255283d88 100644 --- a/packages/playground/src/initializer/internal/state.ts +++ b/packages/playground/src/initializer/internal/state.ts @@ -1,6 +1,8 @@ import { Ref } from '@w5s/core/dist/Ref.js'; import { useGlobal } from '@w5s/global-storage'; + import type { Initializer } from '../Initializer.js'; + import { InitializerStatus } from '../InitializerStatus.js'; import { meta } from '../meta.js'; diff --git a/packages/playground/src/initializer/start.spec.ts b/packages/playground/src/initializer/start.spec.ts index 395c0986d0..a13c83c762 100644 --- a/packages/playground/src/initializer/start.spec.ts +++ b/packages/playground/src/initializer/start.spec.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; + import { Initializer } from './Initializer.js'; import { InitializerStatus } from './InitializerStatus.js'; import { getStatus, state } from './internal/state.js'; @@ -24,7 +25,7 @@ describe(start, () => { }); it('marks initializer as starting before running onStart', async () => { - const statuses: string[] = []; + const statuses: Array = []; const initializer = Initializer('init-2', async () => { statuses.push(getStatus(initializer)); diff --git a/packages/playground/src/initializer/start.ts b/packages/playground/src/initializer/start.ts index b737f56f08..039d885594 100644 --- a/packages/playground/src/initializer/start.ts +++ b/packages/playground/src/initializer/start.ts @@ -1,4 +1,5 @@ import type { Initializer } from './Initializer.js'; + import { InitializerStatus } from './InitializerStatus.js'; import { getStatus, setStatus } from './internal/state.js'; diff --git a/packages/playground/src/initializer/startAll.spec.ts b/packages/playground/src/initializer/startAll.spec.ts index 0b95a13ec0..b1d272faa2 100644 --- a/packages/playground/src/initializer/startAll.spec.ts +++ b/packages/playground/src/initializer/startAll.spec.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; + import { Initializer } from './Initializer.js'; import { InitializerStatus } from './InitializerStatus.js'; import { getStatus, state } from './internal/state.js'; diff --git a/packages/playground/src/initializer/startAll.ts b/packages/playground/src/initializer/startAll.ts index 94d0ce08e7..50d3e03c90 100644 --- a/packages/playground/src/initializer/startAll.ts +++ b/packages/playground/src/initializer/startAll.ts @@ -1,4 +1,5 @@ import type { Awaitable } from '@w5s/core-type'; + import { Initializer } from './Initializer.js'; import { start } from './start.js'; @@ -18,10 +19,9 @@ import { start } from './start.js'; */ export async function startAll< AppContext extends object, - const Initializers extends readonly ( - | (() => Awaitable>) - | (() => Awaitable<{ default: Initializer }>) - )[], + const Initializers extends ReadonlyArray< + | (() => Awaitable>) + | (() => Awaitable<{ default: Initializer }>)>, >( appContext: AppContext, initializers: Initializers, diff --git a/packages/playground/src/job/Job.ts b/packages/playground/src/job/Job.ts index 6c6266dd9b..c3429176e0 100644 --- a/packages/playground/src/job/Job.ts +++ b/packages/playground/src/job/Job.ts @@ -4,26 +4,22 @@ import { randomUUID, type UUID } from '@w5s/uuid'; export namespace Job { export interface Module { + create(payload: Request['payload']): Task; jobName: Request['_']; - Request: Type.Module; - create(payload: Request['payload']): Task; + Request: Type.Module; } } -export type JobId = UUID & Tag<'JobId'>; +export type JobId = Tag<'JobId'> & UUID; export const Job = { - nextJobId: randomUUID() as Task, - define(jobName: JobName, PayloadType: Type.Module): Job.Module<{ _: JobName; payload: Payload }> { const Request = Type.Object({ _: Type.constant(jobName), payload: PayloadType, }, `${jobName}Job`); return { - jobName, - Request, create(payload) { const request = { _: jobName, payload }; const requestEncoded = lazy(() => Codec.encode(Request, request)); @@ -34,8 +30,12 @@ export const Job = { }); }); }, + jobName, + Request, }; }, + + nextJobId: randomUUID() as Task, }; // export const Blah = Job.define('Blah', Type.Object({ diff --git a/packages/playground/src/job/JobProvider.ts b/packages/playground/src/job/JobProvider.ts index 981dfd1c28..b8ad39fb50 100644 --- a/packages/playground/src/job/JobProvider.ts +++ b/packages/playground/src/job/JobProvider.ts @@ -1,8 +1,8 @@ import type { JobRequest } from './JobRequest.js'; export type JobEnqueueOptions = - | { _: 'immediate' } - | { _: 'delayed'; delay: number }; + | { _: 'delayed'; delay: number } + | { _: 'immediate' }; export interface JobProvider { /** diff --git a/packages/playground/src/job/MemoryJobProvider.spec.ts b/packages/playground/src/job/MemoryJobProvider.spec.ts index c04bec722a..9d806e1172 100644 --- a/packages/playground/src/job/MemoryJobProvider.spec.ts +++ b/packages/playground/src/job/MemoryJobProvider.spec.ts @@ -1,4 +1,5 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; + import { MemoryJobProvider } from './MemoryJobProvider.js'; describe(MemoryJobProvider, () => { @@ -14,14 +15,14 @@ describe(MemoryJobProvider, () => { expect(provider.size).toBe(1); expect(provider.peek()).toEqual({ - request, - enqueuedAt: expect.any(Number), availableAt: expect.any(Number), + enqueuedAt: expect.any(Number), + request, }); expect(provider.dequeue()).toEqual({ - request, - enqueuedAt: expect.any(Number), availableAt: expect.any(Number), + enqueuedAt: expect.any(Number), + request, }); expect(provider.size).toBe(0); }); @@ -40,9 +41,9 @@ describe(MemoryJobProvider, () => { vi.advanceTimersByTime(1); expect(provider.size).toBe(1); expect(provider.dequeue()).toEqual({ - request, - enqueuedAt: expect.any(Number), availableAt: expect.any(Number), + enqueuedAt: expect.any(Number), + request, }); }); diff --git a/packages/playground/src/job/MemoryJobProvider.ts b/packages/playground/src/job/MemoryJobProvider.ts index f0d4be43f9..9555e3f46e 100644 --- a/packages/playground/src/job/MemoryJobProvider.ts +++ b/packages/playground/src/job/MemoryJobProvider.ts @@ -1,35 +1,28 @@ import type { JobEnqueueOptions, JobProvider } from './JobProvider.js'; import type { JobRequest } from './JobRequest.js'; -export interface MemoryJobQueueEntry { - readonly request: Request; - readonly enqueuedAt: number; - readonly availableAt: number; -} - export interface MemoryJobProviderOptions { readonly now?: () => number; } -export class MemoryJobProvider implements JobProvider { - readonly #queue: MemoryJobQueueEntry[] = []; - readonly #timers = new Set>(); - readonly #now: () => number; - - constructor(options: MemoryJobProviderOptions = {}) { - this.#now = options.now ?? (() => Date.now()); - } +export interface MemoryJobQueueEntry { + readonly availableAt: number; + readonly enqueuedAt: number; + readonly request: Request; +} +export class MemoryJobProvider implements JobProvider { get size(): number { return this.#queue.length; } - peek(): MemoryJobQueueEntry | undefined { - return this.#queue[0]; - } + readonly #now: () => number; + readonly #queue: Array = []; - dequeue(): MemoryJobQueueEntry | undefined { - return this.#queue.shift(); + readonly #timers = new Set>(); + + constructor(options: MemoryJobProviderOptions = {}) { + this.#now = options.now ?? (() => Date.now()); } clear(): void { @@ -40,15 +33,19 @@ export class MemoryJobProvider implements JobProvider { this.#queue.length = 0; } + dequeue(): MemoryJobQueueEntry | undefined { + return this.#queue.shift(); + } + async enqueue(request: Request, options: JobEnqueueOptions): Promise { const enqueuedAt = this.#now(); const availableAt = options._ === 'delayed' ? enqueuedAt + options.delay : enqueuedAt; const entry: MemoryJobQueueEntry = { - request, - enqueuedAt, availableAt, + enqueuedAt, + request, }; if (options._ === 'delayed') { @@ -62,4 +59,8 @@ export class MemoryJobProvider implements JobProvider { this.#queue.push(entry); } + + peek(): MemoryJobQueueEntry | undefined { + return this.#queue[0]; + } } diff --git a/packages/playground/src/job/configuration.ts b/packages/playground/src/job/configuration.ts index cb34101976..05c1075d37 100644 --- a/packages/playground/src/job/configuration.ts +++ b/packages/playground/src/job/configuration.ts @@ -1,8 +1,10 @@ import { useConfiguration } from '@w5s/application'; -import { meta } from './meta.js'; -import { MemoryJobProvider } from './MemoryJobProvider.js'; + import type { JobProvider } from './JobProvider.js'; +import { MemoryJobProvider } from './MemoryJobProvider.js'; +import { meta } from './meta.js'; + export interface Configuration { /** * The JobProvider instance to be used for managing job queues and execution. diff --git a/packages/playground/src/main.ts b/packages/playground/src/main.ts index 66d1cb6dad..ab15cf805f 100644 --- a/packages/playground/src/main.ts +++ b/packages/playground/src/main.ts @@ -1,19 +1,21 @@ -import { CodecError, Int, Result } from '@w5s/core'; -import { Task } from '@w5s/task'; +import type { LogSendFunction } from '@w5s/log/dist/Log/sendWith.js'; + import { Console } from '@w5s/console'; -import { TimeDuration } from '@w5s/time'; +import { CodecError, Int, Result } from '@w5s/core'; +import { AbortError, assertNever, TimeoutError } from '@w5s/error'; import { HTTPError } from '@w5s/http'; -import { randomUUID as defaultRandomUUID } from '@w5s/uuid'; +import { debug, error, Log as LogModule } from '@w5s/log'; import { EUR, Money } from '@w5s/money'; +import { Task } from '@w5s/task'; import { timeout } from '@w5s/task-timeout'; -import { AbortError, assertNever, TimeoutError } from '@w5s/error'; -import { Log as LogModule, debug, error } from '@w5s/log'; -import type { LogSendFunction } from '@w5s/log/dist/Log/sendWith.js'; +import { TimeDuration } from '@w5s/time'; +import { randomUUID as defaultRandomUUID } from '@w5s/uuid'; + +import { ContainerKey, provide, use } from './di/index.js'; import { pipe } from './pipe.js'; -import { retry, RetryPolicy, RetryResult } from './task-retry/retry.js'; import { Slack } from './slackClient.js'; -import { ContainerKey, provide, use } from './di/index.js'; import { abortable } from './task-abortable/index.js'; +import { retry, RetryPolicy, RetryResult } from './task-retry/retry.js'; const RandomUUID = ContainerKey('RandomUUID', () => defaultRandomUUID); const Logger = ContainerKey('Logger', (): ((name: string) => LogSendFunction) => LogModule.sendWith); @@ -22,24 +24,6 @@ const app = { ...provide(Logger, () => LogModule.sendWith), }; -function sendMessage(text: string) { - const client = Slack({ token: 'token' }); - - return pipe( - Slack.Chat.postMessage(client, { - channel: Slack.ChannelId('my-channel'), - text, - }), - ).to( - (_) => timeout(_, TimeDuration({ minutes: 1 })), - (_) => - retry(_, { - policy: RetryPolicy.retries(Int(3)), - check: (result) => Task.resolve(Result.isError(result) ? RetryResult.Continue() : RetryResult.Done), - }), - ); -} - function main() { const amount = EUR('1.55'); const randomUUID = use(app, RandomUUID); @@ -55,11 +39,11 @@ function main() { (_) => Task.orElse(_, (err) => { switch (err.name) { - case Slack.Error.errorName: { - return log(error`SlackError:${err.message}`); + case AbortError.errorName: { + return log(error`Abort Error:${err.message}`); } - case TimeoutError.errorName: { - return log(error`TimeoutError:${err.message}`); + case CodecError.errorName: { + return log(error`Decode Error:${err.message}`); } case HTTPError.InvalidURL.errorName: { return log(error`InvalidURLError:${err.message}`); @@ -70,11 +54,11 @@ function main() { case HTTPError.ParserError.errorName: { return log(error`ParserError:${err.message}`); } - case CodecError.errorName: { - return log(error`Decode Error:${err.message}`); + case Slack.Error.errorName: { + return log(error`SlackError:${err.message}`); } - case AbortError.errorName: { - return log(error`Abort Error:${err.message}`); + case TimeoutError.errorName: { + return log(error`TimeoutError:${err.message}`); } default: { // return Console.error(`Unknown Error:${error.message}`); @@ -103,11 +87,8 @@ function main2() { return Task.orElse(task, (_error) => { switch (_error.name) { - case Slack.Error.errorName: { - return Console.error(`SlackError:${_error.message}`); - } - case TimeoutError.errorName: { - return Console.error(`TimeoutError:${_error.message}`); + case CodecError.errorName: { + return Console.error(`Decode Error:${_error.message}`); } case HTTPError.InvalidURL.errorName: { return Console.error(`InvalidURLError:${_error.message}`); @@ -118,8 +99,11 @@ function main2() { case HTTPError.ParserError.errorName: { return Console.error(`ParserError:${_error.message}`); } - case CodecError.errorName: { - return Console.error(`Decode Error:${_error.message}`); + case Slack.Error.errorName: { + return Console.error(`SlackError:${_error.message}`); + } + case TimeoutError.errorName: { + return Console.error(`TimeoutError:${_error.message}`); } default: { // return Console.error(`Unknown Error:${error.message}`); @@ -129,6 +113,24 @@ function main2() { }); } +function sendMessage(text: string) { + const client = Slack({ token: 'token' }); + + return pipe( + Slack.Chat.postMessage(client, { + channel: Slack.ChannelId('my-channel'), + text, + }), + ).to( + (_) => timeout(_, TimeDuration({ minutes: 1 })), + (_) => + retry(_, { + check: (result) => Task.resolve(Result.isError(result) ? RetryResult.Continue() : RetryResult.Done), + policy: RetryPolicy.retries(Int(3)), + }), + ); +} + void Task.run(main()); // alternate syntax void main().run(); diff --git a/packages/playground/src/net/IPv4.spec.ts b/packages/playground/src/net/IPv4.spec.ts index 1f705b1372..7932a1b325 100644 --- a/packages/playground/src/net/IPv4.spec.ts +++ b/packages/playground/src/net/IPv4.spec.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { CodecError, Result } from '@w5s/core'; import { describeBounded, describeCodec, @@ -6,14 +6,15 @@ import { describeIndexable, describeType, } from '@w5s/core/dist/Testing.js'; -import { CodecError, Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { IPv4 } from './IPv4.js'; describe('IPv4', () => { describeType(IPv4, () => ({ - typeName: 'IPv4', instances: [IPv4(0xFF_FF_FF_FF)], notInstances: [undefined, 0xFF_FF_FF_FF, '127.0.0.1'], + typeName: 'IPv4', })); describe(IPv4.of, () => { it('should return an IPv4 instance', () => { @@ -39,18 +40,22 @@ describe('IPv4', () => { describeCodec(IPv4, () => ({ decode: [ ['127.0.0.1', Result.Ok(IPv4.of(127, 0, 0, 1))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as IPv4', input: null }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as IPv4' }))], ], encode: [ [IPv4.of(127, 0, 0, 1), '127.0.0.1'], [IPv4.of(192, 168, 0, 1), '192.168.0.1'], ], schema: { - type: 'string', format: 'ipv4', + type: 'string', }, })); describeComparable(IPv4, { + equivalent: () => [ + [IPv4.of(0, 0, 0, 1), IPv4.of(0, 0, 0, 1)], + [IPv4.of(192, 168, 0, 1), IPv4.of(192, 168, 0, 1)], + ], ordered: () => [ // lower to higher IPv4.of(0, 0, 0, 0), @@ -59,14 +64,10 @@ describe('IPv4', () => { IPv4.of(192, 168, 0, 255), IPv4.of(255, 255, 255, 255), ], - equivalent: () => [ - [IPv4.of(0, 0, 0, 1), IPv4.of(0, 0, 0, 1)], - [IPv4.of(192, 168, 0, 1), IPv4.of(192, 168, 0, 1)], - ], }); describeBounded(IPv4, { - minValue: IPv4.of(0, 0, 0, 0), maxValue: IPv4.of(255, 255, 255, 255), + minValue: IPv4.of(0, 0, 0, 0), }); describeIndexable(IPv4, { index: [ diff --git a/packages/playground/src/net/IPv4.ts b/packages/playground/src/net/IPv4.ts index 9bbc8a8b68..f40f1dbb18 100644 --- a/packages/playground/src/net/IPv4.ts +++ b/packages/playground/src/net/IPv4.ts @@ -1,13 +1,12 @@ -import type { Bounded, Int, Codec, Option, Ordering } from '@w5s/core'; -import { Struct } from '@w5s/core/dist/Struct.js'; -import { Symbol } from '@w5s/core/dist/Symbol.js'; +import type { Bounded, Codec, Int, Option, Ordering } from '@w5s/core'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { Comparable } from '@w5s/core/dist/Comparable.js'; import { Indexable } from '@w5s/core/dist/Indexable.js'; +import { Struct } from '@w5s/core/dist/Struct.js'; +import { Symbol } from '@w5s/core/dist/Symbol.js'; import { compare as numberCompare } from '@w5s/num/dist/Number/compare.js'; -export type IPv4Address = Int; - /** * IPv4 string type */ @@ -15,9 +14,14 @@ export interface IPv4 extends Struct<{ [Struct.type]: 'IPv4'; ipv4: IPv4Address; }> {} + +export type IPv4Address = Int; const IPv4Type = Struct.define({ typeName: 'IPv4' }); const IPv4Format = { + format({ ipv4 }: IPv4): string { + return `${(ipv4 >>> 24) & 0xFF}.${(ipv4 >>> 16) & 0xFF}.${(ipv4 >>> 8) & 0xFF}.${ipv4 & 0xFF}`; + }, parse(expression: string): Option { const parts = expression.split('.'); @@ -37,14 +41,10 @@ const IPv4Format = { } return undefined; }, - format({ ipv4 }: IPv4): string { - return `${(ipv4 >>> 24) & 0xFF}.${(ipv4 >>> 16) & 0xFF}.${(ipv4 >>> 8) & 0xFF}.${ipv4 & 0xFF}`; - }, }; const IPv4Codec: Codec = { - [Symbol.encode]: (input) => IPv4Format.format(input), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string') { const parsed = IPv4Format.parse(input); if (parsed != null) { @@ -53,12 +53,17 @@ const IPv4Codec: Codec = { } return error(input, 'IPv4'); }, + [Symbol.encode]: (input) => IPv4Format.format(input), [Symbol.schema]: () => ({ - type: 'string', format: 'ipv4', + type: 'string', }), }; +function compare(left: IPv4, right: IPv4): Ordering { + return numberCompare(left.ipv4 >>> 0, right.ipv4 >>> 0); +} + function fromNumber(value: number): IPv4 { return IPv4Type({ ipv4: (value & 0xFF_FF_FF_FF) as IPv4Address }); } @@ -67,23 +72,19 @@ function of(_0: number, _1: number, _2: number, _3: number) { return IPv4Type({ ipv4: ((_0 << 24) | (_1 << 16) | (_2 << 8) | _3) as IPv4Address }); } -function compare(left: IPv4, right: IPv4): Ordering { - return numberCompare(left.ipv4 >>> 0, right.ipv4 >>> 0); -} - const IPv4Comparable = Comparable({ compare, }); const IPv4Bounded: Bounded = { - minValue: fromNumber(0), maxValue: fromNumber(0xFF_FF_FF_FF), + minValue: fromNumber(0), }; const IPv4Indexable = Indexable({ - indexType: 'number', at: (index) => fromNumber(index), indexOf: (value) => value.ipv4, + indexType: 'number', }); const any = of(0, 0, 0, 0); @@ -106,11 +107,11 @@ export const IPv4 = Callable({ ...IPv4Comparable, ...IPv4Bounded, ...IPv4Indexable, - fromNumber, - of, any, - localhost, - loopback, broadcast, [Callable.symbol]: fromNumber, + fromNumber, + localhost, + loopback, + of, }); diff --git a/packages/playground/src/net/IPv6.spec.ts b/packages/playground/src/net/IPv6.spec.ts index 47d3da9e70..12d4a9ee65 100644 --- a/packages/playground/src/net/IPv6.spec.ts +++ b/packages/playground/src/net/IPv6.spec.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { CodecError, Result } from '@w5s/core'; import { describeBounded, describeCodec, @@ -6,14 +6,15 @@ import { describeIndexable, describeType, } from '@w5s/core/dist/Testing.js'; -import { CodecError, Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { IPv6 } from './IPv6.js'; describe('IPv6', () => { describeType(IPv6, () => ({ - typeName: 'IPv6', instances: [IPv6(0xFF_FF, 0xFF_FF, 0x00_00, 0x00_00, 0x00_00, 0x00_00, 0x7F_00, 0x00_01)], notInstances: [undefined, 0xFF_FF, '::ffff:127.0.0.1'], + typeName: 'IPv6', })); describe(IPv6.of, () => { @@ -50,28 +51,28 @@ describe('IPv6', () => { decode: [ ['::ffff:7f00:1', Result.Ok(IPv6.of(0x00_00, 0x00_00, 0x00_00, 0x00_00, 0x00_00, 0xFF_FF, 0x7F_00, 0x00_01))], ['::ffff:127.0.0.1', Result.Ok(IPv6.of(0x00_00, 0x00_00, 0x00_00, 0x00_00, 0x00_00, 0xFF_FF, 0x7F_00, 0x00_01))], - [null, Result.Error(new CodecError({ message: 'Cannot decode null as IPv6', input: null }))], + [null, Result.Error(new CodecError({ input: null, message: 'Cannot decode null as IPv6' }))], ], encode: [[IPv6.of(0x00_00, 0x00_00, 0x00_00, 0x00_00, 0x00_00, 0xFF_FF, 0x7F_00, 0x00_01), '::ffff:7f00:1']], schema: { - type: 'string', format: 'ipv6', + type: 'string', }, })); describeComparable(IPv6, { + equivalent: () => [[IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0, 1), IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0, 1)]], ordered: () => [ IPv6.of(0, 0, 0, 0, 0, 0, 0, 0), IPv6.of(0, 0, 0, 0, 0, 0, 0, 1), IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0, 0), IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0xC0_A8, 0x00_01), ], - equivalent: () => [[IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0, 1), IPv6.of(0xFF_FF, 0xFF_FF, 0, 0, 0, 0, 0, 1)]], }); describeBounded(IPv6, { - minValue: IPv6.of(0, 0, 0, 0, 0, 0, 0, 0), maxValue: IPv6.of(0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF, 0xFF_FF), + minValue: IPv6.of(0, 0, 0, 0, 0, 0, 0, 0), }); describeIndexable(IPv6, { diff --git a/packages/playground/src/net/IPv6.ts b/packages/playground/src/net/IPv6.ts index e7d30a860b..c58de40140 100644 --- a/packages/playground/src/net/IPv6.ts +++ b/packages/playground/src/net/IPv6.ts @@ -1,14 +1,14 @@ import type { Bounded, Int, Option, Ordering } from '@w5s/core'; -import { Symbol } from '@w5s/core/dist/Symbol.js'; -import { Struct } from '@w5s/core/dist/Struct.js'; + import { Callable } from '@w5s/core/dist/Callable.js'; import { Codec } from '@w5s/core/dist/Codec.js'; import { Comparable } from '@w5s/core/dist/Comparable.js'; import { Indexable } from '@w5s/core/dist/Indexable.js'; +import { Struct } from '@w5s/core/dist/Struct.js'; +import { Symbol } from '@w5s/core/dist/Symbol.js'; import { compare as bigintCompare } from '@w5s/num/dist/BigInt/compare.js'; -import { IPv4 } from './IPv4.js'; -export type IPv6Address = bigint; +import { IPv4 } from './IPv4.js'; /** * IPv6 string type @@ -17,6 +17,8 @@ export interface IPv6 extends Struct<{ [Struct.type]: 'IPv6'; ipv6: IPv6Address; }> {} + +export type IPv6Address = bigint; const IPv6Type = Struct.define({ typeName: 'IPv6' }); const bigIntByteAt = (ipv6Value: bigint, index: number) => @@ -38,6 +40,21 @@ const parseIPv4 = (ipv4Expr: string): Option => { }; const IPv6Format = { + format({ ipv6 }: IPv6): string { + // Convert bigint to 8 segments of 16-bit hex values + return [ + bigIntStringifyAt(ipv6, 0), + bigIntStringifyAt(ipv6, 1), + bigIntStringifyAt(ipv6, 2), + bigIntStringifyAt(ipv6, 3), + bigIntStringifyAt(ipv6, 4), + bigIntStringifyAt(ipv6, 5), + bigIntStringifyAt(ipv6, 6), + bigIntStringifyAt(ipv6, 7), + ] + .join(':') + .replaceAll(/^(:){2,}/g, '::'); + }, parse(expression: string): Option { let parts = expression.split(':'); if (parts.length <= 2) return undefined; @@ -61,6 +78,7 @@ const IPv6Format = { parts = [...Array.from({ length: 6 - parts.length }, () => '0'), ...parts]; let bigintAddress = 0n; + // eslint-disable-next-line ts/prefer-for-of for (let index = 0; index < parts.length; index += 1) { const parsedPart = parseHex(parts[index]!); if (parsedPart == null) return undefined; @@ -70,26 +88,10 @@ const IPv6Format = { return fromBigInt(bigintAddress); }, - format({ ipv6 }: IPv6): string { - // Convert bigint to 8 segments of 16-bit hex values - return [ - bigIntStringifyAt(ipv6, 0), - bigIntStringifyAt(ipv6, 1), - bigIntStringifyAt(ipv6, 2), - bigIntStringifyAt(ipv6, 3), - bigIntStringifyAt(ipv6, 4), - bigIntStringifyAt(ipv6, 5), - bigIntStringifyAt(ipv6, 6), - bigIntStringifyAt(ipv6, 7), - ] - .join(':') - .replaceAll(/^(:){2,}/g, '::'); - }, }; const IPv6Codec: Codec = { - [Symbol.encode]: (input) => IPv6Format.format(input), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { if (typeof input === 'string') { const parsed = IPv6Format.parse(input); if (parsed != null) { @@ -98,12 +100,17 @@ const IPv6Codec: Codec = { } return error(input, 'IPv6'); }, + [Symbol.encode]: (input) => IPv6Format.format(input), [Symbol.schema]: () => ({ - type: 'string', format: 'ipv6', + type: 'string', }), }; +function compare(left: IPv6, right: IPv6): Ordering { + return bigintCompare(left.ipv6, right.ipv6); +} + function fromBigInt(value: bigint): IPv6 { return IPv6Type({ ipv6: value }); } @@ -113,23 +120,19 @@ function of(...parts: [number, number, number, number, number, number, number, n return fromBigInt(bigintAddress); } -function compare(left: IPv6, right: IPv6): Ordering { - return bigintCompare(left.ipv6, right.ipv6); -} - const IPv6Comparable = Comparable({ compare, }); const IPv6Bounded: Bounded = { - minValue: fromBigInt(0n), maxValue: fromBigInt(0xFF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FF_FFn), + minValue: fromBigInt(0n), }; const IPv6Indexable = Indexable({ - indexType: 'bigint', at: (index) => fromBigInt(index), indexOf: (value) => value.ipv6, + indexType: 'bigint', }); const any = of(0, 0, 0, 0, 0, 0, 0, 0); @@ -150,10 +153,10 @@ export const IPv6 = Callable({ ...IPv6Comparable, ...IPv6Bounded, ...IPv6Indexable, - fromBigInt, - of, any, - loopback, - localhost, [Callable.symbol]: of, + fromBigInt, + localhost, + loopback, + of, }); diff --git a/packages/playground/src/pipe.spec.ts b/packages/playground/src/pipe.spec.ts index c2ac28cb20..3745b18a5d 100644 --- a/packages/playground/src/pipe.spec.ts +++ b/packages/playground/src/pipe.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { pipe } from './pipe.js'; describe('pipe', () => { diff --git a/packages/playground/src/pipe.ts b/packages/playground/src/pipe.ts index 3779b522e7..c61b9884c1 100644 --- a/packages/playground/src/pipe.ts +++ b/packages/playground/src/pipe.ts @@ -1,109 +1,5 @@ /* eslint-disable ts/no-unsafe-function-type */ -/** - * Pipe `value` to a sequence of function. - * - * @example - * ```typescript - * pipe(value).to();// value - * pipe(value).to(f);// f(value) or value |> f - * pipe(value).to(f, g);// g(f(value)) or value |> f |> g - * // and so on... - * ``` - * @param value the value to pass to the first function - */ -export function pipe(value: Value): Pipe { - return { - to( - ab?: Function, - bc?: Function, - cd?: Function, - de?: Function, - ef?: Function, - fg?: Function, - gh?: Function, - hi?: Function, - ij?: Function, - jk?: Function, - kl?: Function, - lm?: Function, - mn?: Function, - no?: Function, - op?: Function, - pq?: Function, - qr?: Function, - rs?: Function, - st?: Function, - ) { - switch (arguments.length) { - case 0: { - return value; - } - case 1: { - return ab!(value); - } - case 2: { - return bc!(ab!(value)); - } - case 3: { - return cd!(bc!(ab!(value))); - } - case 4: { - return de!(cd!(bc!(ab!(value)))); - } - case 5: { - return ef!(de!(cd!(bc!(ab!(value))))); - } - case 6: { - return fg!(ef!(de!(cd!(bc!(ab!(value)))))); - } - case 7: { - return gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))); - } - case 8: { - return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))); - } - case 9: { - return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))); - } - case 10: { - return jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))); - } - case 11: { - return kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))); - } - case 12: { - return lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))); - } - case 13: { - return mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))); - } - case 14: { - return no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))); - } - case 15: { - return op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))); - } - case 16: { - return pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))))); - } - case 17: { - return qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))))); - } - case 18: { - return rs!(qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))))))); - } - case 19: { - return st!(rs!(qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))))))); - } - default: { - throw new TypeError('Wrong arity'); - } - } - }, - }; -} - interface Pipe { to(): A; to(ab: (_: A) => B): B; @@ -315,3 +211,107 @@ interface Pipe { st: (_: S) => T, ): T; } + +/** + * Pipe `value` to a sequence of function. + * + * @example + * ```typescript + * pipe(value).to();// value + * pipe(value).to(f);// f(value) or value |> f + * pipe(value).to(f, g);// g(f(value)) or value |> f |> g + * // and so on... + * ``` + * @param value the value to pass to the first function + */ +export function pipe(value: Value): Pipe { + return { + to( + ab?: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function, + ij?: Function, + jk?: Function, + kl?: Function, + lm?: Function, + mn?: Function, + no?: Function, + op?: Function, + pq?: Function, + qr?: Function, + rs?: Function, + st?: Function, + ) { + switch (arguments.length) { + case 0: { + return value; + } + case 1: { + return ab!(value); + } + case 2: { + return bc!(ab!(value)); + } + case 3: { + return cd!(bc!(ab!(value))); + } + case 4: { + return de!(cd!(bc!(ab!(value)))); + } + case 5: { + return ef!(de!(cd!(bc!(ab!(value))))); + } + case 6: { + return fg!(ef!(de!(cd!(bc!(ab!(value)))))); + } + case 7: { + return gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))); + } + case 8: { + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))); + } + case 9: { + return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))); + } + case 10: { + return jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))); + } + case 11: { + return kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))); + } + case 12: { + return lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))); + } + case 13: { + return mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))); + } + case 14: { + return no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))); + } + case 15: { + return op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))); + } + case 16: { + return pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))))); + } + case 17: { + return qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))))); + } + case 18: { + return rs!(qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value)))))))))))))))))); + } + case 19: { + return st!(rs!(qr!(pq!(op!(no!(mn!(lm!(kl!(jk!(ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(value))))))))))))))))))); + } + default: { + throw new TypeError('Wrong arity'); + } + } + }, + }; +} diff --git a/packages/playground/src/secret/Secret.ts b/packages/playground/src/secret/Secret.ts index 7a649abe2f..4197fb060e 100644 --- a/packages/playground/src/secret/Secret.ts +++ b/packages/playground/src/secret/Secret.ts @@ -1,4 +1,5 @@ import type { Struct } from '@w5s/core'; + import { of } from './Secret/of.js'; import { SecretAsString } from './Secret/SecretAsString.js'; import { value } from './Secret/value.js'; @@ -7,14 +8,14 @@ export interface Secret extends Struct<{ _: 'Secret' }> { ['@@secret']: T; /** - * Returns string conversion + * Return JSON conversion */ - toString(): string; + toJSON(): string; /** - * Return JSON conversion + * Returns string conversion */ - toJSON(): string; + toString(): string; } /** diff --git a/packages/playground/src/secret/Secret/Secret.ts b/packages/playground/src/secret/Secret/Secret.ts index 99cb9b17ec..e48838dbfd 100644 --- a/packages/playground/src/secret/Secret/Secret.ts +++ b/packages/playground/src/secret/Secret/Secret.ts @@ -1,4 +1,5 @@ import { Symbol } from '@w5s/core/dist/Symbol.js'; + import { state } from '../internal/state.js'; import { SecretAsString } from './SecretAsString.js'; @@ -13,11 +14,11 @@ export class Secret { return SecretAsString.asString(this); } - toString() { + toJSON() { return SecretAsString.asString(this); } - toJSON() { + toString() { return SecretAsString.asString(this); } } diff --git a/packages/playground/src/secret/Secret/SecretAsString.ts b/packages/playground/src/secret/Secret/SecretAsString.ts index 33517456f6..e067f842d4 100644 --- a/packages/playground/src/secret/Secret/SecretAsString.ts +++ b/packages/playground/src/secret/Secret/SecretAsString.ts @@ -1,4 +1,5 @@ import type { AsString } from '@w5s/core'; + import type { Secret } from '../Secret.js'; export const SecretAsString: AsString, '_'>> = { diff --git a/packages/playground/src/secret/Secret/of.ts b/packages/playground/src/secret/Secret/of.ts index 1ad9d6fe94..bd4f4a815c 100644 --- a/packages/playground/src/secret/Secret/of.ts +++ b/packages/playground/src/secret/Secret/of.ts @@ -1,4 +1,5 @@ import type { Secret } from '../Secret.js'; + import { Secret as SecretImpl } from './Secret.js'; /** diff --git a/packages/playground/src/secret/Secret/value.ts b/packages/playground/src/secret/Secret/value.ts index b460c89550..1558c78f10 100644 --- a/packages/playground/src/secret/Secret/value.ts +++ b/packages/playground/src/secret/Secret/value.ts @@ -1,6 +1,7 @@ -import { state } from '../internal/state.js'; import type { Secret } from '../Secret.js'; +import { state } from '../internal/state.js'; + /** * Returns the content of self * diff --git a/packages/playground/src/secret/index.spec.ts b/packages/playground/src/secret/index.spec.ts index 87c6716fdb..1634682270 100644 --- a/packages/playground/src/secret/index.spec.ts +++ b/packages/playground/src/secret/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/playground/src/secret/internal/state.ts b/packages/playground/src/secret/internal/state.ts index 62356d5726..dfdc07a434 100644 --- a/packages/playground/src/secret/internal/state.ts +++ b/packages/playground/src/secret/internal/state.ts @@ -1,4 +1,5 @@ import { useGlobal } from '@w5s/global-storage'; + import { meta } from '../meta.js'; export type SecretState = WeakMap; diff --git a/packages/playground/src/shallowEqual.spec.ts b/packages/playground/src/shallowEqual.spec.ts index 8d15f8febc..7a9f74ccff 100644 --- a/packages/playground/src/shallowEqual.spec.ts +++ b/packages/playground/src/shallowEqual.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; + import { shallowEqual } from './shallowEqual.js'; describe('shallowEqual', () => { @@ -47,10 +48,10 @@ describe('shallowEqual', () => { }); it('should provide the correct `equalValueFn` arguments', () => { - type TestObject = { - a: number[]; + interface TestObject { + a: Array; b: typeof objectCommon; - }; + } const objectCommon = { common: true }; const object1: TestObject = { a: [1, 2], b: objectCommon }; @@ -66,7 +67,7 @@ describe('shallowEqual', () => { }); it('should not handle comparisons if `equalFn` returns `true`', () => { - const equalFn = (value: string | number) => typeof value === 'string'; + const equalFn = (value: number | string) => typeof value === 'string'; // expect(shallowEqual(['a'], ['b'], equalFn)).toEqual(true); expect(shallowEqual({ 0: 'a' }, { 0: 'b' }, equalFn)).toEqual(true); diff --git a/packages/playground/src/shallowEqual.ts b/packages/playground/src/shallowEqual.ts index c143453ef7..335c5c0f24 100644 --- a/packages/playground/src/shallowEqual.ts +++ b/packages/playground/src/shallowEqual.ts @@ -1,5 +1,6 @@ -type ValueOf = T extends Array ? V : T[keyof T]; +/* eslint-disable ts/prefer-for-of */ type KeyOf = T extends Array ? number : keyof T; +type ValueOf = T extends Array ? V : T[keyof T]; /** * Returns `true` when left and right are strictly equal or have same properties diff --git a/packages/playground/src/slackClient.ts b/packages/playground/src/slackClient.ts index c36e518297..09b902aed2 100644 --- a/packages/playground/src/slackClient.ts +++ b/packages/playground/src/slackClient.ts @@ -1,21 +1,27 @@ -import type { Option, JSONValue } from '@w5s/core'; -import type { Task } from '@w5s/task'; +import type { JSONValue, Option } from '@w5s/core'; import type { Method } from '@w5s/http'; -import { Client } from '@w5s/http/dist/Client.js'; -import { requestSend } from '@w5s/http/dist/requestSend.js'; -import { ResponseParser } from '@w5s/http/dist/ResponseParser.js'; -import { HTTPError } from '@w5s/http/dist/HTTPError.js'; -import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; -import { Tag } from '@w5s/core/dist/Tag.js'; -import { Enum } from '@w5s/core/dist/Enum.js'; +import type { Task } from '@w5s/task'; + import { CodecError } from '@w5s/core/dist/CodecError.js'; -import { mapResult } from '@w5s/task/dist/Task/mapResult.js'; -import { Ok } from '@w5s/core/dist/Result/Ok.js'; +import { Enum } from '@w5s/core/dist/Enum.js'; import { Error as Err } from '@w5s/core/dist/Result/Error.js'; +import { Ok } from '@w5s/core/dist/Result/Ok.js'; +import { Tag } from '@w5s/core/dist/Tag.js'; +import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; import { TimeoutError } from '@w5s/error/dist/TimeoutError.js'; +import { Client } from '@w5s/http/dist/Client.js'; +import { HTTPError } from '@w5s/http/dist/HTTPError.js'; +import { requestSend } from '@w5s/http/dist/requestSend.js'; +import { ResponseParser } from '@w5s/http/dist/ResponseParser.js'; import { andThen } from '@w5s/task/dist/Task/andThen.js'; +import { mapResult } from '@w5s/task/dist/Task/mapResult.js'; export interface Slack { + /** + * HTTP client + */ + readonly httpClient: Client; + /** * Slack base URL */ @@ -25,38 +31,33 @@ export interface Slack { * Slack API token */ readonly slackToken: string; - - /** - * HTTP client - */ - readonly httpClient: Client; } export function Slack({ baseURL: slackBaseURL = 'https://slack.com/api', - token: slackToken, httpClient = Client(), + token: slackToken, }: { baseURL?: Slack['slackBaseURL']; - token: Slack['slackToken']; httpClient?: Client; + token: Slack['slackToken']; }): Slack { return { + httpClient, slackBaseURL, slackToken, - httpClient, }; } export namespace Slack { - type Id = string & Tag; + export type ChannelId = Id<'SlackChannelId'>; - function MakeId>(typeName: string) { - return Tag.define({ typeName, hasInstance: (anyValue) => typeof anyValue === 'string' }); - } + type Id = string & Tag; // export type URL = string; - export type ChannelId = Id<'SlackChannelId'>; + function MakeId>(typeName: string) { + return Tag.define({ hasInstance: (anyValue) => typeof anyValue === 'string', typeName }); + } export const ChannelId = MakeId('SlackChannelId'); export type UserId = Id<'SlackUserId'>; @@ -83,15 +84,12 @@ export namespace Slack { }); export type ErrorCode = Enum.ValueOf; - export class Error extends ErrorClass({ errorName: 'SlackError' })<{ slackErrorCode: ErrorCode }> {} + type ResponseBase = + | { [key: string]: JSONValue; ok: true } + | { error: ErrorCode; ok: false } + | { ok: Exclude }; - function urlWithQuery(url: string, parameters: { [key: string]: string }) { - const urlObject = new URL(url); - for (const [key, value] of Object.entries(parameters)) { - urlObject.searchParams.append(key, value); - } - return urlObject.toString(); - } + type ResponseError = CodecError | Error | HTTPError | TimeoutError; // const TResponseError = Type.Object({ // ok: Type.Boolean.False, @@ -99,21 +97,16 @@ export namespace Slack { // }); // type TResponseError = Type.TypeOf; - type ResponseBase = - | { ok: true; [key: string]: JSONValue } - | { ok: false; error: ErrorCode } - | { ok: Exclude }; - - type ResponseError = CodecError | HTTPError | TimeoutError | Error; + export class Error extends ErrorClass({ errorName: 'SlackError' })<{ slackErrorCode: ErrorCode }> {} - function apiCall(client: Slack, method: Method, parameters: { [key: string]: unknown }): Task { + function apiCall(client: Slack, method: Method, parameters: Record): Task { const { httpClient } = client; const request = requestSend(httpClient, { + method: 'POST', url: urlWithQuery(`${client.slackBaseURL}/${method}`, { token: client.slackToken, ...parameters, }), - method: 'POST', }); const parsed = andThen(request, ResponseParser.json('unsafe')); const requestParsed = mapResult(parsed, (result) => @@ -122,23 +115,31 @@ export namespace Slack { ? Ok(result.value as R) : result.value.ok === false ? Err(new Error({ message: 'Slack Error!', slackErrorCode: result.value.error })) - : Err(new CodecError({ message: 'Decode Error!', input: result.value })) + : Err(new CodecError({ input: result.value, message: 'Decode Error!' })) : result, ); return requestParsed; } + function urlWithQuery(url: string, parameters: Record) { + const urlObject = new URL(url); + for (const [key, value] of Object.entries(parameters)) { + urlObject.searchParams.append(key, value); + } + return urlObject.toString(); + } + export namespace Chat { export function postMessage(client: Slack, request: postMessage.Request) { return apiCall(client, 'chat.postMessage', { as_user: 'true', ...request }); } export namespace postMessage { export interface Request extends Readonly<{ - // username?: Slack.UserId; - text?: Option; - channel?: Option; // blocks?: Array; attachments?: Array; + channel?: Option; + // username?: Slack.UserId; + text?: Option; }> {} export type Response = void; } diff --git a/packages/playground/src/task-abortable/abort.ts b/packages/playground/src/task-abortable/abort.ts index 2a17ad3856..30b849bcb1 100644 --- a/packages/playground/src/task-abortable/abort.ts +++ b/packages/playground/src/task-abortable/abort.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; /** diff --git a/packages/playground/src/task-abortable/abortable.spec.ts b/packages/playground/src/task-abortable/abortable.spec.ts index 027cf98f93..016b0cf51a 100644 --- a/packages/playground/src/task-abortable/abortable.spec.ts +++ b/packages/playground/src/task-abortable/abortable.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { FakeTask, withTask } from '@w5s/task/dist/Testing.js'; import { AbortError } from '@w5s/error'; +import { FakeTask, withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { abortable } from './abortable.js'; describe(abortable, () => { diff --git a/packages/playground/src/task-abortable/abortable.ts b/packages/playground/src/task-abortable/abortable.ts index 47427a5ec9..c45781bac1 100644 --- a/packages/playground/src/task-abortable/abortable.ts +++ b/packages/playground/src/task-abortable/abortable.ts @@ -1,5 +1,5 @@ -import { type TaskLike, Task } from '@w5s/task'; import { AbortError } from '@w5s/error/dist/AbortError.js'; +import { Task, type TaskLike } from '@w5s/task'; import { from } from '@w5s/task/dist/Task/from.js'; import { unsafeCall } from '@w5s/task/dist/Task/unsafeCall.js'; @@ -27,7 +27,7 @@ export interface AbortOptions { export function abortable( task: TaskLike, options: AbortOptions, -): Task { +): Task { return from((parameters) => { const { reject } = parameters; const { signal: abortSignal } = options; diff --git a/packages/playground/src/task-abortable/index.spec.ts b/packages/playground/src/task-abortable/index.spec.ts index 10f8cb5657..f7bf7d38db 100644 --- a/packages/playground/src/task-abortable/index.spec.ts +++ b/packages/playground/src/task-abortable/index.spec.ts @@ -1,14 +1,15 @@ import { describe, expect, it } from 'vitest'; -import * as Module from './index.js'; -import { abortable } from './abortable.js'; + import { abort } from './abort.js'; +import { abortable } from './abortable.js'; +import * as Module from './index.js'; describe('module public API', () => { it('should return correct values', () => { expect(Module).toEqual( expect.objectContaining({ - abortable, abort, + abortable, }), ); }); diff --git a/packages/playground/src/task-abortable/index.ts b/packages/playground/src/task-abortable/index.ts index a6b97e9bed..5bdf976023 100644 --- a/packages/playground/src/task-abortable/index.ts +++ b/packages/playground/src/task-abortable/index.ts @@ -1,2 +1,2 @@ -export * from './abortable.js'; export * from './abort.js'; +export * from './abortable.js'; diff --git a/packages/playground/src/task-disposable/dispose.ts b/packages/playground/src/task-disposable/dispose.ts index 7f40d246d4..f49c76f329 100644 --- a/packages/playground/src/task-disposable/dispose.ts +++ b/packages/playground/src/task-disposable/dispose.ts @@ -1,4 +1,5 @@ import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; /** @@ -11,7 +12,7 @@ import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; * ``` * @param resource The Disposable or AsyncDisposable to dispose */ -export function dispose(resource: Disposable | AsyncDisposable): Task { +export function dispose(resource: AsyncDisposable | Disposable): Task { return taskFrom(({ resolve }) => Symbol.asyncDispose in resource ? resource[Symbol.asyncDispose]().then(resolve) diff --git a/packages/playground/src/task-disposable/index.spec.ts b/packages/playground/src/task-disposable/index.spec.ts index 19f47e0bd9..85b9fe4a33 100644 --- a/packages/playground/src/task-disposable/index.spec.ts +++ b/packages/playground/src/task-disposable/index.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import * as Module from './index.js'; + import { dispose } from './dispose.js'; +import * as Module from './index.js'; import { using } from './using.js'; describe('module public API', () => { diff --git a/packages/playground/src/task-disposable/using.ts b/packages/playground/src/task-disposable/using.ts index 0552dbefa2..74d3dded70 100644 --- a/packages/playground/src/task-disposable/using.ts +++ b/packages/playground/src/task-disposable/using.ts @@ -1,13 +1,11 @@ import type { Task, TaskLike } from '@w5s/task'; + import { all as taskAll } from '@w5s/task/dist/Task/all.js'; import { andRun as taskAndRun } from '@w5s/task/dist/Task/andRun.js'; import { andThen as taskThen } from '@w5s/task/dist/Task/andThen.js'; import { map as taskMap } from '@w5s/task/dist/Task/map.js'; -import { dispose } from './dispose.js'; -function disposeAll(resources: { disposables: ReadonlyArray }) { - return taskAll(resources.disposables.map(dispose)); -} +import { dispose } from './dispose.js'; /** * Returns a task that will be mapped to `thenFn` arguments and then disposed. @@ -23,15 +21,15 @@ function disposeAll(resources: { disposables: ReadonlyArray[], ToValue, ToError>( +export function using>, ToValue, ToError>( tasks: [...T], thenFn: (disposables: { [K in keyof T]: Task.ValueOf }) => TaskLike, ): Task | ToError>; -export function using( +export function using( tasks: Iterable>, thenFn: (disposables: ReadonlyArray) => TaskLike, ): Task, Error | ToError>; -export function using( +export function using( tasks: Iterable>, thenFn: (disposables: any) => TaskLike, ): Task { @@ -44,3 +42,6 @@ export function using returnValue); } +function disposeAll(resources: { disposables: ReadonlyArray }) { + return taskAll(resources.disposables.map(dispose)); +} diff --git a/packages/playground/src/task-retry/retry.spec.ts b/packages/playground/src/task-retry/retry.spec.ts index 1cfa8a468d..48b9596382 100644 --- a/packages/playground/src/task-retry/retry.spec.ts +++ b/packages/playground/src/task-retry/retry.spec.ts @@ -1,8 +1,9 @@ import { Int, Option, Result } from '@w5s/core'; import { Task } from '@w5s/task'; -import { TimeDuration } from '@w5s/time'; -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { TimeDuration } from '@w5s/time'; +import { describe, expect, it, vi } from 'vitest'; + import { defaultRetryState, RetryPolicy, RetryState } from './retry.js'; const expectTask = withTask(expect); @@ -11,20 +12,20 @@ describe('RetryState', () => { it('should return a new state', () => { expect( RetryState({ - retryIndex: Int(1), retryCumulativeDelay: TimeDuration.of(2), + retryIndex: Int(1), retryPreviousDelay: TimeDuration.of(3), }), ).toEqual({ - retryIndex: 1, retryCumulativeDelay: 2, + retryIndex: 1, retryPreviousDelay: 3, }); }); it('should use default values', () => { expect(RetryState({})).toEqual({ - retryIndex: 0, retryCumulativeDelay: 0, + retryIndex: 0, retryPreviousDelay: Option.None, }); }); @@ -32,16 +33,16 @@ describe('RetryState', () => { describe('defaultRetryState', () => { it('should have all values to 0', () => { expect(defaultRetryState).toEqual({ - retryIndex: 0, retryCumulativeDelay: 0, + retryIndex: 0, retryPreviousDelay: Option.None, }); }); }); describe('RetryPolicy', () => { const anyState = RetryState({ - retryIndex: Int(1), retryCumulativeDelay: TimeDuration.of(2), + retryIndex: Int(1), retryPreviousDelay: TimeDuration.of(3), }); const anyDuration = TimeDuration.of(123); @@ -151,14 +152,14 @@ describe('RetryPolicy', () => { it('should return a new state', () => { const policy: RetryPolicy = (_state) => Task.resolve(Option.Some(TimeDuration.of(1))); const state = RetryState({ - retryIndex: Int(1), retryCumulativeDelay: TimeDuration.of(2), + retryIndex: Int(1), retryPreviousDelay: TimeDuration.of(3), }); expectTask(RetryPolicy.apply(policy, state)).toResolveSync( RetryState({ - retryIndex: Int(2), retryCumulativeDelay: TimeDuration.of(3), + retryIndex: Int(2), retryPreviousDelay: TimeDuration.of(1), }), ); @@ -173,14 +174,14 @@ describe('RetryPolicy', () => { it('should return a new state', async () => { const policy: RetryPolicy = (_state) => Task.resolve(Option.Some(TimeDuration.of(1))); const state = RetryState({ - retryIndex: Int(1), retryCumulativeDelay: TimeDuration.of(2), + retryIndex: Int(1), retryPreviousDelay: TimeDuration.of(3), }); await expectTask(RetryPolicy.applyAndDelay(policy, state)).toResolveAsync( RetryState({ - retryIndex: Int(2), retryCumulativeDelay: TimeDuration.of(3), + retryIndex: Int(2), retryPreviousDelay: TimeDuration.of(1), }), ); diff --git a/packages/playground/src/task-retry/retry.ts b/packages/playground/src/task-retry/retry.ts index 6447659429..6f960ed289 100644 --- a/packages/playground/src/task-retry/retry.ts +++ b/packages/playground/src/task-retry/retry.ts @@ -1,17 +1,18 @@ -import type { Option, Int, Result } from '@w5s/core'; +import type { Int, Option, Result } from '@w5s/core'; import type { Task, TaskLike } from '@w5s/task'; +import type { TimeDuration } from '@w5s/time'; + import { Error } from '@w5s/core/dist/Result/Error.js'; import { Ok } from '@w5s/core/dist/Result/Ok.js'; -import { map as taskMap } from '@w5s/task/dist/Task/map.js'; +import { all as taskAll } from '@w5s/task/dist/Task/all.js'; +import { andRun as taskThenRun } from '@w5s/task/dist/Task/andRun.js'; import { andThen as taskThen } from '@w5s/task/dist/Task/andThen.js'; +import { from } from '@w5s/task/dist/Task/from.js'; +import { map as taskMap } from '@w5s/task/dist/Task/map.js'; import { orElse as taskElse } from '@w5s/task/dist/Task/orElse.js'; -import { andRun as taskThenRun } from '@w5s/task/dist/Task/andRun.js'; -import { all as taskAll } from '@w5s/task/dist/Task/all.js'; -import { resolve as taskResolve } from '@w5s/task/dist/Task/resolve.js'; import { reject as taskReject } from '@w5s/task/dist/Task/reject.js'; -import type { TimeDuration } from '@w5s/time'; +import { resolve as taskResolve } from '@w5s/task/dist/Task/resolve.js'; import { delay as timeDelay } from '@w5s/time/dist/Time/delay.js'; -import { from } from '@w5s/task/dist/Task/from.js'; const taskFromResult = (result: Result) => result.ok ? taskResolve(result.value) : taskReject(result.error); @@ -23,14 +24,14 @@ const resolveNone = taskResolve(undefined); */ export interface RetryState { /** - * The index of the current attempt. + * The cumulative delay of the all attempts. */ - readonly retryIndex: Int; + readonly retryCumulativeDelay: TimeDuration; /** - * The cumulative delay of the all attempts. + * The index of the current attempt. */ - readonly retryCumulativeDelay: TimeDuration; + readonly retryIndex: Int; /** * The duration of the current retry attempt @@ -53,8 +54,8 @@ export interface RetryState { */ export function RetryState(parameters: Partial): RetryState { return { - retryIndex: parameters.retryIndex ?? (0 as Int), retryCumulativeDelay: parameters.retryCumulativeDelay ?? (0 as TimeDuration), + retryIndex: parameters.retryIndex ?? (0 as Int), retryPreviousDelay: parameters.retryPreviousDelay, }; } @@ -63,14 +64,12 @@ export function RetryState(parameters: Partial): RetryState { * Default RetryState */ export const defaultRetryState: RetryState = RetryState({ - retryIndex: 0 as Int, retryCumulativeDelay: 0 as TimeDuration, + retryIndex: 0 as Int, retryPreviousDelay: undefined, }); -export interface RetryPolicy { - (state: RetryState): Task, never>; -} +export type RetryPolicy = (state: RetryState) => Task, never>; export const RetryPolicy = { /** * Map the policy delay using `mapFn(delay, state)` @@ -88,19 +87,26 @@ export const RetryPolicy = { }, /** - * Filter the policy delay using `predicate(delay, state)` + * Combines two policies into one. This policy will return : + * - `Option.None`, if one of the policies returns `Option.None`. + * - `Option.Some(max(leftDelay, rightDelay))`, else * * @example * ```typescript - * const maxDelay = TimeDuration.of(4); - * const policy = RetryPolicy.wait(TimeDuration.of(2)); - * const mappedPolicy = RetryPolicy.filter(policy, (delay, state) => state.cumulativeDelay > maxDelay);// Retry until cumulative delay is greater than 4 seconds + * const retryWait1ms = RetryPolicy.wait(TimeDuration.of(1)); + * const retryLimit3 = RetryPolicy.limitRetries(3); + * const retryWait1msAndLimit3 = RetryPolicy.append(retryWait1ms, retryLimit3); * ``` - * @param policy The policy - * @param predicate The predicate function + * @param left The left policy + * @param right The right policy */ - filter(policy: RetryPolicy, predicate: (delay: TimeDuration, state: RetryState) => boolean): RetryPolicy { - return RetryPolicy.andThen(policy, (delay, state) => (predicate(delay, state) ? delay : undefined)); + append(left: RetryPolicy, right: RetryPolicy): RetryPolicy { + return (state: RetryState) => { + const allTask = taskAll([left(state), right(state)]); + return taskMap(allTask, ([leftResult, rightResult]) => + leftResult == null || rightResult == null ? undefined : (Math.max(+leftResult, +rightResult) as TimeDuration), + ); + }; }, /** @@ -121,8 +127,8 @@ export const RetryPolicy = { retryPreviousDelay == null ? retryPreviousDelay : RetryState({ - retryIndex: (+state.retryIndex + 1) as Int, retryCumulativeDelay: (+state.retryCumulativeDelay + +retryPreviousDelay) as TimeDuration, + retryIndex: (+state.retryIndex + 1) as Int, retryPreviousDelay, }), ); @@ -148,26 +154,19 @@ export const RetryPolicy = { }, /** - * Combines two policies into one. This policy will return : - * - `Option.None`, if one of the policies returns `Option.None`. - * - `Option.Some(max(leftDelay, rightDelay))`, else + * Filter the policy delay using `predicate(delay, state)` * * @example * ```typescript - * const retryWait1ms = RetryPolicy.wait(TimeDuration.of(1)); - * const retryLimit3 = RetryPolicy.limitRetries(3); - * const retryWait1msAndLimit3 = RetryPolicy.append(retryWait1ms, retryLimit3); + * const maxDelay = TimeDuration.of(4); + * const policy = RetryPolicy.wait(TimeDuration.of(2)); + * const mappedPolicy = RetryPolicy.filter(policy, (delay, state) => state.cumulativeDelay > maxDelay);// Retry until cumulative delay is greater than 4 seconds * ``` - * @param left The left policy - * @param right The right policy + * @param policy The policy + * @param predicate The predicate function */ - append(left: RetryPolicy, right: RetryPolicy): RetryPolicy { - return (state: RetryState) => { - const allTask = taskAll([left(state), right(state)]); - return taskMap(allTask, ([leftResult, rightResult]) => - leftResult == null || rightResult == null ? undefined : (Math.max(+leftResult, +rightResult) as TimeDuration), - ); - }; + filter(policy: RetryPolicy, predicate: (delay: TimeDuration, state: RetryState) => boolean): RetryPolicy { + return RetryPolicy.andThen(policy, (delay, state) => (predicate(delay, state) ? delay : undefined)); }, /** @@ -184,6 +183,20 @@ export const RetryPolicy = { return resolveNone; } as RetryPolicy, + /** + * A retry policy that retries immediately, but only up to `count` times. + * + * @example + * ```typescript + * const policy = RetryPolicy.retries(Int(3));// Retry 3 times + * ``` + * @category Constructor + * @param count The number of retries to allow + */ + retries(count: Int): RetryPolicy { + return ({ retryIndex }) => taskResolve(retryIndex >= count ? undefined : (0 as TimeDuration)); + }, + /** * A retry policy with a constant delay and unlimited retries. * @@ -234,20 +247,6 @@ export const RetryPolicy = { }; }, - /** - * A retry policy that retries immediately, but only up to `count` times. - * - * @example - * ```typescript - * const policy = RetryPolicy.retries(Int(3));// Retry 3 times - * ``` - * @category Constructor - * @param count The number of retries to allow - */ - retries(count: Int): RetryPolicy { - return ({ retryIndex }) => taskResolve(retryIndex >= count ? undefined : (0 as TimeDuration)); - }, - /** * Set a time upper bound for any delays that may be directed by the given policy. * @@ -264,32 +263,32 @@ export const RetryPolicy = { }, }; -interface RetryDoneResult { - readonly done: true; -} -interface RetryContinueResult { - readonly done: false; - readonly value: Option; -} - /** * Acts like the iterator protocol for retry attempts. * When `{ done: true }` is returned, the retry operation is complete. * When `{ done: false, value: Option.None }` is returned, the retry operation will be done using the default policy delay. * When `{ done: false, value: Option.Some(TimeDuration.of(...)) }` is returned, the retry operation will be done using given delay. */ -export type RetryResult = RetryDoneResult | RetryContinueResult; +export type RetryResult = RetryContinueResult | RetryDoneResult; +interface RetryContinueResult { + readonly done: false; + readonly value: Option; +} + +interface RetryDoneResult { + readonly done: true; +} export const RetryResult = { - Done: Object.freeze({ done: true }), Continue: (value: Option = undefined): RetryContinueResult => ({ done: false, value }), + Done: Object.freeze({ done: true }), }; export function retry( - taskOrGetter: TaskLike | ((state: RetryState) => TaskLike), + taskOrGetter: ((state: RetryState) => TaskLike) | TaskLike, options: retry.Options, ): Task { - const { policy, check, initialState = defaultRetryState } = options; + const { check, initialState = defaultRetryState, policy } = options; const go = (state: RetryState): Task => andThenResult(typeof taskOrGetter === 'function' ? taskOrGetter(state) : taskOrGetter, (result) => taskThen(check(result), (retryResult) => @@ -310,11 +309,11 @@ export function retry( return go(initialState); } export namespace retry { - export type Options = { - policy: RetryPolicy; - initialState?: RetryState; + export interface Options { check: (result: Result) => Task; - }; + initialState?: RetryState; + policy: RetryPolicy; + } } function andThenResult( diff --git a/packages/random/README.md b/packages/random/README.md index 98a4e8778d..6ebdcc5dfc 100644 --- a/packages/random/README.md +++ b/packages/random/README.md @@ -21,17 +21,17 @@ npm install @w5s/random import { randomNumber } from '@w5s/random'; import { Task } from '@w5s/task'; +export function main(): void { + const userTask = createUser('John Doe'); + console.log(Task.run(userTask)); // > Result.Ok({ id: 'XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX', name: 'John Doe' }) +} + function createUser(name: string) { return Task.map(randomNumber(1, 3), (id) => ({ id, name, })); } - -export function main(): void { - const userTask = createUser('John Doe'); - console.log(Task.run(userTask)); // > Result.Ok({ id: 'XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX', name: 'John Doe' }) -} ``` diff --git a/packages/random/example/.eslintrc.cjs b/packages/random/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/random/example/.eslintrc.cjs +++ b/packages/random/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/random/example/usage.ts b/packages/random/example/usage.ts index b4d1633f2d..5135e33e0a 100644 --- a/packages/random/example/usage.ts +++ b/packages/random/example/usage.ts @@ -1,14 +1,14 @@ import { randomNumber } from '@w5s/random'; import { Task } from '@w5s/task'; +export function main(): void { + const userTask = createUser('John Doe'); + console.log(Task.run(userTask)); // > Result.Ok({ id: 'XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX', name: 'John Doe' }) +} + function createUser(name: string) { return Task.map(randomNumber(1, 3), (id) => ({ id, name, })); } - -export function main(): void { - const userTask = createUser('John Doe'); - console.log(Task.run(userTask)); // > Result.Ok({ id: 'XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX', name: 'John Doe' }) -} diff --git a/packages/random/src/Random.spec.ts b/packages/random/src/Random.spec.ts index fa972ba806..cfa139c8ad 100644 --- a/packages/random/src/Random.spec.ts +++ b/packages/random/src/Random.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Random } from './Random.js'; import { next } from './Random/next.js'; diff --git a/packages/random/src/Random/next.spec.ts b/packages/random/src/Random/next.spec.ts index 42019cd44c..4843a5acbe 100644 --- a/packages/random/src/Random/next.spec.ts +++ b/packages/random/src/Random/next.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { next } from './next.js'; +import { describe, expect, it } from 'vitest'; + import { configuration } from '../configuration.js'; +import { next } from './next.js'; describe('next', () => { const expectTask = withTask(expect); diff --git a/packages/random/src/Random/next.ts b/packages/random/src/Random/next.ts index 7d6e5c4dc6..085067e7b3 100644 --- a/packages/random/src/Random/next.ts +++ b/packages/random/src/Random/next.ts @@ -1,7 +1,9 @@ import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; -import { configuration } from '../configuration.js'; + import type { RandomGenerator } from '../RandomGenerator.js'; +import { configuration } from '../configuration.js'; + /** * @example * ```typescript diff --git a/packages/random/src/Testing.spec.ts b/packages/random/src/Testing.spec.ts index dbff93044b..3995cee074 100644 --- a/packages/random/src/Testing.spec.ts +++ b/packages/random/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('index', () => { diff --git a/packages/random/src/Testing/fakeRandomGenerator.ts b/packages/random/src/Testing/fakeRandomGenerator.ts index 8e1234796f..395788058c 100644 --- a/packages/random/src/Testing/fakeRandomGenerator.ts +++ b/packages/random/src/Testing/fakeRandomGenerator.ts @@ -1,4 +1,5 @@ import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + import type { RandomGenerator } from '../RandomGenerator.js'; /** diff --git a/packages/random/src/configuration.spec.ts b/packages/random/src/configuration.spec.ts index 643113dc8c..a18ba923c6 100644 --- a/packages/random/src/configuration.spec.ts +++ b/packages/random/src/configuration.spec.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'vitest'; + import { configuration } from './configuration.js'; describe('configuration', () => { diff --git a/packages/random/src/configuration.ts b/packages/random/src/configuration.ts index 70afe1fd8e..8c2fb0aefc 100644 --- a/packages/random/src/configuration.ts +++ b/packages/random/src/configuration.ts @@ -1,17 +1,16 @@ import { useConfiguration } from '@w5s/application'; -import { meta } from './meta.js'; -interface RandomNumberFunction { - /** - * Returns a new random number between 0 and 1 - */ - (): number; -} +import { meta } from './meta.js'; export interface Configuration { readonly randomNumberGenerator: RandomNumberFunction; } +/** + * Returns a new random number between 0 and 1 + */ +type RandomNumberFunction = () => number; + /** * Random Application */ diff --git a/packages/random/src/index.spec.ts b/packages/random/src/index.spec.ts index db87a5ddf0..65975e9de3 100644 --- a/packages/random/src/index.spec.ts +++ b/packages/random/src/index.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { it('exports', () => { expect(new Set(Object.keys(Module))).toEqual( new Set([ + 'configuration', // List of all public exports 'meta', - 'configuration', 'randomBoolean', 'randomInt', 'randomNumber', diff --git a/packages/random/src/index.ts b/packages/random/src/index.ts index 5f1986679c..eb87dd4731 100644 --- a/packages/random/src/index.ts +++ b/packages/random/src/index.ts @@ -1,6 +1,6 @@ -export * from './meta.js'; export * from './configuration.js'; -export * from './RandomGenerator.js'; +export * from './meta.js'; export * from './randomBoolean.js'; +export * from './RandomGenerator.js'; export * from './randomInt.js'; export * from './randomNumber.js'; diff --git a/packages/random/src/randomBoolean.spec.ts b/packages/random/src/randomBoolean.spec.ts index e96048e97b..5d6ea90bd1 100644 --- a/packages/random/src/randomBoolean.spec.ts +++ b/packages/random/src/randomBoolean.spec.ts @@ -1,8 +1,9 @@ -import { describe, expect, it, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Symbol } from '@w5s/core'; -import { randomBoolean } from './randomBoolean.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { next } from './Random/next.js'; +import { randomBoolean } from './randomBoolean.js'; import { fakeRandomGenerator } from './Testing.js'; describe('randomBoolean', () => { diff --git a/packages/random/src/randomBoolean.ts b/packages/random/src/randomBoolean.ts index 8c576ee30e..2ab78d373b 100644 --- a/packages/random/src/randomBoolean.ts +++ b/packages/random/src/randomBoolean.ts @@ -1,8 +1,11 @@ import type { Task } from '@w5s/task'; + import { map } from '@w5s/task/dist/Task/map.js'; -import { next } from './Random/next.js'; + import type { RandomGenerator } from './RandomGenerator.js'; +import { next } from './Random/next.js'; + /** * Return a Task that will generate booleans. * diff --git a/packages/random/src/randomInt.spec.ts b/packages/random/src/randomInt.spec.ts index 86214abb5e..d0ab134ff6 100644 --- a/packages/random/src/randomInt.spec.ts +++ b/packages/random/src/randomInt.spec.ts @@ -1,8 +1,9 @@ import { Int, Symbol } from '@w5s/core'; -import { describe, expect, it, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { randomInt } from './randomInt.js'; +import { describe, expect, it, vi } from 'vitest'; + import { next } from './Random/next.js'; +import { randomInt } from './randomInt.js'; import { fakeRandomGenerator } from './Testing.js'; describe('randomInt', () => { @@ -15,11 +16,11 @@ describe('randomInt', () => { expectTask(task).toResolveSync(-8); }); it.each([ - [{ genValue: 0, min: Int(-2), max: Int(2) }, -2], - [{ genValue: 0.5, min: Int(-2), max: Int(2) }, 0], - [{ genValue: 0.8, min: Int(-2), max: Int(2) }, 1], - [{ genValue: 1, min: Int(-2), max: Int(2) }, 2], - ])('should return correct bounded values %s', async ({ genValue, min, max }, expected) => { + [{ genValue: 0, max: Int(2), min: Int(-2) }, -2], + [{ genValue: 0.5, max: Int(2), min: Int(-2) }, 0], + [{ genValue: 0.8, max: Int(2), min: Int(-2) }, 1], + [{ genValue: 1, max: Int(2), min: Int(-2) }, 2], + ])('should return correct bounded values %s', async ({ genValue, max, min }, expected) => { const gen = fakeRandomGenerator(() => genValue); const genNum = randomInt(min, max, gen); expectTask(genNum).toResolveSync(expected); diff --git a/packages/random/src/randomInt.ts b/packages/random/src/randomInt.ts index 39da1f0f89..20f01ee8d0 100644 --- a/packages/random/src/randomInt.ts +++ b/packages/random/src/randomInt.ts @@ -1,9 +1,12 @@ import type { Int } from '@w5s/core'; import type { Task } from '@w5s/task'; + import { map } from '@w5s/task/dist/Task/map.js'; -import { randomNumber } from './randomNumber.js'; + import type { RandomGenerator } from './RandomGenerator.js'; +import { randomNumber } from './randomNumber.js'; + const toInt = (value: number) => Math.floor(value) as Int; /** diff --git a/packages/random/src/randomNumber.spec.ts b/packages/random/src/randomNumber.spec.ts index 77f8c1b370..365fd6debd 100644 --- a/packages/random/src/randomNumber.spec.ts +++ b/packages/random/src/randomNumber.spec.ts @@ -1,6 +1,7 @@ -import { describe, expect, it, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Symbol } from '@w5s/core'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { next } from './Random/next.js'; import { randomNumber } from './randomNumber.js'; import { fakeRandomGenerator } from './Testing.js'; @@ -15,10 +16,10 @@ describe('randomNumber', () => { expectTask(task).toResolveSync(-1.508); }); it.each([ - [{ genValue: 0, min: -2, max: 2 }, -2], - [{ genValue: 0.5, min: -2, max: 2 }, 0], - [{ genValue: 1, min: -2, max: 2 }, 2], - ])('should return correct bounded values %s', async ({ genValue, min, max }, expected) => { + [{ genValue: 0, max: 2, min: -2 }, -2], + [{ genValue: 0.5, max: 2, min: -2 }, 0], + [{ genValue: 1, max: 2, min: -2 }, 2], + ])('should return correct bounded values %s', async ({ genValue, max, min }, expected) => { const gen = fakeRandomGenerator(() => genValue); const genNum = randomNumber(min, max, gen); expectTask(genNum).toResolveSync(expected); diff --git a/packages/random/src/randomNumber.ts b/packages/random/src/randomNumber.ts index 70b4abf03a..40b3cadfea 100644 --- a/packages/random/src/randomNumber.ts +++ b/packages/random/src/randomNumber.ts @@ -1,8 +1,11 @@ import type { Task } from '@w5s/task'; + import { map } from '@w5s/task/dist/Task/map.js'; -import { next } from './Random/next.js'; + import type { RandomGenerator } from './RandomGenerator.js'; +import { next } from './Random/next.js'; + /** * Return a Task that will generate floating numbers between [`min`, `max`]. * diff --git a/packages/system/README.md b/packages/system/README.md index 40b4d04514..c2efabf407 100644 --- a/packages/system/README.md +++ b/packages/system/README.md @@ -18,7 +18,7 @@ npm install @w5s/system ```ts -import { FileSystem, FilePath } from '@w5s/system'; +import { FilePath, FileSystem } from '@w5s/system'; import { Task } from '@w5s/task'; declare function log(message: string): Task; diff --git a/packages/system/example/.eslintrc.cjs b/packages/system/example/.eslintrc.cjs index 7b08e8b9b3..f4abfcb015 100644 --- a/packages/system/example/.eslintrc.cjs +++ b/packages/system/example/.eslintrc.cjs @@ -3,8 +3,8 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', 'ts/no-floating-promises': 'off', }, }; diff --git a/packages/system/example/usage.ts b/packages/system/example/usage.ts index 67d5131010..49564d0af8 100644 --- a/packages/system/example/usage.ts +++ b/packages/system/example/usage.ts @@ -1,4 +1,4 @@ -import { FileSystem, FilePath } from '@w5s/system'; +import { FilePath, FileSystem } from '@w5s/system'; import { Task } from '@w5s/task'; declare function log(message: string): Task; diff --git a/packages/system/src/FileError.spec.ts b/packages/system/src/FileError.spec.ts index 6ad8f3dc73..b1b1faf54a 100644 --- a/packages/system/src/FileError.spec.ts +++ b/packages/system/src/FileError.spec.ts @@ -1,8 +1,10 @@ import { Option } from '@w5s/core'; -import { describe, it, expect } from 'vitest'; -import { FileError } from './FileError.js'; +import { describe, expect, it } from 'vitest'; + import type { FilePath } from './FilePath.js'; +import { FileError } from './FileError.js'; + describe('FileError', () => { const anyPath = 'anyPath' as FilePath; @@ -10,17 +12,17 @@ describe('FileError', () => { it('should construct FileError instance', () => { expect( new FileError({ - fileErrorType: 'OtherError', code: 'ENOENT', errno: Option.Some(2), + fileErrorType: 'OtherError', path: Option.Some(anyPath), syscall: Option.Some('read'), }), ).toEqual( expect.objectContaining({ - name: 'FileError', - fileErrorType: 'OtherError', code: 'ENOENT', + fileErrorType: 'OtherError', + name: 'FileError', path: anyPath, syscall: 'read', }), diff --git a/packages/system/src/FileError.ts b/packages/system/src/FileError.ts index 3b1273df56..7cf1ac48bd 100644 --- a/packages/system/src/FileError.ts +++ b/packages/system/src/FileError.ts @@ -1,12 +1,14 @@ import type { Option } from '@w5s/core'; + import { ErrorClass } from '@w5s/error/dist/ErrorClass.js'; + import type { FilePath } from './FilePath.js'; export const FileErrorType = { AlreadyExists: 'AlreadyExists', IllegalOperation: 'IllegalOperation', - UserError: 'UserError', OtherError: 'OtherError', + UserError: 'UserError', } as const; export type FileErrorType = (typeof FileErrorType)[keyof typeof FileErrorType]; @@ -16,9 +18,9 @@ export type FileErrorType = (typeof FileErrorType)[keyof typeof FileErrorType]; export class FileError extends ErrorClass({ errorName: 'FileError', })<{ - fileErrorType: FileErrorType; - errno: Option; code: Option; + errno: Option; + fileErrorType: FileErrorType; path: Option; syscall: Option; }> {} diff --git a/packages/system/src/FilePath.spec.ts b/packages/system/src/FilePath.spec.ts index 59405cb60e..36e9680e50 100644 --- a/packages/system/src/FilePath.spec.ts +++ b/packages/system/src/FilePath.spec.ts @@ -1,12 +1,13 @@ import { Option } from '@w5s/core'; -import { describe, it, expect } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it } from 'vitest'; + import { FilePath } from './FilePath.js'; describe('FilePath', () => { - const { separator, dirname, concat, resolve, parse, format, relative, normalize, basename, extname, isAbsolute, isRelative, isParentOf } = FilePath; - const absolutePath = (...parts: string[]) => (separator + parts.join(separator)) as FilePath; - const relativePath = (...parts: string[]) => parts.join(separator) as FilePath; + const { basename, concat, dirname, extname, format, isAbsolute, isParentOf, isRelative, normalize, parse, relative, resolve, separator } = FilePath; + const absolutePath = (...parts: Array) => (separator + parts.join(separator)) as FilePath; + const relativePath = (...parts: Array) => parts.join(separator) as FilePath; const expectTask = withTask(expect); describe(dirname, () => { @@ -51,11 +52,11 @@ describe('FilePath', () => { it('should parse empty path', () => { const path = relativePath(''); expect(parse(path)).toStrictEqual({ - root: Option.None, base: Option.None, dir: Option.None, ext: Option.None, name: Option.None, + root: Option.None, }); }); }); @@ -64,11 +65,11 @@ describe('FilePath', () => { it('should format empty path object', () => { expect( format({ - root: Option.None, base: Option.None, dir: Option.None, ext: Option.None, name: Option.None, + root: Option.None, }), ).toBe(''); }); @@ -124,17 +125,17 @@ describe('FilePath', () => { }); describe(isParentOf, () => { it.each([ - [{ parent: '', child: '' }, false], - [{ parent: '/first/second', child: '/first' }, false], - [{ parent: '/first', child: '/first' }, false], - [{ parent: '/first', child: '/first/second' }, true], - [{ parent: 'first', child: 'first/second' }, true], - [{ parent: '../first', child: '../first/second' }, true], - [{ parent: String.raw`c:\first`, child: String.raw`c:\first` }, false], - [{ parent: String.raw`c:\first`, child: String.raw`c:\first\second` }, true], - ] as [{ parent: string; child: string }, boolean][])( + [{ child: '', parent: '' }, false], + [{ child: '/first', parent: '/first/second' }, false], + [{ child: '/first', parent: '/first' }, false], + [{ child: '/first/second', parent: '/first' }, true], + [{ child: 'first/second', parent: 'first' }, true], + [{ child: '../first/second', parent: '../first' }, true], + [{ child: String.raw`c:\first`, parent: String.raw`c:\first` }, false], + [{ child: String.raw`c:\first\second`, parent: String.raw`c:\first` }, true], + ] as Array<[{ child: string; parent: string }, boolean]>)( 'should return correct value for %s', - ({ parent, child }, expected) => { + ({ child, parent }, expected) => { expect(isParentOf(FilePath(parent), FilePath(child))).toBe(expected); }, ); diff --git a/packages/system/src/FilePath.ts b/packages/system/src/FilePath.ts index 8beb54a8e8..f312a4702d 100644 --- a/packages/system/src/FilePath.ts +++ b/packages/system/src/FilePath.ts @@ -1,19 +1,20 @@ -import nodePath from 'node:path'; -import type { Tag, Option } from '@w5s/core'; +import type { Option, Tag } from '@w5s/core'; import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; +import nodePath from 'node:path'; -function orEmpty(optionalValue: Option) { - return optionalValue ?? ''; -} +export type FileName = string; + +export type FilePath = string & Tag<'FilePath'>; function filterNotEmpty(value: string): Option { return value === '' ? undefined : (value as V); } -export type FileName = string; - -export type FilePath = string & Tag<'FilePath'>; +function orEmpty(optionalValue: Option) { + return optionalValue ?? ''; +} /** * @namespace @@ -24,37 +25,37 @@ export const FilePath = Object.assign( return value as FilePath; }, { - delimiter: nodePath.delimiter as FilePath.Delimiter, - separator: nodePath.sep as FilePath.Separator, - /** - * Normalize a string path, reducing '..' and '.' parts. When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. + * Return the last portion of a path. Similar to the Unix basename command. + * Often used to extract the file name from a fully qualified path. * * @example * ```typescript - * const path = FilePath.normalize('foo/./bar/../baz//quux/');// FilePath('foo/baz/quux/') + * const path = FilePath.basename('/foo/bar.html');// 'bar.html' * ``` - * @param path The path to normalize + * @param path The path to extract base name from + * @param extension The extension to remove */ - normalize(path: FilePath): FilePath { - return nodePath.normalize(path) as FilePath; + basename(path: FilePath, extension?: Option): FileName { + return nodePath.basename(path, extension) as FilePath; }, /** - * Return the last portion of a path. Similar to the Unix basename command. - * Often used to extract the file name from a fully qualified path. + * Join all arguments together and normalize the resulting path. * * @example * ```typescript - * const path = FilePath.basename('/foo/bar.html');// 'bar.html' + * const paths = [FilePath('hello'), FilePath('world')]; + * FilePath.concat(paths);// FilePath('hello/world') * ``` - * @param path The path to extract base name from - * @param extension The extension to remove + * @param paths paths to join. */ - basename(path: FilePath, extension?: Option): FileName { - return nodePath.basename(path, extension) as FilePath; + concat(paths: ReadonlyArray): FilePath { + return nodePath.join(...paths) as FilePath; }, + delimiter: nodePath.delimiter as FilePath.Delimiter, + /** * Return the directory name of a path. Similar to the Unix dirname command. * @@ -99,14 +100,50 @@ export const FilePath = Object.assign( */ format(parsed: Partial): FilePath { return nodePath.format({ - root: orEmpty(parsed.root), - dir: orEmpty(parsed.dir), base: orEmpty(parsed.base), + dir: orEmpty(parsed.dir), ext: orEmpty(parsed.ext), name: orEmpty(parsed.name), + root: orEmpty(parsed.root), }) as FilePath; }, + isAbsolute(path: FilePath): boolean { + return nodePath.isAbsolute(path); + }, + + isParentOf(parentPath: FilePath, childPath: FilePath): boolean { + const parentPathNormalized = nodePath.normalize(parentPath); + + if (childPath.length <= parentPathNormalized.length) { + return false; + } + + const subPathNormalized = nodePath.normalize(childPath); + const subPathWithTrailingSep = subPathNormalized.endsWith(nodePath.sep) + ? subPathNormalized + : subPathNormalized + nodePath.sep; + + return subPathWithTrailingSep.startsWith(parentPathNormalized); + }, + + isRelative(path: FilePath): boolean { + return !nodePath.isAbsolute(path); + }, + + /** + * Normalize a string path, reducing '..' and '.' parts. When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. + * + * @example + * ```typescript + * const path = FilePath.normalize('foo/./bar/../baz//quux/');// FilePath('foo/baz/quux/') + * ``` + * @param path The path to normalize + */ + normalize(path: FilePath): FilePath { + return nodePath.normalize(path) as FilePath; + }, + /** * Returns an object from a path string - the opposite of `format()`. * @@ -119,11 +156,11 @@ export const FilePath = Object.assign( parse(string: FilePath): FilePath.Parsed { const parsed = nodePath.parse(string); return { - root: filterNotEmpty(parsed.root), - dir: filterNotEmpty(parsed.dir), base: filterNotEmpty(parsed.base), + dir: filterNotEmpty(parsed.dir), ext: filterNotEmpty(parsed.ext), name: filterNotEmpty(parsed.name), + root: filterNotEmpty(parsed.root), }; }, @@ -167,54 +204,19 @@ export const FilePath = Object.assign( return taskFrom(({ resolve }) => resolve(nodePath.resolve(...from, to) as FilePath)); }, - /** - * Join all arguments together and normalize the resulting path. - * - * @example - * ```typescript - * const paths = [FilePath('hello'), FilePath('world')]; - * FilePath.concat(paths);// FilePath('hello/world') - * ``` - * @param paths paths to join. - */ - concat(paths: ReadonlyArray): FilePath { - return nodePath.join(...paths) as FilePath; - }, - - isAbsolute(path: FilePath): boolean { - return nodePath.isAbsolute(path); - }, - - isRelative(path: FilePath): boolean { - return !nodePath.isAbsolute(path); - }, - - isParentOf(parentPath: FilePath, childPath: FilePath): boolean { - const parentPathNormalized = nodePath.normalize(parentPath); - - if (childPath.length <= parentPathNormalized.length) { - return false; - } - - const subPathNormalized = nodePath.normalize(childPath); - const subPathWithTrailingSep = subPathNormalized.endsWith(nodePath.sep) - ? subPathNormalized - : subPathNormalized + nodePath.sep; - - return subPathWithTrailingSep.startsWith(parentPathNormalized); - }, + separator: nodePath.sep as FilePath.Separator, }, ); export namespace FilePath { export type Delimiter = ':' | ';'; - export type Extension = `.${string}` | ''; - export type Separator = '/' | '\\'; - + export type Extension = '' | `.${string}`; export interface Parsed { - readonly root: Option; - readonly dir: Option; readonly base: Option; + readonly dir: Option; readonly ext: Option; readonly name: Option; + readonly root: Option; } + + export type Separator = '/' | '\\'; } diff --git a/packages/system/src/FileSize.spec.ts b/packages/system/src/FileSize.spec.ts index 37656fb9ff..8aa4026a58 100644 --- a/packages/system/src/FileSize.spec.ts +++ b/packages/system/src/FileSize.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { FileSize } from './FileSize.js'; describe('FileSize', () => { diff --git a/packages/system/src/FileStatus.ts b/packages/system/src/FileStatus.ts index 7eb14add3c..87dd265032 100644 --- a/packages/system/src/FileStatus.ts +++ b/packages/system/src/FileStatus.ts @@ -1,6 +1,8 @@ import type { Int, Tag } from '@w5s/core'; import type { Time } from '@w5s/time'; + import { Struct } from '@w5s/core/dist/Struct.js'; + import type { FileSize } from './FileSize.js'; /** @@ -8,167 +10,167 @@ import type { FileSize } from './FileSize.js'; */ export type DeviceID = Int & Tag<'DeviceID'>; -/** - * DeviceID constructor - * - * @example - * ```typescript - * const value = FileID(1);// 1 - * ``` - * @category Constructor - * @param value an initial numeric value - */ -export function DeviceID(value: number): DeviceID { - return value as DeviceID; -} - /** * File identifier type */ export type FileID = Int & Tag<'FileID'>; -/** - * FileID constructor - * - * @example - * ```typescript - * const value = FileID(1);// 1 - * ``` - * @category Constructor - * @param value an initial numeric value - */ -export function FileID(value: number): FileID { - return value as FileID; -} - -/** - * User identifier type - */ -export type UserID = Int & Tag<'UserID'>; - -/** - * UserID constructor - * - * @example - * ```typescript - * const value = UserID(1);// 1 - * ``` - * @category Constructor - * @param value an initial numeric value - */ -export function UserID(value: number): UserID { - return value as UserID; -} - -/** - * Group identifier type - */ -export type GroupID = Int & Tag<'GroupID'>; - -/** - * UserID constructor - * - * @example - * ```typescript - * const value = UserID(1);// 1 - * ``` - * @category Constructor - * @param value an initial numeric value - */ -export function GroupID(value: number): GroupID { - return value as GroupID; -} - export interface FileStatus extends Struct<{ _: 'FileStatus'; /** - * The device identifier + * Time of last access */ - deviceID: DeviceID; + accessTime: Time; /** - * The file identifier + * The device identifier */ - fileID: FileID; + deviceID: DeviceID; // fileMode: FileMode; /** - * The amount of links to the file + * The group identifier of the file */ - linkCount: Int; + fileGroup: GroupID; /** - * The owner identifier of the file + * The file identifier */ - fileOwner: UserID; + fileID: FileID; /** - * The group identifier of the file + * The owner identifier of the file */ - fileGroup: GroupID; + fileOwner: UserID; /** - * The id of the special device + * The size of the file (in bytes) */ - specialDeviceID: DeviceID; + fileSize: FileSize; /** - * The size of the file (in bytes) + * Checks if this file is a block device. */ - fileSize: FileSize; + isBlockDevice: boolean; /** - * Time of last access + * Checks if this file is a character device. */ - accessTime: Time; + isCharacterDevice: boolean; /** - * Time of last modification. + * Checks if this file is a directory device. */ - modificationTime: Time; + isDirectory: boolean; /** - * Time of last status change (i.e. owner, group, link count, mode, etc.). + * Checks if this file is a regular file device. */ - statusChangeTime: Time; + isFile: boolean; /** - * Checks if this file is a block device. + * Checks if this file is a named pipe device. */ - isBlockDevice: boolean; + isNamedPipe: boolean; /** - * Checks if this file is a character device. + * Checks if this file is a socket device. */ - isCharacterDevice: boolean; + isSocket: boolean; /** - * Checks if this file is a named pipe device. + * Checks if this file is a symbolic link device. */ - isNamedPipe: boolean; + isSymbolicLink: boolean; /** - * Checks if this file is a regular file device. + * The amount of links to the file */ - isFile: boolean; + linkCount: Int; /** - * Checks if this file is a directory device. + * Time of last modification. */ - isDirectory: boolean; + modificationTime: Time; /** - * Checks if this file is a symbolic link device. + * The id of the special device */ - isSymbolicLink: boolean; + specialDeviceID: DeviceID; /** - * Checks if this file is a socket device. + * Time of last status change (i.e. owner, group, link count, mode, etc.). */ - isSocket: boolean; + statusChangeTime: Time; }> {} +/** + * Group identifier type + */ +export type GroupID = Int & Tag<'GroupID'>; + +/** + * User identifier type + */ +export type UserID = Int & Tag<'UserID'>; + +/** + * DeviceID constructor + * + * @example + * ```typescript + * const value = FileID(1);// 1 + * ``` + * @category Constructor + * @param value an initial numeric value + */ +export function DeviceID(value: number): DeviceID { + return value as DeviceID; +} + +/** + * FileID constructor + * + * @example + * ```typescript + * const value = FileID(1);// 1 + * ``` + * @category Constructor + * @param value an initial numeric value + */ +export function FileID(value: number): FileID { + return value as FileID; +} + +/** + * UserID constructor + * + * @example + * ```typescript + * const value = UserID(1);// 1 + * ``` + * @category Constructor + * @param value an initial numeric value + */ +export function GroupID(value: number): GroupID { + return value as GroupID; +} + +/** + * UserID constructor + * + * @example + * ```typescript + * const value = UserID(1);// 1 + * ``` + * @category Constructor + * @param value an initial numeric value + */ +export function UserID(value: number): UserID { + return value as UserID; +} + /** * FileStatus constructor * diff --git a/packages/system/src/FileSystem.spec.ts b/packages/system/src/FileSystem.spec.ts index 105f712057..3adf831823 100644 --- a/packages/system/src/FileSystem.spec.ts +++ b/packages/system/src/FileSystem.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { FileSystem } from './FileSystem.js'; describe('FileSystem', () => { @@ -14,11 +15,11 @@ describe('FileSystem', () => { 'ensureFile', 'ensureSymbolicLink', 'listDirectory', + 'move', 'readFile', 'readFileStatus', 'readSymbolicLink', 'readSymbolicLinkStatus', - 'move', 'remove', 'rename', 'writeFile', diff --git a/packages/system/src/FileSystem.ts b/packages/system/src/FileSystem.ts index 650ed98cbf..8234c7ae5c 100644 --- a/packages/system/src/FileSystem.ts +++ b/packages/system/src/FileSystem.ts @@ -1,16 +1,16 @@ -import * as fsEmptyDirectory from './FileSystem/emptyDirectory.js'; -import * as fsCreateDirectory from './FileSystem/createDirectory.js'; import * as fsCopyFile from './FileSystem/copyFile.js'; +import * as fsCreateDirectory from './FileSystem/createDirectory.js'; import * as fsCreateSymbolicLink from './FileSystem/createSymbolicLink.js'; -import * as fsReadSymbolicLink from './FileSystem/readSymbolicLink.js'; -import * as fsListDirectory from './FileSystem/listDirectory.js'; +import * as fsEmptyDirectory from './FileSystem/emptyDirectory.js'; import * as fsEnsure from './FileSystem/ensure.js'; -import * as fsReadFileStatus from './FileSystem/readFileStatus.js'; +import * as fsListDirectory from './FileSystem/listDirectory.js'; +import * as fsMove from './FileSystem/move.js'; import * as fsReadFile from './FileSystem/readFile.js'; +import * as fsReadFileStatus from './FileSystem/readFileStatus.js'; +import * as fsReadSymbolicLink from './FileSystem/readSymbolicLink.js'; import * as fsRemove from './FileSystem/remove.js'; import * as fsRename from './FileSystem/rename.js'; import * as fsWriteFile from './FileSystem/writeFile.js'; -import * as fsMove from './FileSystem/move.js'; /** * @namespace diff --git a/packages/system/src/FileSystem/copyFile.spec.ts b/packages/system/src/FileSystem/copyFile.spec.ts index 73d18d65a2..b02aad235f 100644 --- a/packages/system/src/FileSystem/copyFile.spec.ts +++ b/packages/system/src/FileSystem/copyFile.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { copyFile } from './copyFile.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { copyFile } from './copyFile.js'; describe(copyFile, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/copyFile.ts b/packages/system/src/FileSystem/copyFile.ts index 75fcb0c038..5554fbd48f 100644 --- a/packages/system/src/FileSystem/copyFile.ts +++ b/packages/system/src/FileSystem/copyFile.ts @@ -1,8 +1,10 @@ import type { Task } from '@w5s/task'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Asynchronously copies `source` to `destination`. By default, `destination` is overwritten if it already exists. * diff --git a/packages/system/src/FileSystem/createDirectory.spec.ts b/packages/system/src/FileSystem/createDirectory.spec.ts index 66c9cbdc5e..10de1abedf 100644 --- a/packages/system/src/FileSystem/createDirectory.spec.ts +++ b/packages/system/src/FileSystem/createDirectory.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { createDirectory } from './createDirectory.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { createDirectory } from './createDirectory.js'; describe(createDirectory, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/createDirectory.ts b/packages/system/src/FileSystem/createDirectory.ts index 909877004d..4763860e5c 100644 --- a/packages/system/src/FileSystem/createDirectory.ts +++ b/packages/system/src/FileSystem/createDirectory.ts @@ -1,9 +1,11 @@ -import type * as nodeFS from 'node:fs'; import type { Task } from '@w5s/task'; +import type * as nodeFS from 'node:fs'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Asynchronously creates a directory. * diff --git a/packages/system/src/FileSystem/createSymbolicLink.spec.ts b/packages/system/src/FileSystem/createSymbolicLink.spec.ts index 289443ad9f..b4b436fa6b 100644 --- a/packages/system/src/FileSystem/createSymbolicLink.spec.ts +++ b/packages/system/src/FileSystem/createSymbolicLink.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { createSymbolicLink } from './createSymbolicLink.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { createSymbolicLink } from './createSymbolicLink.js'; describe(createSymbolicLink, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/createSymbolicLink.ts b/packages/system/src/FileSystem/createSymbolicLink.ts index ba508b7c88..7050cc756f 100644 --- a/packages/system/src/FileSystem/createSymbolicLink.ts +++ b/packages/system/src/FileSystem/createSymbolicLink.ts @@ -1,8 +1,10 @@ import type { Task } from '@w5s/task'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Reads the contents of the symbolic link referred to by path. * diff --git a/packages/system/src/FileSystem/emptyDirectory.spec.ts b/packages/system/src/FileSystem/emptyDirectory.spec.ts index b4662681fe..ab180ecec8 100644 --- a/packages/system/src/FileSystem/emptyDirectory.spec.ts +++ b/packages/system/src/FileSystem/emptyDirectory.spec.ts @@ -1,8 +1,9 @@ import { Symbol } from '@w5s/core'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { emptyDirectory } from './emptyDirectory.js'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + import { fsStub, withFile } from '../Testing.js'; +import { emptyDirectory } from './emptyDirectory.js'; describe(emptyDirectory, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/emptyDirectory.ts b/packages/system/src/FileSystem/emptyDirectory.ts index ea61a95563..9e8b0e1d0c 100644 --- a/packages/system/src/FileSystem/emptyDirectory.ts +++ b/packages/system/src/FileSystem/emptyDirectory.ts @@ -1,8 +1,24 @@ import type { Task } from '@w5s/task'; -import { Internal, errnoTask } from '../Internal.js'; + import type { FileError } from '../FileError.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + +/** + * Ensures that a directory is empty. Deletes directory contents if the directory is not empty. If the directory does not exist, it is created. The directory itself is not deleted. + * + * @example + * ```typescript + * const task = emptyDirectory(FilePath('/path/to/directory')); + * await Task.run(task);// Will delete directory contents + * ``` + * @param filePath The directory to empty + */ +export function emptyDirectory(filePath: FilePath): Task { + return errnoTask(emptyDirectoryAsync)(filePath); +} + export async function emptyDirectoryAsync(path: string): Promise { try { const items = await Internal.FS.readdir(path); @@ -18,17 +34,3 @@ export async function emptyDirectoryAsync(path: string): Promise { await Internal.FS.mkdir(path, { recursive: true }); } } - -/** - * Ensures that a directory is empty. Deletes directory contents if the directory is not empty. If the directory does not exist, it is created. The directory itself is not deleted. - * - * @example - * ```typescript - * const task = emptyDirectory(FilePath('/path/to/directory')); - * await Task.run(task);// Will delete directory contents - * ``` - * @param filePath The directory to empty - */ -export function emptyDirectory(filePath: FilePath): Task { - return errnoTask(emptyDirectoryAsync)(filePath); -} diff --git a/packages/system/src/FileSystem/ensure.spec.ts b/packages/system/src/FileSystem/ensure.spec.ts index ff72100bfc..1ed584db13 100644 --- a/packages/system/src/FileSystem/ensure.spec.ts +++ b/packages/system/src/FileSystem/ensure.spec.ts @@ -1,6 +1,7 @@ import { Symbol } from '@w5s/core'; -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + import { fsStub, withFile } from '../Testing.js'; import { ensureDirectory, ensureFile, ensureSymbolicLink } from './ensure.js'; @@ -40,11 +41,11 @@ describe(ensureDirectory, () => { const task = ensureDirectory(ensured); await expectTask(task).toRejectAsync( expect.objectContaining({ - name: 'FileError', - message: `Ensure path exists, expected 'directory', got 'file'`, - fileErrorType: 'UserError', - errno: undefined, code: undefined, + errno: undefined, + fileErrorType: 'UserError', + message: `Ensure path exists, expected 'directory', got 'file'`, + name: 'FileError', path: expect.any(String), syscall: undefined, }), @@ -75,11 +76,11 @@ describe(ensureFile, () => { const task = ensureFile(ensured); await expectTask(task).toRejectAsync( expect.objectContaining({ - name: 'FileError', - message: `Ensure path exists, expected 'file', got 'directory'`, - fileErrorType: 'UserError', - errno: undefined, code: undefined, + errno: undefined, + fileErrorType: 'UserError', + message: `Ensure path exists, expected 'file', got 'directory'`, + name: 'FileError', path: expect.any(String), syscall: undefined, }), @@ -114,11 +115,11 @@ describe(ensureSymbolicLink, () => { const task = ensureSymbolicLink(source, destination); await expectTask(task).toRejectAsync( expect.objectContaining({ - name: 'FileError', - message: `Ensure path exists, expected 'symlink', got 'directory'`, - fileErrorType: 'UserError', - errno: undefined, code: undefined, + errno: undefined, + fileErrorType: 'UserError', + message: `Ensure path exists, expected 'symlink', got 'directory'`, + name: 'FileError', path: expect.any(String), syscall: undefined, }), diff --git a/packages/system/src/FileSystem/ensure.ts b/packages/system/src/FileSystem/ensure.ts index 18068e1b7b..eadb599216 100644 --- a/packages/system/src/FileSystem/ensure.ts +++ b/packages/system/src/FileSystem/ensure.ts @@ -1,19 +1,11 @@ import type { Option } from '@w5s/core'; import type { Task } from '@w5s/task'; -import { FilePath } from '../FilePath.js'; + import { FileError } from '../FileError.js'; +import { FilePath } from '../FilePath.js'; import { ErrnoException, errnoTask, Internal } from '../Internal.js'; -type FileType = 'file' | 'directory' | 'symlink'; - -export async function ensureDirectoryAsync(filePath: FilePath): Promise { - const linkType = await linkStat(filePath); - if (linkType == null) { - await Internal.FS.mkdir(filePath, { recursive: true }); - } else { - ensureType(filePath, 'directory', linkType); - } -} +type FileType = 'directory' | 'file' | 'symlink'; /** * Ensures that the directory exists. If the directory structure does not exist, it is created. @@ -29,13 +21,12 @@ export function ensureDirectory(filePath: FilePath): Task { return errnoTask(ensureDirectoryAsync)(filePath); } -export async function ensureFileAsync(filePath: FilePath): Promise { +export async function ensureDirectoryAsync(filePath: FilePath): Promise { const linkType = await linkStat(filePath); if (linkType == null) { - await ensureDirectoryAsync(FilePath.dirname(filePath)); - await Internal.FS.writeFile(filePath, ''); + await Internal.FS.mkdir(filePath, { recursive: true }); } else { - ensureType(filePath, 'file', linkType); + ensureType(filePath, 'directory', linkType); } } @@ -53,13 +44,13 @@ export function ensureFile(filePath: FilePath): Task { return errnoTask(ensureFileAsync)(filePath); } -export async function ensureSymbolicLinkAsync(source: FilePath, destination: FilePath): Promise { - const destinationLinkType = await linkStat(destination); - if (destinationLinkType == null) { - await ensureDirectoryAsync(FilePath.dirname(destination)); - await Internal.FS.symlink(source, destination); +export async function ensureFileAsync(filePath: FilePath): Promise { + const linkType = await linkStat(filePath); + if (linkType == null) { + await ensureDirectoryAsync(FilePath.dirname(filePath)); + await Internal.FS.writeFile(filePath, ''); } else { - ensureType(destination, 'symlink', destinationLinkType); + ensureType(filePath, 'file', linkType); } } @@ -78,16 +69,13 @@ export function ensureSymbolicLink(source: FilePath, destination: FilePath): Tas return errnoTask(ensureSymbolicLinkAsync)(source, destination); } -async function linkStat(filePath: FilePath): Promise> { - try { - const stats = await Internal.FS.lstat(filePath); - - return stats.isFile() ? 'file' : stats.isDirectory() ? 'directory' : stats.isSymbolicLink() ? 'symlink' : undefined; - } catch (error: unknown) { - if ((error as ErrnoException).code === 'ENOENT') { - return undefined; - } - throw error; +export async function ensureSymbolicLinkAsync(source: FilePath, destination: FilePath): Promise { + const destinationLinkType = await linkStat(destination); + if (destinationLinkType == null) { + await ensureDirectoryAsync(FilePath.dirname(destination)); + await Internal.FS.symlink(source, destination); + } else { + ensureType(destination, 'symlink', destinationLinkType); } } @@ -99,11 +87,24 @@ function ensureType(filePath: FilePath, expectedType: FileType, actualType: File function ensureTypeError(filePath: FilePath, expectedType: FileType, actualType: FileType) { return new FileError({ + code: undefined, + errno: undefined, fileErrorType: 'UserError', message: `Ensure path exists, expected '${expectedType}', got '${actualType}'`, path: filePath, - errno: undefined, - code: undefined, syscall: undefined, }); } + +async function linkStat(filePath: FilePath): Promise> { + try { + const stats = await Internal.FS.lstat(filePath); + + return stats.isFile() ? 'file' : stats.isDirectory() ? 'directory' : stats.isSymbolicLink() ? 'symlink' : undefined; + } catch (error: unknown) { + if ((error as ErrnoException).code === 'ENOENT') { + return undefined; + } + throw error; + } +} diff --git a/packages/system/src/FileSystem/listDirectory.spec.ts b/packages/system/src/FileSystem/listDirectory.spec.ts index d1b8c407a4..1fc65a3574 100644 --- a/packages/system/src/FileSystem/listDirectory.spec.ts +++ b/packages/system/src/FileSystem/listDirectory.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { listDirectory } from './listDirectory.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { listDirectory } from './listDirectory.js'; describe(listDirectory, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/listDirectory.ts b/packages/system/src/FileSystem/listDirectory.ts index bf03545b98..44b561826d 100644 --- a/packages/system/src/FileSystem/listDirectory.ts +++ b/packages/system/src/FileSystem/listDirectory.ts @@ -1,10 +1,12 @@ -import type * as nodeFS from 'node:fs'; import type { Array } from '@w5s/core-type'; import type { Task } from '@w5s/task'; +import type * as nodeFS from 'node:fs'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Reads the contents of a directory. * @@ -18,7 +20,7 @@ import type { FilePath } from '../FilePath.js'; */ export function listDirectory(filePath: FilePath, options?: listDirectory.Options): Task, FileError> { // @ts-ignore - `readdir` returns an array of strings instead of a Array - return errnoTask<[path: nodeFS.PathLike, options?: BufferEncoding], string[]>(Internal.FS.readdir)(filePath, options); + return errnoTask<[path: nodeFS.PathLike, options?: BufferEncoding], Array>(Internal.FS.readdir)(filePath, options); } export namespace listDirectory { export type Options = BufferEncoding; diff --git a/packages/system/src/FileSystem/move.spec.ts b/packages/system/src/FileSystem/move.spec.ts index 1bb495b374..437b29ed72 100644 --- a/packages/system/src/FileSystem/move.spec.ts +++ b/packages/system/src/FileSystem/move.spec.ts @@ -1,7 +1,8 @@ -import * as nodeFS from 'node:fs'; import { Symbol } from '@w5s/core'; -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; +import * as nodeFS from 'node:fs'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + import { fsStub, withFile } from '../Testing.js'; import { move } from './move.js'; @@ -26,11 +27,11 @@ describe('move', () => { const task = move(srcDir, destDir); await expectTask(task).toRejectAsync( expect.objectContaining({ - name: 'FileError', + code: 'ENOENT', + errno: -2, fileErrorType: 'OtherError', + name: 'FileError', path: expect.any(String), - errno: -2, - code: 'ENOENT', syscall: 'stat', }), ); @@ -63,11 +64,11 @@ describe('move', () => { const task = move(srcFile, destFile); await expectTask(task).toRejectAsync( expect.objectContaining({ - name: 'FileError', + code: 'ENOENT', + errno: -2, fileErrorType: 'OtherError', + name: 'FileError', path: expect.any(String), - errno: -2, - code: 'ENOENT', syscall: 'stat', }), ); @@ -88,12 +89,12 @@ describe('move', () => { const taskFail = move(srcFile, destFile); await expectTask(taskFail).toRejectAsync( expect.objectContaining({ - name: 'FileError', + code: undefined, + errno: undefined, fileErrorType: 'UserError', - path: expect.any(String), message: 'Destination already exists', - errno: undefined, - code: undefined, + name: 'FileError', + path: expect.any(String), syscall: undefined, }), ); @@ -152,12 +153,12 @@ describe('move', () => { await expectTask(move(srcDir, destDir)).toRejectAsync( expect.objectContaining({ - name: 'FileError', + code: undefined, + errno: undefined, fileErrorType: 'UserError', - path: expect.any(String), message: `Cannot move '${srcDir}' to a subdirectory of itself, '${destDir}'.`, - errno: undefined, - code: undefined, + name: 'FileError', + path: expect.any(String), syscall: undefined, }), ); diff --git a/packages/system/src/FileSystem/move.ts b/packages/system/src/FileSystem/move.ts index 51f4b4e54c..3030ed4767 100644 --- a/packages/system/src/FileSystem/move.ts +++ b/packages/system/src/FileSystem/move.ts @@ -1,7 +1,24 @@ import type { Task } from '@w5s/task'; + import { FileError } from '../FileError.js'; -import { errnoTask, Internal } from '../Internal.js'; import { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + +/** + * Move a `source` file or directory to `destination` + * + * @example + * ```typescript + * const moveTask = move(FilePath('source'), FilePath('destination')); + * Task.run(moveTask); + * ``` + * @param source The source path + * @param destination The destination path + * @param options The options to use + */ +export function move(source: FilePath, destination: FilePath, options?: move.Options): Task { + return errnoTask(moveAsync)(source, destination, options); +} export async function moveAsync(source: FilePath, destination: FilePath, options?: move.Options): Promise { const sourceStatus = await Internal.FS.stat(source); @@ -19,49 +36,22 @@ export async function moveAsync(source: FilePath, destination: FilePath, options await Internal.FS.rename(source, destination); } - -/** - * Move a `source` file or directory to `destination` - * - * @example - * ```typescript - * const moveTask = move(FilePath('source'), FilePath('destination')); - * Task.run(moveTask); - * ``` - * @param source The source path - * @param destination The destination path - * @param options The options to use - */ -export function move(source: FilePath, destination: FilePath, options?: move.Options): Task { - return errnoTask(moveAsync)(source, destination, options); -} export namespace move { - export type Options = { + export interface Options { /** * If `true`, the destination is overwritten if it exists. */ overwrite?: boolean; - }; -} - -function subdirectoryError(source: FilePath, destination: FilePath) { - return new FileError({ - fileErrorType: 'UserError', - path: destination, - message: `Cannot move '${source}' to a subdirectory of itself, '${destination}'.`, - errno: undefined, - code: undefined, - syscall: undefined, - }); + } } function alreadyExistError(destination: FilePath) { return new FileError({ + code: undefined, + errno: undefined, fileErrorType: 'UserError', message: 'Destination already exists', path: destination, - errno: undefined, - code: undefined, syscall: undefined, }); } @@ -74,3 +64,14 @@ async function existsAsync(filePath: FilePath): Promise { return false; } } + +function subdirectoryError(source: FilePath, destination: FilePath) { + return new FileError({ + code: undefined, + errno: undefined, + fileErrorType: 'UserError', + message: `Cannot move '${source}' to a subdirectory of itself, '${destination}'.`, + path: destination, + syscall: undefined, + }); +} diff --git a/packages/system/src/FileSystem/readFile.spec.ts b/packages/system/src/FileSystem/readFile.spec.ts index 7dda929a13..8b89fa5573 100644 --- a/packages/system/src/FileSystem/readFile.spec.ts +++ b/packages/system/src/FileSystem/readFile.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Symbol } from '@w5s/core'; import { TaskCanceler } from '@w5s/task'; -import { readFile } from './readFile.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { readFile } from './readFile.js'; describe(readFile, () => { const expectTask = withTask(expect); @@ -34,9 +35,9 @@ describe(readFile, () => { const canceler = new TaskCanceler(); const task = readFile(FilePath('myPath')); task[Symbol.run]({ - resolve: () => {}, - reject: () => {}, canceler, + reject: () => {}, + resolve: () => {}, }); canceler.cancel(); diff --git a/packages/system/src/FileSystem/readFile.ts b/packages/system/src/FileSystem/readFile.ts index d4e492e023..a951d48b2b 100644 --- a/packages/system/src/FileSystem/readFile.ts +++ b/packages/system/src/FileSystem/readFile.ts @@ -1,11 +1,14 @@ -import type * as nodeFS from 'node:fs'; import type { Option } from '@w5s/core'; import type { Task } from '@w5s/task'; +import type * as nodeFS from 'node:fs'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoExceptionHandler } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoExceptionHandler, Internal } from '../Internal.js'; + /** * Asynchronously reads the entire contents of a file. * @@ -21,7 +24,7 @@ export function readFile( file: FilePath, options?: readFile.Options, ): Task { - return taskFrom(async ({ resolve, reject, canceler }) => { + return taskFrom(async ({ canceler, reject, resolve }) => { const controller = new AbortController(); canceler.onCancel = () => { controller.abort(); @@ -39,7 +42,7 @@ export function readFile( }); } export namespace readFile { - export type Options = { + export interface Options { /** * The file encoding */ @@ -49,5 +52,5 @@ export namespace readFile { * The system flag used to determine if the file should be truncated */ flag?: Option; - }; + } } diff --git a/packages/system/src/FileSystem/readFileStatus.spec.ts b/packages/system/src/FileSystem/readFileStatus.spec.ts index 2e8040aa8d..1ac69715e2 100644 --- a/packages/system/src/FileSystem/readFileStatus.spec.ts +++ b/packages/system/src/FileSystem/readFileStatus.spec.ts @@ -1,13 +1,14 @@ import { Int } from '@w5s/core'; -import { Time } from '@w5s/time'; -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { readFileStatus, readSymbolicLinkStatus } from './readFileStatus.js'; -import { FilePath } from '../FilePath.js'; +import { Time } from '@w5s/time'; +import { describe, expect, it, vi } from 'vitest'; + import { generateStats } from '../_test/config.js'; -import { Internal } from '../Internal.js'; -import { DeviceID, FileID, FileStatus, GroupID, UserID } from '../FileStatus.js'; +import { FilePath } from '../FilePath.js'; import { FileSize } from '../FileSize.js'; +import { DeviceID, FileID, FileStatus, GroupID, UserID } from '../FileStatus.js'; +import { Internal } from '../Internal.js'; +import { readFileStatus, readSymbolicLinkStatus } from './readFileStatus.js'; const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/readFileStatus.ts b/packages/system/src/FileSystem/readFileStatus.ts index 9e2b883bb5..198082fb54 100644 --- a/packages/system/src/FileSystem/readFileStatus.ts +++ b/packages/system/src/FileSystem/readFileStatus.ts @@ -1,36 +1,15 @@ -import type * as nodeFS from 'node:fs'; import type { Int } from '@w5s/core'; import type { Task } from '@w5s/task'; import type { Time } from '@w5s/time'; +import type * as nodeFS from 'node:fs'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; -import type { DeviceID, FileID, GroupID, UserID } from '../FileStatus.js'; -import { FileStatus } from '../FileStatus.js'; import type { FileSize } from '../FileSize.js'; +import type { DeviceID, FileID, GroupID, UserID } from '../FileStatus.js'; -function fileStatusFromNodeJSStats(stats: nodeFS.Stats): FileStatus { - return FileStatus.create({ - accessTime: stats.atimeMs as Time, - deviceID: stats.dev as DeviceID, - fileGroup: stats.gid as GroupID, - fileID: stats.ino as FileID, - fileOwner: stats.uid as UserID, - fileSize: stats.size as FileSize, - isBlockDevice: stats.isBlockDevice(), - isCharacterDevice: stats.isCharacterDevice(), - isDirectory: stats.isDirectory(), - isFile: stats.isFile(), - isNamedPipe: stats.isFIFO(), - isSocket: stats.isSocket(), - isSymbolicLink: stats.isSymbolicLink(), - linkCount: stats.nlink as Int, - modificationTime: stats.mtimeMs as Time, - specialDeviceID: stats.rdev as DeviceID, - statusChangeTime: stats.ctimeMs as Time, - // fileMode: FileMode(stats.mode), - }); -} +import { FileStatus } from '../FileStatus.js'; +import { errnoTask, Internal } from '../Internal.js'; /** * Returns a `FileStatus` object for the given `filePath`, if `filePath` refers to a symbolic link it returns the status of the link target. @@ -59,3 +38,26 @@ export function readFileStatus(filePath: FilePath): Task export function readSymbolicLinkStatus(filePath: FilePath): Task { return errnoTask(async (p: string) => fileStatusFromNodeJSStats(await Internal.FS.lstat(p)))(filePath); } + +function fileStatusFromNodeJSStats(stats: nodeFS.Stats): FileStatus { + return FileStatus.create({ + accessTime: stats.atimeMs as Time, + deviceID: stats.dev as DeviceID, + fileGroup: stats.gid as GroupID, + fileID: stats.ino as FileID, + fileOwner: stats.uid as UserID, + fileSize: stats.size as FileSize, + isBlockDevice: stats.isBlockDevice(), + isCharacterDevice: stats.isCharacterDevice(), + isDirectory: stats.isDirectory(), + isFile: stats.isFile(), + isNamedPipe: stats.isFIFO(), + isSocket: stats.isSocket(), + isSymbolicLink: stats.isSymbolicLink(), + linkCount: stats.nlink as Int, + modificationTime: stats.mtimeMs as Time, + specialDeviceID: stats.rdev as DeviceID, + statusChangeTime: stats.ctimeMs as Time, + // fileMode: FileMode(stats.mode), + }); +} diff --git a/packages/system/src/FileSystem/readSymbolicLink.spec.ts b/packages/system/src/FileSystem/readSymbolicLink.spec.ts index 53526d27f4..fd43f88695 100644 --- a/packages/system/src/FileSystem/readSymbolicLink.spec.ts +++ b/packages/system/src/FileSystem/readSymbolicLink.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { readSymbolicLink } from './readSymbolicLink.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { readSymbolicLink } from './readSymbolicLink.js'; describe(readSymbolicLink, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/readSymbolicLink.ts b/packages/system/src/FileSystem/readSymbolicLink.ts index 34a2a8cea1..05945a0026 100644 --- a/packages/system/src/FileSystem/readSymbolicLink.ts +++ b/packages/system/src/FileSystem/readSymbolicLink.ts @@ -1,9 +1,11 @@ import type { Option } from '@w5s/core'; import type { Task } from '@w5s/task'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Reads the contents of the symbolic link referred to by path. * @@ -19,10 +21,10 @@ export function readSymbolicLink(path: FilePath, options?: readSymbolicLink.Opti return errnoTask(Internal.FS.readlink)(path, options) as Task; } export namespace readSymbolicLink { - export type Options = { + export interface Options { /** * The file encoding */ encoding?: Option; - }; + } } diff --git a/packages/system/src/FileSystem/remove.spec.ts b/packages/system/src/FileSystem/remove.spec.ts index bbfd880ca3..a673347ba3 100644 --- a/packages/system/src/FileSystem/remove.spec.ts +++ b/packages/system/src/FileSystem/remove.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { remove } from './remove.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { remove } from './remove.js'; describe(remove, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/remove.ts b/packages/system/src/FileSystem/remove.ts index 96b8c221d2..8e8ab696bd 100644 --- a/packages/system/src/FileSystem/remove.ts +++ b/packages/system/src/FileSystem/remove.ts @@ -1,9 +1,11 @@ -import type * as nodeFS from 'node:fs'; import type { Task } from '@w5s/task'; +import type * as nodeFS from 'node:fs'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Removes files and directories (modeled on the standard POSIX `rm` utility). * diff --git a/packages/system/src/FileSystem/rename.spec.ts b/packages/system/src/FileSystem/rename.spec.ts index 27c82c1ad9..86f2a42fc9 100644 --- a/packages/system/src/FileSystem/rename.spec.ts +++ b/packages/system/src/FileSystem/rename.spec.ts @@ -1,8 +1,9 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { rename } from './rename.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { rename } from './rename.js'; describe(rename, () => { const expectTask = withTask(expect); diff --git a/packages/system/src/FileSystem/rename.ts b/packages/system/src/FileSystem/rename.ts index 81a81b1d30..8b908fc845 100644 --- a/packages/system/src/FileSystem/rename.ts +++ b/packages/system/src/FileSystem/rename.ts @@ -1,8 +1,10 @@ import type { Task } from '@w5s/task'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoTask } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoTask, Internal } from '../Internal.js'; + /** * Renames `oldPath` to `newPath`. * diff --git a/packages/system/src/FileSystem/writeFile.spec.ts b/packages/system/src/FileSystem/writeFile.spec.ts index 83bfcd2e78..25f0bdb29b 100644 --- a/packages/system/src/FileSystem/writeFile.spec.ts +++ b/packages/system/src/FileSystem/writeFile.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; -import { withTask } from '@w5s/task/dist/Testing.js'; import { Symbol } from '@w5s/core'; import { TaskCanceler } from '@w5s/task'; -import { writeFile } from './writeFile.js'; +import { withTask } from '@w5s/task/dist/Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FilePath } from '../FilePath.js'; import { Internal } from '../Internal.js'; +import { writeFile } from './writeFile.js'; describe(writeFile, () => { const expectTask = withTask(expect); @@ -55,9 +56,9 @@ describe(writeFile, () => { }; const task = writeFile(FilePath('oldPath'), content); task[Symbol.run]({ - resolve: () => {}, - reject: () => {}, canceler, + reject: () => {}, + resolve: () => {}, }); expect(fileContent).toEqual('0123456789'); }); diff --git a/packages/system/src/FileSystem/writeFile.ts b/packages/system/src/FileSystem/writeFile.ts index 3bfa237856..68bdca5390 100644 --- a/packages/system/src/FileSystem/writeFile.ts +++ b/packages/system/src/FileSystem/writeFile.ts @@ -1,11 +1,14 @@ -import type * as nodeFS from 'node:fs'; import type { Option } from '@w5s/core'; import type { Task } from '@w5s/task'; +import type * as nodeFS from 'node:fs'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + import type { FileError } from '../FileError.js'; -import { Internal, errnoExceptionHandler } from '../Internal.js'; import type { FilePath } from '../FilePath.js'; +import { errnoExceptionHandler, Internal } from '../Internal.js'; + /** * Asynchronously writes data to a file, replacing the file if it already exists. * @@ -21,14 +24,14 @@ import type { FilePath } from '../FilePath.js'; export function writeFile( file: FilePath, data: - | string - | NodeJS.TypedArray + | AsyncIterable | DataView - | AsyncIterable - | Iterable, + | Iterable + | NodeJS.TypedArray + | string, options?: writeFile.Options, ): Task { - return taskFrom(async ({ resolve, reject, canceler }) => { + return taskFrom(async ({ canceler, reject, resolve }) => { const controller = new AbortController(); canceler.onCancel = () => { controller.abort(); @@ -46,20 +49,20 @@ export function writeFile( }); } export namespace writeFile { - export type Options = { + export interface Options { /** * The file encoding */ encoding?: Option; /** - * The file mode + * The system flag used to determine if the file should be truncated */ - mode?: Option; + flag?: Option; /** - * The system flag used to determine if the file should be truncated + * The file mode */ - flag?: Option; - }; + mode?: Option; + } } diff --git a/packages/system/src/Internal.spec.ts b/packages/system/src/Internal.spec.ts index a490e8b2df..7309d307da 100644 --- a/packages/system/src/Internal.spec.ts +++ b/packages/system/src/Internal.spec.ts @@ -1,10 +1,12 @@ import { Option } from '@w5s/core'; -import { describe, it, expect } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { FileError } from './FileError.js'; -import { ErrnoException, errnoExceptionHandler, errnoTask, errnoTaskSync } from './Internal.js'; +import { describe, expect, it } from 'vitest'; + import type { FilePath } from './FilePath.js'; + import { anyErrnoException, anyError } from './_test/config.js'; +import { FileError } from './FileError.js'; +import { ErrnoException, errnoExceptionHandler, errnoTask, errnoTaskSync } from './Internal.js'; const expectTask = withTask(expect); @@ -25,24 +27,24 @@ describe('errnoExceptionHandler', () => { it('should convert anything to "OtherError"', () => { expect(errnoExceptionHandler('anything')).toEqual( new FileError({ + cause: 'anything', + code: Option.None, + errno: Option.None, fileErrorType: 'OtherError', path: Option.None, - cause: 'anything', syscall: Option.None, - errno: Option.None, - code: Option.None, }), ); }); it('should convert any ErrnoException to "OtherError" and forward properties', () => { expect(errnoExceptionHandler(anyErrnoException)).toEqual( new FileError({ + cause: anyErrnoException, + code: anyErrnoException.code, + errno: anyErrnoException.errno, fileErrorType: 'OtherError', path: anyErrnoException.path as FilePath, - cause: anyErrnoException, syscall: anyErrnoException.syscall, - errno: anyErrnoException.errno, - code: anyErrnoException.code, }), ); }); diff --git a/packages/system/src/Internal.ts b/packages/system/src/Internal.ts index 7153f119fb..19c5003048 100644 --- a/packages/system/src/Internal.ts +++ b/packages/system/src/Internal.ts @@ -1,10 +1,13 @@ -import * as nodeFS from 'node:fs'; -import nodePath from 'node:path'; import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; -import { FileError } from './FileError.js'; +import * as nodeFS from 'node:fs'; +import nodePath from 'node:path'; + import type { FilePath } from './FilePath.js'; +import { FileError } from './FileError.js'; + export const Internal = { FS: { ...nodeFS.promises, ...nodeFS.constants }, Path: nodePath, @@ -27,26 +30,26 @@ export function errnoExceptionHandler(error: unknown): FileError { ? error : ErrnoException.hasInstance(error) ? new FileError({ + cause: error, + code: error.code, + errno: error.errno, fileErrorType: 'OtherError', path: error.path as FilePath, - cause: error, syscall: error.syscall, - errno: error.errno, - code: error.code, }) : new FileError({ + cause: error, + code: undefined, + errno: undefined, fileErrorType: 'OtherError', path: undefined, - cause: error, syscall: undefined, - errno: undefined, - code: undefined, }); } -export function errnoTask(fn: (...args: A) => Promise) { +export function errnoTask, R>(fn: (...args: A) => Promise) { return (...args: A): Task, FileError> => - taskFrom(async ({ resolve, reject }) => { + taskFrom(async ({ reject, resolve }) => { try { resolve(await fn(...args)); } catch (error_: unknown) { @@ -55,9 +58,9 @@ export function errnoTask(fn: (...args: A) => Promise }); } -export function errnoTaskSync(fn: (...args: A) => R) { +export function errnoTaskSync, R>(fn: (...args: A) => R) { return (...args: A): Task => - taskFrom(({ resolve, reject }) => { + taskFrom(({ reject, resolve }) => { try { resolve(fn(...args)); } catch (error_: unknown) { diff --git a/packages/system/src/Process.spec.ts b/packages/system/src/Process.spec.ts index 40cc6ac987..db3e0354ea 100644 --- a/packages/system/src/Process.spec.ts +++ b/packages/system/src/Process.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect, vi } from 'vitest'; import { withTask } from '@w5s/task/dist/Testing.js'; -import { errnoExceptionHandler } from './Internal.js'; +import { describe, expect, it, vi } from 'vitest'; + +import { anyErrnoException } from './_test/config.js'; import { FilePath } from './FilePath.js'; +import { errnoExceptionHandler } from './Internal.js'; import { Process } from './Process.js'; -import { anyErrnoException } from './_test/config.js'; describe('Process', () => { const expectTask = withTask(expect); diff --git a/packages/system/src/Process.ts b/packages/system/src/Process.ts index d925665ff9..023d30311d 100644 --- a/packages/system/src/Process.ts +++ b/packages/system/src/Process.ts @@ -1,9 +1,12 @@ import type { Task } from '@w5s/task'; + import { from as taskFrom } from '@w5s/task/dist/Task/from.js'; + import type { FileError } from './FileError.js'; -import { errnoTaskSync } from './Internal.js'; import type { FilePath } from './FilePath.js'; +import { errnoTaskSync } from './Internal.js'; + /** * @namespace */ diff --git a/packages/system/src/Testing.spec.ts b/packages/system/src/Testing.spec.ts index 9edcab4f05..65e412f345 100644 --- a/packages/system/src/Testing.spec.ts +++ b/packages/system/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('index', () => { diff --git a/packages/system/src/Testing/fsStub.spec.ts b/packages/system/src/Testing/fsStub.spec.ts index d98ea67942..5120b2038d 100644 --- a/packages/system/src/Testing/fsStub.spec.ts +++ b/packages/system/src/Testing/fsStub.spec.ts @@ -1,7 +1,8 @@ -import { describe, it, expect, afterAll } from 'vitest'; +import { Symbol } from '@w5s/core'; import nodePath from 'node:path'; import { fileURLToPath } from 'node:url'; -import { Symbol } from '@w5s/core'; +import { afterAll, describe, expect, it } from 'vitest'; + import { fsStub } from './fsStub.js'; import { withFile } from './withFile.js'; @@ -11,7 +12,7 @@ describe('fsStub', () => { const fsContext = fsStub({ cwd, }); - const { path, mkdir, touch } = fsContext; + const { mkdir, path, touch } = fsContext; const expectFile = withFile(expect); afterAll(async () => { diff --git a/packages/system/src/Testing/fsStub.ts b/packages/system/src/Testing/fsStub.ts index 66e8f46ca0..afb51167b0 100644 --- a/packages/system/src/Testing/fsStub.ts +++ b/packages/system/src/Testing/fsStub.ts @@ -1,57 +1,25 @@ -import nodePath from 'node:path'; +import { type Option, Symbol } from '@w5s/core'; import * as fs from 'node:fs'; -import { Symbol, type Option } from '@w5s/core'; +import nodePath from 'node:path'; + import type { FilePath } from '../FilePath.js'; /** - * Return a new `FSStubModule` - * - * @example - * ```typescript - * await using fs = fsStub({ - * cwd: // ... - * }); - * ``` - * @param options + * Options to create a fsStub */ -export function fsStub(options: FSOptions = {}): FSStubModule { - const { - cwd = process.cwd(), - - testPath = () => nodePath.join('.cache', `test_${Math.random().toString(36)}`), - } = options; - const tmpPath = nodePath.join(cwd, testPath()) as FilePath; - const dispose = () => fs.promises.rm(tmpPath, { recursive: true, force: true }); - const path = (...parts: string[]) => nodePath.join(tmpPath, ...parts) as FilePath; - const mkdir = (pathString: string) => fs.promises.mkdir(pathString, { recursive: true }) as Promise>; - const { symlink } = fs.promises; - const touch = async (pathString: string) => { - await mkdir(nodePath.dirname(pathString)); - await fs.promises.writeFile(pathString, ''); - }; - return { - tmpPath, - path, - mkdir, - symlink, - touch, - [Symbol.asyncDispose]: dispose, - }; -} - -export interface FSStubModule extends AsyncDisposable { +export interface FSOptions { /** - * A temporary path + * Current working directory */ - tmpPath: FilePath; + cwd?: string; /** - * Return a new path - * - * @param parts + * Return a new sub path from `pwd` */ - path(...parts: string[]): FilePath; + testPath?: () => string; +} +export interface FSStubModule extends AsyncDisposable { /** * Create a directory named `pathString` relative to `rootPath` * @@ -59,6 +27,13 @@ export interface FSStubModule extends AsyncDisposable { */ mkdir(pathString: string): Promise>; + /** + * Return a new path + * + * @param parts + */ + path(...parts: Array): FilePath; + /** * * @param target @@ -66,6 +41,11 @@ export interface FSStubModule extends AsyncDisposable { */ symlink(target: string, path: string): Promise; + /** + * A temporary path + */ + tmpPath: FilePath; + /** * Create a new `pathString` relative to `rootPath` * @@ -75,16 +55,37 @@ export interface FSStubModule extends AsyncDisposable { } /** - * Options to create a fsStub + * Return a new `FSStubModule` + * + * @example + * ```typescript + * await using fs = fsStub({ + * cwd: // ... + * }); + * ``` + * @param options */ -export interface FSOptions { - /** - * Current working directory - */ - cwd?: string; +export function fsStub(options: FSOptions = {}): FSStubModule { + const { + cwd = process.cwd(), - /** - * Return a new sub path from `pwd` - */ - testPath?: () => string; + testPath = () => nodePath.join('.cache', `test_${Math.random().toString(36)}`), + } = options; + const tmpPath = nodePath.join(cwd, testPath()) as FilePath; + const dispose = () => fs.promises.rm(tmpPath, { force: true, recursive: true }); + const path = (...parts: Array) => nodePath.join(tmpPath, ...parts) as FilePath; + const mkdir = (pathString: string) => fs.promises.mkdir(pathString, { recursive: true }) as Promise>; + const { symlink } = fs.promises; + const touch = async (pathString: string) => { + await mkdir(nodePath.dirname(pathString)); + await fs.promises.writeFile(pathString, ''); + }; + return { + mkdir, + path, + [Symbol.asyncDispose]: dispose, + symlink, + tmpPath, + touch, + }; } diff --git a/packages/system/src/Testing/withFile.spec.ts b/packages/system/src/Testing/withFile.spec.ts index 71856a93d1..6e07a85dd0 100644 --- a/packages/system/src/Testing/withFile.spec.ts +++ b/packages/system/src/Testing/withFile.spec.ts @@ -1,6 +1,7 @@ -import { describe, expect, it } from 'vitest'; import nodePath from 'node:path'; import { fileURLToPath } from 'node:url'; +import { describe, expect, it } from 'vitest'; + import { withFile } from './withFile.js'; describe('withFile', () => { @@ -15,8 +16,8 @@ describe('withFile', () => { await expectFile('blah').toExist(); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: 'expected blah to exist', + name: 'AssertionError', }), ); }); @@ -27,8 +28,8 @@ describe('withFile', () => { await expectFile(__dirname).toBeAFile(); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: `expected ${__dirname} to be a file`, + name: 'AssertionError', }), ); }); @@ -39,8 +40,8 @@ describe('withFile', () => { await expectFile(__filename).toBeADirectory(); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: `expected ${__filename} to be a directory`, + name: 'AssertionError', }), ); }); @@ -51,8 +52,8 @@ describe('withFile', () => { await expectFile(__filename).toBeASymbolicLink(); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: `expected ${__filename} to be a symbolic link`, + name: 'AssertionError', }), ); }); @@ -63,8 +64,8 @@ describe('withFile', () => { await expectFile(nodePath.join(fixtureDir, 'test1')).toHaveFileContent(''); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: String.raw`expected 'test1_content\n' to deeply equal ''`, + name: 'AssertionError', }), ); }); @@ -75,8 +76,8 @@ describe('withFile', () => { await expectFile(fixtureDir).toHaveDirContent([]); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: `expected [ 'test1', 'test2' ] to deeply equal []`, + name: 'AssertionError', }), ); }); @@ -87,8 +88,8 @@ describe('withFile', () => { await expectFile(nodePath.join(__dirname, '__fixture__')).toHaveDirLength(1); }).rejects.toEqual( expect.objectContaining({ - name: 'AssertionError', message: `expected [ 'test1', 'test2' ] to have property "length" with value 1`, + name: 'AssertionError', }), ); }); diff --git a/packages/system/src/Testing/withFile.ts b/packages/system/src/Testing/withFile.ts index 61d84770aa..72fb04a740 100644 --- a/packages/system/src/Testing/withFile.ts +++ b/packages/system/src/Testing/withFile.ts @@ -1,19 +1,8 @@ import type { ExpectFunction } from '@w5s/core-type'; + import * as fs from 'node:fs'; export interface ExpectFile { - /** - * Assert that the file exists - */ - toExist(): Promise; - - /** - * Assert that the file has the content equals to `expectedContent` - * - * @param expectedContent the expected content - */ - toHaveFileContent(expectedContent: string): Promise; - /** * Assert that the file is (not) a directory */ @@ -29,12 +18,17 @@ export interface ExpectFile { */ toBeASymbolicLink(): Promise; + /** + * Assert that the file exists + */ + toExist(): Promise; + /** * Assert that a file (not) containing `expectedContent` entries * * @param expectedContent the expected entry list */ - toHaveDirContent(expectedContent: string[]): Promise; + toHaveDirContent(expectedContent: Array): Promise; /** * Assert that a file (not) containing `expectedLength` entry count @@ -42,6 +36,13 @@ export interface ExpectFile { * @param expectedLength the expected length */ toHaveDirLength(expectedLength: number): Promise; + + /** + * Assert that the file has the content equals to `expectedContent` + * + * @param expectedContent the expected content + */ + toHaveFileContent(expectedContent: string): Promise; } /** @@ -74,17 +75,6 @@ export function withFile(expectFn: ExpectFunction) { }; const failDoesNotExist = (filePath: string) => fail(`expected ${filePath} to exist`); const create = (filePath: string, isNot: boolean): ExpectFile => ({ - async toExist() { - const stat = await lstat(filePath); - const exists = stat != null; - if (exists === isNot) { - fail(`expected ${filePath} ${isNot ? 'not ' : ''}to exist`); - } - }, - async toHaveFileContent(expectedContent: string) { - const actualContent = await fs.promises.readFile(filePath, 'utf8'); - expectIf(isNot, actualContent).toEqual(expectedContent); - }, async toBeADirectory() { const stat = (await lstat(filePath)) ?? failDoesNotExist(filePath); if (stat.isDirectory() === isNot) { @@ -103,12 +93,23 @@ export function withFile(expectFn: ExpectFunction) { fail(`expected ${filePath} ${isNot ? 'not ' : ''}to be a symbolic link`); } }, - async toHaveDirContent(content: string[]) { + async toExist() { + const stat = await lstat(filePath); + const exists = stat != null; + if (exists === isNot) { + fail(`expected ${filePath} ${isNot ? 'not ' : ''}to exist`); + } + }, + async toHaveDirContent(content: Array) { return expectFn(fs.promises.readdir(filePath)).resolves.toEqual(content); }, async toHaveDirLength(length: number) { return expectFn(fs.promises.readdir(filePath)).resolves.toHaveProperty('length', length); }, + async toHaveFileContent(expectedContent: string) { + const actualContent = await fs.promises.readFile(filePath, 'utf8'); + expectIf(isNot, actualContent).toEqual(expectedContent); + }, }); return (filePath: string) => Object.assign(create(filePath, false), { diff --git a/packages/system/src/_test/config.ts b/packages/system/src/_test/config.ts index cc546d180d..f6aa034229 100644 --- a/packages/system/src/_test/config.ts +++ b/packages/system/src/_test/config.ts @@ -1,4 +1,5 @@ import * as fs from 'node:fs'; + import type { FilePath } from '../FilePath.js'; import type { ErrnoException } from '../Internal.js'; // import * as url from 'node:url'; @@ -27,42 +28,42 @@ export const generateStats = (): fs.Stats => { const isFIFO = randomBoolean(); const isSocket = randomBoolean(); return { - isFile: () => isFile, - isDirectory: () => isDirectory, - isSymbolicLink: () => isSymbolicLink, - isBlockDevice: () => isBlockDevice, - isCharacterDevice: () => isCharacterDevice, - isFIFO: () => isFIFO, - isSocket: () => isSocket, - size: 0, atime: randomDate(), get atimeMs() { return this.atime.getTime(); }, - // atimeNs: Math.random(), - mtime: randomDate(), - get mtimeMs() { - return this.mtime.getTime(); + // ctimeNs: Math.random(), + birthtime: randomDate(), + get birthtimeMs() { + return this.birthtime.getTime(); }, + blksize: randomInt(), + blocks: randomInt(), // mtimeNs: Math.random(), ctime: randomDate(), get ctimeMs() { return this.ctime.getTime(); }, - // ctimeNs: Math.random(), - birthtime: randomDate(), - get birthtimeMs() { - return this.birthtime.getTime(); - }, // birthtimeNs: Math.random(), dev: randomInt(), + gid: randomInt(), ino: randomInt(), + isBlockDevice: () => isBlockDevice, + isCharacterDevice: () => isCharacterDevice, + isDirectory: () => isDirectory, + isFIFO: () => isFIFO, + isFile: () => isFile, + isSocket: () => isSocket, + isSymbolicLink: () => isSymbolicLink, mode: randomInt(), + // atimeNs: Math.random(), + mtime: randomDate(), + get mtimeMs() { + return this.mtime.getTime(); + }, nlink: randomInt(), - uid: randomInt(), - gid: randomInt(), rdev: randomInt(), - blksize: randomInt(), - blocks: randomInt(), + size: 0, + uid: randomInt(), }; }; diff --git a/packages/system/src/index.spec.ts b/packages/system/src/index.spec.ts index e142a5dc62..dcf86f80ef 100644 --- a/packages/system/src/index.spec.ts +++ b/packages/system/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './index.js'; describe('index', () => { diff --git a/packages/system/src/index.ts b/packages/system/src/index.ts index 6718ec2d6d..4c753e56ee 100644 --- a/packages/system/src/index.ts +++ b/packages/system/src/index.ts @@ -1,6 +1,6 @@ -export * from './FileSystem.js'; -export * from './FileSize.js'; +export * from './FileError.js'; export * from './FilePath.js'; +export * from './FileSize.js'; export * from './FileStatus.js'; -export * from './FileError.js'; +export * from './FileSystem.js'; export * from './Process.js'; diff --git a/packages/task-timeout/README.md b/packages/task-timeout/README.md index c62c9be49e..10615f3d3e 100644 --- a/packages/task-timeout/README.md +++ b/packages/task-timeout/README.md @@ -30,8 +30,16 @@ import { Task } from '@w5s/task'; import { timeout } from '@w5s/task-timeout'; import { TimeDuration } from '@w5s/time'; +export function main() { + // Example of a task that will + const someTask = sayHelloWorld(TimeDuration({ seconds: 2 })); // log "Hello world" after 2 seconds + const withTimeout = timeout(someTask, TimeDuration({ seconds: 1 })); // set timeout to 1 second + + return withTimeout; +} + function sayHelloWorld(delay: TimeDuration) { - return Task.from(({ resolve, canceler }) => { + return Task.from(({ canceler, resolve }) => { const timerId = setTimeout(() => { console.log('Hello World!'); resolve(undefined); @@ -40,14 +48,6 @@ function sayHelloWorld(delay: TimeDuration) { }); } -export function main() { - // Example of a task that will - const someTask = sayHelloWorld(TimeDuration({ seconds: 2 })); // log "Hello world" after 2 seconds - const withTimeout = timeout(someTask, TimeDuration({ seconds: 1 })); // set timeout to 1 second - - return withTimeout; -} - void Task.run(main()); ``` diff --git a/packages/task-timeout/example/.eslintrc.cjs b/packages/task-timeout/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/task-timeout/example/.eslintrc.cjs +++ b/packages/task-timeout/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/task-timeout/example/usage.ts b/packages/task-timeout/example/usage.ts index 3a640e0461..10289c95e7 100644 --- a/packages/task-timeout/example/usage.ts +++ b/packages/task-timeout/example/usage.ts @@ -2,8 +2,16 @@ import { Task } from '@w5s/task'; import { timeout } from '@w5s/task-timeout'; import { TimeDuration } from '@w5s/time'; +export function main() { + // Example of a task that will + const someTask = sayHelloWorld(TimeDuration({ seconds: 2 })); // log "Hello world" after 2 seconds + const withTimeout = timeout(someTask, TimeDuration({ seconds: 1 })); // set timeout to 1 second + + return withTimeout; +} + function sayHelloWorld(delay: TimeDuration) { - return Task.from(({ resolve, canceler }) => { + return Task.from(({ canceler, resolve }) => { const timerId = setTimeout(() => { console.log('Hello World!'); resolve(undefined); @@ -12,12 +20,4 @@ function sayHelloWorld(delay: TimeDuration) { }); } -export function main() { - // Example of a task that will - const someTask = sayHelloWorld(TimeDuration({ seconds: 2 })); // log "Hello world" after 2 seconds - const withTimeout = timeout(someTask, TimeDuration({ seconds: 1 })); // set timeout to 1 second - - return withTimeout; -} - void Task.run(main()); diff --git a/packages/task-timeout/src/index.spec.ts b/packages/task-timeout/src/index.spec.ts index 41b148329c..1cf1e88235 100644 --- a/packages/task-timeout/src/index.spec.ts +++ b/packages/task-timeout/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Std from './index.js'; describe('index', () => { diff --git a/packages/task-timeout/src/timeout.spec.ts b/packages/task-timeout/src/timeout.spec.ts index 6255f57bdf..524912bc73 100644 --- a/packages/task-timeout/src/timeout.spec.ts +++ b/packages/task-timeout/src/timeout.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect, vi } from 'vitest'; import { Option, Symbol } from '@w5s/core'; -import { Task, type TaskLike } from '@w5s/task'; -import { TimeDuration } from '@w5s/time'; import { TimeoutError } from '@w5s/error'; +import { Task, type TaskLike } from '@w5s/task'; import { withTask } from '@w5s/task/dist/Testing.js'; +import { TimeDuration } from '@w5s/time'; +import { describe, expect, it, vi } from 'vitest'; + import { timeout } from './timeout.js'; describe(timeout, () => { diff --git a/packages/task-timeout/src/timeout.ts b/packages/task-timeout/src/timeout.ts index 3863c3f8bd..7c108a872e 100644 --- a/packages/task-timeout/src/timeout.ts +++ b/packages/task-timeout/src/timeout.ts @@ -1,11 +1,12 @@ +import type { Option } from '@w5s/core'; import type { Task, TaskLike } from '@w5s/task'; import type { TimeDuration } from '@w5s/time'; + import { TimeoutError } from '@w5s/error/dist/TimeoutError.js'; import { from } from '@w5s/task/dist/Task/from.js'; -import { TaskCanceler } from '@w5s/task/dist/TaskCanceler.js'; import { unsafeCall } from '@w5s/task/dist/Task/unsafeCall.js'; +import { TaskCanceler } from '@w5s/task/dist/TaskCanceler.js'; import { TimeDurationAsString } from '@w5s/time/dist/TimeDuration/TimeDurationAsString.js'; -import type { Option } from '@w5s/core'; const timeDurationString = TimeDurationAsString.asString; @@ -26,10 +27,10 @@ const timeDurationString = TimeDurationAsString.asString; export function timeout( self: TaskLike, delay: Option, -): Task { +): Task { return delay == null ? from(self) - : from(({ resolve, reject, canceler }) => { + : from(({ canceler, reject, resolve }) => { const taskCanceler = new TaskCanceler(); const timeoutId = setTimeout(() => { @@ -48,15 +49,15 @@ export function timeout( }; return unsafeCall(self, { - resolve: (value) => { - timeoutCancel(); - resolve(value); - }, + canceler: taskCanceler, reject: (error) => { timeoutCancel(); reject(error); }, - canceler: taskCanceler, + resolve: (value) => { + timeoutCancel(); + resolve(value); + }, }); }); } diff --git a/packages/task/README.md b/packages/task/README.md index f03fb9356b..c43e6333f2 100644 --- a/packages/task/README.md +++ b/packages/task/README.md @@ -22,15 +22,6 @@ npm install @w5s/task ```ts import { Task } from '@w5s/task'; -function randomNumber() { - return Task.create(() => Task.ok(Math.random())); -} - -function log(value: unknown) { - // This is a lazy operation that will only be evaluated when the Task is run - return Task.create(() => Task.ok(console.log(value))); -} - // This function returns a task that will do nothing until Task.run is called on it export function main() { // 1. Generate a random number @@ -41,6 +32,15 @@ export function main() { return Task.andThen(squareValueTask, log); } +function log(value: unknown) { + // This is a lazy operation that will only be evaluated when the Task is run + return Task.create(() => Task.ok(console.log(value))); +} + +function randomNumber() { + return Task.create(() => Task.ok(Math.random())); +} + // runTask is impure and should be put at the edge of the program void Task.run(main()); // prints { _: 'Result/Ok', value: * } diff --git a/packages/task/example/.eslintrc.cjs b/packages/task/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/task/example/.eslintrc.cjs +++ b/packages/task/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/task/example/usage.ts b/packages/task/example/usage.ts index e742ecb692..5093e35409 100644 --- a/packages/task/example/usage.ts +++ b/packages/task/example/usage.ts @@ -1,14 +1,5 @@ import { Task } from '@w5s/task'; -function randomNumber() { - return Task.create(() => Task.ok(Math.random())); -} - -function log(value: unknown) { - // This is a lazy operation that will only be evaluated when the Task is run - return Task.create(() => Task.ok(console.log(value))); -} - // This function returns a task that will do nothing until Task.run is called on it export function main() { // 1. Generate a random number @@ -19,6 +10,15 @@ export function main() { return Task.andThen(squareValueTask, log); } +function log(value: unknown) { + // This is a lazy operation that will only be evaluated when the Task is run + return Task.create(() => Task.ok(console.log(value))); +} + +function randomNumber() { + return Task.create(() => Task.ok(Math.random())); +} + // runTask is impure and should be put at the edge of the program void Task.run(main()); // prints { _: 'Result/Ok', value: * } diff --git a/packages/task/src/Task.spec.ts b/packages/task/src/Task.spec.ts index f15fa25244..7a5afa0762 100644 --- a/packages/task/src/Task.spec.ts +++ b/packages/task/src/Task.spec.ts @@ -1,26 +1,27 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Task } from './Task.js'; -import { resolve } from './Task/resolve.js'; import { all } from './Task/all.js'; +import { allKeyed } from './Task/allKeyed.js'; import { allSettled } from './Task/allSettled.js'; +import { allSettledKeyed } from './Task/allSettledKeyed.js'; import { andRun } from './Task/andRun.js'; import { andThen } from './Task/andThen.js'; import { any } from './Task/any.js'; import { create } from './Task/create.js'; +import { error } from './Task/error.js'; +import { from } from './Task/from.js'; import { hasInstance } from './Task/hasInstance.js'; +import { ignore } from './Task/ignore.js'; import { map } from './Task/map.js'; import { mapError } from './Task/mapError.js'; +import { mapResult } from './Task/mapResult.js'; +import { ok } from './Task/ok.js'; import { orElse } from './Task/orElse.js'; import { reject } from './Task/reject.js'; -import { tryCall } from './Task/tryCall.js'; +import { resolve } from './Task/resolve.js'; import { run } from './Task/run.js'; -import { from } from './Task/from.js'; -import { mapResult } from './Task/mapResult.js'; -import { ignore } from './Task/ignore.js'; -import { error } from './Task/error.js'; -import { ok } from './Task/ok.js'; -import { allKeyed } from './Task/allKeyed.js'; -import { allSettledKeyed } from './Task/allSettledKeyed.js'; +import { tryCall } from './Task/tryCall.js'; describe('Task', () => { it('is an alias to functions', () => { @@ -33,8 +34,8 @@ describe('Task', () => { andThen, any, create, - from, error, + from, hasInstance, ignore, map, @@ -44,8 +45,8 @@ describe('Task', () => { orElse, reject, resolve, - tryCall, run, + tryCall, }); }); }); diff --git a/packages/task/src/Task.ts b/packages/task/src/Task.ts index 27848954d3..89dfead89f 100644 --- a/packages/task/src/Task.ts +++ b/packages/task/src/Task.ts @@ -1,51 +1,66 @@ import type { Awaitable } from '@w5s/async'; import type { Result } from '@w5s/core'; -import type { Symbol } from '@w5s/core/dist/Symbol.js'; import type { PartialKeys } from '@w5s/core-type'; -import { create } from './Task/create.js'; -import { resolve } from './Task/resolve.js'; -import { reject } from './Task/reject.js'; +import type { Symbol } from '@w5s/core/dist/Symbol.js'; + +import type { TaskCanceler } from './TaskCanceler.js'; + import { all } from './Task/all.js'; -import { any } from './Task/any.js'; +import { allKeyed } from './Task/allKeyed.js'; import { allSettled } from './Task/allSettled.js'; -import { map } from './Task/map.js'; -import { mapError } from './Task/mapError.js'; -import { andThen } from './Task/andThen.js'; +import { allSettledKeyed } from './Task/allSettledKeyed.js'; import { andRun } from './Task/andRun.js'; -import { orElse } from './Task/orElse.js'; -import { tryCall } from './Task/tryCall.js'; -import { hasInstance } from './Task/hasInstance.js'; -import { run } from './Task/run.js'; +import { andThen } from './Task/andThen.js'; +import { any } from './Task/any.js'; +import { create } from './Task/create.js'; +import { error } from './Task/error.js'; import { from } from './Task/from.js'; -import { mapResult } from './Task/mapResult.js'; +import { hasInstance } from './Task/hasInstance.js'; import { ignore } from './Task/ignore.js'; +import { map } from './Task/map.js'; +import { mapError } from './Task/mapError.js'; +import { mapResult } from './Task/mapResult.js'; import { ok } from './Task/ok.js'; -import { error } from './Task/error.js'; -import { allKeyed } from './Task/allKeyed.js'; -import { allSettledKeyed } from './Task/allSettledKeyed.js'; -import type { TaskCanceler } from './TaskCanceler.js'; +import { orElse } from './Task/orElse.js'; +import { reject } from './Task/reject.js'; +import { resolve } from './Task/resolve.js'; +import { run } from './Task/run.js'; +import { tryCall } from './Task/tryCall.js'; /** - * A function that runs the task and returns a {@link @w5s/core!Result} + * An implementation of {@link @w5s/task!TaskLike} */ -export type TaskRunner = ( - task: TaskLike, - canceler: TaskCanceler, -) => Awaitable>; +export interface Task extends TaskLike { + /** + * Shorthand to run the current task + * + * @param options + */ + run(options?: TaskRunOptions): Awaitable>; +} -export interface TaskParametersOverrides extends PartialKeys< - Pick, 'resolve' | 'reject' | 'canceler'>, - 'canceler' -> {} +export type TaskFunction = (parameters: TaskParameters) => Awaitable; + +/** + * A Task interface that represents a lazy computation that will be evaluated later. + * The result of the computation is a {@link @w5s/core!Result} + * A task is also cancelable and can run other subtasks + */ +export interface TaskLike { + /** + * A callback with side effects + */ + readonly [Symbol.run]: TaskFunction; +} /** * All context passed to task in order to execute */ export interface TaskParameters { /** - * Resolve callback + * Reference to cancel function */ - readonly resolve: (value: Value) => Awaitable; + readonly canceler: TaskCanceler; /** * Reject callback @@ -53,45 +68,32 @@ export interface TaskParameters { readonly reject: (error: Error) => Awaitable; /** - * Reference to cancel function + * Resolve callback */ - readonly canceler: TaskCanceler; + readonly resolve: (value: Value) => Awaitable; } -export type TaskFunction = (parameters: TaskParameters) => Awaitable; - -/** - * Options for running a task - */ -export type TaskRunOptions = { - /** - * The abort signal to use for the task. - */ - signal?: AbortSignal; -}; +export interface TaskParametersOverrides extends PartialKeys< + Pick, 'canceler' | 'reject' | 'resolve'>, + 'canceler' +> {} /** - * A Task interface that represents a lazy computation that will be evaluated later. - * The result of the computation is a {@link @w5s/core!Result} - * A task is also cancelable and can run other subtasks + * A function that runs the task and returns a {@link @w5s/core!Result} */ -export interface TaskLike { - /** - * A callback with side effects - */ - readonly [Symbol.run]: TaskFunction; -} +export type TaskRunner = ( + task: TaskLike, + canceler: TaskCanceler, +) => Awaitable>; /** - * An implementation of {@link @w5s/task!TaskLike} + * Options for running a task */ -export interface Task extends TaskLike { +export interface TaskRunOptions { /** - * Shorthand to run the current task - * - * @param options + * The abort signal to use for the task. */ - run(options?: TaskRunOptions): Awaitable>; + signal?: AbortSignal; } /** @@ -117,18 +119,18 @@ export const Task = { orElse, reject, resolve, - tryCall, run, + tryCall, }; export namespace Task { /** - * Extracts value type of task T + * Extracts error type of task T */ - export type ValueOf = T extends Task ? V : never; + export type ErrorOf = T extends Task ? Error : never; /** - * Extracts error type of task T + * Extracts value type of task T */ - export type ErrorOf = T extends Task ? Error : never; + export type ValueOf = T extends Task ? V : never; } diff --git a/packages/task/src/Task/Task.spec.ts b/packages/task/src/Task/Task.spec.ts index d2dcf97050..6fbe6e6b02 100644 --- a/packages/task/src/Task/Task.spec.ts +++ b/packages/task/src/Task/Task.spec.ts @@ -1,5 +1,6 @@ -import { describe, expect, it } from 'vitest'; import { Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { Task } from './Task.js'; describe('Task', () => { diff --git a/packages/task/src/Task/Task.ts b/packages/task/src/Task/Task.ts index 797bdffd3b..3e33b54201 100644 --- a/packages/task/src/Task/Task.ts +++ b/packages/task/src/Task/Task.ts @@ -1,7 +1,10 @@ import type { Awaitable } from '@w5s/async'; import type { Result } from '@w5s/core'; + import { Symbol } from '@w5s/core/dist/Symbol.js'; + import type { TaskFunction, Task as TaskInterface, TaskRunOptions } from '../Task.js'; + import { run as taskRun } from './run.js'; const $run = Symbol.run; diff --git a/packages/task/src/Task/TaskAggregateState.ts b/packages/task/src/Task/TaskAggregateState.ts index c52a39ea94..ef0aff08f9 100644 --- a/packages/task/src/Task/TaskAggregateState.ts +++ b/packages/task/src/Task/TaskAggregateState.ts @@ -1,50 +1,35 @@ import type { TaskLike, TaskParameters } from '../Task.js'; + import { TaskCanceler } from '../TaskCanceler.js'; import { unsafeCall } from './unsafeCall.js'; -interface TaskInputEntry { - /** - * The task to run - */ - task: TaskLike; - - /** - * The key of the task (number or string) - */ - key: Key; -} - -interface TaskEntry extends TaskInputEntry { +interface TaskAggregateState { /** - * The canceler of the task + * Cancel all the tasks */ - canceler: TaskCanceler; -} + cancelAll: () => void; -interface TaskAggregateStateConfiguration { /** - * Cancel children when parent is cancelled + * Cancel the tasks if the predicate is true + * + * @param predicate the predicate to check if the tasks should be cancelled */ - cancelChildrenFromParent?: boolean; -} + cancelIf: (predicate: (entry: TaskEntry) => boolean) => void; -interface TaskAggregateState { /** * Check if the aggregate state is complete */ isComplete: () => boolean; /** - * Cancel all the tasks + * Reject the aggregate state */ - cancelAll: () => void; + reject: (error: ReturnError) => void; /** - * Cancel the tasks if the predicate is true - * - * @param predicate the predicate to check if the tasks should be cancelled + * Resolve the aggregate state */ - cancelIf: (predicate: (entry: TaskEntry) => boolean) => void; + resolve: (value: ReturnValue) => void; /** * Run all the tasks @@ -61,16 +46,32 @@ interface TaskAggregateState { self: TaskAggregateState, ) => void, ) => void; +} +interface TaskAggregateStateConfiguration { /** - * Resolve the aggregate state + * Cancel children when parent is cancelled */ - resolve: (value: ReturnValue) => void; + cancelChildrenFromParent?: boolean; +} +interface TaskEntry extends TaskInputEntry { /** - * Reject the aggregate state + * The canceler of the task */ - reject: (error: ReturnError) => void; + canceler: TaskCanceler; +} + +interface TaskInputEntry { + /** + * The key of the task (number or string) + */ + key: Key; + + /** + * The task to run + */ + task: TaskLike; } export function TaskAggregateState( @@ -78,7 +79,7 @@ export function TaskAggregateState( taskParameters: TaskParameters, options: TaskAggregateStateConfiguration = {}, ): TaskAggregateState { - const { reject, resolve, canceler: parentCanceler } = taskParameters; + const { canceler: parentCanceler, reject, resolve } = taskParameters; const taskEntries = tasks.map((task) => ({ ...task, canceler: new TaskCanceler() })); const taskCount = taskEntries.length; let taskCompleted = 0; @@ -130,19 +131,19 @@ export function TaskAggregateState( ) => { for (const entry of taskEntries) { unsafeCall(entry.task, { + canceler: entry.canceler, // eslint-disable-next-line ts/no-loop-func - resolve: (value: Value) => { + reject: (error: Error) => { taskCompleted += 1; // eslint-disable-next-line ts/no-use-before-define - resolveTask(value, entry, self); + rejectTask(error, entry, self); }, // eslint-disable-next-line ts/no-loop-func - reject: (error: Error) => { + resolve: (value: Value) => { taskCompleted += 1; // eslint-disable-next-line ts/no-use-before-define - rejectTask(error, entry, self); + resolveTask(value, entry, self); }, - canceler: entry.canceler, }); } }; @@ -150,12 +151,12 @@ export function TaskAggregateState( setCancelChildrenFromParent(options.cancelChildrenFromParent ?? false); const self = { - isComplete, cancelAll, cancelIf, - runAll, - resolve: withClose(resolve), + isComplete, reject: withClose(reject), + resolve: withClose(resolve), + runAll, }; return self; } diff --git a/packages/task/src/Task/_stub.spec.ts b/packages/task/src/Task/_stub.spec.ts index 3cb223eabe..1905c0da16 100644 --- a/packages/task/src/Task/_stub.spec.ts +++ b/packages/task/src/Task/_stub.spec.ts @@ -5,7 +5,7 @@ export const allSyncCombination = [ ['async', 'sync'], ['sync', 'async'], ['async', 'async'], -] as Array<['sync' | 'async', 'sync' | 'async']>; +] as Array<['async' | 'sync', 'async' | 'sync']>; describe('allSyncCombination', () => { it('exports combinations', () => { diff --git a/packages/task/src/Task/all.spec.ts b/packages/task/src/Task/all.spec.ts index 364aa8958d..d87ed40163 100644 --- a/packages/task/src/Task/all.spec.ts +++ b/packages/task/src/Task/all.spec.ts @@ -1,9 +1,11 @@ /* eslint-disable unicorn/prefer-array-from-map */ -import { describe, expect, it, vi } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { all } from './all.js'; -import { FakeTask, withTask } from '../Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import type { Task } from '../Task.js'; + +import { FakeTask, withTask } from '../Testing.js'; +import { all } from './all.js'; import { run } from './run.js'; describe(all, () => { @@ -28,11 +30,11 @@ describe(all, () => { const taskData = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { + canceler, task: taskIndex === 0 - ? FakeTask({ delayMs: 1, error: `error${taskIndex}`, canceler }) - : FakeTask({ delayMs: 100, value: `value${taskIndex}`, canceler }), - canceler, + ? FakeTask({ canceler, delayMs: 1, error: `error${taskIndex}` }) + : FakeTask({ canceler, delayMs: 100, value: `value${taskIndex}` }), }; }); const allTask = all(taskData.map((_) => _.task)); @@ -47,8 +49,8 @@ describe(all, () => { const taskData = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { - task: FakeTask({ value: `value${taskIndex}`, canceler, delayMs: 2 }), canceler, + task: FakeTask({ canceler, delayMs: 2, value: `value${taskIndex}` }), }; }); diff --git a/packages/task/src/Task/all.ts b/packages/task/src/Task/all.ts index 99e557e686..a8e480e617 100644 --- a/packages/task/src/Task/all.ts +++ b/packages/task/src/Task/all.ts @@ -1,7 +1,8 @@ import type { Task, TaskLike } from '../Task.js'; -import { TaskAggregateState } from './TaskAggregateState.js'; -import { from } from './from.js'; + import { emptyArray } from '../internal/emptyArray.js'; +import { from } from './from.js'; +import { TaskAggregateState } from './TaskAggregateState.js'; /** * Resolves with the array of all task values, or reject with the first error @@ -22,18 +23,18 @@ import { emptyArray } from '../internal/emptyArray.js'; * ``` * @param tasks tasks to be run in parallel */ -export function all[]>( +export function all>>( tasks: [...T], ): Task<{ [K in keyof T]: Task.ValueOf }, Task.ErrorOf>; export function all(tasks: Iterable>): Task, Error>; export function all(tasks: Iterable>): Task, Error> { return from((parameters) => { - const taskArray = Array.from(tasks, (task, key) => ({ task, key })); + const taskArray = Array.from(tasks, (task, key) => ({ key, task })); if (taskArray.length === 0) { parameters.resolve(emptyArray); } else { // eslint-disable-next-line unicorn/no-new-array - const values = new Array(taskArray.length); + const values = new Array(taskArray.length); TaskAggregateState(taskArray, parameters, { cancelChildrenFromParent: true }).runAll( (value, entry, self) => { values[entry.key] = value; diff --git a/packages/task/src/Task/allKeyed.spec.ts b/packages/task/src/Task/allKeyed.spec.ts index 33e277b2c9..024a260a91 100644 --- a/packages/task/src/Task/allKeyed.spec.ts +++ b/packages/task/src/Task/allKeyed.spec.ts @@ -1,10 +1,12 @@ /* eslint-disable unicorn/prefer-array-from-map */ -import { describe, expect, it, vi } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it, vi } from 'vitest'; + +import type { Task } from '../Task.js'; + +import { FakeTask, withTask } from '../Testing.js'; import { allKeyed } from './allKeyed.js'; import { run as taskRun } from './run.js'; -import { FakeTask, withTask } from '../Testing.js'; -import type { Task } from '../Task.js'; describe(allKeyed, () => { const expectTask = withTask(expect); @@ -28,12 +30,12 @@ describe(allKeyed, () => { const taskData = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { + canceler, key: `task${taskIndex}`, task: taskIndex === 0 - ? FakeTask({ delayMs: 1, error: `error${taskIndex}`, canceler }) - : FakeTask({ delayMs: 100, value: `value${taskIndex}`, canceler }), - canceler, + ? FakeTask({ canceler, delayMs: 1, error: `error${taskIndex}` }) + : FakeTask({ canceler, delayMs: 100, value: `value${taskIndex}` }), }; }); const allTask = allKeyed(Object.fromEntries(taskData.map(({ key, task }) => [key, task]))); @@ -48,9 +50,9 @@ describe(allKeyed, () => { const taskEntries = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { - key: `task${taskIndex}`, - task: FakeTask({ value: `value${taskIndex}`, canceler, delayMs: 2 }), canceler, + key: `task${taskIndex}`, + task: FakeTask({ canceler, delayMs: 2, value: `value${taskIndex}` }), }; }); const allTask = allKeyed(Object.fromEntries(taskEntries.map(({ key, task }) => [key, task]))); diff --git a/packages/task/src/Task/allKeyed.ts b/packages/task/src/Task/allKeyed.ts index 3c0e3edb98..0bf8afcdcf 100644 --- a/packages/task/src/Task/allKeyed.ts +++ b/packages/task/src/Task/allKeyed.ts @@ -1,6 +1,7 @@ import type { Task, TaskLike } from '../Task.js'; -import { TaskAggregateState } from './TaskAggregateState.js'; + import { from } from './from.js'; +import { TaskAggregateState } from './TaskAggregateState.js'; /** * Resolves with the record of all task values, or reject with the first error @@ -27,7 +28,6 @@ export function allKeyed>>( return from((parameters) => { const taskArray = Object.entries(tasks).map(([key, task]) => ({ key, task })); if (taskArray.length === 0) { - // eslint-disable-next-line ts/consistent-type-assertions parameters.resolve({} as { [K in keyof TaskRecord]: Task.ValueOf }); } else { const values: Record = {}; diff --git a/packages/task/src/Task/allSettled.spec.ts b/packages/task/src/Task/allSettled.spec.ts index 758fccec8a..cdeea70b0c 100644 --- a/packages/task/src/Task/allSettled.spec.ts +++ b/packages/task/src/Task/allSettled.spec.ts @@ -1,8 +1,9 @@ /* eslint-disable unicorn/prefer-array-from-map */ -import { describe, it, expect, vi } from 'vitest'; import { Result } from '@w5s/core'; -import { allSettled } from './allSettled.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FakeTask, withTask } from '../Testing.js'; +import { allSettled } from './allSettled.js'; import { run as taskRun } from './run.js'; describe(allSettled, () => { @@ -31,9 +32,9 @@ describe(allSettled, () => { const taskEntries = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { - key: taskIndex, - task: FakeTask({ value: `value${taskIndex}`, canceler, delayMs: 2 }), canceler, + key: taskIndex, + task: FakeTask({ canceler, delayMs: 2, value: `value${taskIndex}` }), }; }); const allTask = allSettled(taskEntries.map(({ task }) => task)); diff --git a/packages/task/src/Task/allSettled.ts b/packages/task/src/Task/allSettled.ts index 2f289015db..dc1da2b0c4 100644 --- a/packages/task/src/Task/allSettled.ts +++ b/packages/task/src/Task/allSettled.ts @@ -1,10 +1,13 @@ import type { Result } from '@w5s/core/dist/Result.js'; + import { Error } from '@w5s/core/dist/Result/Error.js'; import { Ok } from '@w5s/core/dist/Result/Ok.js'; + import type { Task, TaskLike } from '../Task.js'; -import { TaskAggregateState } from './TaskAggregateState.js'; -import { from } from './from.js'; + import { emptyArray } from '../internal/emptyArray.js'; +import { from } from './from.js'; +import { TaskAggregateState } from './TaskAggregateState.js'; /** * Resolves an array of all task results @@ -19,7 +22,7 @@ import { emptyArray } from '../internal/emptyArray.js'; * ``` * @param tasks tasks to be run in parallel */ -export function allSettled[]>( +export function allSettled>>( tasks: [...T], ): Task<{ [K in keyof T]: Result, Task.ErrorOf> }, never>; export function allSettled( @@ -29,7 +32,7 @@ export function allSettled( tasks: Iterable>, ): Task>, never> { return from((parameters) => { - const taskArray = Array.from(tasks, (task, key) => ({ task, key })); + const taskArray = Array.from(tasks, (task, key) => ({ key, task })); if (taskArray.length === 0) { parameters.resolve(emptyArray); diff --git a/packages/task/src/Task/allSettledKeyed.spec.ts b/packages/task/src/Task/allSettledKeyed.spec.ts index e76e8d2756..775ceaf417 100644 --- a/packages/task/src/Task/allSettledKeyed.spec.ts +++ b/packages/task/src/Task/allSettledKeyed.spec.ts @@ -1,11 +1,13 @@ /* eslint-disable unicorn/prefer-array-from-map */ -import { describe, expect, it, vi } from 'vitest'; -import { assertType } from '@w5s/core-type'; import { Result } from '@w5s/core'; +import { assertType } from '@w5s/core-type'; +import { describe, expect, it, vi } from 'vitest'; + +import type { Task } from '../Task.js'; + +import { FakeTask, withTask } from '../Testing.js'; import { allSettledKeyed } from './allSettledKeyed.js'; import { run as taskRun } from './run.js'; -import { FakeTask, withTask } from '../Testing.js'; -import type { Task } from '../Task.js'; describe(allSettledKeyed, () => { const expectTask = withTask(expect); @@ -46,9 +48,9 @@ describe(allSettledKeyed, () => { const taskEntries = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { - key: `task${taskIndex}`, - task: FakeTask({ value: `value${taskIndex}`, canceler, delayMs: 2 }), canceler, + key: `task${taskIndex}`, + task: FakeTask({ canceler, delayMs: 2, value: `value${taskIndex}` }), }; }); const allTask = allSettledKeyed(Object.fromEntries(taskEntries.map(({ key, task }) => [key, task]))); diff --git a/packages/task/src/Task/allSettledKeyed.ts b/packages/task/src/Task/allSettledKeyed.ts index a2253e7d76..dff72b8b95 100644 --- a/packages/task/src/Task/allSettledKeyed.ts +++ b/packages/task/src/Task/allSettledKeyed.ts @@ -1,9 +1,11 @@ import type { Result } from '@w5s/core'; + import type { Task, TaskLike } from '../Task.js'; -import { TaskAggregateState } from './TaskAggregateState.js'; + +import { error as resultError } from './error.js'; import { from } from './from.js'; import { ok as resultOk } from './ok.js'; -import { error as resultError } from './error.js'; +import { TaskAggregateState } from './TaskAggregateState.js'; /** * Resolves with the record of all task values, or reject with the first error @@ -28,7 +30,6 @@ export function allSettledKeyed { const taskArray = Object.entries(tasks).map(([key, task]) => ({ key, task })); if (taskArray.length === 0) { - // eslint-disable-next-line ts/consistent-type-assertions parameters.resolve({} as { [K in keyof TaskRecord]: Task.ValueOf }); } else { const state = TaskAggregateState(taskArray, parameters, { cancelChildrenFromParent: true }); diff --git a/packages/task/src/Task/andRun.spec.ts b/packages/task/src/Task/andRun.spec.ts index d5a53aa2ba..e5478c0870 100644 --- a/packages/task/src/Task/andRun.spec.ts +++ b/packages/task/src/Task/andRun.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; -import { allSyncCombination } from './_stub.spec.js'; +import { describe, expect, it, vi } from 'vitest'; + import { FakeTask, withTask } from '../Testing.js'; +import { allSyncCombination } from './_stub.spec.js'; import { andRun } from './andRun.js'; -import { run } from './run.js'; import { from } from './from.js'; +import { run } from './run.js'; describe(andRun, () => { const anyValue = Object.freeze({ foo: true }); diff --git a/packages/task/src/Task/andRun.ts b/packages/task/src/Task/andRun.ts index 7eefa1a61b..68a1a845b1 100644 --- a/packages/task/src/Task/andRun.ts +++ b/packages/task/src/Task/andRun.ts @@ -1,4 +1,5 @@ import type { Task, TaskLike } from '../Task.js'; + import { andThen } from './andThen.js'; import { map } from './map.js'; diff --git a/packages/task/src/Task/andThen.spec.ts b/packages/task/src/Task/andThen.spec.ts index bf5eada91d..1435da1635 100644 --- a/packages/task/src/Task/andThen.spec.ts +++ b/packages/task/src/Task/andThen.spec.ts @@ -1,13 +1,14 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; -import { allSyncCombination } from './_stub.spec.js'; -import { FakeTask, withTask } from '../Testing.js'; -import { andThen } from './andThen.js'; +import { describe, expect, it, vi } from 'vitest'; + import { taskRun } from '../internal/taskRun.js'; import { TaskCanceler } from '../TaskCanceler.js'; +import { FakeTask, withTask } from '../Testing.js'; +import { allSyncCombination } from './_stub.spec.js'; +import { andThen } from './andThen.js'; describe(andThen, () => { - // eslint-disable-next-line ts/no-unused-vars + // eslint-disable-next-line unused-imports/no-unused-vars const anyError = Object.freeze({ message: 'error message' }); const anyValue = Object.freeze({ foo: true }); const expectTask = withTask(expect); @@ -46,14 +47,14 @@ describe(andThen, () => { const result = taskRun(thenTask, canceler); await result; expect(task[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); expect(afterTask[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); }); }); diff --git a/packages/task/src/Task/andThen.ts b/packages/task/src/Task/andThen.ts index 759aa3affd..18bce9b5f7 100644 --- a/packages/task/src/Task/andThen.ts +++ b/packages/task/src/Task/andThen.ts @@ -1,4 +1,5 @@ import type { Task, TaskLike } from '../Task.js'; + import { from } from './from.js'; import { unsafeCall } from './unsafeCall.js'; @@ -23,9 +24,9 @@ export function andThen( ): Task { return from((parameters) => unsafeCall(self, { - resolve: (value) => unsafeCall(fn(value), parameters), - reject: parameters.reject, canceler: parameters.canceler, + reject: parameters.reject, + resolve: (value) => unsafeCall(fn(value), parameters), }), ); } diff --git a/packages/task/src/Task/any.spec.ts b/packages/task/src/Task/any.spec.ts index 6c03f86272..27e9a89b1f 100644 --- a/packages/task/src/Task/any.spec.ts +++ b/packages/task/src/Task/any.spec.ts @@ -1,10 +1,12 @@ /* eslint-disable unicorn/prefer-array-from-map */ -import { describe, it, expect, vi } from 'vitest'; -import { AggregateError } from '@w5s/error'; import { assertType } from '@w5s/core-type'; -import { any } from './any.js'; -import { FakeTask, withTask } from '../Testing.js'; +import { AggregateError } from '@w5s/error'; +import { describe, expect, it, vi } from 'vitest'; + import type { Task } from '../Task.js'; + +import { FakeTask, withTask } from '../Testing.js'; +import { any } from './any.js'; import { run } from './run.js'; describe(any, () => { @@ -29,11 +31,11 @@ describe(any, () => { const taskData = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { + canceler, task: taskIndex === 0 - ? FakeTask({ delayMs: 1, value: `value${taskIndex}`, canceler }) - : FakeTask({ delayMs: 100, error: `error${taskIndex}`, canceler }), - canceler, + ? FakeTask({ canceler, delayMs: 1, value: `value${taskIndex}` }) + : FakeTask({ canceler, delayMs: 100, error: `error${taskIndex}` }), }; }); const anyTask = any(taskData.map((_) => _.task)); @@ -49,8 +51,8 @@ describe(any, () => { const taskData = Array.from({ length: taskCount }).map((_, taskIndex) => { const canceler = vi.fn(); return { - task: FakeTask({ delayMs: 2, value: `value${taskIndex}`, canceler }), canceler, + task: FakeTask({ canceler, delayMs: 2, value: `value${taskIndex}` }), }; }); diff --git a/packages/task/src/Task/any.ts b/packages/task/src/Task/any.ts index 44281945b0..6e38a736cc 100644 --- a/packages/task/src/Task/any.ts +++ b/packages/task/src/Task/any.ts @@ -1,5 +1,7 @@ import type { AggregateError } from '@w5s/error'; + import type { Task, TaskLike } from '../Task.js'; + import { from } from './from.js'; import { TaskAggregateState } from './TaskAggregateState.js'; @@ -22,16 +24,16 @@ import { TaskAggregateState } from './TaskAggregateState.js'; * ``` * @param tasks tasks to be run in parallel */ -export function any[]>( +export function any>>( tasks: [...T], ): Task, AggregateError<{ [K in keyof T]: Task.ErrorOf }>>; -export function any(tasks: Iterable>): Task>; -export function any(tasks: Iterable>): Task> { +export function any(tasks: Iterable>): Task>>; +export function any(tasks: Iterable>): Task>> { return from((parameters) => { - const taskArray = Array.from(tasks, (task, key) => ({ task, key })); + const taskArray = Array.from(tasks, (task, key) => ({ key, task })); if (taskArray.length === 0) { - parameters.reject(globalThis.AggregateError([]) as AggregateError); + parameters.reject(globalThis.AggregateError([]) as AggregateError>); } else { // eslint-disable-next-line unicorn/no-new-array const errors = new Array(taskArray.length); @@ -44,7 +46,7 @@ export function any(tasks: Iterable>): Task (error, entry, self) => { errors[entry.key] = error; if (self.isComplete()) { - self.reject(globalThis.AggregateError(errors) as AggregateError); + self.reject(globalThis.AggregateError(errors) as AggregateError>); } }, ); diff --git a/packages/task/src/Task/create.spec.ts b/packages/task/src/Task/create.spec.ts index 5ba9cb7e06..610fb13cf6 100644 --- a/packages/task/src/Task/create.spec.ts +++ b/packages/task/src/Task/create.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; +import { describe, expect, it, vi } from 'vitest'; + +import { TaskCanceler } from '../TaskCanceler.js'; import { create } from './create.js'; -import { ok } from './ok.js'; import { error } from './error.js'; -import { TaskCanceler } from '../TaskCanceler.js'; +import { ok } from './ok.js'; vi.mock('./run.js', async () => ({ run: vi.fn(), @@ -18,7 +19,7 @@ describe(create, () => { const resolve = vi.fn(); const reject = vi.fn(); - task[Symbol.run]({ resolve, reject, canceler: anyCanceler }); + task[Symbol.run]({ canceler: anyCanceler, reject, resolve }); expect(resolve).toHaveBeenCalledTimes(1); expect(resolve).toHaveBeenCalledWith('foo'); }); @@ -27,7 +28,7 @@ describe(create, () => { const resolve = vi.fn(); const reject = vi.fn(); - task[Symbol.run]({ resolve, reject, canceler: anyCanceler }); + task[Symbol.run]({ canceler: anyCanceler, reject, resolve }); expect(resolve).toHaveBeenCalledTimes(1); expect(resolve).toHaveBeenCalledWith(undefined); }); @@ -36,7 +37,7 @@ describe(create, () => { const resolve = vi.fn(); const reject = vi.fn(); - task[Symbol.run]({ resolve, reject, canceler: anyCanceler }); + task[Symbol.run]({ canceler: anyCanceler, reject, resolve }); expect(reject).toHaveBeenCalledTimes(1); expect(reject).toHaveBeenCalledWith('err'); }); @@ -47,7 +48,7 @@ describe(create, () => { const resolve = vi.fn(); const reject = vi.fn(); - await task[Symbol.run]({ resolve, reject, canceler: anyCanceler }); + await task[Symbol.run]({ canceler: anyCanceler, reject, resolve }); expect(resolve).toHaveBeenCalledTimes(1); expect(resolve).toHaveBeenCalledWith('value'); }); @@ -56,7 +57,7 @@ describe(create, () => { const resolve = vi.fn(); const reject = vi.fn(); - await task[Symbol.run]({ resolve, reject, canceler: anyCanceler }); + await task[Symbol.run]({ canceler: anyCanceler, reject, resolve }); expect(resolve).toHaveBeenCalledTimes(1); expect(resolve).toHaveBeenCalledWith(undefined); }); @@ -70,9 +71,9 @@ describe(create, () => { }); task[Symbol.run]({ - resolve: () => {}, - reject: () => {}, canceler: someCanceler, + reject: () => {}, + resolve: () => {}, }); expect(innerCanceler).toBe(someCanceler); }); diff --git a/packages/task/src/Task/create.ts b/packages/task/src/Task/create.ts index 97fdcb7ed7..969977ec45 100644 --- a/packages/task/src/Task/create.ts +++ b/packages/task/src/Task/create.ts @@ -1,10 +1,13 @@ import type { Awaitable } from '@w5s/async'; -import { tryCall } from '@w5s/async/dist/tryCall.js'; import type { Result } from '@w5s/core/dist/Result.js'; + +import { tryCall } from '@w5s/async/dist/tryCall.js'; + import type { Task, TaskLike } from '../Task.js'; import type { TaskCanceler } from '../TaskCanceler.js'; -import { from } from './from.js'; + import { taskRun } from '../internal/taskRun.js'; +import { from } from './from.js'; /** * Task constructor @@ -31,7 +34,7 @@ export function create( run: (task: TaskLike) => Awaitable>; }) => Awaitable>, ): Task { - return from(({ resolve, reject, canceler }) => { + return from(({ canceler, reject, resolve }) => { canceler.onCancel = undefined; return tryCall( () => diff --git a/packages/task/src/Task/error.spec.ts b/packages/task/src/Task/error.spec.ts index b0fccd1171..11e721081e 100644 --- a/packages/task/src/Task/error.spec.ts +++ b/packages/task/src/Task/error.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { error } from './error.js'; describe(error, () => { diff --git a/packages/task/src/Task/from.spec.ts b/packages/task/src/Task/from.spec.ts index 6898e7238d..48280dc907 100644 --- a/packages/task/src/Task/from.spec.ts +++ b/packages/task/src/Task/from.spec.ts @@ -1,6 +1,7 @@ -import { describe, expect, it } from 'vitest'; -import { Result } from '@w5s/core/dist/Result.js'; import { Symbol } from '@w5s/core'; +import { Result } from '@w5s/core/dist/Result.js'; +import { describe, expect, it } from 'vitest'; + import { from } from './from.js'; import { run } from './run.js'; diff --git a/packages/task/src/Task/from.ts b/packages/task/src/Task/from.ts index c7271545ca..462f289b62 100644 --- a/packages/task/src/Task/from.ts +++ b/packages/task/src/Task/from.ts @@ -1,5 +1,7 @@ import { Symbol } from '@w5s/core/dist/Symbol.js'; + import type { TaskFunction, TaskLike } from '../Task.js'; + import { Task } from './Task.js'; /** @@ -12,7 +14,7 @@ import { Task } from './Task.js'; * ``` * @param taskLike */ -export function from(taskLike: TaskLike | TaskFunction): Task { +export function from(taskLike: TaskFunction | TaskLike): Task { return taskLike instanceof Task ? taskLike : new Task(typeof taskLike === 'function' ? taskLike : taskLike[Symbol.run]); diff --git a/packages/task/src/Task/hasInstance.spec.ts b/packages/task/src/Task/hasInstance.spec.ts index 002f307f2c..7278245af4 100644 --- a/packages/task/src/Task/hasInstance.spec.ts +++ b/packages/task/src/Task/hasInstance.spec.ts @@ -1,8 +1,10 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; +import { describe, expect, it } from 'vitest'; + +import type { TaskLike } from '../Task.js'; + import { hasInstance } from './hasInstance.js'; import { resolve } from './resolve.js'; -import type { TaskLike } from '../Task.js'; describe(hasInstance, () => { const anyValue = 'anyValue'; diff --git a/packages/task/src/Task/hasInstance.ts b/packages/task/src/Task/hasInstance.ts index 5331aed830..0a4d2d0389 100644 --- a/packages/task/src/Task/hasInstance.ts +++ b/packages/task/src/Task/hasInstance.ts @@ -1,4 +1,5 @@ import { Symbol } from '@w5s/core/dist/Symbol.js'; + import type { TaskLike } from '../Task.js'; /** diff --git a/packages/task/src/Task/ignore.spec.ts b/packages/task/src/Task/ignore.spec.ts index eaf595c4ce..c65c0ad911 100644 --- a/packages/task/src/Task/ignore.spec.ts +++ b/packages/task/src/Task/ignore.spec.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; -import { ignore } from './ignore.js'; +import { describe, expect, it } from 'vitest'; + import { withTask } from '../Testing.js'; +import { ignore } from './ignore.js'; import { resolve } from './resolve.js'; describe(ignore, () => { diff --git a/packages/task/src/Task/ignore.ts b/packages/task/src/Task/ignore.ts index 1a3d866b49..212dd495ee 100644 --- a/packages/task/src/Task/ignore.ts +++ b/packages/task/src/Task/ignore.ts @@ -1,7 +1,6 @@ import type { Task } from '../Task.js'; -import { map } from './map.js'; -function ignoreValue(_anyValue: unknown): void {} +import { map } from './map.js'; /** * Ignores value of task @@ -16,3 +15,5 @@ function ignoreValue(_anyValue: unknown): void {} export function ignore(self: Task): Task { return map(self, ignoreValue); } + +function ignoreValue(_anyValue: unknown): void {} diff --git a/packages/task/src/Task/map.spec.ts b/packages/task/src/Task/map.spec.ts index 4da6c07fd4..558f722fd2 100644 --- a/packages/task/src/Task/map.spec.ts +++ b/packages/task/src/Task/map.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; -import { FakeTask, withTask } from '../Testing.js'; -import { map } from './map.js'; +import { describe, expect, it, vi } from 'vitest'; + import { taskRun } from '../internal/taskRun.js'; import { TaskCanceler } from '../TaskCanceler.js'; +import { FakeTask, withTask } from '../Testing.js'; +import { map } from './map.js'; describe(map, () => { const anyError = 'anyError'; @@ -39,9 +40,9 @@ describe(map, () => { const canceler = new TaskCanceler(); const result = taskRun(mapTask, canceler); expect(task[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); await result; }); diff --git a/packages/task/src/Task/map.ts b/packages/task/src/Task/map.ts index bd23530a69..12b6df9801 100644 --- a/packages/task/src/Task/map.ts +++ b/packages/task/src/Task/map.ts @@ -1,4 +1,5 @@ import type { Task, TaskLike } from '../Task.js'; + import { from } from './from.js'; import { unsafeCall } from './unsafeCall.js'; @@ -18,7 +19,7 @@ export function map( self: TaskLike, fn: (value: ValueFrom) => ValueTo, ): Task { - return from(({ resolve, reject, canceler }) => - unsafeCall(self, { resolve: (value) => resolve(fn(value)), reject, canceler }), + return from(({ canceler, reject, resolve }) => + unsafeCall(self, { canceler, reject, resolve: (value) => resolve(fn(value)) }), ); } diff --git a/packages/task/src/Task/mapError.spec.ts b/packages/task/src/Task/mapError.spec.ts index 29d47ea354..c99caf449f 100644 --- a/packages/task/src/Task/mapError.spec.ts +++ b/packages/task/src/Task/mapError.spec.ts @@ -1,9 +1,10 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; -import { mapError } from './mapError.js'; -import { FakeTask, withTask } from '../Testing.js'; +import { describe, expect, it, vi } from 'vitest'; + import { taskRun } from '../internal/taskRun.js'; import { TaskCanceler } from '../TaskCanceler.js'; +import { FakeTask, withTask } from '../Testing.js'; +import { mapError } from './mapError.js'; describe(mapError, () => { const anyError = Object.freeze({ message: 'error message' }); @@ -42,9 +43,9 @@ describe(mapError, () => { const result = taskRun(mapTask, canceler); expect(task[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); await result; }); diff --git a/packages/task/src/Task/mapError.ts b/packages/task/src/Task/mapError.ts index d352ec8977..30a99f4721 100644 --- a/packages/task/src/Task/mapError.ts +++ b/packages/task/src/Task/mapError.ts @@ -1,4 +1,5 @@ import type { Task, TaskLike } from '../Task.js'; + import { from } from './from.js'; import { unsafeCall } from './unsafeCall.js'; @@ -18,7 +19,7 @@ export function mapError( self: TaskLike, fn: (error: ErrorFrom) => ErrorTo, ): Task { - return from(({ reject, resolve, canceler }) => - unsafeCall(self, { reject: (error) => reject(fn(error)), resolve, canceler }), + return from(({ canceler, reject, resolve }) => + unsafeCall(self, { canceler, reject: (error) => reject(fn(error)), resolve }), ); } diff --git a/packages/task/src/Task/mapResult.spec.ts b/packages/task/src/Task/mapResult.spec.ts index b1a851987b..94714b6da5 100644 --- a/packages/task/src/Task/mapResult.spec.ts +++ b/packages/task/src/Task/mapResult.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { FakeTask, withTask } from '../Testing.js'; import { mapResult } from './mapResult.js'; diff --git a/packages/task/src/Task/mapResult.ts b/packages/task/src/Task/mapResult.ts index b27c365501..ae69d2974b 100644 --- a/packages/task/src/Task/mapResult.ts +++ b/packages/task/src/Task/mapResult.ts @@ -1,11 +1,13 @@ import type { Result } from '@w5s/core'; -import { error } from './error.js'; -import { ok } from './ok.js'; + import type { Task, TaskLike, TaskParameters } from '../Task.js'; + +import { error } from './error.js'; import { from } from './from.js'; +import { ok } from './ok.js'; import { unsafeCall } from './unsafeCall.js'; -const complete = ({ resolve, reject }: TaskParameters, result: Result) => +const complete = ({ reject, resolve }: TaskParameters, result: Result) => result.ok ? resolve(result.value) : reject(result.error); /** @@ -27,9 +29,9 @@ export function mapResult( ): Task { return from((parameters) => unsafeCall(self, { + canceler: parameters.canceler, reject: (error_) => complete(parameters, mapFn(error(error_))), resolve: (value) => complete(parameters, mapFn(ok(value))), - canceler: parameters.canceler, }), ); } diff --git a/packages/task/src/Task/ok.spec.ts b/packages/task/src/Task/ok.spec.ts index 638b14d557..e562bf6f09 100644 --- a/packages/task/src/Task/ok.spec.ts +++ b/packages/task/src/Task/ok.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, expect } from 'vitest'; import { Result } from '@w5s/core'; +import { describe, expect, it } from 'vitest'; + import { ok } from './ok.js'; describe(ok, () => { diff --git a/packages/task/src/Task/orElse.spec.ts b/packages/task/src/Task/orElse.spec.ts index 639dc24850..54eafa107e 100644 --- a/packages/task/src/Task/orElse.spec.ts +++ b/packages/task/src/Task/orElse.spec.ts @@ -1,10 +1,11 @@ -import { describe, it, expect, vi } from 'vitest'; import { Symbol } from '@w5s/core'; -import { allSyncCombination } from './_stub.spec.js'; -import { FakeTask, withTask } from '../Testing.js'; -import { orElse } from './orElse.js'; +import { describe, expect, it, vi } from 'vitest'; + import { taskRun } from '../internal/taskRun.js'; import { TaskCanceler } from '../TaskCanceler.js'; +import { FakeTask, withTask } from '../Testing.js'; +import { allSyncCombination } from './_stub.spec.js'; +import { orElse } from './orElse.js'; describe(orElse, () => { const anyError = Object.freeze({ message: 'error message' }); @@ -49,14 +50,14 @@ describe(orElse, () => { await result; expect(task[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); expect(afterTask[Symbol.run]).toHaveBeenCalledWith({ - resolve: expect.any(Function), - reject: expect.any(Function), canceler, + reject: expect.any(Function), + resolve: expect.any(Function), }); }); }); diff --git a/packages/task/src/Task/orElse.ts b/packages/task/src/Task/orElse.ts index 86b71994cf..30c5798411 100644 --- a/packages/task/src/Task/orElse.ts +++ b/packages/task/src/Task/orElse.ts @@ -1,4 +1,5 @@ import type { Task, TaskLike } from '../Task.js'; + import { from } from './from.js'; import { unsafeCall } from './unsafeCall.js'; @@ -23,9 +24,9 @@ export function orElse( ): Task { return from((parameters) => unsafeCall(self, { + canceler: parameters.canceler, reject: (error) => unsafeCall(fn(error), parameters), resolve: parameters.resolve, - canceler: parameters.canceler, }), ); } diff --git a/packages/task/src/Task/reject.spec.ts b/packages/task/src/Task/reject.spec.ts index 879a9ef5b6..1fcd6db975 100644 --- a/packages/task/src/Task/reject.spec.ts +++ b/packages/task/src/Task/reject.spec.ts @@ -1,9 +1,11 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { reject } from './reject.js'; -import { withTask } from '../Testing.js'; +import { describe, expect, it } from 'vitest'; + import type { Task } from '../Task.js'; +import { withTask } from '../Testing.js'; +import { reject } from './reject.js'; + describe(reject, () => { const anyError = 'anyError'; const expectTask = withTask(expect); diff --git a/packages/task/src/Task/reject.ts b/packages/task/src/Task/reject.ts index 38357ef82e..6d7d3eea97 100644 --- a/packages/task/src/Task/reject.ts +++ b/packages/task/src/Task/reject.ts @@ -1,4 +1,5 @@ import type { Task } from '../Task.js'; + import { from } from './from.js'; /** @@ -12,7 +13,6 @@ import { from } from './from.js'; * @category Constructor */ export function reject(): Task; - /** * Constructor that always returns a failed `Task` that rejects `errorValue`. * This is a shorthand for `Task(({ error }) => error(errorValue))` diff --git a/packages/task/src/Task/resolve.spec.ts b/packages/task/src/Task/resolve.spec.ts index 9a2b436b6b..233a539305 100644 --- a/packages/task/src/Task/resolve.spec.ts +++ b/packages/task/src/Task/resolve.spec.ts @@ -1,9 +1,11 @@ -import { describe, it, expect } from 'vitest'; import { assertType } from '@w5s/core-type'; -import { resolve } from './resolve.js'; -import { withTask } from '../Testing.js'; +import { describe, expect, it } from 'vitest'; + import type { Task } from '../Task.js'; +import { withTask } from '../Testing.js'; +import { resolve } from './resolve.js'; + describe(resolve, () => { const anyValue = 'anyValue'; const expectTask = withTask(expect); diff --git a/packages/task/src/Task/resolve.ts b/packages/task/src/Task/resolve.ts index 7d84eb1508..afc3703455 100644 --- a/packages/task/src/Task/resolve.ts +++ b/packages/task/src/Task/resolve.ts @@ -1,4 +1,5 @@ import type { Task } from '../Task.js'; + import { from } from './from.js'; /** @@ -12,7 +13,6 @@ import { from } from './from.js'; * @category Constructor */ export function resolve(): Task; - /** * Returns a successful task that always resolves `value`. * This is a shorthand for `Task.from(({ resolve }) => resolve(value))` diff --git a/packages/task/src/Task/run.spec.ts b/packages/task/src/Task/run.spec.ts index f74e59a21c..d1685ae958 100644 --- a/packages/task/src/Task/run.spec.ts +++ b/packages/task/src/Task/run.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it, vi } from 'vitest'; import { Result, Symbol } from '@w5s/core'; -import { run } from './run.js'; +import { describe, expect, it, vi } from 'vitest'; + import { Task, type TaskLike } from '../Task.js'; +import { run } from './run.js'; const anyError = new Error('TestError'); const anyObject = Object.freeze({ foo: true }); diff --git a/packages/task/src/Task/run.ts b/packages/task/src/Task/run.ts index 512dd076df..6b4e667a51 100644 --- a/packages/task/src/Task/run.ts +++ b/packages/task/src/Task/run.ts @@ -1,8 +1,10 @@ import type { Awaitable } from '@w5s/async'; import type { Result } from '@w5s/core'; + import type { TaskLike, TaskRunOptions } from '../Task.js'; -import { TaskCanceler } from '../TaskCanceler.js'; + import { taskRun } from '../internal/taskRun.js'; +import { TaskCanceler } from '../TaskCanceler.js'; /** * Run `task` and return the result or a promise of the result diff --git a/packages/task/src/Task/tryCall.spec.ts b/packages/task/src/Task/tryCall.spec.ts index fac43e29a1..35e6243faf 100644 --- a/packages/task/src/Task/tryCall.spec.ts +++ b/packages/task/src/Task/tryCall.spec.ts @@ -1,14 +1,15 @@ -import { describe, it, expect, vi } from 'vitest'; -import { tryCall } from './tryCall.js'; +import { describe, expect, it, vi } from 'vitest'; + import { withTask } from '../Testing.js'; +import { tryCall } from './tryCall.js'; describe(tryCall, () => { const expectTask = withTask(expect); const anyValue = 'return_value'; class TestError extends Error { - override name = 'TestError'; public innerError: unknown; + override name = 'TestError'; constructor(innerError: unknown = undefined) { super('TestMessage'); diff --git a/packages/task/src/Task/tryCall.ts b/packages/task/src/Task/tryCall.ts index 9a40f42a5e..146effcc5d 100644 --- a/packages/task/src/Task/tryCall.ts +++ b/packages/task/src/Task/tryCall.ts @@ -1,9 +1,12 @@ import type { Awaitable } from '@w5s/async'; -import { tryCall as asyncTryCall } from '@w5s/async/dist/tryCall.js'; + import { isPromiseLike } from '@w5s/async/dist/isPromiseLike.js'; -import { from } from './from.js'; +import { tryCall as asyncTryCall } from '@w5s/async/dist/tryCall.js'; + import type { Task } from '../Task.js'; +import { from } from './from.js'; + /** * Creates a new `Task` that resolves `sideEffect()`. * When an exception is thrown then it rejects `onError([thrown error])`. @@ -25,7 +28,7 @@ export function tryCall( sideEffect: () => Awaitable, onError?: (error: unknown) => Awaitable, ): Task { - return from(({ resolve, reject }) => + return from(({ reject, resolve }) => asyncTryCall( sideEffect, resolve, diff --git a/packages/task/src/Task/unsafeCall.ts b/packages/task/src/Task/unsafeCall.ts index 234ead6ff1..cc1f42e270 100644 --- a/packages/task/src/Task/unsafeCall.ts +++ b/packages/task/src/Task/unsafeCall.ts @@ -1,5 +1,7 @@ import type { Awaitable } from '@w5s/async'; + import { Symbol } from '@w5s/core/dist/Symbol.js'; + import type { TaskLike, TaskParameters } from '../Task.js'; /** diff --git a/packages/task/src/Testing.spec.ts b/packages/task/src/Testing.spec.ts index 899b2d58d9..47c6ec974a 100644 --- a/packages/task/src/Testing.spec.ts +++ b/packages/task/src/Testing.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Module from './Testing.js'; describe('index', () => { diff --git a/packages/task/src/Testing/FakeTask.spec.ts b/packages/task/src/Testing/FakeTask.spec.ts index ea6059bc60..87f07de44c 100644 --- a/packages/task/src/Testing/FakeTask.spec.ts +++ b/packages/task/src/Testing/FakeTask.spec.ts @@ -1,7 +1,8 @@ -import { describe, expect, it } from 'vitest'; import { Result } from '@w5s/core'; -import { FakeTask } from './FakeTask.js'; +import { describe, expect, it } from 'vitest'; + import { run } from '../Task/run.js'; +import { FakeTask } from './FakeTask.js'; describe(FakeTask, () => { it('should resolve value', () => { diff --git a/packages/task/src/Testing/FakeTask.ts b/packages/task/src/Testing/FakeTask.ts index cb1ffe956f..c797dbf652 100644 --- a/packages/task/src/Testing/FakeTask.ts +++ b/packages/task/src/Testing/FakeTask.ts @@ -1,23 +1,11 @@ import type { Option } from '@w5s/core'; + import type { Task } from '../Task.js'; import type { TaskCanceler } from '../TaskCanceler.js'; + import { from } from '../Task/from.js'; import { unsafeCall } from '../Task/unsafeCall.js'; -function delay(milliseconds: number, canceler: TaskCanceler): Promise { - return milliseconds === 0 - ? Promise.resolve(true) - : new Promise((resolve) => { - const timerId = setTimeout(resolve, milliseconds, true); - const cancelerCurrent = canceler.onCancel; - canceler.onCancel = () => { - clearTimeout(timerId); - cancelerCurrent?.(); - resolve(true); - }; - }); -} - /** * Options to create a TaskStub */ @@ -32,12 +20,6 @@ export type FakeTaskOptions = { */ delayMs?: Option; } & ( - | { - /** - * The value to resolve - */ - value: Value; - } | { /** * The error to reject @@ -50,6 +32,12 @@ export type FakeTaskOptions = { */ throwError: unknown; } + | { + /** + * The value to resolve + */ + value: Value; + } ); /** @@ -72,7 +60,7 @@ export type FakeTaskOptions = { export function FakeTask(options: FakeTaskOptions): Task { const { canceler = () => {}, delayMs } = options; const isAsync = delayMs != null && delayMs >= 0; - const base = from(({ resolve, reject }) => { + const base = from(({ reject, resolve }) => { if ('value' in options) { resolve(options.value); } else if ('error' in options) { @@ -92,3 +80,17 @@ export function FakeTask(options: FakeTaskOptions< }) : base; } + +function delay(milliseconds: number, canceler: TaskCanceler): Promise { + return milliseconds === 0 + ? Promise.resolve(true) + : new Promise((resolve) => { + const timerId = setTimeout(resolve, milliseconds, true); + const cancelerCurrent = canceler.onCancel; + canceler.onCancel = () => { + clearTimeout(timerId); + cancelerCurrent?.(); + resolve(true); + }; + }); +} diff --git a/packages/task/src/Testing/withTask.ts b/packages/task/src/Testing/withTask.ts index 537513dd60..2397671ce3 100644 --- a/packages/task/src/Testing/withTask.ts +++ b/packages/task/src/Testing/withTask.ts @@ -1,51 +1,53 @@ import type { ExpectFunction } from '@w5s/core-type'; + +import type { TaskLike } from '../Task.js'; + import { error as Error } from '../Task/error.js'; import { ok } from '../Task/ok.js'; -import type { TaskLike } from '../Task.js'; import { run } from '../Task/run.js'; export interface ExpectTask { /** - * Asserts that task resolve value asynchronously or synchronously + * Asserts that task rejects value asynchronously or synchronously * * @param value */ - toResolve(value: unknown): Promise; + toReject(value: unknown): Promise; /** - * Asserts that task resolve value asynchronously + * Asserts that task rejects value asynchronously * - * @param value + * @param error */ - toResolveAsync(value: unknown): Promise; + toRejectAsync(error: unknown): Promise; /** - * Asserts that task resolve value synchronously + * Asserts that task rejects value synchronously * - * @param value + * @param error */ - toResolveSync(value: unknown): void; + toRejectSync(error: unknown): void; /** - * Asserts that task rejects value asynchronously or synchronously + * Asserts that task resolve value asynchronously or synchronously * * @param value */ - toReject(value: unknown): Promise; + toResolve(value: unknown): Promise; /** - * Asserts that task rejects value asynchronously + * Asserts that task resolve value asynchronously * - * @param error + * @param value */ - toRejectAsync(error: unknown): Promise; + toResolveAsync(value: unknown): Promise; /** - * Asserts that task rejects value synchronously + * Asserts that task resolve value synchronously * - * @param error + * @param value */ - toRejectSync(error: unknown): void; + toResolveSync(value: unknown): void; /** * Asserts that task throws an error asynchronously or synchronously @@ -83,41 +85,41 @@ export interface ExpectTask { */ export function withTask(expectFn: ExpectFunction) { const create = (task: TaskLike, isNot: boolean): ExpectTask => ({ - async toResolve(value: V) { + async toReject(error_: E) { const getResult = async () => run(task); const expectValue = expectFn(getResult()).resolves; - await (isNot ? expectValue.not : expectValue).toEqual(ok(value)); + await (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); }, - async toResolveAsync(value: V) { + async toRejectAsync(error_: E) { const result = run(task); - const expectValue = expectFn(result).resolves; + const expectValue = expectFn(result).resolves; // The promise should be resolved with a Result.Error() - await (isNot ? expectValue.not : expectValue).toEqual(ok(value)); + await (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); }, - toResolveSync(value: V) { + toRejectSync(error_: E) { const result = run(task); const expectValue = expectFn(result); - (isNot ? expectValue.not : expectValue).toEqual(ok(value)); + (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); }, - async toReject(error_: E) { + async toResolve(value: V) { const getResult = async () => run(task); const expectValue = expectFn(getResult()).resolves; - await (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); + await (isNot ? expectValue.not : expectValue).toEqual(ok(value)); }, - async toRejectAsync(error_: E) { + async toResolveAsync(value: V) { const result = run(task); - const expectValue = expectFn(result).resolves; // The promise should be resolved with a Result.Error() + const expectValue = expectFn(result).resolves; - await (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); + await (isNot ? expectValue.not : expectValue).toEqual(ok(value)); }, - toRejectSync(error_: E) { + toResolveSync(value: V) { const result = run(task); const expectValue = expectFn(result); - (isNot ? expectValue.not : expectValue).toEqual(Error(error_)); + (isNot ? expectValue.not : expectValue).toEqual(ok(value)); }, async toThrow(error_: unknown) { const getResult = async () => run(task); @@ -125,15 +127,15 @@ export function withTask(expectFn: ExpectFunction) { await (isNot ? expectValue.not : expectValue).toEqual(error_); }, - toThrowSync(error_: unknown) { - const expectValue = expectFn(() => run(task)); - (isNot ? expectValue.not : expectValue).toThrow(error_); - }, async toThrowAsync(error_: unknown) { const expectValue = expectFn(run(task)).rejects; await (isNot ? expectValue.not : expectValue).toEqual(error_); }, + toThrowSync(error_: unknown) { + const expectValue = expectFn(() => run(task)); + (isNot ? expectValue.not : expectValue).toThrow(error_); + }, }); return (task: TaskLike) => diff --git a/packages/task/src/index.spec.ts b/packages/task/src/index.spec.ts index c7395a058d..a9df0f2355 100644 --- a/packages/task/src/index.spec.ts +++ b/packages/task/src/index.spec.ts @@ -1,4 +1,5 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import * as Std from './index.js'; describe('index', () => { diff --git a/packages/task/src/internal/taskRun.ts b/packages/task/src/internal/taskRun.ts index 31315b6f5d..a787eac0f1 100644 --- a/packages/task/src/internal/taskRun.ts +++ b/packages/task/src/internal/taskRun.ts @@ -1,10 +1,13 @@ import type { Awaitable } from '@w5s/async'; -import { isPromiseLike } from '@w5s/async/dist/isPromiseLike.js'; import type { Result } from '@w5s/core'; -import { error } from '../Task/error.js'; -import { ok } from '../Task/ok.js'; + +import { isPromiseLike } from '@w5s/async/dist/isPromiseLike.js'; + import type { TaskLike } from '../Task.js'; import type { TaskCanceler } from '../TaskCanceler.js'; + +import { error } from '../Task/error.js'; +import { ok } from '../Task/ok.js'; import { unsafeCall } from '../Task/unsafeCall.js'; /** @@ -32,9 +35,9 @@ export function taskRun( let rejectHandler = (_error: unknown) => {}; const runValue: Awaitable = unsafeCall(self, { - resolve: (_value) => resolveHandler(ok(_value)), - reject: (_error) => resolveHandler(error(_error)), canceler, + reject: (_error) => resolveHandler(error(_error)), + resolve: (_value) => resolveHandler(ok(_value)), }); // Try to catch promise errors if (isPromiseLike(runValue)) { @@ -47,7 +50,7 @@ export function taskRun( })(); } if (returnValue === undefined) { - const { promise, resolve, reject } = Promise.withResolvers>(); + const { promise, reject, resolve } = Promise.withResolvers>(); resolveHandler = resolve; rejectHandler = reject; return promise; diff --git a/packages/time/README.md b/packages/time/README.md index 6fb254a866..afed9ebcb3 100644 --- a/packages/time/README.md +++ b/packages/time/README.md @@ -18,8 +18,8 @@ npm install @w5s/time ```ts -import { Time, TimeDuration } from '@w5s/time'; import { Task } from '@w5s/task'; +import { Time, TimeDuration } from '@w5s/time'; export function nowPlusTwoMinutes() { return Task.map(Time.now(), (currentTime) => Time['+'](currentTime, TimeDuration({ minutes: 2 }))); diff --git a/packages/time/example/.eslintrc.cjs b/packages/time/example/.eslintrc.cjs index e4fd9328e3..c8b4d05302 100644 --- a/packages/time/example/.eslintrc.cjs +++ b/packages/time/example/.eslintrc.cjs @@ -3,7 +3,7 @@ module.exports = { project: require.resolve('./tsconfig.json'), }, rules: { - 'no-console': 'off', 'import/no-extraneous-dependencies': 'off', + 'no-console': 'off', }, }; diff --git a/packages/time/example/usage.ts b/packages/time/example/usage.ts index 395e2d076d..e0629ecd32 100644 --- a/packages/time/example/usage.ts +++ b/packages/time/example/usage.ts @@ -1,5 +1,5 @@ -import { Time, TimeDuration } from '@w5s/time'; import { Task } from '@w5s/task'; +import { Time, TimeDuration } from '@w5s/time'; export function nowPlusTwoMinutes() { return Task.map(Time.now(), (currentTime) => Time['+'](currentTime, TimeDuration({ minutes: 2 }))); diff --git a/packages/time/src/Time.spec.ts b/packages/time/src/Time.spec.ts index 4d1b929996..f10716b4ed 100644 --- a/packages/time/src/Time.spec.ts +++ b/packages/time/src/Time.spec.ts @@ -1,12 +1,13 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + import { Time } from './Time.js'; -import { TimeComparable } from './Time/TimeComparable.js'; import { delay } from './Time/delay.js'; -import { now } from './Time/now.js'; -import { parse } from './Time/parse.js'; import { format } from './Time/format.js'; import { from } from './Time/from.js'; +import { now } from './Time/now.js'; +import { parse } from './Time/parse.js'; import { TimeBounded } from './Time/TimeBounded.js'; +import { TimeComparable } from './Time/TimeComparable.js'; import { TimeNumeric } from './Time/TimeNumeric.js'; describe('Time', () => { @@ -17,10 +18,10 @@ describe('Time', () => { expect(Time).toEqual( expect.objectContaining({ delay, - now, - parse, format, from, + now, + parse, }), ); }); diff --git a/packages/time/src/Time.ts b/packages/time/src/Time.ts index d2e84fd388..623195c796 100644 --- a/packages/time/src/Time.ts +++ b/packages/time/src/Time.ts @@ -1,15 +1,16 @@ import { Callable } from '@w5s/core/dist/Callable.js'; -import { TimeDuration } from './TimeDuration/TimeDuration.js'; -import { Time as TimeType } from './Time/Time.js'; -import { of } from './Time/of.js'; -import { now } from './Time/now.js'; + import { delay } from './Time/delay.js'; -import { parse } from './Time/parse.js'; import { format } from './Time/format.js'; import { from } from './Time/from.js'; -import { TimeComparable } from './Time/TimeComparable.js'; +import { now } from './Time/now.js'; +import { of } from './Time/of.js'; +import { parse } from './Time/parse.js'; +import { Time as TimeType } from './Time/Time.js'; import { TimeBounded } from './Time/TimeBounded.js'; +import { TimeComparable } from './Time/TimeComparable.js'; import { TimeNumeric } from './Time/TimeNumeric.js'; +import { TimeDuration } from './TimeDuration/TimeDuration.js'; export type { TimeParameters } from './Time/from.js'; @@ -28,12 +29,8 @@ export const Time = Callable({ ...TimeComparable, ...TimeBounded, ...TimeNumeric, - of, - now, + [Callable.symbol]: from, delay, - parse, - format, - from, /** * Return the difference between 2 time values @@ -50,5 +47,10 @@ export const Time = Callable({ diff(left: Time, right: Time): TimeDuration { return TimeDuration(left - right); }, - [Callable.symbol]: from, + format, + from, + now, + + of, + parse, }); diff --git a/packages/time/src/Time/Time.spec.ts b/packages/time/src/Time/Time.spec.ts index 1194727a44..bbf1b1a60c 100644 --- a/packages/time/src/Time/Time.spec.ts +++ b/packages/time/src/Time/Time.spec.ts @@ -1,35 +1,36 @@ +import { CodecError, Result } from '@w5s/core'; import { describeCodec, describeType } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; -import { CodecError, Result } from '@w5s/core'; + import { Time } from './Time.js'; import { TimeBounded } from './TimeBounded.js'; describe('Time', () => { describeType(Time, () => ({ - typeName: 'Time', instances: [TimeBounded.minValue, Time(-1), Time(0), Time(1), TimeBounded.maxValue], notInstances: [null, undefined, [], NaN], + typeName: 'Time', })); describeCodec(Time, () => ({ - encode: [ - [Time(1), '1970-01-01T00:00:00.001Z'], - [Time(0), '1970-01-01T00:00:00.000Z'], - ], decode: [ ['1970-01-01T00:00:00.000Z', Result.Ok(Time(0))], [ null, Result.Error( new CodecError({ - message: 'Cannot decode null as Time', input: null, + message: 'Cannot decode null as Time', }), ), ], ], + encode: [ + [Time(1), '1970-01-01T00:00:00.001Z'], + [Time(0), '1970-01-01T00:00:00.000Z'], + ], schema: { - type: 'string', format: 'date-time', + type: 'string', }, })); }); diff --git a/packages/time/src/Time/Time.ts b/packages/time/src/Time/Time.ts index 9c12dedcf7..db155d68ab 100644 --- a/packages/time/src/Time/Time.ts +++ b/packages/time/src/Time/Time.ts @@ -1,5 +1,6 @@ -import { Tag } from '@w5s/core/dist/Tag.js'; import { Symbol } from '@w5s/core/dist/Symbol.js'; +import { Tag } from '@w5s/core/dist/Tag.js'; + import { parse } from './parse.js'; /** @@ -8,14 +9,14 @@ import { parse } from './parse.js'; export type Time = number & Tag<'Time'>; export const Time = Tag.define({ - typeName: 'Time', hasInstance(anyValue) { return typeof anyValue === 'number' && anyValue >= -8.64e15 && anyValue <= 8.64e15; }, - [Symbol.encode]: (input) => new Date(input).toISOString(), - [Symbol.decode]: (input, { ok, error }) => { + [Symbol.decode]: (input, { error, ok }) => { const timestamp = typeof input === 'string' ? parse(input) : undefined; return timestamp == null ? error(input, 'Time') : ok(timestamp); }, - [Symbol.schema]: () => ({ type: 'string', format: 'date-time' }), + [Symbol.encode]: (input) => new Date(input).toISOString(), + [Symbol.schema]: () => ({ format: 'date-time', type: 'string' }), + typeName: 'Time', }); diff --git a/packages/time/src/Time/TimeBounded.spec.ts b/packages/time/src/Time/TimeBounded.spec.ts index d80d50cfe8..7b6a1c2405 100644 --- a/packages/time/src/Time/TimeBounded.spec.ts +++ b/packages/time/src/Time/TimeBounded.spec.ts @@ -1,10 +1,11 @@ -import { describe } from 'vitest'; import { describeBounded } from '@w5s/core/dist/Testing.js'; +import { describe } from 'vitest'; + import { TimeBounded } from './TimeBounded.js'; describe('TimeBounded', () => { describeBounded(TimeBounded, { - minValue: -8.64e15, maxValue: 8.64e15, + minValue: -8.64e15, }); }); diff --git a/packages/time/src/Time/TimeBounded.ts b/packages/time/src/Time/TimeBounded.ts index d82c347416..3631c7c143 100644 --- a/packages/time/src/Time/TimeBounded.ts +++ b/packages/time/src/Time/TimeBounded.ts @@ -1,4 +1,5 @@ import type { Bounded } from '@w5s/core'; + import type { Time } from '../Time.js'; const bound = 8.64e15; diff --git a/packages/time/src/Time/TimeComparable.spec.ts b/packages/time/src/Time/TimeComparable.spec.ts index 1b6ee8940e..a8f76c2f28 100644 --- a/packages/time/src/Time/TimeComparable.spec.ts +++ b/packages/time/src/Time/TimeComparable.spec.ts @@ -1,15 +1,16 @@ import { describeComparable } from '@w5s/core/dist/Testing.js'; import { describe } from 'vitest'; + import { Time } from './Time.js'; import { TimeComparable } from './TimeComparable.js'; describe('TimeComparable', () => { describeComparable(TimeComparable, { - ordered: () => [Time(0), Time(1), Time(2)], equivalent: () => [ [Time(0), Time(0)], [Time(1), Time(1)], [Time(1.1), Time(1.1)], ], + ordered: () => [Time(0), Time(1), Time(2)], }); }); diff --git a/packages/time/src/Time/TimeComparable.ts b/packages/time/src/Time/TimeComparable.ts index 0ec773be13..4fbf5015d7 100644 --- a/packages/time/src/Time/TimeComparable.ts +++ b/packages/time/src/Time/TimeComparable.ts @@ -1,7 +1,9 @@ import { Comparable } from '@w5s/core/dist/Comparable.js'; -import { compare } from './compare.js'; + import type { Time } from './Time.js'; +import { compare } from './compare.js'; + export const TimeComparable = Comparable