Merge branch 'main' of github.com:Warky-Devs/artemis-kit

This commit is contained in:
2026-04-07 18:29:00 +02:00
14 changed files with 1498 additions and 4 deletions

View File

@@ -1,5 +1,29 @@
# @warkypublic/artemis-kit # @warkypublic/artemis-kit
## 1.0.10
### Patch Changes
- 4058dd3: Added object retrocycle and decycle
## 1.0.9
### Patch Changes
- 0439207: Added tryFromBaseN and tryToBaseN
## 1.0.8
### Patch Changes
- 67a17e5: Added toBaseN and fromBaseN with test cases
## 1.0.7
### Patch Changes
- 1bd493a: Fixed object.getNestedValue to handle null values
## 1.0.6 ## 1.0.6
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "@warkypublic/artemis-kit", "name": "@warkypublic/artemis-kit",
"version": "1.0.6", "version": "1.0.10",
"description": "A comprehensive TypeScript/JavaScript utility library focused on precision and efficiency.", "description": "A comprehensive TypeScript/JavaScript utility library focused on precision and efficiency.",
"type": "module", "type": "module",
"main": "./src/index.ts", "main": "./src/index.ts",
@@ -156,6 +156,7 @@
"typescript-eslint": "^8.17.0", "typescript-eslint": "^8.17.0",
"vite": "^6.0.2", "vite": "^6.0.2",
"vite-plugin-dts": "^4.3.0", "vite-plugin-dts": "^4.3.0",
"@anthropic-ai/claude-code": "^0.2.99",
"vitest": "^2.1.8" "vitest": "^2.1.8"
}, },
"engines": { "engines": {

344
pnpm-lock.yaml generated
View File

@@ -15,6 +15,9 @@ importers:
specifier: ^11.0.3 specifier: ^11.0.3
version: 11.0.3 version: 11.0.3
devDependencies: devDependencies:
'@anthropic-ai/claude-code':
specifier: ^0.2.99
version: 0.2.99
'@changesets/cli': '@changesets/cli':
specifier: ^2.27.10 specifier: ^2.27.10
version: 2.27.10 version: 2.27.10
@@ -51,6 +54,11 @@ importers:
packages: packages:
'@anthropic-ai/claude-code@0.2.99':
resolution: {integrity: sha512-KG+pFtiqSRmrSzcBRtgiPSqu9zaGg7GIlppKLEyDBlTn9M9JJbe1SLY5W8eB2AXC/fro+ePmM9cHzHO+zhkr7g==}
engines: {node: '>=18.0.0'}
hasBin: true
'@babel/helper-string-parser@7.25.9': '@babel/helper-string-parser@7.25.9':
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -463,6 +471,45 @@ packages:
resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
engines: {node: '>=18.18'} engines: {node: '>=18.18'}
'@img/sharp-darwin-arm64@0.33.5':
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [darwin]
'@img/sharp-libvips-darwin-arm64@1.0.4':
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
cpu: [arm64]
os: [darwin]
'@img/sharp-libvips-linux-arm@1.0.5':
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
cpu: [arm]
os: [linux]
'@img/sharp-libvips-linux-x64@1.0.4':
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
cpu: [x64]
os: [linux]
'@img/sharp-linux-arm@0.33.5':
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
'@img/sharp-linux-x64@0.33.5':
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
'@img/sharp-win32-x64@0.33.5':
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [win32]
'@jridgewell/sourcemap-codec@1.5.0': '@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
@@ -827,10 +874,22 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
better-path-resolve@1.0.0: better-path-resolve@1.0.0:
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
engines: {node: '>=4'} engines: {node: '>=4'}
better-sqlite3@11.9.1:
resolution: {integrity: sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==}
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
brace-expansion@1.1.11: brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@@ -841,6 +900,9 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
cac@6.7.14: cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -864,6 +926,9 @@ packages:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
ci-info@3.9.0: ci-info@3.9.0:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -918,10 +983,18 @@ packages:
decimal.js@10.4.3: decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
decompress-response@6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
deep-eql@5.0.2: deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
deep-is@0.1.4: deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -933,10 +1006,17 @@ packages:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'} engines: {node: '>=8'}
detect-libc@2.0.4:
resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
engines: {node: '>=8'}
dir-glob@3.0.1: dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'} engines: {node: '>=8'}
end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
enquirer@2.4.1: enquirer@2.4.1:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
@@ -1015,6 +1095,10 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
expect-type@1.1.0: expect-type@1.1.0:
resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@@ -1046,6 +1130,9 @@ packages:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
fill-range@7.1.1: fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1069,6 +1156,9 @@ packages:
resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
fs-extra@7.0.1: fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'} engines: {node: '>=6 <7 || >=8'}
@@ -1085,6 +1175,9 @@ packages:
function-bind@1.1.2: function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
glob-parent@5.1.2: glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -1146,6 +1239,9 @@ packages:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
ignore@5.3.2: ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
@@ -1162,6 +1258,12 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'} engines: {node: '>=0.8.19'}
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
is-core-module@2.15.1: is-core-module@2.15.1:
resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -1284,6 +1386,10 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
minimatch@3.0.8: minimatch@3.0.8:
resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==}
@@ -1294,6 +1400,12 @@ packages:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
mlly@1.7.3: mlly@1.7.3:
resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
@@ -1312,12 +1424,22 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
node-abi@3.75.0:
resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==}
engines: {node: '>=10'}
nwsapi@2.2.16: nwsapi@2.2.16:
resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
optionator@0.9.4: optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -1414,6 +1536,11 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
prebuild-install@7.1.3:
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
engines: {node: '>=10'}
hasBin: true
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -1423,6 +1550,9 @@ packages:
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
hasBin: true hasBin: true
pump@3.0.2:
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
punycode@2.3.1: punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -1430,10 +1560,18 @@ packages:
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
rc@1.2.8:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
read-yaml-file@1.1.0: read-yaml-file@1.1.0:
resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==}
engines: {node: '>=6'} engines: {node: '>=6'}
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
regenerator-runtime@0.14.1: regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
@@ -1468,6 +1606,9 @@ packages:
run-parallel@1.2.0: run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
safer-buffer@2.1.2: safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -1500,6 +1641,12 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'} engines: {node: '>=14'}
simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
slash@3.0.0: slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1528,6 +1675,9 @@ packages:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
engines: {node: '>=0.6.19'} engines: {node: '>=0.6.19'}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
strip-ansi@6.0.1: strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1536,6 +1686,10 @@ packages:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'} engines: {node: '>=4'}
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
strip-json-comments@3.1.1: strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1555,6 +1709,13 @@ packages:
symbol-tree@3.2.4: symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
tar-fs@2.1.2:
resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==}
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
term-size@2.2.1: term-size@2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1606,6 +1767,9 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=4.2.0' typescript: '>=4.2.0'
tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -1640,6 +1804,9 @@ packages:
uri-js@4.4.1: uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
uuid@11.0.3: uuid@11.0.3:
resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==}
hasBin: true hasBin: true
@@ -1792,6 +1959,9 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
ws@8.18.0: ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
@@ -1820,6 +1990,15 @@ packages:
snapshots: snapshots:
'@anthropic-ai/claude-code@0.2.99':
dependencies:
better-sqlite3: 11.9.1
optionalDependencies:
'@img/sharp-darwin-arm64': 0.33.5
'@img/sharp-linux-arm': 0.33.5
'@img/sharp-linux-x64': 0.33.5
'@img/sharp-win32-x64': 0.33.5
'@babel/helper-string-parser@7.25.9': {} '@babel/helper-string-parser@7.25.9': {}
'@babel/helper-validator-identifier@7.25.9': {} '@babel/helper-validator-identifier@7.25.9': {}
@@ -2172,6 +2351,33 @@ snapshots:
'@humanwhocodes/retry@0.4.1': {} '@humanwhocodes/retry@0.4.1': {}
'@img/sharp-darwin-arm64@0.33.5':
optionalDependencies:
'@img/sharp-libvips-darwin-arm64': 1.0.4
optional: true
'@img/sharp-libvips-darwin-arm64@1.0.4':
optional: true
'@img/sharp-libvips-linux-arm@1.0.5':
optional: true
'@img/sharp-libvips-linux-x64@1.0.4':
optional: true
'@img/sharp-linux-arm@0.33.5':
optionalDependencies:
'@img/sharp-libvips-linux-arm': 1.0.5
optional: true
'@img/sharp-linux-x64@0.33.5':
optionalDependencies:
'@img/sharp-libvips-linux-x64': 1.0.4
optional: true
'@img/sharp-win32-x64@0.33.5':
optional: true
'@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/sourcemap-codec@1.5.0': {}
'@manypkg/find-root@1.1.0': '@manypkg/find-root@1.1.0':
@@ -2571,10 +2777,27 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
base64-js@1.5.1: {}
better-path-resolve@1.0.0: better-path-resolve@1.0.0:
dependencies: dependencies:
is-windows: 1.0.2 is-windows: 1.0.2
better-sqlite3@11.9.1:
dependencies:
bindings: 1.5.0
prebuild-install: 7.1.3
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
brace-expansion@1.1.11: brace-expansion@1.1.11:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@@ -2588,6 +2811,11 @@ snapshots:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
cac@6.7.14: {} cac@6.7.14: {}
callsites@3.1.0: {} callsites@3.1.0: {}
@@ -2609,6 +2837,8 @@ snapshots:
check-error@2.1.1: {} check-error@2.1.1: {}
chownr@1.1.4: {}
ci-info@3.9.0: {} ci-info@3.9.0: {}
color-convert@2.0.1: color-convert@2.0.1:
@@ -2652,18 +2882,30 @@ snapshots:
decimal.js@10.4.3: {} decimal.js@10.4.3: {}
decompress-response@6.0.0:
dependencies:
mimic-response: 3.1.0
deep-eql@5.0.2: {} deep-eql@5.0.2: {}
deep-extend@0.6.0: {}
deep-is@0.1.4: {} deep-is@0.1.4: {}
delayed-stream@1.0.0: {} delayed-stream@1.0.0: {}
detect-indent@6.1.0: {} detect-indent@6.1.0: {}
detect-libc@2.0.4: {}
dir-glob@3.0.1: dir-glob@3.0.1:
dependencies: dependencies:
path-type: 4.0.0 path-type: 4.0.0
end-of-stream@1.4.4:
dependencies:
once: 1.4.0
enquirer@2.4.1: enquirer@2.4.1:
dependencies: dependencies:
ansi-colors: 4.1.3 ansi-colors: 4.1.3
@@ -2802,6 +3044,8 @@ snapshots:
esutils@2.0.3: {} esutils@2.0.3: {}
expand-template@2.0.3: {}
expect-type@1.1.0: {} expect-type@1.1.0: {}
extendable-error@0.1.7: {} extendable-error@0.1.7: {}
@@ -2834,6 +3078,8 @@ snapshots:
dependencies: dependencies:
flat-cache: 4.0.1 flat-cache: 4.0.1
file-uri-to-path@1.0.0: {}
fill-range@7.1.1: fill-range@7.1.1:
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
@@ -2861,6 +3107,8 @@ snapshots:
combined-stream: 1.0.8 combined-stream: 1.0.8
mime-types: 2.1.35 mime-types: 2.1.35
fs-constants@1.0.0: {}
fs-extra@7.0.1: fs-extra@7.0.1:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -2878,6 +3126,8 @@ snapshots:
function-bind@1.1.2: {} function-bind@1.1.2: {}
github-from-package@0.0.0: {}
glob-parent@5.1.2: glob-parent@5.1.2:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
@@ -2939,6 +3189,8 @@ snapshots:
dependencies: dependencies:
safer-buffer: 2.1.2 safer-buffer: 2.1.2
ieee754@1.2.1: {}
ignore@5.3.2: {} ignore@5.3.2: {}
import-fresh@3.3.0: import-fresh@3.3.0:
@@ -2950,6 +3202,10 @@ snapshots:
imurmurhash@0.1.4: {} imurmurhash@0.1.4: {}
inherits@2.0.4: {}
ini@1.3.8: {}
is-core-module@2.15.1: is-core-module@2.15.1:
dependencies: dependencies:
hasown: 2.0.2 hasown: 2.0.2
@@ -3076,6 +3332,8 @@ snapshots:
dependencies: dependencies:
mime-db: 1.52.0 mime-db: 1.52.0
mimic-response@3.1.0: {}
minimatch@3.0.8: minimatch@3.0.8:
dependencies: dependencies:
brace-expansion: 1.1.11 brace-expansion: 1.1.11
@@ -3088,6 +3346,10 @@ snapshots:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
minimist@1.2.8: {}
mkdirp-classic@0.5.3: {}
mlly@1.7.3: mlly@1.7.3:
dependencies: dependencies:
acorn: 8.14.0 acorn: 8.14.0
@@ -3103,10 +3365,20 @@ snapshots:
nanoid@3.3.8: {} nanoid@3.3.8: {}
napi-build-utils@2.0.0: {}
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
node-abi@3.75.0:
dependencies:
semver: 7.6.3
nwsapi@2.2.16: {} nwsapi@2.2.16: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
optionator@0.9.4: optionator@0.9.4:
dependencies: dependencies:
deep-is: 0.1.4 deep-is: 0.1.4
@@ -3188,14 +3460,41 @@ snapshots:
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.1 source-map-js: 1.2.1
prebuild-install@7.1.3:
dependencies:
detect-libc: 2.0.4
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 2.0.0
node-abi: 3.75.0
pump: 3.0.2
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.2
tunnel-agent: 0.6.0
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
prettier@2.8.8: {} prettier@2.8.8: {}
pump@3.0.2:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
punycode@2.3.1: {} punycode@2.3.1: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
rc@1.2.8:
dependencies:
deep-extend: 0.6.0
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
read-yaml-file@1.1.0: read-yaml-file@1.1.0:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -3203,6 +3502,12 @@ snapshots:
pify: 4.0.1 pify: 4.0.1
strip-bom: 3.0.0 strip-bom: 3.0.0
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
regenerator-runtime@0.14.1: {} regenerator-runtime@0.14.1: {}
require-from-string@2.0.2: {} require-from-string@2.0.2: {}
@@ -3249,6 +3554,8 @@ snapshots:
dependencies: dependencies:
queue-microtask: 1.2.3 queue-microtask: 1.2.3
safe-buffer@5.2.1: {}
safer-buffer@2.1.2: {} safer-buffer@2.1.2: {}
saxes@6.0.0: saxes@6.0.0:
@@ -3271,6 +3578,14 @@ snapshots:
signal-exit@4.1.0: {} signal-exit@4.1.0: {}
simple-concat@1.0.1: {}
simple-get@4.0.1:
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
slash@3.0.0: {} slash@3.0.0: {}
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
@@ -3290,12 +3605,18 @@ snapshots:
string-argv@0.3.2: {} string-argv@0.3.2: {}
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
strip-ansi@6.0.1: strip-ansi@6.0.1:
dependencies: dependencies:
ansi-regex: 5.0.1 ansi-regex: 5.0.1
strip-bom@3.0.0: {} strip-bom@3.0.0: {}
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}
supports-color@7.2.0: supports-color@7.2.0:
@@ -3310,6 +3631,21 @@ snapshots:
symbol-tree@3.2.4: {} symbol-tree@3.2.4: {}
tar-fs@2.1.2:
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.2
tar-stream: 2.2.0
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
term-size@2.2.1: {} term-size@2.2.1: {}
tinybench@2.9.0: {} tinybench@2.9.0: {}
@@ -3348,6 +3684,10 @@ snapshots:
dependencies: dependencies:
typescript: 5.7.2 typescript: 5.7.2
tunnel-agent@0.6.0:
dependencies:
safe-buffer: 5.2.1
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
@@ -3375,6 +3715,8 @@ snapshots:
dependencies: dependencies:
punycode: 2.3.1 punycode: 2.3.1
util-deprecate@1.0.2: {}
uuid@11.0.3: {} uuid@11.0.3: {}
vite-node@2.1.8: vite-node@2.1.8:
@@ -3495,6 +3837,8 @@ snapshots:
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
wrappy@1.0.2: {}
ws@8.18.0: {} ws@8.18.0: {}
xml-name-validator@5.0.0: {} xml-name-validator@5.0.0: {}

108
src/llm/claude.ts Normal file
View File

@@ -0,0 +1,108 @@
interface ClaudeCompletionResponse {
id: string;
type: string;
role: string;
content: Array<{
type: string;
text?: string;
}>;
model: string;
stop_reason: string;
stop_sequence: string | null;
usage: {
input_tokens: number;
output_tokens: number;
};
}
interface ClaudeCompletionOptions {
prompt: string;
options?: {
url?: string;
apiKey?: string;
model?: string;
maxTokens?: number;
temperature?: number;
topP?: number;
stopSequences?: string[];
system?: string;
};
}
export async function getClaudeCompletion({
prompt,
options: {
url = "https://api.anthropic.com/v1/messages",
apiKey = "x-demo",
model = "claude-3-sonnet-20240229",
maxTokens = 1024,
temperature = 0.7,
topP = 1,
stopSequences = [],
system = "",
} = {},
}: ClaudeCompletionOptions): Promise<string> {
try {
if (!prompt) {
throw new Error("Blank prompt");
}
if (!url) {
throw new Error("Claude API URL is not set");
}
if (!apiKey) {
throw new Error("Claude API key is not set");
}
const requestBody: any = {
model,
messages: [
{
role: "user",
content: prompt,
},
],
max_tokens: maxTokens,
temperature,
top_p: topP,
};
if (stopSequences && stopSequences.length > 0) {
requestBody.stop_sequences = stopSequences;
}
if (system) {
requestBody.system = system;
}
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
"anthropic-version": "2023-06-01",
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
throw new Error(`Claude API error: ${response.statusText}`);
}
const data: ClaudeCompletionResponse = await response.json();
// Extract text from the response
let responseText = "";
for (const content of data.content) {
if (content.type === "text" && content.text) {
responseText += content.text;
}
}
return responseText.trim();
} catch (error) {
console.error("Error:", error);
throw error;
}
}

View File

@@ -0,0 +1,18 @@
import { describe, it, expect } from "vitest";
import { OpenAPI, Claude } from "./index";
describe("LLM Module", () => {
describe("OpenAPI", () => {
it("should export getTextCompletion", () => {
expect(OpenAPI.getTextCompletion).toBeDefined();
expect(typeof OpenAPI.getTextCompletion).toBe("function");
});
});
describe("Claude", () => {
it("should export getClaudeCompletion", () => {
expect(Claude.getClaudeCompletion).toBeDefined();
expect(typeof Claude.getClaudeCompletion).toBe("function");
});
});
});

View File

@@ -1,9 +1,15 @@
import { getTextCompletion } from "./openapi"; import { getTextCompletion } from "./openapi";
import { getClaudeCompletion } from "./claude";
export const OpenAPI = { export const OpenAPI = {
getTextCompletion, getTextCompletion,
}; };
export const Claude = {
getClaudeCompletion,
};
export default { export default {
OpenAPI, OpenAPI,
Claude,
}; };

187
src/object/decycle.test.ts Normal file
View File

@@ -0,0 +1,187 @@
import { describe, it, expect } from 'vitest';
import { decycle, retrocycle } from './decycle';
describe('decycle and retrocycle functions', () => {
it('should handle non-circular objects correctly', () => {
const obj = { a: 1, b: 'string', c: true };
const decycled = decycle(obj);
expect(decycled).toEqual(obj);
const restored = retrocycle(decycled);
expect(restored).toEqual(obj);
});
it('should handle arrays correctly', () => {
const arr = [1, 'string', true, { nested: 'object' }];
const decycled = decycle(arr);
expect(decycled).toEqual(arr);
const restored = retrocycle(decycled);
expect(restored).toEqual(arr);
});
it('should handle circular references in arrays', () => {
const arr: any[] = [1, 2, 3];
arr.push(arr); // Create circular reference
const decycled = decycle(arr);
expect(decycled).toEqual([1, 2, 3, { $ref: '$' }]);
const restored = retrocycle(decycled);
expect(restored[0]).toBe(1);
expect(restored[1]).toBe(2);
expect(restored[2]).toBe(3);
expect(restored[3]).toBe(restored); // Circular reference restored
});
it('should handle circular references in objects', () => {
const obj: any = { a: 1, b: 'string' };
obj.self = obj; // Create circular reference
const decycled = decycle(obj);
expect(decycled).toEqual({ a: 1, b: 'string', self: { $ref: '$' } });
const restored = retrocycle(decycled);
expect(restored.a).toBe(1);
expect(restored.b).toBe('string');
expect(restored.self).toBe(restored); // Circular reference restored
});
it('should handle nested objects with circular references', () => {
const inner: any = { x: 1 };
const outer: any = { a: inner, b: 'string' };
inner.parent = outer; // Create circular reference
const decycled = decycle(outer);
expect(decycled).toEqual({
a: { x: 1, parent: { $ref: '$' } },
b: 'string'
});
const restored = retrocycle(decycled);
expect(restored.a.x).toBe(1);
expect(restored.a.parent).toBe(restored); // Circular reference restored
});
it('should handle multiple references to the same object', () => {
const shared = { id: 'shared' };
const obj = { a: shared, b: shared };
const decycled = decycle(obj);
expect(decycled).toEqual({
a: { id: 'shared' },
b: { $ref: '$["a"]' }
});
const restored = retrocycle(decycled);
expect(restored.a).toBe(restored.b); // Both refer to the same object
});
it('should work with custom replacer function', () => {
const obj = { a: 1, b: 2, secret: 'hidden' };
const replacer = (value: any) => {
if (value && typeof value === 'object' && 'secret' in value) {
const copy = { ...value };
copy.secret = '[REDACTED]';
return copy;
}
return value;
};
const decycled = decycle(obj, replacer);
expect(decycled).toEqual({ a: 1, b: 2, secret: '[REDACTED]' });
});
it('should handle null and undefined values', () => {
const obj = { a: null, b: undefined, c: { d: null } };
const decycled = decycle(obj);
expect(decycled).toEqual(obj);
const restored = retrocycle(decycled);
expect(restored).toEqual(obj);
});
it('should handle built-in objects like Date, RegExp, and more', () => {
const date = new Date('2023-01-01');
const regexp = /test/g;
const obj = {
date,
regexp,
bool: new Boolean(true),
num: new Number(42),
str: new String("test")
};
const decycled = decycle(obj);
expect(decycled.date).toBeInstanceOf(Date);
expect(decycled.regexp).toBeInstanceOf(RegExp);
expect(decycled.bool).toBeInstanceOf(Boolean);
expect(decycled.num).toBeInstanceOf(Number);
expect(decycled.str).toBeInstanceOf(String);
const restored = retrocycle(decycled);
expect(restored.date).toBeInstanceOf(Date);
expect(restored.date.toISOString()).toBe(date.toISOString());
expect(restored.regexp).toBeInstanceOf(RegExp);
expect(restored.regexp.source).toBe(regexp.source);
});
it('should handle complex nested circular references', () => {
const a: any = { name: 'a' };
const b: any = { name: 'b' };
const c: any = { name: 'c' };
a.child = b;
b.child = c;
c.parent = a; // Circular reference
const decycled = decycle(a);
expect(decycled).toEqual({
name: 'a',
child: {
name: 'b',
child: {
name: 'c',
parent: { $ref: '$' }
}
}
});
const restored = retrocycle(decycled);
expect(restored.name).toBe('a');
expect(restored.child.name).toBe('b');
expect(restored.child.child.name).toBe('c');
expect(restored.child.child.parent).toBe(restored); // Circular reference restored
});
it('should handle arrays with multiple circular references', () => {
const arr1: any[] = [1, 2];
const arr2: any[] = [3, 4];
arr1.push(arr2);
arr2.push(arr1); // Circular reference
const decycled = decycle(arr1);
expect(decycled).toEqual([1, 2, [3, 4, { $ref: '$' }]]);
const restored = retrocycle(decycled);
expect(restored[0]).toBe(1);
expect(restored[1]).toBe(2);
expect(restored[2][0]).toBe(3);
expect(restored[2][1]).toBe(4);
expect(restored[2][2]).toBe(restored); // Circular reference restored
});
it('should work with JSON.stringify and JSON.parse for circular structures', () => {
const obj: any = { a: 1, b: 'string' };
obj.self = obj; // Create circular reference
const decycled = decycle(obj);
const jsonStr = JSON.stringify(decycled);
const parsed = JSON.parse(jsonStr);
const restored = retrocycle(parsed);
expect(restored.a).toBe(1);
expect(restored.b).toBe('string');
expect(restored.self).toBe(restored); // Circular reference restored
});
});

146
src/object/decycle.ts Normal file
View File

@@ -0,0 +1,146 @@
/**
* Interface for an object with a $ref property pointing to a path
*/
export interface RefObject {
$ref: string;
}
/**
* Makes a deep copy of an object or array, replacing circular references
* with objects of the form {"$ref": PATH} where PATH is a JSONPath string
* that locates the first occurrence.
*
* @param object - The object to decycle
* @param replacer - Optional function to replace values during the process
* @returns A decycled copy of the object
*/
export function decycle<T=any>(
object: T,
replacer?: (value: any) => any
): any {
"use strict";
// Object to path mappings
const objects = new WeakMap<object, string>();
return (function derez(value: any, path: string): any {
// The path of an earlier occurrence of value
let old_path: string | undefined;
// The new object or array
let nu: any;
// If a replacer function was provided, then call it to get a replacement value.
if (replacer !== undefined) {
value = replacer(value);
}
// typeof null === "object", so go on if this value is really an object but not
// one of the weird builtin objects.
if (
typeof value === "object"
&& value !== null
&& !(value instanceof Boolean)
&& !(value instanceof Date)
&& !(value instanceof Number)
&& !(value instanceof RegExp)
&& !(value instanceof String)
) {
// If the value is an object or array, look to see if we have already
// encountered it. If so, return a {"$ref":PATH} object. This uses an
// ES6 WeakMap.
old_path = objects.get(value);
if (old_path !== undefined) {
return {$ref: old_path};
}
// Otherwise, accumulate the unique value and its path.
objects.set(value, path);
// If it is an array, replicate the array.
if (Array.isArray(value)) {
nu = [];
value.forEach(function (element, i) {
nu[i] = derez(element, path + "[" + i + "]");
});
} else {
// If it is an object, replicate the object.
nu = {};
Object.keys(value).forEach(function (name) {
nu[name] = derez(
value[name],
path + "[" + JSON.stringify(name) + "]"
);
});
}
return nu;
}
return value;
}(object, "$"));
}
/**
* Restores an object that was reduced by decycle. Members whose values are
* objects of the form {$ref: PATH} are replaced with references to the value
* found by the PATH. This will restore cycles.
*
* @param $ - The object to restore cycles in
* @returns The object with restored cycles
*/
export function retrocycle<T>($: T): T {
"use strict";
// Regular expression to validate JSONPath format
// NOTE: This function uses eval() which can be a security risk.
// Consider using a safer alternative in production environments.
// eslint-disable-next-line no-control-regex
const px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
(function rez(value: any): void {
// The rez function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is a path, then it
// replaces the $ref object with a reference to the value that is found by
// the path.
if (value && typeof value === "object") {
if (Array.isArray(value)) {
value.forEach(function (element, i) {
if (typeof element === "object" && element !== null) {
const path = element.$ref;
if (typeof path === "string" && px.test(path)) {
// Security warning: eval is used here
value[i] = eval(path);
} else {
rez(element);
}
}
});
} else {
Object.keys(value).forEach(function (name) {
const item = value[name];
if (typeof item === "object" && item !== null) {
const path = item.$ref;
if (typeof path === "string" && px.test(path)) {
// Security warning: eval is used here
value[name] = eval(path);
} else {
rez(item);
}
}
});
}
}
}($));
return $;
}
/**
*
* @description Converts a object with circular references to JSON
* @param json
* @param object
* @returns
*/
export function stringify_json<T=any>(
object: T,
) {
return JSON.stringify(retrocycle(object))
}

View File

@@ -1,3 +1,5 @@
export {getNestedValue,setNestedValue} from './nested' export {getNestedValue,setNestedValue} from './nested'
export {objectCompare} from './compare' export {objectCompare} from './compare'
export {createSelectOptions} from './util' export {createSelectOptions} from './util'
export {decycle,retrocycle, stringify_json} from './decycle'
export type {RefObject} from './decycle'

View File

@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest"; import { describe, expect, test } from "vitest";
import { getNestedValue, setNestedValue } from "./nested"; import { findObjectByKeyValues, findObjectPath, getNestedValue, setNestedValue } from "./nested";
describe("getNestedValue", () => { describe("getNestedValue", () => {
const testObj = { const testObj = {
@@ -170,3 +170,178 @@ describe("setNestedValue", () => {
expect(obj.list[0]).toBe("item"); expect(obj.list[0]).toBe("item");
}); });
}); });
describe("findObjectPath", () => {
const testObj = {
user: {
name: "John",
id: 1,
contacts: [
{ id: 101, email: "john@example.com", phone: "123-456" },
{ id: 102, email: "john.alt@example.com", phone: "789-012" },
],
settings: {
id: 201,
notifications: {
email: true,
push: false,
},
},
},
meta: {
created: "2023-01-01",
tags: ["important", "user"],
},
items: [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" },
{ id: 1, name: "Item 3" }, // Duplicate ID
],
config: {
defaultUser: { id: 1 }
}
};
test("should find simple property matches", () => {
const paths = findObjectPath(testObj, { id: 1 });
expect(paths).toContain("user");
expect(paths).toContain("items[0]");
expect(paths).toContain("items[2]");
expect(paths).toContain("config.defaultUser");
});
test("should find nested property matches", () => {
const paths = findObjectPath(testObj, { email: true });
expect(paths).toContain("user.settings.notifications");
});
test("should find matches in arrays", () => {
const paths = findObjectPath(testObj, { id: 101 });
expect(paths).toContain("user.contacts[0]");
const paths2 = findObjectPath(testObj, { id: 102 });
expect(paths2).toContain("user.contacts[1]");
});
test("should find matches with multiple criteria", () => {
const paths = findObjectPath(testObj, { id: 1, name: "Item 1" });
expect(paths).toContain("items[0]");
expect(paths).not.toContain("items[2]"); // Has id: 1 but different name
expect(paths).not.toContain("user"); // Has id: 1 but no name property
});
test("should return empty array for no matches", () => {
const paths = findObjectPath(testObj, { id: 999 });
expect(paths).toEqual([]);
});
test("should handle empty criteria", () => {
const paths = findObjectPath(testObj, {});
expect(paths).toEqual([]);
});
test("should handle null or undefined input", () => {
expect(findObjectPath(null, { id: 1 })).toEqual([]);
expect(findObjectPath(undefined, { id: 1 })).toEqual([]);
expect(findObjectPath(testObj, null)).toEqual([]);
expect(findObjectPath(testObj, undefined)).toEqual([]);
});
test("should work with setNestedValue", () => {
const obj = { ...testObj }; // Clone to avoid modifying test object
const paths = findObjectPath(obj, { id: 101 });
expect(paths.length).toBeGreaterThan(0);
const path = paths[0];
const originalValue = getNestedValue(path, obj);
const updatedValue = { ...originalValue, email: "updated@example.com" };
setNestedValue(path, updatedValue, obj);
expect(getNestedValue(`${path}.email`, obj)).toBe("updated@example.com");
});
test("should find path to primitive array values", () => {
const paths = findObjectPath(testObj, { 0: "important" });
expect(paths).toContain("meta.tags");
});
});
// Only add these tests if you're implementing the advanced version
describe("findObjectByKeyValues", () => {
const testObj = {
user: {
name: "John",
id: 1,
contacts: [
{ id: 101, email: "john@example.com", phone: "123-456" },
{ id: 102, email: "JOHN.alt@example.com", phone: "789-012" },
],
},
items: [
{ id: 1, name: "Item 1", status: "active" },
{ id: 2, name: "Item 2", status: "inactive" },
{ id: 3, name: "Item 3", status: "active" },
],
};
test("should handle partial matches", () => {
const paths = findObjectByKeyValues(testObj, { id: 1, name: "Unknown" }, { partialMatch: true });
expect(paths).toContain("user");
expect(paths).toContain("items[0]");
});
test("should handle maxDepth option", () => {
// Should not find matches beyond depth 1
const paths = findObjectByKeyValues(testObj, { id: 101 }, { maxDepth: 1 });
expect(paths).toEqual([]);
// Should not find matches at depth 2
const paths2 = findObjectByKeyValues(testObj, { id: 101 }, { maxDepth: 3 });
expect(paths2).toContain("user.contacts[0]");
});
test("should handle returnFirstMatch option", () => {
// Should return only the first match
const paths = findObjectByKeyValues(testObj, { status: "active" }, { returnFirstMatch: true });
expect(paths.length).toBe(1);
expect(paths[0]).toBe("items[0]");
});
test("should handle case insensitive matching", () => {
// Should match regardless of case
const paths = findObjectByKeyValues(testObj, { email: "john.alt@example.com" }, { caseSensitive: false });
expect(paths).toContain("user.contacts[1]");
});
test("should use custom comparison function", () => {
// Custom comparator that checks if string contains substring
const customCompare = (a: any, b: any) => {
if (typeof a === 'string' && typeof b === 'string') {
return a.includes(b);
}
return a === b;
};
const paths = findObjectByKeyValues(testObj, { email: "@example" }, { customCompare });
expect(paths).toContain("user.contacts[0]");
expect(paths).toContain("user.contacts[1]");
});
test("should combine multiple options", () => {
const paths = findObjectByKeyValues(
testObj,
{ id: 1, status: "active" },
{
partialMatch: true,
maxDepth: 2,
returnFirstMatch: true
}
);
expect(paths.length).toBe(1);
// Either user or items[0] could be returned since we're stopping at first match
expect(paths[0] === "user" || paths[0] === "items[0]").toBeTruthy();
});
});

View File

@@ -20,7 +20,8 @@ export function getNestedValue(path: string, obj: Record<string, any>): any {
if (parts.length === 0) return undefined; if (parts.length === 0) return undefined;
return parts.reduce((prev, curr) => { return parts.reduce((prev, curr) => {
if (prev === undefined) return undefined; if (prev === null || prev === undefined) return undefined;
if (typeof prev !== "object") return undefined;
return prev[curr]; return prev[curr];
}, obj); }, obj);
} }
@@ -101,3 +102,176 @@ export function setNestedValue(
current[lastKey] = value; current[lastKey] = value;
return obj; return obj;
} }
export function findObjectByKeyValues(
obj: Record<string, any>,
criteria: Record<string, any>,
options: {
partialMatch?: boolean;
maxDepth?: number;
returnFirstMatch?: boolean;
caseSensitive?: boolean;
customCompare?: (a: any, b: any) => boolean;
} = {}
): string[] {
// Handle invalid inputs
if (!obj || typeof obj !== 'object') {
return [];
}
// Handle empty criteria
if (!criteria || typeof criteria !== 'object' || Object.keys(criteria).length === 0) {
return [];
}
const {
partialMatch = false,
maxDepth = Infinity,
returnFirstMatch = false,
caseSensitive = true,
customCompare
} = options;
const results: string[] = [];
// Helper function for comparing values
const compareValues = (a: any, b: any): boolean => {
if (customCompare) {
return customCompare(a, b);
}
// Handle string comparison with case sensitivity option
if (typeof a === 'string' && typeof b === 'string' && !caseSensitive) {
return a.toLowerCase() === b.toLowerCase();
}
return a === b;
};
// Recursive search function
const search = (
currentObj: Record<string, any>,
currentPath: string = '',
depth: number = 0
): void => {
// Check depth first - don't process objects beyond max depth
if (depth > maxDepth) {
return;
}
// Skip if not a valid object
if (!currentObj || typeof currentObj !== 'object') {
return;
}
// Check if current object matches criteria
let matchCount = 0;
const criteriaKeys = Object.keys(criteria);
for (const key of criteriaKeys) {
if (key in currentObj && compareValues(currentObj[key], criteria[key])) {
matchCount++;
}
}
const isMatch = partialMatch
? matchCount > 0
: matchCount === criteriaKeys.length;
// If matched, add to results
if (isMatch && criteriaKeys.length > 0) {
results.push(currentPath);
if (returnFirstMatch) {
return;
}
}
// Recursively search nested objects and arrays
if (Array.isArray(currentObj)) {
for (let i = 0; i < currentObj.length; i++) {
const item = currentObj[i];
if (item && typeof item === 'object') {
const nextPath = currentPath ? `${currentPath}[${i}]` : `[${i}]`;
search(item, nextPath, depth + 1);
if (returnFirstMatch && results.length > 0) {
return;
}
}
}
} else {
for (const [key, value] of Object.entries(currentObj)) {
if (value && typeof value === 'object') {
const nextPath = currentPath ? `${currentPath}.${key}` : key;
search(value, nextPath, depth + 1);
if (returnFirstMatch && results.length > 0) {
return;
}
}
}
}
};
search(obj);
return results;
}
/**
* Finds objects in a nested structure that match specified key-value pairs
* Returns paths compatible with setNestedValue function
* @param obj - Source object to search within
* @param criteria - Object with key-value pairs to match against
* @returns Array of paths where matching objects were found
*/
export function findObjectPath(
obj: Record<string, any>,
criteria: Record<string, any>
): string[] {
const results: string[] = [];
// Handle invalid inputs
if (!obj || typeof obj !== 'object') {
return results;
}
// Handle empty criteria - should return empty array
if (!criteria || typeof criteria !== 'object' || Object.keys(criteria).length === 0) {
return results;
}
const search = (currentObj: any, path: string = '') => {
// Skip if not an object or is null
if (!currentObj || typeof currentObj !== 'object') {
return;
}
// Check if current object matches all criteria
let matches = true;
for (const [key, value] of Object.entries(criteria)) {
if (!(key in currentObj) || currentObj[key] !== value) {
matches = false;
break;
}
}
if (matches) {
results.push(path);
}
// Continue searching in nested properties
if (Array.isArray(currentObj)) {
for (let i = 0; i < currentObj.length; i++) {
const newPath = path ? `${path}[${i}]` : `[${i}]`;
search(currentObj[i], newPath);
}
} else {
for (const [key, value] of Object.entries(currentObj)) {
const newPath = path ? `${path}.${key}` : key;
search(value, newPath);
}
}
};
search(obj);
return results;
}

View File

@@ -0,0 +1,184 @@
import { describe, it, expect } from 'vitest';
import { fromBaseN, toBaseN } from './baseNumber'; // Update with actual path
// This test suite targets ES6+ environments
describe('Base-N Converters', () => {
describe('fromBaseN', () => {
// Basic conversion tests
it('should convert base 10 strings correctly', () => {
expect(fromBaseN('0', 10)).toBe(BigInt(0));
expect(fromBaseN('123', 10)).toBe(BigInt(123));
expect(fromBaseN('9999', 10)).toBe(BigInt(9999));
});
it('should convert base 2 (binary) strings correctly', () => {
expect(fromBaseN('0', 2)).toBe(BigInt(0));
expect(fromBaseN('1', 2)).toBe(BigInt(1));
expect(fromBaseN('10', 2)).toBe(BigInt(2));
expect(fromBaseN('1010', 2)).toBe(BigInt(10));
expect(fromBaseN('11111111', 2)).toBe(BigInt(255));
});
it('should convert base 16 (hex) strings correctly', () => {
expect(fromBaseN('0', 16)).toBe(BigInt(0));
expect(fromBaseN('A', 16)).toBe(BigInt(10));
expect(fromBaseN('F', 16)).toBe(BigInt(15));
expect(fromBaseN('10', 16)).toBe(BigInt(16));
expect(fromBaseN('FF', 16)).toBe(BigInt(255));
expect(fromBaseN('ABC', 16)).toBe(BigInt(2748));
expect(fromBaseN('DEADBEEF', 16)).toBe(BigInt(3735928559));
});
it('should convert base 36 strings correctly', () => {
expect(fromBaseN('0', 36)).toBe(BigInt(0));
expect(fromBaseN('Z', 36)).toBe(BigInt(35));
expect(fromBaseN('10', 36)).toBe(BigInt(36));
expect(fromBaseN('CLAUDE', 36)).toBe(BigInt(761371970));
});
// Case insensitivity
it('should be case insensitive', () => {
expect(fromBaseN('abc', 16)).toBe(BigInt(2748));
expect(fromBaseN('ABC', 16)).toBe(BigInt(2748));
expect(fromBaseN('AbC', 16)).toBe(BigInt(2748));
expect(fromBaseN('claude', 36)).toBe(BigInt(761371970));
expect(fromBaseN('CLAUDE', 36)).toBe(BigInt(761371970));
});
// Default base
it('should use base 36 by default', () => {
expect(fromBaseN('Z')).toBe(BigInt(35));
expect(fromBaseN('10')).toBe(BigInt(36));
});
// Edge cases
it('should handle empty string or null', () => {
expect(fromBaseN('')).toBe(BigInt(0));
expect(fromBaseN('', 10)).toBe(BigInt(0));
});
it('should handle very large numbers', () => {
expect(fromBaseN('ZZZZZZZZZZZZ', 36)).toBe(BigInt('4738381338321616895'));
});
// Error cases
it('should throw error for invalid base', () => {
expect(() => fromBaseN('123', 1)).toThrow('Base must be between 2 and 36');
expect(() => fromBaseN('123', 37)).toThrow('Base must be between 2 and 36');
});
it('should throw error for invalid characters', () => {
expect(() => fromBaseN('12$3', 10)).toThrow('Invalid character in input string: $');
expect(() => fromBaseN('XYZ', 10)).toThrow('Digit Z is invalid for base 10');
});
it('should throw error for digit out of range for base', () => {
expect(() => fromBaseN('129', 9)).toThrow('Digit 9 is invalid for base 9');
expect(() => fromBaseN('12A', 10)).toThrow('Digit A is invalid for base 10');
});
});
describe('toBaseN', () => {
// Basic conversion tests
it('should convert to base 10 strings correctly', () => {
expect(toBaseN(0, 10)).toBe('0');
expect(toBaseN(123, 10)).toBe('123');
expect(toBaseN(9999, 10)).toBe('9999');
});
it('should convert to base 2 (binary) strings correctly', () => {
expect(toBaseN(0, 2)).toBe('0');
expect(toBaseN(1, 2)).toBe('1');
expect(toBaseN(2, 2)).toBe('10');
expect(toBaseN(10, 2)).toBe('1010');
expect(toBaseN(255, 2)).toBe('11111111');
});
it('should convert to base 16 (hex) strings correctly', () => {
expect(toBaseN(0, 16)).toBe('0');
expect(toBaseN(10, 16)).toBe('A');
expect(toBaseN(15, 16)).toBe('F');
expect(toBaseN(16, 16)).toBe('10');
expect(toBaseN(255, 16)).toBe('FF');
expect(toBaseN(2748, 16)).toBe('ABC');
expect(toBaseN(3735928559, 16)).toBe('DEADBEEF');
});
it('should convert to base 36 strings correctly', () => {
expect(toBaseN(0, 36)).toBe('0');
expect(toBaseN(35, 36)).toBe('Z');
expect(toBaseN(36, 36)).toBe('10');
expect(toBaseN(761371970, 36)).toBe('CLAUDE');
});
// Default base
it('should use base 36 by default', () => {
expect(toBaseN(35)).toBe('Z');
expect(toBaseN(36)).toBe('10');
});
// Edge cases
it('should handle zero', () => {
expect(toBaseN(0)).toBe('0');
expect(toBaseN(BigInt(0))).toBe('0');
});
it('should handle negative numbers', () => {
expect(toBaseN(-123, 10)).toBe('-123');
expect(toBaseN(-15, 16)).toBe('-F');
expect(toBaseN(-35, 36)).toBe('-Z');
});
it('should handle BigInt inputs', () => {
expect(toBaseN(BigInt(123), 10)).toBe('123');
expect(toBaseN(BigInt('9007199254740991'), 16)).toBe('1FFFFFFFFFFFFF');
expect(toBaseN(BigInt('4738381338321616895'), 36)).toBe('ZZZZZZZZZZZZ');
});
// Error cases
it('should throw error for invalid base', () => {
expect(() => toBaseN(123, 1)).toThrow('Base must be between 2 and 36');
expect(() => toBaseN(123, 37)).toThrow('Base must be between 2 and 36');
});
});
// Round-trip tests
describe('round-trip conversions', () => {
it('should preserve value when converting back and forth', () => {
const testValues = [
0, 1, 42, 123, 255, 1000, 9999, 65535, 16777215, 2147483647,
// Large values as BigInt
BigInt('4738381338321616895'),
BigInt('761371970') // Value for 'CLAUDE' in base 36
];
const bases = [2, 8, 10, 16, 36];
for (const value of testValues) {
for (const base of bases) {
// Convert to string in base-n, then back to number
const baseStr = toBaseN(value, base);
const backToNumber = fromBaseN(baseStr, base);
// Convert BigInt to string for comparison since BigInt !== number
const originalValue = typeof value === 'bigint' ? value : BigInt(value);
expect(backToNumber).toBe(originalValue);
}
}
});
it('should handle random values in round-trip conversions', () => {
// Test with 10 random values
for (let i = 0; i < 10; i++) {
const randomValue = Math.floor(Math.random() * 1000000);
const randomBase = Math.floor(Math.random() * 35) + 2; // Random base between 2-36
const baseStr = toBaseN(randomValue, randomBase);
const backToNumber = fromBaseN(baseStr, randomBase);
expect(backToNumber).toBe(BigInt(randomValue));
}
});
});
});

124
src/strings/baseNumber.ts Normal file
View File

@@ -0,0 +1,124 @@
/**
* Convert a string in a given base to a decimal number
* This implementation targets ES6+ and uses BigInt for large number support
*
* @param str The string to convert
* @param base The base to convert from (2-36)
* @returns The decimal number as BigInt
*/
export function fromBaseN(str: string, base: number = 36): bigint {
// Input validation
if (base < 2 || base > 36) {
throw new Error('Base must be between 2 and 36');
}
// Convert empty string or null to 0
if (!str) {
return BigInt(0);
}
// Use standard alphanumeric characters for conversion: 0-9, A-Z
const lookupString = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = BigInt(0);
let power = BigInt(1);
// Process string right to left
for (let i = str.length - 1; i >= 0; i--) {
const char = str[i].toUpperCase();
const digit = lookupString.indexOf(char);
// Check if character is valid
if (digit === -1) {
throw new Error(`Invalid character in input string: ${char}`);
}
// Validate digit is within base range
if (digit >= base) {
throw new Error(`Digit ${char} is invalid for base ${base}`);
}
result += BigInt(digit) * power;
power *= BigInt(base);
}
return result;
}
/**
* Convert a decimal number to a string in a given base
* This implementation targets ES6+ and uses BigInt for large number support
*
* @param num The decimal number to convert
* @param base The base to convert to (2-36)
* @returns The string representation in the specified base
*/
export function toBaseN(num: number | bigint, base: number = 36): string {
// Input validation
if (base < 2 || base > 36) {
throw new Error('Base must be between 2 and 36');
}
// Handle 0 separately
if (num === 0 || num === BigInt(0)) {
return '0';
}
// Convert to BigInt to handle large numbers
const bigNum = typeof num === 'number' ? BigInt(num) : num;
// Use standard alphanumeric characters for conversion: 0-9, A-Z
const lookupString = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
let remaining = bigNum > BigInt(0) ? bigNum : -bigNum; // Handle negative numbers
const bigBase = BigInt(base);
while (remaining > BigInt(0)) {
const digitValue = Number(remaining % bigBase);
const digitChar = lookupString[digitValue];
result = digitChar + result;
remaining = remaining / bigBase;
}
// Add negative sign if necessary
return bigNum < BigInt(0) ? '-' + result : result;
}
/**
* Convert a string in a given base to a decimal number, if it fails, returns fallback
* This implementation targets ES6+ and uses BigInt for large number support
*
* @param str The string to convert
* @param base The base to convert from (2-36)
* @returns The decimal number as BigInt
*/
export function tryFromBaseN(str: string, base: number = 36, fallback: bigint | number = 0): bigint| number {
try {
return fromBaseN(str, base)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch(_e) {
return fallback
}
}
/**
* Convert a decimal number to a string in a given base, it it fails, use fallback
* This implementation targets ES6+ and uses BigInt for large number support
*
* @param num The decimal number to convert
* @param base The base to convert to (2-36)
* @returns The string representation in the specified base
*/
export function tryToBaseN(num: number | bigint, base: number = 36, fallback: string = ""): string {
try {
return toBaseN(num, base)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch(_e) {
return fallback
}
}

View File

@@ -7,3 +7,4 @@ export * from "./legacy";
export * from "./uuid"; export * from "./uuid";
export * from "./time"; export * from "./time";
export * from "./blankValue"; export * from "./blankValue";
export * from "./baseNumber";