From 3eb23eb27a7722274bd2f9cd35c75d2d61fc2fbd Mon Sep 17 00:00:00 2001 From: Puechberty Arthur Date: Mon, 13 Apr 2026 19:42:38 +0200 Subject: [PATCH] reorganizage du projet et mise en place d'un vrai build --- .dockerignore | 2 +- .gitignore | 2 +- AGENT.md | 15 +- Dockerfile | 7 +- README.md | 14 +- package-lock.json | 683 +++++++++++++++--- package.json | 8 +- scripts/build.mjs | 45 ++ src/commands/memberMessagePanel.ts | 2 +- src/events/guildMemberAdd.ts | 2 +- src/events/guildMemberRemove.ts | 2 +- src/events/index.ts | 2 +- src/events/ready.ts | 2 +- src/framework/commands/deploy.ts | 2 +- src/framework/commands/registry.ts | 2 +- src/framework/commands/slashBuilder.ts | 2 +- .../handlers/commandExecutionContext.ts | 2 +- src/framework/i18n/I18nService.ts | 140 ---- .../memberMessages/memberMessageSender.ts | 2 +- {locales => src/i18n}/en.json | 0 {locales => src/i18n}/es.json | 0 {locales => src/i18n}/fr.json | 0 src/i18n/index.ts | 155 ++++ src/index.ts | 2 +- src/scripts/deployCommands.ts | 25 - {src/tests => tests}/argTokenizer.test.ts | 4 +- {src/tests => tests}/defineCommand.test.ts | 2 +- {src/tests => tests}/presenceTypes.test.ts | 2 +- .../tests => tests}/templateVariables.test.ts | 2 +- tsconfig.json | 2 +- 30 files changed, 823 insertions(+), 307 deletions(-) create mode 100644 scripts/build.mjs delete mode 100644 src/framework/i18n/I18nService.ts rename {locales => src/i18n}/en.json (100%) rename {locales => src/i18n}/es.json (100%) rename {locales => src/i18n}/fr.json (100%) create mode 100644 src/i18n/index.ts delete mode 100644 src/scripts/deployCommands.ts rename {src/tests => tests}/argTokenizer.test.ts (80%) rename {src/tests => tests}/defineCommand.test.ts (93%) rename {src/tests => tests}/presenceTypes.test.ts (96%) rename {src/tests => tests}/templateVariables.test.ts (95%) diff --git a/.dockerignore b/.dockerignore index 26898c5..9e29168 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ node_modules -dist +build .git .gitignore .env diff --git a/.gitignore b/.gitignore index af0670d..7c14924 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules/ -dist/ +build/ .env .env.* !.env.example diff --git a/AGENT.md b/AGENT.md index d50bca3..3bda19f 100644 --- a/AGENT.md +++ b/AGENT.md @@ -8,22 +8,19 @@ Ce fichier décrit le projet, sa structure, les conventions de code et la procé Vue d'ensemble du projet ----------------------- -- Tech stack: TypeScript + Discord.js (bot template). Le code source est dans `src/` et la sortie build dans `dist/` (à ignorer). -- Localisation: `locales/` contient `en.json`, `fr.json`, `es.json`. -- Scripts utiles: `scripts/deployCommands.ts` pour (re)déployer les slash commands. +- Tech stack: TypeScript + Discord.js (bot template). Le code source est dans `src/` et la sortie build dans `build/` (à ignorer). +- Localisation: `src/i18n/` contient `en.json`, `fr.json`, `es.json`. Organisation des fichiers ------------------------ - Racine: - `package.json`, `tsconfig.json`, `Dockerfile`, `docker-compose.yml` — scripts et infra. - - `locales/` — fichiers de traduction. - `src/` (code TypeScript): - `index.ts` — point d'entrée, boot du bot. - `commands/` — définitions de commandes (chaque fichier expose une commande). - `events/` — un fichier par événement Discord (ex: `guildMemberAdd.ts`). `src/events/index.ts` centralise l'enregistrement. - `framework/` — bibliothèque interne: helpers commandes, `i18n/`, `memberMessages/`, `presence/`, `execution/`, `handlers/`, `config/`, `types/`. - `utils/` — helpers génériques (ex: `templateVariables.ts`). - - `scripts/` — utilitaires (ex: `deployCommands.ts`). - `tests/` — tests unitaires ciblant managers, stores et utilitaires. Principes et conventions de code @@ -33,7 +30,7 @@ Principes et conventions de code - Events: un seul fichier par événement; exporter une fonction `registerX(client, i18n)` ou une fonction d'enregistrement équivalente. Centraliser les imports dans `src/events/index.ts`. - Typage: utiliser TypeScript strict, signatures fortement typées pour les handlers (`onPrefixMessage(message: Message)` etc.). - Tests: privilégier les tests unitaires pour managers/stores/transformations. Mockez les adaptateurs Discord. -- i18n: utiliser `I18nService` pour traductions. Ajouter toutes les clés dans `locales/*.json`. +- i18n: utiliser `I18nService` pour traductions. Ajouter toutes les clés dans `src/i18n/*.json`. - Nommage: fichiers en lowerCamelCase (ex: `welcome.ts`, `memberMessagePanel.ts`). Exports nommés préférés pour faciliter le mocking. - Sécurité: ne pas committer de secrets (`.env*` doit être dans `.gitignore`). @@ -42,9 +39,9 @@ Procédure standard pour ajouter une nouvelle commande 1. Créer le fichier dans `src/commands/myCommand.ts`. 2. Utiliser `defineCommand({ meta, args, examples, execute })` pour déclarer la commande. 3. Implémenter `execute()` de façon minimale: valider les args et appeler un service dans `src/framework/` si la logique est non triviale. -4. Ajouter les clés de traduction dans `locales/en.json`, `locales/fr.json`, `locales/es.json` (ex: `commands.myCommand.success`). +4. Ajouter les clés de traduction dans `src/i18n/en.json`, `src/i18n/fr.json`, `src/i18n/es.json` (ex: `commands.myCommand.success`). 5. Écrire des tests unitaires dans `tests/` pour le service/manager; si la commande est juste un wrapper, testez le service. -6. Si c'est une slash command, vérifier que `scripts/deployCommands.ts`/le registre inclut la commande; exécuter le déploiement si nécessaire. +6. Si c'est une slash command, vérifier que le registre inclut la commande; redémarrer le bot avec `AUTO_DEPLOY_SLASH=true` si synchronisation nécessaire. 7. Lancer `npm run build` puis `npm test` (ou la suite de scripts définie dans `package.json`). 8. Ouvrir une PR documentant le changement et incluant les tests et les traductions. @@ -75,7 +72,7 @@ Tests et CI Déploiement / exécution ----------------------- - Utiliser `Dockerfile` / `docker-compose.yml` fournis pour le déploiement en conteneur. -- Pour les slash commands, exécuter `scripts/deployCommands.ts` (ou le script npm associé). +- Pour les slash commands, activer `AUTO_DEPLOY_SLASH=true` pour une synchronisation automatique au démarrage. Revue et PR ----------- diff --git a/Dockerfile b/Dockerfile index 2e158ec..cdd83b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,8 +6,8 @@ COPY package.json package-lock.json ./ RUN npm ci COPY tsconfig.json ./ +COPY scripts ./scripts COPY src ./src -COPY locales ./locales RUN npm run build @@ -19,7 +19,6 @@ ENV NODE_ENV=production COPY package.json package-lock.json ./ RUN npm ci --omit=dev -COPY --from=builder /app/dist ./dist -COPY locales ./locales +COPY --from=builder /app/build ./build -CMD ["node", "dist/index.js"] +CMD ["node", "build/index.js"] diff --git a/README.md b/README.md index 0491d95..c69f797 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ Professional command framework template for Discord.js `14.26.2` with: 4. Optional values: - `DATABASE_SSL` (`true` for managed cloud DB, `false` for local Docker) - `PRESENCE_STREAM_URL` (used when activity type is `STREAMING`) -5. Deploy slash commands: - npm run deploy:commands -6. Start in development: + - `AUTO_DEPLOY_SLASH` (`true` to sync slash commands on startup) + - `DEV_GUILD_ID` (optional guild scope for faster slash sync) +5. Start in development: npm run dev -7. Validate code quality: +6. Validate code quality: - npm run typecheck - npm run test - npm run check @@ -81,14 +81,14 @@ An example with two bot services is available in `docker-compose.multi-bot.examp - `src/framework/types/command.ts`: strict command schema - `src/framework/commands/defineCommand.ts`: default command completion -- `src/framework/commands/registry.ts`: trigger/name mapping generated from locales +- `src/framework/commands/registry.ts`: trigger/name mapping generated from i18n dictionaries - `src/framework/commands/argParser.ts`: prefix/slash args parsing from schema - `src/framework/execution/CommandExecutor.ts`: unified pipeline (permissions/cooldown/execute) - `src/framework/handlers/prefixHandler.ts`: prefix entrypoint - `src/framework/handlers/slashHandler.ts`: slash entrypoint - `src/framework/presence/presenceStore.ts`: PostgreSQL presence storage - `src/framework/presence/presenceTypes.ts`: shared presence types/validation -- `locales/*.json`: external i18n dictionaries +- `src/i18n/*.json`: external i18n dictionaries - `src/commands/*`: business commands only (`execute`, optional `cooldown`) ## Included Commands @@ -104,4 +104,4 @@ An example with two bot services is available in `docker-compose.multi-bot.examp 1. Create a command object in `src/commands/...` 2. Follow the schema in `src/framework/types/command.ts` 3. Add command to `src/commands/index.ts` -4. Deploy slash commands again (`npm run deploy:commands`) +4. If `AUTO_DEPLOY_SLASH=true`, restart the bot to sync slash commands automatically diff --git a/package-lock.json b/package-lock.json index 1c2b415..76b6d8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "devDependencies": { "@types/node": "20.17.24", "@types/pg": "^8.20.0", + "esbuild": "^0.25.12", "tsx": "4.19.2", "typescript": "5.8.2" }, @@ -165,9 +166,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -182,9 +183,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -199,9 +200,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -216,9 +217,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -233,9 +234,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -250,9 +251,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -267,9 +268,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -284,9 +285,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -301,9 +302,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -318,9 +319,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -335,9 +336,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -352,9 +353,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -369,9 +370,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -386,9 +387,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -403,9 +404,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -420,9 +421,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -437,9 +438,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -453,10 +454,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -471,9 +489,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -488,9 +506,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -504,10 +522,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -522,9 +557,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -539,9 +574,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -556,9 +591,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -943,9 +978,9 @@ } }, "node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -956,30 +991,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/fast-deep-equal": { @@ -1214,6 +1251,454 @@ "fsevents": "~2.3.3" } }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/typescript": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", diff --git a/package.json b/package.json index e08600b..395a986 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,11 @@ }, "scripts": { "dev": "tsx watch src/index.ts", - "build": "tsc -p tsconfig.json", + "build": "npm run typecheck && node scripts/build.mjs", "typecheck": "tsc -p tsconfig.json --noEmit", - "test": "node --import tsx --test src/**/*.test.ts", + "test": "node --import tsx --test tests/**/*.test.ts", "check": "npm run typecheck && npm run test", - "start": "node dist/index.js", - "deploy:commands": "tsx src/scripts/deployCommands.ts" + "start": "node build/index.js" }, "dependencies": { "@napi-rs/canvas": "^0.1.97", @@ -25,6 +24,7 @@ "devDependencies": { "@types/node": "20.17.24", "@types/pg": "^8.20.0", + "esbuild": "^0.25.12", "tsx": "4.19.2", "typescript": "5.8.2" } diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..21316f6 --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,45 @@ +import { cp, mkdir, readdir, rm } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { build } from "esbuild"; + +const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url)); +const ROOT_DIR = path.resolve(SCRIPT_DIR, ".."); +const OUTPUT_DIR = path.join(ROOT_DIR, "build"); +const SOURCE_I18N_DIR = path.join(ROOT_DIR, "src", "i18n"); +const OUTPUT_I18N_DIR = path.join(OUTPUT_DIR, "i18n"); + +const main = async () => { + await rm(OUTPUT_DIR, { recursive: true, force: true }); + + await build({ + absWorkingDir: ROOT_DIR, + entryPoints: ["src/index.ts"], + outfile: "build/index.js", + bundle: true, + packages: "external", + minify: true, + legalComments: "none", + platform: "node", + format: "esm", + target: ["node18"], + tsconfig: "tsconfig.json", + logLevel: "info", + }); + + await mkdir(OUTPUT_I18N_DIR, { recursive: true }); + const localeEntries = await readdir(SOURCE_I18N_DIR, { withFileTypes: true }); + for (const entry of localeEntries) { + if (!entry.isFile() || !entry.name.endsWith(".json")) { + continue; + } + + await cp(path.join(SOURCE_I18N_DIR, entry.name), path.join(OUTPUT_I18N_DIR, entry.name), { force: true }); + } +}; + +main().catch((error) => { + console.error("[build] failed", error); + process.exit(1); +}); diff --git a/src/commands/memberMessagePanel.ts b/src/commands/memberMessagePanel.ts index 3e8eaf9..402fc04 100644 --- a/src/commands/memberMessagePanel.ts +++ b/src/commands/memberMessagePanel.ts @@ -23,7 +23,7 @@ import { } from "discord.js"; import { env } from "../framework/config/env.js"; -import { I18nService } from "../framework/i18n/I18nService.js"; +import { I18nService } from "../i18n/index.js"; import { dispatchMemberMessage } from "../framework/memberMessages/memberMessageSender.js"; import { getMemberMessageStore } from "../framework/memberMessages/memberMessageStore.js"; import { diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index 415b19f..107d8ca 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -1,5 +1,5 @@ import { Events, type Client } from "discord.js"; -import type { I18nService } from "../framework/i18n/I18nService.js"; +import type { I18nService } from "../i18n/index.js"; import { dispatchMemberMessage } from "../framework/memberMessages/memberMessageSender.js"; /** diff --git a/src/events/guildMemberRemove.ts b/src/events/guildMemberRemove.ts index 6fc7933..d941ea4 100644 --- a/src/events/guildMemberRemove.ts +++ b/src/events/guildMemberRemove.ts @@ -1,5 +1,5 @@ import { Events, type Client } from "discord.js"; -import type { I18nService } from "../framework/i18n/I18nService.js"; +import type { I18nService } from "../i18n/index.js"; import { dispatchMemberMessage } from "../framework/memberMessages/memberMessageSender.js"; /** diff --git a/src/events/index.ts b/src/events/index.ts index ab08aba..a7f1725 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -1,5 +1,5 @@ import type { Client, Message, ChatInputCommandInteraction } from "discord.js"; -import type { I18nService } from "../framework/i18n/I18nService.js"; +import type { I18nService } from "../i18n/index.js"; import { registerMessageCreate } from "./messageCreate.js"; import { registerInteractionCreate } from "./interactionCreate.js"; diff --git a/src/events/ready.ts b/src/events/ready.ts index 3c228d6..3f9c6e3 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -3,7 +3,7 @@ import { deployApplicationCommands } from "../framework/commands/deploy.js"; import { env } from "../framework/config/env.js"; import { restorePresenceFromStorage } from "../commands/presence.js"; import type { CommandRegistry } from "../framework/commands/registry.js"; -import type { I18nService } from "../framework/i18n/I18nService.js"; +import type { I18nService } from "../i18n/index.js"; /** * Attache le listener `ready` et exécute les tâches post-démarrage: diff --git a/src/framework/commands/deploy.ts b/src/framework/commands/deploy.ts index a22083d..4e108ec 100644 --- a/src/framework/commands/deploy.ts +++ b/src/framework/commands/deploy.ts @@ -2,7 +2,7 @@ import { REST, Routes } from "discord.js"; import { buildSlashPayload } from "./slashBuilder.js"; import type { CommandRegistry } from "./registry.js"; -import type { I18nService } from "../i18n/I18nService.js"; +import type { I18nService } from "../../i18n/index.js"; export interface DeployCommandsOptions { token: string; diff --git a/src/framework/commands/registry.ts b/src/framework/commands/registry.ts index 9a68bc1..23200f9 100644 --- a/src/framework/commands/registry.ts +++ b/src/framework/commands/registry.ts @@ -1,6 +1,6 @@ import type { BotCommand, PrefixTriggerMatch } from "../types/command.js"; import { SUPPORTED_LANGS } from "../types/command.js"; -import type { I18nService } from "../i18n/I18nService.js"; +import type { I18nService } from "../../i18n/index.js"; const normalize = (value: string): string => value.trim().toLowerCase(); diff --git a/src/framework/commands/slashBuilder.ts b/src/framework/commands/slashBuilder.ts index 74ee7a1..30099af 100644 --- a/src/framework/commands/slashBuilder.ts +++ b/src/framework/commands/slashBuilder.ts @@ -5,7 +5,7 @@ import { } from "discord.js"; import type { BotCommand, CommandArgument, SupportedLang } from "../types/command.js"; -import type { I18nService } from "../i18n/I18nService.js"; +import type { I18nService } from "../../i18n/index.js"; const LANG_TO_DISCORD_LOCALE: Record = { en: "en-US", diff --git a/src/framework/handlers/commandExecutionContext.ts b/src/framework/handlers/commandExecutionContext.ts index 298ca55..f0e36d5 100644 --- a/src/framework/handlers/commandExecutionContext.ts +++ b/src/framework/handlers/commandExecutionContext.ts @@ -1,5 +1,5 @@ import type { CommandRegistry } from "../commands/registry.js"; -import type { I18nService } from "../i18n/I18nService.js"; +import type { I18nService } from "../../i18n/index.js"; import type { BotCommand, CommandExecutionContext, diff --git a/src/framework/i18n/I18nService.ts b/src/framework/i18n/I18nService.ts deleted file mode 100644 index 66f41e9..0000000 --- a/src/framework/i18n/I18nService.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { SUPPORTED_LANGS, type SupportedLang, type TranslationVars } from "../types/command.js"; - -type JsonObject = Record; - -const DISCORD_LOCALE_MAP: Record = { - en: "en", - "en-us": "en", - "en-gb": "en", - fr: "fr", - "fr-fr": "fr", - es: "es", - "es-es": "es", - "es-419": "es", -}; - -const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)); -const LOCALES_DIR = path.resolve(CURRENT_DIR, "../../../locales"); - -export class I18nService { - private readonly dictionaries: Record; - - public constructor(private readonly defaultLang: SupportedLang) { - this.dictionaries = this.loadDictionaries(); - } - - public resolveLang(input?: string | null): SupportedLang { - if (!input) { - return this.defaultLang; - } - - const normalized = input.toLowerCase(); - - const direct = DISCORD_LOCALE_MAP[normalized]; - if (direct) { - return direct; - } - - const short = normalized.split("-")[0]; - const fromShort = short ? DISCORD_LOCALE_MAP[short] : undefined; - if (fromShort) { - return fromShort; - } - - return this.defaultLang; - } - - public t(lang: SupportedLang, key: string, vars: TranslationVars = {}): string { - const fromLang = this.lookup(this.dictionaries[lang], key); - const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); - - const template = typeof fromLang === "string" ? fromLang : typeof fromDefault === "string" ? fromDefault : key; - - return this.format(template, vars); - } - - public commandT(lang: SupportedLang, commandName: string, relativeKey: string, vars: TranslationVars = {}): string { - return this.t(lang, `${this.commandBaseKey(commandName)}.${relativeKey}`, vars); - } - - public commandName(lang: SupportedLang, commandName: string): string { - const key = `${this.commandBaseKey(commandName)}.name`; - const fromLang = this.lookup(this.dictionaries[lang], key); - if (typeof fromLang === "string" && fromLang.length > 0) { - return fromLang; - } - - const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); - if (typeof fromDefault === "string" && fromDefault.length > 0) { - return fromDefault; - } - - return commandName; - } - - public commandTrigger(lang: SupportedLang, commandName: string): string { - return this.commandName(lang, commandName).trim().toLowerCase(); - } - - public commandObject(lang: SupportedLang, commandName: string): Record { - const key = this.commandBaseKey(commandName); - const fromLang = this.lookup(this.dictionaries[lang], key); - if (this.isObject(fromLang)) { - return fromLang; - } - - const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); - if (this.isObject(fromDefault)) { - return fromDefault; - } - - return {}; - } - - public format(template: string, vars: TranslationVars = {}): string { - return this.interpolate(template, vars); - } - - private loadDictionaries(): Record { - return SUPPORTED_LANGS.reduce>((acc, lang) => { - const filePath = path.join(LOCALES_DIR, `${lang}.json`); - const raw = readFileSync(filePath, "utf-8"); - acc[lang] = JSON.parse(raw) as JsonObject; - return acc; - }, {} as Record); - } - - private lookup(source: JsonObject, key: string): unknown { - const parts = key.split("."); - let current: unknown = source; - - for (const part of parts) { - if (!current || typeof current !== "object" || Array.isArray(current)) { - return undefined; - } - - current = (current as JsonObject)[part]; - } - - return current; - } - - private commandBaseKey(commandName: string): string { - return `commands.${commandName}`; - } - - private isObject(value: unknown): value is Record { - return Boolean(value) && typeof value === "object" && !Array.isArray(value); - } - - private interpolate(template: string, vars: TranslationVars): string { - return template.replace(/\{\{(\w+)\}\}/g, (_, variable: string) => { - const value = vars[variable]; - return value === undefined || value === null ? "" : String(value); - }); - } -} diff --git a/src/framework/memberMessages/memberMessageSender.ts b/src/framework/memberMessages/memberMessageSender.ts index 40c2a07..15f08ca 100644 --- a/src/framework/memberMessages/memberMessageSender.ts +++ b/src/framework/memberMessages/memberMessageSender.ts @@ -11,7 +11,7 @@ import { type User, } from "discord.js"; -import type { I18nService } from "../i18n/I18nService.js"; +import type { I18nService } from "../../i18n/index.js"; import type { SupportedLang } from "../types/command.js"; import { renderMemberMessageImage } from "./memberMessageImage.js"; import { getMemberMessageStore } from "./memberMessageStore.js"; diff --git a/locales/en.json b/src/i18n/en.json similarity index 100% rename from locales/en.json rename to src/i18n/en.json diff --git a/locales/es.json b/src/i18n/es.json similarity index 100% rename from locales/es.json rename to src/i18n/es.json diff --git a/locales/fr.json b/src/i18n/fr.json similarity index 100% rename from locales/fr.json rename to src/i18n/fr.json diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..f08589a --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,155 @@ +import { existsSync, readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { SUPPORTED_LANGS, type SupportedLang, type TranslationVars } from "../framework/types/command.js"; + +type JsonObject = Record; + +const DISCORD_LOCALE_MAP: Record = { + en: "en", + "en-us": "en", + "en-gb": "en", + fr: "fr", + "fr-fr": "fr", + es: "es", + "es-es": "es", + "es-419": "es", +}; + +const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)); +const LOCALE_DIR_CANDIDATES = [ + CURRENT_DIR, + path.resolve(process.cwd(), "src", "i18n"), + path.resolve(process.cwd(), "build", "i18n"), +]; + +const resolveLocaleFilePath = (lang: SupportedLang): string => { + for (const directory of LOCALE_DIR_CANDIDATES) { + const filePath = path.join(directory, `${lang}.json`); + if (existsSync(filePath)) { + return filePath; + } + } + + throw new Error(`[i18n] missing locale file for "${lang}"`); +}; + +export class I18nService { + private readonly dictionaries: Record; + + public constructor(private readonly defaultLang: SupportedLang) { + this.dictionaries = this.loadDictionaries(); + } + + public resolveLang(input?: string | null): SupportedLang { + if (!input) { + return this.defaultLang; + } + + const normalized = input.toLowerCase(); + + const direct = DISCORD_LOCALE_MAP[normalized]; + if (direct) { + return direct; + } + + const short = normalized.split("-")[0]; + const fromShort = short ? DISCORD_LOCALE_MAP[short] : undefined; + if (fromShort) { + return fromShort; + } + + return this.defaultLang; + } + + public t(lang: SupportedLang, key: string, vars: TranslationVars = {}): string { + const fromLang = this.lookup(this.dictionaries[lang], key); + const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); + + const template = typeof fromLang === "string" ? fromLang : typeof fromDefault === "string" ? fromDefault : key; + + return this.format(template, vars); + } + + public commandT(lang: SupportedLang, commandName: string, relativeKey: string, vars: TranslationVars = {}): string { + return this.t(lang, `${this.commandBaseKey(commandName)}.${relativeKey}`, vars); + } + + public commandName(lang: SupportedLang, commandName: string): string { + const key = `${this.commandBaseKey(commandName)}.name`; + const fromLang = this.lookup(this.dictionaries[lang], key); + if (typeof fromLang === "string" && fromLang.length > 0) { + return fromLang; + } + + const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); + if (typeof fromDefault === "string" && fromDefault.length > 0) { + return fromDefault; + } + + return commandName; + } + + public commandTrigger(lang: SupportedLang, commandName: string): string { + return this.commandName(lang, commandName).trim().toLowerCase(); + } + + public commandObject(lang: SupportedLang, commandName: string): Record { + const key = this.commandBaseKey(commandName); + const fromLang = this.lookup(this.dictionaries[lang], key); + if (this.isObject(fromLang)) { + return fromLang; + } + + const fromDefault = this.lookup(this.dictionaries[this.defaultLang], key); + if (this.isObject(fromDefault)) { + return fromDefault; + } + + return {}; + } + + public format(template: string, vars: TranslationVars = {}): string { + return this.interpolate(template, vars); + } + + private loadDictionaries(): Record { + return SUPPORTED_LANGS.reduce>((acc, lang) => { + const filePath = resolveLocaleFilePath(lang); + const raw = readFileSync(filePath, "utf-8"); + acc[lang] = JSON.parse(raw) as JsonObject; + return acc; + }, {} as Record); + } + + private lookup(source: JsonObject, key: string): unknown { + const parts = key.split("."); + let current: unknown = source; + + for (const part of parts) { + if (!current || typeof current !== "object" || Array.isArray(current)) { + return undefined; + } + + current = (current as JsonObject)[part]; + } + + return current; + } + + private commandBaseKey(commandName: string): string { + return `commands.${commandName}`; + } + + private isObject(value: unknown): value is Record { + return Boolean(value) && typeof value === "object" && !Array.isArray(value); + } + + private interpolate(template: string, vars: TranslationVars): string { + return template.replace(/\{\{(\w+)\}\}/g, (_, variable: string) => { + const value = vars[variable]; + return value === undefined || value === null ? "" : String(value); + }); + } +} diff --git a/src/index.ts b/src/index.ts index 183efc6..0a39444 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ import { env } from "./framework/config/env.js"; import { CommandExecutor } from "./framework/execution/CommandExecutor.js"; import { createPrefixHandler } from "./framework/handlers/prefixHandler.js"; import { createSlashHandler } from "./framework/handlers/slashHandler.js"; -import { I18nService } from "./framework/i18n/I18nService.js"; +import { I18nService } from "./i18n/index.js"; import { initMemberMessageStore, shutdownMemberMessageStore, diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts deleted file mode 100644 index 9496b45..0000000 --- a/src/scripts/deployCommands.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { commandList } from "../commands/index.js"; -import { deployApplicationCommands } from "../framework/commands/deploy.js"; -import { CommandRegistry } from "../framework/commands/registry.js"; -import { env } from "../framework/config/env.js"; -import { I18nService } from "../framework/i18n/I18nService.js"; - -const main = async (): Promise => { - const i18n = new I18nService(env.DEFAULT_LANG); - const registry = new CommandRegistry(commandList, i18n); - - const result = await deployApplicationCommands({ - token: env.DISCORD_TOKEN, - clientId: env.DISCORD_CLIENT_ID, - registry, - i18n, - ...(env.DEV_GUILD_ID ? { guildId: env.DEV_GUILD_ID } : {}), - }); - - console.log(`[deploy] ${result.count} commands deployed (${result.scope})`); -}; - -main().catch((error) => { - console.error("[deploy] failed", error); - process.exitCode = 1; -}); diff --git a/src/tests/argTokenizer.test.ts b/tests/argTokenizer.test.ts similarity index 80% rename from src/tests/argTokenizer.test.ts rename to tests/argTokenizer.test.ts index 7262813..94e4939 100644 --- a/src/tests/argTokenizer.test.ts +++ b/tests/argTokenizer.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { tokenizePrefixInput } from "../framework/commands/argParser.js"; +import { tokenizePrefixInput } from "../src/framework/commands/argParser.js"; test("tokenizePrefixInput parse les quotes simples et doubles", () => { const tokens = tokenizePrefixInput('"hello world" test \'foo bar\''); @@ -14,6 +14,6 @@ test("tokenizePrefixInput conserve les tokens non quotes", () => { }); test("tokenizePrefixInput gere les quotes echappees", () => { - const tokens = tokenizePrefixInput('"say \\\"hello\\\"" done'); + const tokens = tokenizePrefixInput('"say \\"hello\\"" done'); assert.deepEqual(tokens, ['say "hello"', "done"]); }); diff --git a/src/tests/defineCommand.test.ts b/tests/defineCommand.test.ts similarity index 93% rename from src/tests/defineCommand.test.ts rename to tests/defineCommand.test.ts index 119d833..f8cd76f 100644 --- a/src/tests/defineCommand.test.ts +++ b/tests/defineCommand.test.ts @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { defineCommand } from "../framework/commands/defineCommand.js"; +import { defineCommand } from "../src/framework/commands/defineCommand.js"; test("defineCommand refuse un argument requis apres un optionnel", () => { assert.throws(() => { diff --git a/src/tests/presenceTypes.test.ts b/tests/presenceTypes.test.ts similarity index 96% rename from src/tests/presenceTypes.test.ts rename to tests/presenceTypes.test.ts index f033c8b..dbbffda 100644 --- a/src/tests/presenceTypes.test.ts +++ b/tests/presenceTypes.test.ts @@ -8,7 +8,7 @@ import { parsePresenceState, sanitizeActivityTexts, sanitizePresenceRotationIntervalSeconds, -} from "../framework/presence/presenceTypes.js"; +} from "../src/framework/presence/presenceTypes.js"; test("sanitizeActivityTexts fallback sur le texte par defaut", () => { const texts = sanitizeActivityTexts([" ", ""]); diff --git a/src/tests/templateVariables.test.ts b/tests/templateVariables.test.ts similarity index 95% rename from src/tests/templateVariables.test.ts rename to tests/templateVariables.test.ts index 09eb12f..b452b59 100644 --- a/src/tests/templateVariables.test.ts +++ b/tests/templateVariables.test.ts @@ -5,7 +5,7 @@ import { extractTemplateVariables, hasTemplateVariable, renderTemplate, -} from "../framework/utils/templateVariables.js"; +} from "../src/framework/utils/templateVariables.js"; test("renderTemplate remplace les variables et applique les alias", () => { const output = renderTemplate( diff --git a/tsconfig.json b/tsconfig.json index 7c5b545..d5bf092 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "module": "NodeNext", "moduleResolution": "NodeNext", "rootDir": "src", - "outDir": "dist", + "outDir": "build", "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true,