From 1aff6b7c92a8cad0689c07a67b7dcb88d74e40a7 Mon Sep 17 00:00:00 2001 From: Hossein Pourdavar Date: Thu, 19 Feb 2026 11:08:14 +0330 Subject: [PATCH 1/4] feat(ddd): add DeepImmutable type and related tests Introduce a new DeepImmutable type that recursively marks types as immutable, preserving class instances and converting collections to their readonly counterparts. Additionally, add tests to validate the behavior of DeepImmutable across various data structures, ensuring type safety and correctness. --- packages/ddd/package.json | 3 + .../types/__tests__/deep-immutable.test-d.ts | 92 +++++ .../src/domain/types/deep-immutable.type.ts | 32 ++ pnpm-lock.yaml | 364 +++++++++++++++++- 4 files changed, 489 insertions(+), 2 deletions(-) create mode 100644 packages/ddd/src/domain/types/__tests__/deep-immutable.test-d.ts create mode 100644 packages/ddd/src/domain/types/deep-immutable.type.ts diff --git a/packages/ddd/package.json b/packages/ddd/package.json index efa476e..f653805 100644 --- a/packages/ddd/package.json +++ b/packages/ddd/package.json @@ -8,6 +8,7 @@ "types": "./dist/index.d.ts", "scripts": { "test": "vitest run", + "test:types": "tsd -f 'src/domain/types/__tests__/*.test-d.ts'", "lint": "eslint 'src/**/*.ts'", "lint:fix": "eslint 'src/**/*.ts' --fix", "check-types": "tsc --noEmit", @@ -23,8 +24,10 @@ "@rineex/typescript-config": "workspace:*", "@types/node": "24.10.4", "@vitest/ui": "4.0.16", + "expect-type": "1.3.0", "fast-deep-equal": "3.1.3", "isbot": "5.1.32", + "tsd": "0.33.0", "tslib": "2.8.1", "tsup": "8.5.1", "typescript": "5.9.3", diff --git a/packages/ddd/src/domain/types/__tests__/deep-immutable.test-d.ts b/packages/ddd/src/domain/types/__tests__/deep-immutable.test-d.ts new file mode 100644 index 0000000..ec19146 --- /dev/null +++ b/packages/ddd/src/domain/types/__tests__/deep-immutable.test-d.ts @@ -0,0 +1,92 @@ +/* eslint-disable vitest/require-hook */ +import { expectAssignable, expectType } from 'tsd'; + +import type { DeepImmutable } from '../deep-immutable.type'; + +// Helper to get a value of type DeepImmutable without runtime value (for type assertions only) +function imm(): DeepImmutable { + return undefined as unknown as DeepImmutable; +} + +// --- Primitives remain as-is --- +expectType(imm()); +expectType(imm()); +expectType(imm()); +expectType(imm()); +expectType(imm()); +expectType(imm()); + +// --- Functions are preserved --- +expectType<(x: number) => string>(imm<(x: number) => string>()); +expectType<() => void>(imm<() => void>()); + +// --- Date is preserved --- +expectType(imm()); + +// --- Promise: deep readonly of resolved type --- +expectAssignable>( + imm>(), +); +expectAssignable>(imm>()); + +// --- Map → ReadonlyMap with deep immutable keys & values --- +expectType>(imm>()); +expectAssignable>( + imm>(), +); + +// --- Set → ReadonlySet with deep immutable elements --- +expectType>(imm>()); +expectType>(imm>()); + +// --- Array → readonly array with deep immutable elements --- +expectType(imm()); +expectType(imm()); + +// --- Plain objects: recursively readonly (not class instances) --- +expectAssignable<{ readonly a: number; readonly b: string }>( + imm<{ a: number; b: string }>(), +); +expectAssignable<{ + readonly id: number; + readonly nested: { readonly name: string }; +}>(imm<{ id: number; nested: { name: string } }>()); + +// --- Class instances are preserved (not recursively made readonly) --- +class Entity { + constructor(public id: string) {} +} +expectType(imm()); +expectAssignable(imm()); + +// --- After immutability, value is still typed as instance of the class --- +class AggregateRoot { + constructor( + public readonly id: string, + public version: number, + ) {} + doSomething(): void {} +} +// DeepImmutable must still be AggregateRoot (instance of it) +expectType(imm()); +// Type-level "instanceof": immutable value is assignable where class is required +function acceptInstanceOfAggregateRoot(_instance: AggregateRoot): void {} +acceptInstanceOfAggregateRoot(imm()); + +// --- Nested structures --- +type Nested = { + arr: number[]; + map: Map; + set: Set; +}; +expectAssignable<{ + readonly arr: readonly number[]; + readonly map: ReadonlyMap; + readonly set: ReadonlySet; +}>(imm()); + +// --- Edge: empty object --- +expectType<{}>(imm<{}>()); + +// --- Edge: tuple is treated as array → readonly (number | string)[] --- +expectType(imm<[number, string]>()); diff --git a/packages/ddd/src/domain/types/deep-immutable.type.ts b/packages/ddd/src/domain/types/deep-immutable.type.ts new file mode 100644 index 0000000..7085f78 --- /dev/null +++ b/packages/ddd/src/domain/types/deep-immutable.type.ts @@ -0,0 +1,32 @@ +/** + * DeepImmutable recursively marks T as immutable. + * - Preserves class instances + * - Converts Array, Map, Set to readonly + * - Preserves functions and Date + * - Preserves Promise types + */ +export type DeepImmutable = + // Functions are preserved + T extends (...args: any[]) => any + ? T + : // Date is preserved + T extends Date + ? T + : // Promise: deep readonly of the resolved type + T extends Promise + ? Promise> + : // Map: converted to ReadonlyMap with deep immutable keys & values + T extends Map + ? ReadonlyMap, DeepImmutable> + : // Set: converted to ReadonlySet with deep immutable elements + T extends Set + ? ReadonlySet> + : // Array: converted to readonly array with deep immutable elements + T extends (infer U)[] + ? readonly DeepImmutable[] + : // Plain objects (not class instances) are recursively made readonly + T extends object + ? T extends { constructor: Function } + ? T // Preserve class instances + : { readonly [K in keyof T]: DeepImmutable } + : T; // primitives remain as-is diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 234af30..82025f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 2.29.8(@types/node@24.10.4) '@fullstacksjs/eslint-config': specifier: 13.8.2 - version: 13.8.2(@types/eslint@9.6.1)(@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@29.7.0(@types/node@24.10.4))(prettier@3.7.4)(react@19.2.3)(tailwindcss@4.1.18)(typescript@5.9.3)(vitest@4.0.16) + version: 13.8.2(@types/eslint@9.6.1)(@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.44.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@29.7.0(@types/node@24.10.4))(prettier@3.7.4)(react@19.2.3)(tailwindcss@4.1.18)(typescript@5.9.3)(vitest@4.0.16) '@svitejs/changesets-changelog-github-compact': specifier: 1.2.0 version: 1.2.0 @@ -231,6 +231,12 @@ importers: '@vitest/ui': specifier: 4.0.16 version: 4.0.16(vitest@4.0.16) + expect-type: + specifier: 1.3.0 + version: 1.3.0 + tsd: + specifier: 0.33.0 + version: 0.33.0 tslib: specifier: 2.8.1 version: 2.8.1 @@ -251,7 +257,7 @@ importers: devDependencies: '@fullstacksjs/eslint-config': specifier: 13.8.2 - version: 13.8.2(@types/eslint@9.6.1)(@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.44.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@29.7.0(@types/node@24.10.4))(prettier@3.7.4)(react@19.2.3)(tailwindcss@4.1.18)(typescript@5.9.3)(vitest@4.0.16) + version: 13.8.2(@types/eslint@9.6.1)(@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/utils@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(jest@29.7.0(@types/node@24.10.4))(prettier@3.7.4)(react@19.2.3)(tailwindcss@4.1.18)(typescript@5.9.3)(vitest@4.0.16) eslint-plugin-react-hooks: specifier: 7.0.1 version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) @@ -2072,6 +2078,10 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tsd/typescript@5.9.3': + resolution: {integrity: sha512-JSSdNiS0wgd8GHhBwnMAI18Y8XPhLVN+dNelPfZCXFhy9Lb3NbnFyp9JKxxr54jSUkEJPk3cidvCoHducSaRMQ==} + engines: {node: '>=14.17'} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -2107,6 +2117,9 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/eslint@7.29.0': + resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==} + '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} @@ -2152,6 +2165,9 @@ packages: '@types/lodash@4.17.21': resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + '@types/minimist@1.2.5': + resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -2161,6 +2177,9 @@ packages: '@types/node@24.10.4': resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} @@ -2587,6 +2606,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2712,6 +2735,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase-keys@6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -2953,6 +2980,14 @@ packages: supports-color: optional: true + decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dedent@1.7.1: resolution: {integrity: sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==} peerDependencies: @@ -3133,6 +3168,10 @@ packages: peerDependencies: eslint: '>=6.0.0' + eslint-formatter-pretty@4.1.0: + resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==} + engines: {node: '>=10'} + eslint-import-context@0.1.9: resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -3308,6 +3347,9 @@ packages: eslint: '>6.6.0' turbo: '>2.0.0' + eslint-rule-docs@1.1.235: + resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3638,6 +3680,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -3675,6 +3721,13 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3721,6 +3774,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -3748,6 +3805,10 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -3833,6 +3894,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3875,6 +3940,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -4116,6 +4185,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -4198,6 +4271,10 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -4205,6 +4282,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -4215,6 +4296,14 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + + map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -4230,6 +4319,10 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + meow@9.0.0: + resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} + engines: {node: '>=10'} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -4269,6 +4362,10 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} @@ -4280,6 +4377,10 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4362,6 +4463,13 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -4612,6 +4720,10 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + plur@4.0.0: + resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} + engines: {node: '>=10'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -4741,6 +4853,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + railroad-diagrams@1.0.0: resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==} @@ -4766,6 +4882,14 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -4782,6 +4906,10 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} @@ -5049,6 +5177,18 @@ packages: spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -5166,6 +5306,10 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -5187,6 +5331,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -5277,6 +5425,10 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true + trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + ts-api-utils@2.4.0: resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} @@ -5316,6 +5468,11 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} + tsd@0.33.0: + resolution: {integrity: sha512-/PQtykJFVw90QICG7zyPDMIyueOXKL7jOJVoX5pILnb3Ux+7QqynOxfVvarE+K+yi7BZyOSY4r+OZNWSWRiEwQ==} + engines: {node: '>=14.16'} + hasBin: true + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -5399,6 +5556,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-fest@0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -5407,10 +5568,18 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + type-fest@0.7.1: resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} engines: {node: '>=8'} + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} @@ -5523,6 +5692,9 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -5698,11 +5870,18 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -7276,6 +7455,8 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tsd/typescript@5.9.3': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -7326,6 +7507,11 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/eslint@7.29.0': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@types/eslint@9.6.1': dependencies: '@types/estree': 1.0.8 @@ -7384,6 +7570,8 @@ snapshots: '@types/lodash@4.17.21': {} + '@types/minimist@1.2.5': {} + '@types/ms@2.1.0': {} '@types/node@12.20.55': {} @@ -7392,6 +7580,8 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/normalize-package-data@2.4.4': {} + '@types/qs@6.14.0': {} '@types/range-parser@1.2.7': {} @@ -7920,6 +8110,8 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + arrify@1.0.1: {} + assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} @@ -8089,6 +8281,12 @@ snapshots: callsites@3.1.0: {} + camelcase-keys@6.2.2: + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + camelcase@5.3.1: {} camelcase@6.3.0: {} @@ -8357,6 +8555,13 @@ snapshots: dependencies: ms: 2.1.3 + decamelize-keys@1.1.1: + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + + decamelize@1.2.0: {} + dedent@1.7.1: {} deep-is@0.1.4: {} @@ -8598,6 +8803,17 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) semver: 7.7.3 + eslint-formatter-pretty@4.1.0: + dependencies: + '@types/eslint': 7.29.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + eslint-rule-docs: 1.1.235 + log-symbols: 4.1.0 + plur: 4.0.0 + string-width: 4.2.3 + supports-hyperlinks: 2.3.0 + eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: get-tsconfig: 4.13.0 @@ -8910,6 +9126,8 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) turbo: 2.6.3 + eslint-rule-docs@1.1.235: {} + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -9372,6 +9590,8 @@ snapshots: graphemer@1.4.0: {} + hard-rejection@2.1.0: {} + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -9402,6 +9622,12 @@ snapshots: dependencies: hermes-estree: 0.25.1 + hosted-git-info@2.8.9: {} + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + html-escaper@2.0.2: {} http-errors@2.0.1: @@ -9440,6 +9666,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -9473,6 +9701,8 @@ snapshots: ipaddr.js@1.9.1: {} + irregular-plurals@3.5.0: {} + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -9562,6 +9792,8 @@ snapshots: is-number@7.0.0: {} + is-plain-obj@1.1.0: {} + is-promise@4.0.0: {} is-regex@1.2.1: @@ -9602,6 +9834,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-unicode-supported@0.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -10018,6 +10252,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kind-of@6.0.3: {} + kleur@3.0.3: {} language-subtag-registry@0.3.23: {} @@ -10092,6 +10328,11 @@ snapshots: lodash@4.17.21: {} + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + log-update@6.1.0: dependencies: ansi-escapes: 7.2.0 @@ -10104,6 +10345,10 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -10116,6 +10361,10 @@ snapshots: dependencies: tmpl: 1.0.5 + map-obj@1.0.1: {} + + map-obj@4.3.0: {} + math-intrinsics@1.1.0: {} mdn-data@2.23.0: {} @@ -10125,6 +10374,21 @@ snapshots: media-typer@1.1.0: {} + meow@9.0.0: + dependencies: + '@types/minimist': 1.2.5 + camelcase-keys: 6.2.2 + decamelize: 1.2.0 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -10154,6 +10418,8 @@ snapshots: mimic-function@5.0.1: {} + min-indent@1.0.1: {} + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -10166,6 +10432,12 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimist-options@4.1.0: + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + minimist@1.2.8: {} mkdirp@0.5.6: @@ -10236,6 +10508,20 @@ snapshots: node-releases@2.0.27: {} + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.11 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-package-data@3.0.3: + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.16.1 + semver: 7.7.3 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} npm-run-path@2.0.2: @@ -10469,6 +10755,10 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 + plur@4.0.0: + dependencies: + irregular-plurals: 3.5.0 + possible-typed-array-names@1.1.0: {} postcss-import@16.1.1(postcss@8.5.6): @@ -10563,6 +10853,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-lru@4.0.1: {} + railroad-diagrams@1.0.0: {} randexp@0.4.6: @@ -10588,6 +10880,19 @@ snapshots: dependencies: pify: 2.3.0 + read-pkg-up@7.0.1: + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + + read-pkg@5.2.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -10608,6 +10913,11 @@ snapshots: dependencies: resolve: 1.22.11 + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + redis-errors@1.2.0: {} redis-parser@3.0.0: @@ -10952,6 +11262,20 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.22 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-license-ids@3.0.22: {} + split2@4.2.0: {} sprintf-js@1.0.3: {} @@ -11067,6 +11391,10 @@ snapshots: strip-final-newline@2.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} strtok3@10.3.4: @@ -11091,6 +11419,11 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} synckit@0.11.11: @@ -11166,6 +11499,8 @@ snapshots: tree-kill@1.2.2: {} + trim-newlines@3.0.1: {} + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -11202,6 +11537,16 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tsd@0.33.0: + dependencies: + '@tsd/typescript': 5.9.3 + eslint-formatter-pretty: 4.1.0 + globby: 11.1.0 + jest-diff: 29.7.0 + meow: 9.0.0 + path-exists: 4.0.0 + read-pkg-up: 7.0.1 + tslib@2.8.1: {} tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.2): @@ -11293,12 +11638,18 @@ snapshots: type-detect@4.0.8: {} + type-fest@0.18.1: {} + type-fest@0.20.2: {} type-fest@0.21.3: {} + type-fest@0.6.0: {} + type-fest@0.7.1: {} + type-fest@0.8.1: {} + type-fest@2.19.0: {} type-fest@4.41.0: {} @@ -11444,6 +11795,11 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + vary@1.1.2: {} vite-tsconfig-paths@6.0.2(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)): @@ -11632,8 +11988,12 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yaml@2.8.2: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} yargs@17.7.2: From 5eec5cd8782d76364ca9c35ecb3d9a70ae703fe6 Mon Sep 17 00:00:00 2001 From: Hossein Pourdavar Date: Thu, 19 Feb 2026 11:08:51 +0330 Subject: [PATCH 2/4] refactor(ddd): simplify Immutable type using DeepImmutable Replace the previous implementation of the Immutable type with the newly introduced DeepImmutable type for improved clarity and maintainability. This change enhances type safety while preserving the functionality of marking types as immutable. --- packages/ddd/src/domain/entities/entity.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/ddd/src/domain/entities/entity.ts b/packages/ddd/src/domain/entities/entity.ts index e6afbe2..ef15c01 100644 --- a/packages/ddd/src/domain/entities/entity.ts +++ b/packages/ddd/src/domain/entities/entity.ts @@ -1,22 +1,13 @@ import { deepFreeze } from '@/utils'; +import { DeepImmutable } from '../types/deep-immutable.type'; import { EntityId } from '../types'; // export type Immutable = { // readonly [K in keyof T]: Immutable; // }; -export type Immutable = T extends (...args: any[]) => any - ? T - : T extends Date - ? T - : T extends Map - ? ReadonlyMap, Immutable> - : T extends Set - ? ReadonlySet> - : T extends object - ? { readonly [K in keyof T]: Immutable } - : T; +export type Immutable = DeepImmutable; /** * Configuration for the base Entity constructor. From 3efe26f54152966d7a2e19fec5e25f2f4048c235 Mon Sep 17 00:00:00 2001 From: Hossein Pourdavar Date: Thu, 19 Feb 2026 11:16:48 +0330 Subject: [PATCH 3/4] feat(ci): add type testing to CI workflow Introduce a new "Type Tests" job in the CI workflow that runs `pnpm run test:types`. Added a corresponding script and turbo task for type testing, enhancing the testing capabilities of the project. --- .changeset/ci-and-testing-improvements.md | 10 ++++++++++ .github/workflows/ci.yml | 13 +++++++++++++ package.json | 1 + turbo.json | 4 ++++ 4 files changed, 28 insertions(+) create mode 100644 .changeset/ci-and-testing-improvements.md diff --git a/.changeset/ci-and-testing-improvements.md b/.changeset/ci-and-testing-improvements.md new file mode 100644 index 0000000..8caca35 --- /dev/null +++ b/.changeset/ci-and-testing-improvements.md @@ -0,0 +1,10 @@ +--- +'@rineex/ddd': patch +--- + +### CI and Testing Improvements + +- Added a new "Type Tests" job that runs `pnpm run test:types` in the CI + workflow. +- Introduced a new script "test:types" and turbo task with inputs for + `src/**/*.test-d.ts` for type testing. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72aa93c..3cd89ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,19 @@ jobs: - name: Run Tests run: pnpm run test + type-tests: + name: Type Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Tools + uses: ./.github/setup + - name: Run Type Tests + run: pnpm run test:types + build: name: Build runs-on: ubuntu-latest diff --git a/package.json b/package.json index 302de1e..28a0a7e 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", "test": "turbo run test", + "test:types": "turbo run test:types", "test:ci": "turbo run test build", "check-types": "turbo run check-types", "prepublish": "pnpm run build", diff --git a/turbo.json b/turbo.json index 38a3fb7..d4a757d 100644 --- a/turbo.json +++ b/turbo.json @@ -13,6 +13,10 @@ "inputs": ["$TURBO_DEFAULT$", "src/**/*.test.ts", "src/**/*.test.tsx"], "outputs": ["coverage/**"] }, + "test:types": { + "inputs": ["$TURBO_DEFAULT$", "src/**/*.test-d.ts"], + "outputs": [] + }, "lint": { "dependsOn": ["^lint"], "inputs": ["$TURBO_DEFAULT$"] From de635b527c2d355687f5c9b3da7ff84216a801e1 Mon Sep 17 00:00:00 2001 From: Hossein Pourdavar Date: Thu, 19 Feb 2026 11:25:51 +0330 Subject: [PATCH 4/4] fix(turbo): add build dependency to type testing task Update the "test:types" task in turbo.json to depend on the "build" task, ensuring that type tests are run after the build process, improving the reliability of type checking in the CI workflow. --- turbo.json | 1 + 1 file changed, 1 insertion(+) diff --git a/turbo.json b/turbo.json index d4a757d..68e9b56 100644 --- a/turbo.json +++ b/turbo.json @@ -14,6 +14,7 @@ "outputs": ["coverage/**"] }, "test:types": { + "dependsOn": ["build"], "inputs": ["$TURBO_DEFAULT$", "src/**/*.test-d.ts"], "outputs": [] },