create-bubbles 0.1.22 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +5 -0
- package/index.js +1 -1
- package/package.json +25 -24
- package/template-taro-react-oxc/.env.development +1 -1
- package/template-taro-react-oxc/.env.production +1 -1
- package/template-taro-react-oxc/project.config.json +1 -1
- package/template-taro-vue-eslint/project.config.json +2 -2
- package/{template-vp-monorepo-react-nestjs → template-vp-monorepo-react-hono}/.spaces/server//347/231/273/345/275/225/JWT/344/270/216RefreshToken/350/275/256/346/215/242/351/211/264/346/235/203/346/236/266/346/236/204/345/256/236/347/216/260/346/214/207/345/215/227.md +588 -1133
- package/template-vp-monorepo-react-hono/.vite-hooks/commit-msg +2 -0
- package/template-vp-monorepo-react-hono/.vite-hooks/pre-commit +2 -0
- package/template-vp-monorepo-react-hono/.vscode/extensions.json +3 -0
- package/template-vp-monorepo-react-hono/.vscode/settings.json +23 -0
- package/template-vp-monorepo-react-hono/AGENTS.md +16 -0
- package/template-vp-monorepo-react-hono/README.md +54 -0
- package/template-vp-monorepo-react-hono/apps/server/.env.example +13 -0
- package/template-vp-monorepo-react-hono/apps/server/README.md +75 -0
- package/template-vp-monorepo-react-hono/apps/server/drizzle/0000_flaky_madame_masque.sql +18 -0
- package/template-vp-monorepo-react-hono/apps/server/drizzle/meta/0000_snapshot.json +153 -0
- package/template-vp-monorepo-react-hono/apps/server/drizzle/meta/_journal.json +13 -0
- package/template-vp-monorepo-react-hono/apps/server/drizzle.config.ts +19 -0
- package/template-vp-monorepo-react-hono/apps/server/package.json +46 -0
- package/template-vp-monorepo-react-hono/apps/server/src/app.test.ts +57 -0
- package/template-vp-monorepo-react-hono/apps/server/src/app.ts +68 -0
- package/template-vp-monorepo-react-hono/apps/server/src/common/errors/app-error.ts +23 -0
- package/template-vp-monorepo-react-hono/apps/server/src/common/http/response.ts +21 -0
- package/template-vp-monorepo-react-hono/apps/server/src/common/logger.ts +30 -0
- package/template-vp-monorepo-react-hono/apps/server/src/config/env.ts +54 -0
- package/template-vp-monorepo-react-hono/apps/server/src/index.bun.ts +60 -0
- package/template-vp-monorepo-react-hono/apps/server/src/index.ts +73 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/database/client.ts +46 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/database/schema/index.ts +1 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/database/schema/job-runs.ts +42 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/queue/connection.ts +6 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/redis/client.ts +39 -0
- package/template-vp-monorepo-react-hono/apps/server/src/infrastructure/redis/options.ts +28 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/health/health.routes.ts +17 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/health/health.service.ts +59 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.queue.ts +46 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.repository.ts +101 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.routes.ts +46 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.schemas.ts +9 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.service.ts +57 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.types.ts +11 -0
- package/template-vp-monorepo-react-hono/apps/server/src/modules/jobs/jobs.worker.ts +108 -0
- package/template-vp-monorepo-react-hono/apps/server/src/runtime/shutdown.ts +38 -0
- package/template-vp-monorepo-react-hono/apps/server/src/worker.ts +48 -0
- package/template-vp-monorepo-react-hono/apps/server/tsconfig.json +15 -0
- package/template-vp-monorepo-react-hono/apps/server/vite.config.ts +15 -0
- package/template-vp-monorepo-react-hono/apps/web/.env +2 -0
- package/template-vp-monorepo-react-hono/apps/web/.env.dev +1 -0
- package/template-vp-monorepo-react-hono/apps/web/.env.prod +1 -0
- package/template-vp-monorepo-react-hono/apps/web/index.html +13 -0
- package/template-vp-monorepo-react-hono/apps/web/package.json +35 -0
- package/template-vp-monorepo-react-hono/apps/web/public/favicon.svg +1 -0
- package/template-vp-monorepo-react-hono/apps/web/public/icons.svg +24 -0
- package/template-vp-monorepo-react-hono/apps/web/src/App.tsx +25 -0
- package/template-vp-monorepo-react-hono/apps/web/src/assets/hero.png +0 -0
- package/template-vp-monorepo-react-hono/apps/web/src/assets/react.svg +1 -0
- package/template-vp-monorepo-react-hono/apps/web/src/assets/vite.svg +1 -0
- package/template-vp-monorepo-react-hono/apps/web/src/components/Loading/PageLoading.tsx +11 -0
- package/template-vp-monorepo-react-hono/apps/web/src/locales/en_US.json +4 -0
- package/template-vp-monorepo-react-hono/apps/web/src/locales/zh_CN.json +4 -0
- package/template-vp-monorepo-react-hono/apps/web/src/main.tsx +5 -0
- package/template-vp-monorepo-react-hono/apps/web/src/pages/home/index.tsx +47 -0
- package/template-vp-monorepo-react-hono/apps/web/src/router/index.tsx +25 -0
- package/template-vp-monorepo-react-hono/apps/web/src/router/modules/.gitkeep +0 -0
- package/template-vp-monorepo-react-hono/apps/web/src/styles/index.css +7 -0
- package/template-vp-monorepo-react-hono/apps/web/src/types/auto-imports.d.ts +58 -0
- package/template-vp-monorepo-react-hono/apps/web/src/utils/env/index.ts +6 -0
- package/template-vp-monorepo-react-hono/apps/web/src/utils/request/core/index.ts +420 -0
- package/template-vp-monorepo-react-hono/apps/web/src/utils/request/core/utils.ts +39 -0
- package/template-vp-monorepo-react-hono/apps/web/src/utils/request/index.ts +61 -0
- package/template-vp-monorepo-react-hono/apps/web/tsconfig.json +18 -0
- package/template-vp-monorepo-react-hono/apps/web/vite.config.ts +45 -0
- package/template-vp-monorepo-react-hono/commitlint.config.js +1 -0
- package/template-vp-monorepo-react-hono/docker-compose.yml +41 -0
- package/template-vp-monorepo-react-hono/mise.toml +4 -0
- package/template-vp-monorepo-react-hono/package.json +37 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/package.json +20 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/format.ts +9 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/i18n.ts +73 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/index.ts +24 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/storage.ts +47 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/store.ts +48 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/src/types.ts +36 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/tsconfig.json +4 -0
- package/template-vp-monorepo-react-hono/packages/i18n/core/vite.config.ts +13 -0
- package/template-vp-monorepo-react-hono/packages/i18n/react/package.json +28 -0
- package/template-vp-monorepo-react-hono/packages/i18n/react/src/index.tsx +26 -0
- package/template-vp-monorepo-react-hono/packages/i18n/react/src/use-store.ts +14 -0
- package/template-vp-monorepo-react-hono/packages/i18n/react/tsconfig.json +9 -0
- package/template-vp-monorepo-react-hono/packages/i18n/react/vite.config.ts +16 -0
- package/template-vp-monorepo-react-hono/packages/i18n/vue/package.json +27 -0
- package/template-vp-monorepo-react-hono/packages/i18n/vue/src/index.ts +52 -0
- package/template-vp-monorepo-react-hono/packages/i18n/vue/src/use-store.ts +19 -0
- package/template-vp-monorepo-react-hono/packages/i18n/vue/tsconfig.json +8 -0
- package/template-vp-monorepo-react-hono/packages/i18n/vue/vite.config.ts +16 -0
- package/template-vp-monorepo-react-hono/pnpm-workspace.yaml +57 -0
- package/template-vp-monorepo-react-hono/scripts/clean.mjs +48 -0
- package/template-vp-monorepo-react-hono/tsconfig.base.json +10 -0
- package/template-vp-monorepo-react-hono/tsconfig.bundler.json +12 -0
- package/template-vp-monorepo-react-hono/tsconfig.json +11 -0
- package/template-vp-monorepo-react-hono/tsconfig.lib.json +10 -0
- package/template-vp-monorepo-react-hono/vite.config.ts +20 -0
- package/template-vp-monorepo-react-nestjs/.spaces/server/todo.md +991 -0
- package/template-vp-monorepo-react-nestjs/.vscode/launch.json +16 -0
- package/template-vp-monorepo-react-nestjs/.vscode/settings.json +21 -17
- package/template-vp-monorepo-react-nestjs/apps/server/.env.development +3 -39
- package/template-vp-monorepo-react-nestjs/apps/server/.swcrc +8 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle.config.ts +8 -3
- package/template-vp-monorepo-react-nestjs/apps/server/nest-cli.json +8 -1
- package/template-vp-monorepo-react-nestjs/apps/server/package.json +11 -6
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.controller.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +20 -15
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +16 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/auth.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/response.ts +0 -4
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/session.constants.ts +28 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/current-auth.decorator.ts +16 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/public.decorator.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/dto/api-failure.dto.ts +25 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/error/common.error.ts +40 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/exceptions/app.exception.ts +55 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/filters/global-exception.filter.ts +384 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/openapi/response-headers.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/index.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/session.config.ts +36 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +7 -8
- package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +29 -8
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.controller.ts +55 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.errors.ts +42 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.module.ts +26 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.repository.ts +40 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +129 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/auth-repsponse.dto.ts +31 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/login.dto.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/register.dto.ts +17 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/guards/session-auth.guard.ts +50 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password.service.ts +24 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-store.service.ts +198 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-token.service.ts +29 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session.script.ts +221 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session.types.ts +24 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.controller.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/dto/create-user.dto.ts +3 -5
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.service.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/utils/env-arr.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/error-catalog.spec.ts +30 -0
- package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.build.json +11 -1
- package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.json +12 -20
- package/template-vp-monorepo-react-nestjs/apps/server/vite.config.ts +15 -0
- package/template-vp-monorepo-react-nestjs/apps/web/package.json +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/tsconfig.json +5 -15
- package/template-vp-monorepo-react-nestjs/apps/web-vue/commitlint.config.js +1 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/lefthook.yml +1 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/package.json +1 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/api/index.ts +5 -5
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/components/Icon/svg-icon.vue +3 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/lib.ts +6 -6
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/useEcharts.ts +34 -29
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/i18n/instance.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/index.vue +17 -32
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/locales/en_US.json +4 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/locales/zh_CN.json +4 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/index.ts +3 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/permissionGuard.ts +7 -7
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/index.ts +7 -7
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/interface.ts +6 -6
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/index.ts +6 -6
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/modules/user.ts +9 -9
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/styles/index.scss +3 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/types/antdv-next.d.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/env.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/index.ts +63 -45
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/utils.ts +12 -6
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/index.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/config.ts +687 -687
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/index.vue +7 -7
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/tree-chart.vue +2 -7
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/home/index.vue +13 -3
- package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.json +5 -17
- package/template-vp-monorepo-react-nestjs/apps/web-vue/uno.config.ts +5 -5
- package/template-vp-monorepo-react-nestjs/i18n.config.ts +22 -0
- package/template-vp-monorepo-react-nestjs/package.json +12 -1
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/README.md +113 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/docs/excel-sync-plan.md +618 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/package.json +31 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/cli.ts +5 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/command.ts +512 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/config.ts +15 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/files.ts +67 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/index.ts +19 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/load-config.ts +228 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/report.ts +57 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.test.ts +81 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.ts +290 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/sync.ts +274 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/command.test.ts +209 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/config.test.ts +19 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/load-config.test.ts +194 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/report.test.ts +63 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/sync.test.ts +203 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/temporary-directory.ts +25 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/tsconfig.json +9 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/vite.config.ts +18 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/tsconfig.json +1 -12
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/tsconfig.json +3 -10
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/tsconfig.json +3 -10
- package/template-vp-monorepo-react-nestjs/packages/shared/package.json +40 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/index.ts +13 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/auth.ts +35 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/common.ts +11 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/index.ts +11 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/account.ts +5 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/index.ts +2 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/session-terminal.ts +11 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/tsconfig.json +4 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/vite.config.ts +17 -0
- package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +6 -6
- package/template-vp-monorepo-react-nestjs/scripts/clean.mjs +48 -0
- package/template-vp-monorepo-react-nestjs/tsconfig.base.json +10 -0
- package/template-vp-monorepo-react-nestjs/tsconfig.bundler.json +12 -0
- package/template-vp-monorepo-react-nestjs/tsconfig.json +8 -6
- package/template-vp-monorepo-react-nestjs/tsconfig.lib.json +10 -0
- package/template-vp-monorepo-react-nestjs/vite.config.ts +2 -1
- package/template-vp-vue-eslint-vapor/.env +6 -0
- package/template-vp-vue-eslint-vapor/.env.development +2 -0
- package/template-vp-vue-eslint-vapor/.env.production +2 -0
- package/template-vp-vue-eslint-vapor/.vite-hooks/commit-msg +1 -0
- package/template-vp-vue-eslint-vapor/.vite-hooks/pre-commit +1 -0
- package/template-vp-vue-eslint-vapor/.vscode/extensions.json +3 -0
- package/template-vp-vue-eslint-vapor/AGENTS.md +16 -0
- package/template-vp-vue-eslint-vapor/README.md +93 -0
- package/template-vp-vue-eslint-vapor/commitlint.config.js +1 -0
- package/template-vp-vue-eslint-vapor/eslint.config.js +13 -0
- package/template-vp-vue-eslint-vapor/index.html +13 -0
- package/template-vp-vue-eslint-vapor/package.json +64 -0
- package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +2 -0
- package/template-vp-vue-eslint-vapor/public/vite.svg +1 -0
- package/template-vp-vue-eslint-vapor/src/App.vue +7 -0
- package/template-vp-vue-eslint-vapor/src/api/index.ts +12 -0
- package/template-vp-vue-eslint-vapor/src/assets/icon/home.svg +3 -0
- package/template-vp-vue-eslint-vapor/src/assets/icon/logo.svg +1 -0
- package/template-vp-vue-eslint-vapor/src/assets/image/.gitkeep +0 -0
- package/template-vp-vue-eslint-vapor/src/components/Icon/svg-icon.vue +29 -0
- package/template-vp-vue-eslint-vapor/src/hooks/chart/lib.ts +57 -0
- package/template-vp-vue-eslint-vapor/src/hooks/chart/useEcharts.ts +65 -0
- package/template-vp-vue-eslint-vapor/src/layout/default/header/index.vue +57 -0
- package/template-vp-vue-eslint-vapor/src/layout/default/index.vue +138 -0
- package/template-vp-vue-eslint-vapor/src/main.ts +19 -0
- package/template-vp-vue-eslint-vapor/src/router/guard/index.ts +7 -0
- package/template-vp-vue-eslint-vapor/src/router/guard/permissionGuard.ts +13 -0
- package/template-vp-vue-eslint-vapor/src/router/index.ts +18 -0
- package/template-vp-vue-eslint-vapor/src/router/interface.ts +9 -0
- package/template-vp-vue-eslint-vapor/src/router/modules/index.ts +33 -0
- package/template-vp-vue-eslint-vapor/src/store/index.ts +11 -0
- package/template-vp-vue-eslint-vapor/src/store/modules/user.ts +17 -0
- package/template-vp-vue-eslint-vapor/src/styles/font.scss +0 -0
- package/template-vp-vue-eslint-vapor/src/styles/index.scss +29 -0
- package/template-vp-vue-eslint-vapor/src/styles/variables.scss +3 -0
- package/template-vp-vue-eslint-vapor/src/types/vite-env.d.ts +15 -0
- package/template-vp-vue-eslint-vapor/src/utils/env.ts +11 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/core/index.ts +425 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/core/utils.ts +39 -0
- package/template-vp-vue-eslint-vapor/src/utils/request/index.ts +44 -0
- package/template-vp-vue-eslint-vapor/src/views/example/echart/config.ts +1794 -0
- package/template-vp-vue-eslint-vapor/src/views/example/echart/index.vue +20 -0
- package/template-vp-vue-eslint-vapor/src/views/example/tree-chart.vue +16 -0
- package/template-vp-vue-eslint-vapor/src/views/home/index.vue +16 -0
- package/template-vp-vue-eslint-vapor/src/views/login/index.vue +9 -0
- package/template-vp-vue-eslint-vapor/tsconfig.json +32 -0
- package/template-vp-vue-eslint-vapor/tsconfig.tsbuildinfo +1 -0
- package/template-vp-vue-eslint-vapor/uno.config.ts +17 -0
- package/template-vp-vue-eslint-vapor/vite.config.ts +66 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/decorator.ts +0 -2
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/bypass.ts +0 -12
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/interceptors/transform.ts +0 -34
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/model/response.ts +0 -23
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/auth.config.ts +0 -64
- package/template-vp-monorepo-react-nestjs/apps/web-vue/pnpm-workspace.yaml +0 -16
- /package/{template-vp-monorepo-react-nestjs/apps/server/src/config/security.config.ts → template-vp-monorepo-react-hono/.agents/auth.config.ts} +0 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { isAbsolute, relative, resolve, sep } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import type { I18nProjectConfig } from './config.ts'
|
|
5
|
+
import { scanFiles, type ScanFilesResult } from './files.ts'
|
|
6
|
+
import { loadConfig } from './load-config.ts'
|
|
7
|
+
import { createSyncReport, type SyncFileReport, writeSyncReport } from './report.ts'
|
|
8
|
+
import { syncProject } from './sync.ts'
|
|
9
|
+
|
|
10
|
+
export type CliCommand = 'check' | 'sync'
|
|
11
|
+
|
|
12
|
+
export interface CliEnvironment {
|
|
13
|
+
cwd?: string
|
|
14
|
+
stdout?: (message: string) => void
|
|
15
|
+
stderr?: (message: string) => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ParsedArguments {
|
|
19
|
+
command: CliCommand
|
|
20
|
+
configPath?: string
|
|
21
|
+
projects: string[]
|
|
22
|
+
clean: boolean
|
|
23
|
+
allowEmpty: boolean
|
|
24
|
+
dryRun: boolean
|
|
25
|
+
failOnStale: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ProjectExecution {
|
|
29
|
+
name: string
|
|
30
|
+
scan: ScanFilesResult
|
|
31
|
+
catalogs: Record<string, string>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface ProjectCatalogs {
|
|
35
|
+
name: string
|
|
36
|
+
catalogs: Record<string, string>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface SummaryTotals {
|
|
40
|
+
added: number
|
|
41
|
+
unused: number
|
|
42
|
+
deleted: number
|
|
43
|
+
unchanged: number
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class CliUsageError extends Error {
|
|
47
|
+
override name = 'CliUsageError'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const helpText = `用法:
|
|
51
|
+
bubbles-i18n sync [options]
|
|
52
|
+
bubbles-i18n check [options]
|
|
53
|
+
|
|
54
|
+
命令:
|
|
55
|
+
sync 把源码中缺失的静态 tr() key 添加到配置的语言包。
|
|
56
|
+
check 只检查、不修改语言包;存在缺失 key 时返回失败。
|
|
57
|
+
|
|
58
|
+
选项:
|
|
59
|
+
--config <path> 使用指定配置文件,不再自动查找 i18n.config.ts。
|
|
60
|
+
--project <name> 只处理指定项目;可以多次传入。
|
|
61
|
+
--dry-run 预览同步结果,不修改语言包。
|
|
62
|
+
--clean 删除源码中已不存在的 key。
|
|
63
|
+
--allow-empty 配合 --clean,允许空扫描结果清空语言包。
|
|
64
|
+
--fail-on-stale check 时发现废弃 key 也返回失败。
|
|
65
|
+
-h, --help 显示帮助信息。
|
|
66
|
+
|
|
67
|
+
安全保护:
|
|
68
|
+
项目的 include 未匹配到任何源文件时,--clean 始终拒绝执行。
|
|
69
|
+
已有翻译保持不变;新增项默认使用 key 作为翻译值。`
|
|
70
|
+
|
|
71
|
+
export async function runCli(
|
|
72
|
+
arguments_: readonly string[],
|
|
73
|
+
environment: CliEnvironment = {},
|
|
74
|
+
): Promise<number> {
|
|
75
|
+
const writeOutput = environment.stdout ?? defaultStdout
|
|
76
|
+
|
|
77
|
+
if (arguments_.length === 0) {
|
|
78
|
+
writeOutput(helpText)
|
|
79
|
+
return 1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (arguments_.includes('--help') || arguments_.includes('-h')) {
|
|
83
|
+
writeOutput(helpText)
|
|
84
|
+
return 0
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const options = parseArguments(arguments_)
|
|
88
|
+
const cwd = resolve(environment.cwd ?? process.cwd())
|
|
89
|
+
const loaded = await loadConfig({ cwd, configPath: options.configPath })
|
|
90
|
+
const allProjectCatalogs = Object.entries(loaded.config.projects).map(
|
|
91
|
+
([name, project]): ProjectCatalogs => ({
|
|
92
|
+
name,
|
|
93
|
+
catalogs: resolveCatalogs(loaded.rootDir, project.catalogs),
|
|
94
|
+
}),
|
|
95
|
+
)
|
|
96
|
+
const reportPath = loaded.config.report
|
|
97
|
+
? resolveFromRoot(loaded.rootDir, loaded.config.report)
|
|
98
|
+
: undefined
|
|
99
|
+
|
|
100
|
+
validateOutputPaths(allProjectCatalogs, reportPath, loaded.configPath)
|
|
101
|
+
if (reportPath) {
|
|
102
|
+
await assertSafeReportTarget(reportPath)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const projectEntries = selectProjects(loaded.config.projects, options.projects)
|
|
106
|
+
const executions = await Promise.all(
|
|
107
|
+
projectEntries.map(async ([name, project]): Promise<ProjectExecution> => {
|
|
108
|
+
const scan = await scanFiles({
|
|
109
|
+
rootDir: loaded.rootDir,
|
|
110
|
+
include: project.include,
|
|
111
|
+
exclude: project.exclude,
|
|
112
|
+
callNames: loaded.config.callNames,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
if (options.clean && scan.files.length === 0) {
|
|
116
|
+
throw new CliUsageError(
|
|
117
|
+
`Refusing --clean for project "${name}" because its include patterns matched no source files.`,
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
name,
|
|
123
|
+
scan,
|
|
124
|
+
catalogs: resolveCatalogs(loaded.rootDir, project.catalogs),
|
|
125
|
+
}
|
|
126
|
+
}),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if (reportPath) {
|
|
130
|
+
assertReportIsNotSourceFile(executions, reportPath)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Validate every selected catalog before any project is allowed to write.
|
|
134
|
+
const previews = await Promise.all(
|
|
135
|
+
executions.map((execution) =>
|
|
136
|
+
syncProject({
|
|
137
|
+
project: execution.name,
|
|
138
|
+
catalogs: execution.catalogs,
|
|
139
|
+
keys: execution.scan.keys,
|
|
140
|
+
clean: options.clean,
|
|
141
|
+
allowEmpty: options.allowEmpty,
|
|
142
|
+
dryRun: true,
|
|
143
|
+
}),
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
let fileReports = previews.flat()
|
|
148
|
+
if (options.command === 'sync' && !options.dryRun) {
|
|
149
|
+
fileReports = []
|
|
150
|
+
for (const execution of executions) {
|
|
151
|
+
fileReports.push(
|
|
152
|
+
...(await syncProject({
|
|
153
|
+
project: execution.name,
|
|
154
|
+
catalogs: execution.catalogs,
|
|
155
|
+
keys: execution.scan.keys,
|
|
156
|
+
clean: options.clean,
|
|
157
|
+
allowEmpty: options.allowEmpty,
|
|
158
|
+
})),
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const portableReports = fileReports.map((file) => ({
|
|
164
|
+
...file,
|
|
165
|
+
path: toPortablePath(loaded.rootDir, file.path),
|
|
166
|
+
}))
|
|
167
|
+
const report = createSyncReport({
|
|
168
|
+
command: options.command,
|
|
169
|
+
clean: options.clean,
|
|
170
|
+
dryRun: options.command === 'check' || options.dryRun,
|
|
171
|
+
files: portableReports,
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
if (reportPath) {
|
|
175
|
+
await writeSyncReport(report, reportPath)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
printSummary({
|
|
179
|
+
command: options.command,
|
|
180
|
+
dryRun: options.dryRun,
|
|
181
|
+
configPath: toPortablePath(cwd, loaded.configPath),
|
|
182
|
+
reportPath: reportPath ? toPortablePath(loaded.rootDir, reportPath) : undefined,
|
|
183
|
+
executions,
|
|
184
|
+
files: portableReports,
|
|
185
|
+
writeOutput,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
if (options.command === 'check') {
|
|
189
|
+
const totals = summarize(portableReports)
|
|
190
|
+
const failedForMissing = totals.added > 0
|
|
191
|
+
const failedForStale = options.failOnStale && totals.unused > 0
|
|
192
|
+
|
|
193
|
+
if (failedForMissing || failedForStale) {
|
|
194
|
+
writeOutput(
|
|
195
|
+
`Check failed: ${totals.added} missing catalog entries, ${totals.unused} unused entries.`,
|
|
196
|
+
)
|
|
197
|
+
return 1
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
writeOutput('Check passed.')
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return 0
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function main(
|
|
207
|
+
arguments_: readonly string[] = process.argv.slice(2),
|
|
208
|
+
environment: CliEnvironment = {},
|
|
209
|
+
): Promise<number> {
|
|
210
|
+
const writeError = environment.stderr ?? defaultStderr
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
return await runCli(arguments_, environment)
|
|
214
|
+
} catch (error) {
|
|
215
|
+
writeError(`Error: ${errorMessage(error)}`)
|
|
216
|
+
if (error instanceof CliUsageError) {
|
|
217
|
+
writeError('Run "bubbles-i18n --help" for usage.')
|
|
218
|
+
}
|
|
219
|
+
return 2
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function parseArguments(arguments_: readonly string[]): ParsedArguments {
|
|
224
|
+
const command = arguments_[0]
|
|
225
|
+
if (command !== 'sync' && command !== 'check') {
|
|
226
|
+
throw new CliUsageError(`Unknown command "${command ?? ''}".`)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let configPath: string | undefined
|
|
230
|
+
const projects = new Set<string>()
|
|
231
|
+
let clean = false
|
|
232
|
+
let allowEmpty = false
|
|
233
|
+
let dryRun = false
|
|
234
|
+
let failOnStale = false
|
|
235
|
+
|
|
236
|
+
for (let index = 1; index < arguments_.length; index += 1) {
|
|
237
|
+
const argument = arguments_[index] ?? ''
|
|
238
|
+
|
|
239
|
+
if (argument === '--config') {
|
|
240
|
+
const [value, nextIndex] = readOptionValue(arguments_, index, '--config')
|
|
241
|
+
configPath = value
|
|
242
|
+
index = nextIndex
|
|
243
|
+
} else if (argument.startsWith('--config=')) {
|
|
244
|
+
configPath = readInlineOptionValue(argument, '--config')
|
|
245
|
+
} else if (argument === '--project') {
|
|
246
|
+
const [value, nextIndex] = readOptionValue(arguments_, index, '--project')
|
|
247
|
+
projects.add(value)
|
|
248
|
+
index = nextIndex
|
|
249
|
+
} else if (argument.startsWith('--project=')) {
|
|
250
|
+
projects.add(readInlineOptionValue(argument, '--project'))
|
|
251
|
+
} else if (argument === '--clean') {
|
|
252
|
+
clean = true
|
|
253
|
+
} else if (argument === '--allow-empty') {
|
|
254
|
+
allowEmpty = true
|
|
255
|
+
} else if (argument === '--dry-run') {
|
|
256
|
+
dryRun = true
|
|
257
|
+
} else if (argument === '--fail-on-stale') {
|
|
258
|
+
failOnStale = true
|
|
259
|
+
} else {
|
|
260
|
+
throw new CliUsageError(`Unknown option "${argument}".`)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (command === 'check' && clean) {
|
|
265
|
+
throw new CliUsageError('--clean is only available with the sync command.')
|
|
266
|
+
}
|
|
267
|
+
if (command === 'check' && dryRun) {
|
|
268
|
+
throw new CliUsageError('check is already read-only; --dry-run is only available with sync.')
|
|
269
|
+
}
|
|
270
|
+
if (command === 'sync' && failOnStale) {
|
|
271
|
+
throw new CliUsageError('--fail-on-stale is only available with the check command.')
|
|
272
|
+
}
|
|
273
|
+
if (allowEmpty && !clean) {
|
|
274
|
+
throw new CliUsageError('--allow-empty requires --clean.')
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
command,
|
|
279
|
+
configPath,
|
|
280
|
+
projects: [...projects],
|
|
281
|
+
clean,
|
|
282
|
+
allowEmpty,
|
|
283
|
+
dryRun,
|
|
284
|
+
failOnStale,
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function readOptionValue(
|
|
289
|
+
arguments_: readonly string[],
|
|
290
|
+
index: number,
|
|
291
|
+
option: string,
|
|
292
|
+
): [value: string, nextIndex: number] {
|
|
293
|
+
const value = arguments_[index + 1]
|
|
294
|
+
if (!value || value.startsWith('--')) {
|
|
295
|
+
throw new CliUsageError(`${option} requires a value.`)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return [value, index + 1]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function readInlineOptionValue(argument: string, option: string): string {
|
|
302
|
+
const value = argument.slice(option.length + 1)
|
|
303
|
+
if (value.length === 0) {
|
|
304
|
+
throw new CliUsageError(`${option} requires a value.`)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return value
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function selectProjects(
|
|
311
|
+
projects: Readonly<Record<string, I18nProjectConfig>>,
|
|
312
|
+
selectedNames: readonly string[],
|
|
313
|
+
): Array<[name: string, project: I18nProjectConfig]> {
|
|
314
|
+
if (selectedNames.length === 0) {
|
|
315
|
+
return Object.entries(projects)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return selectedNames.map((name) => {
|
|
319
|
+
if (!Object.prototype.hasOwnProperty.call(projects, name)) {
|
|
320
|
+
throw new CliUsageError(
|
|
321
|
+
`Unknown project "${name}". Available projects: ${Object.keys(projects).join(', ')}.`,
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const project = projects[name]
|
|
326
|
+
if (!project) {
|
|
327
|
+
throw new CliUsageError(`Project "${name}" has an invalid configuration.`)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return [name, project]
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function resolveCatalogs(
|
|
335
|
+
rootDir: string,
|
|
336
|
+
catalogs: Readonly<Record<string, string>>,
|
|
337
|
+
): Record<string, string> {
|
|
338
|
+
return Object.fromEntries(
|
|
339
|
+
Object.entries(catalogs).map(([locale, path]) => [locale, resolveFromRoot(rootDir, path)]),
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function resolveFromRoot(rootDir: string, path: string): string {
|
|
344
|
+
return isAbsolute(path) ? resolve(path) : resolve(rootDir, path)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function validateOutputPaths(
|
|
348
|
+
projects: readonly ProjectCatalogs[],
|
|
349
|
+
reportPath: string | undefined,
|
|
350
|
+
configPath: string,
|
|
351
|
+
): void {
|
|
352
|
+
const owners = new Map<string, string>()
|
|
353
|
+
|
|
354
|
+
for (const project of projects) {
|
|
355
|
+
for (const [locale, path] of Object.entries(project.catalogs)) {
|
|
356
|
+
const normalizedPath = normalizeComparablePath(path)
|
|
357
|
+
const owner = `${project.name}/${locale}`
|
|
358
|
+
const existingOwner = owners.get(normalizedPath)
|
|
359
|
+
if (existingOwner) {
|
|
360
|
+
throw new CliUsageError(
|
|
361
|
+
`Catalog path "${path}" is configured by both ${existingOwner} and ${owner}.`,
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
owners.set(normalizedPath, owner)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (reportPath && owners.has(normalizeComparablePath(reportPath))) {
|
|
369
|
+
throw new CliUsageError(`Report path must not overwrite a catalog: "${reportPath}".`)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (reportPath && normalizeComparablePath(reportPath) === normalizeComparablePath(configPath)) {
|
|
373
|
+
throw new CliUsageError(`Report path must not overwrite the config file: "${reportPath}".`)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async function assertSafeReportTarget(reportPath: string): Promise<void> {
|
|
378
|
+
let source: string
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
source = await readFile(reportPath, 'utf8')
|
|
382
|
+
} catch (error) {
|
|
383
|
+
if (isMissingPathError(error)) {
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
throw error
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let value: unknown
|
|
390
|
+
try {
|
|
391
|
+
value = JSON.parse(source)
|
|
392
|
+
} catch {
|
|
393
|
+
throw new CliUsageError(`Refusing to overwrite existing non-report file at "${reportPath}".`)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (!isSyncReportLike(value)) {
|
|
397
|
+
throw new CliUsageError(`Refusing to overwrite existing non-report file at "${reportPath}".`)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function assertReportIsNotSourceFile(
|
|
402
|
+
executions: readonly ProjectExecution[],
|
|
403
|
+
reportPath: string,
|
|
404
|
+
): void {
|
|
405
|
+
const normalizedReportPath = normalizeComparablePath(reportPath)
|
|
406
|
+
|
|
407
|
+
for (const execution of executions) {
|
|
408
|
+
if (
|
|
409
|
+
execution.scan.files.some(
|
|
410
|
+
(sourcePath) => normalizeComparablePath(sourcePath) === normalizedReportPath,
|
|
411
|
+
)
|
|
412
|
+
) {
|
|
413
|
+
throw new CliUsageError(
|
|
414
|
+
`Report path must not overwrite a scanned source file: "${reportPath}".`,
|
|
415
|
+
)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function normalizeComparablePath(path: string): string {
|
|
421
|
+
const normalized = resolve(path)
|
|
422
|
+
return process.platform === 'win32' ? normalized.toLowerCase() : normalized
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function toPortablePath(rootDir: string, path: string): string {
|
|
426
|
+
const relativePath = relative(rootDir, path)
|
|
427
|
+
const displayPath = relativePath === '' ? '.' : relativePath
|
|
428
|
+
return displayPath.split(sep).join('/')
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function summarize(files: readonly SyncFileReport[]): SummaryTotals {
|
|
432
|
+
return files.reduce<SummaryTotals>(
|
|
433
|
+
(totals, file) => ({
|
|
434
|
+
added: totals.added + file.added.length,
|
|
435
|
+
unused: totals.unused + file.unused.length,
|
|
436
|
+
deleted: totals.deleted + file.deleted.length,
|
|
437
|
+
unchanged: totals.unchanged + file.unchangedCount,
|
|
438
|
+
}),
|
|
439
|
+
{ added: 0, unused: 0, deleted: 0, unchanged: 0 },
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function printSummary(options: {
|
|
444
|
+
command: CliCommand
|
|
445
|
+
dryRun: boolean
|
|
446
|
+
configPath: string
|
|
447
|
+
reportPath?: string
|
|
448
|
+
executions: readonly ProjectExecution[]
|
|
449
|
+
files: readonly SyncFileReport[]
|
|
450
|
+
writeOutput: (message: string) => void
|
|
451
|
+
}): void {
|
|
452
|
+
const action = options.command === 'check' ? 'check' : options.dryRun ? 'sync dry-run' : 'sync'
|
|
453
|
+
options.writeOutput(`bubbles-i18n ${action}`)
|
|
454
|
+
options.writeOutput(`Config: ${options.configPath}`)
|
|
455
|
+
|
|
456
|
+
for (const execution of options.executions) {
|
|
457
|
+
options.writeOutput(
|
|
458
|
+
`Project ${execution.name}: ${execution.scan.files.length} source files, ${execution.scan.keys.size} keys.`,
|
|
459
|
+
)
|
|
460
|
+
if (execution.scan.skippedBinaryFiles.length > 0) {
|
|
461
|
+
options.writeOutput(` Skipped binary files: ${execution.scan.skippedBinaryFiles.length}.`)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
for (const file of options.files.filter((candidate) => candidate.project === execution.name)) {
|
|
465
|
+
options.writeOutput(
|
|
466
|
+
` ${file.locale} ${file.path}: added ${file.added.length}, unused ${file.unused.length}, deleted ${file.deleted.length}, unchanged ${file.unchangedCount}.`,
|
|
467
|
+
)
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const totals = summarize(options.files)
|
|
472
|
+
options.writeOutput(
|
|
473
|
+
`Total: added ${totals.added}, unused ${totals.unused}, deleted ${totals.deleted}, unchanged ${totals.unchanged}.`,
|
|
474
|
+
)
|
|
475
|
+
if (options.reportPath) {
|
|
476
|
+
options.writeOutput(`Report: ${options.reportPath}`)
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function defaultStdout(message: string): void {
|
|
481
|
+
process.stdout.write(`${message}\n`)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function defaultStderr(message: string): void {
|
|
485
|
+
process.stderr.write(`${message}\n`)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function errorMessage(error: unknown): string {
|
|
489
|
+
if (!(error instanceof Error)) {
|
|
490
|
+
return String(error)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const cause = (error as Error & { cause?: unknown }).cause
|
|
494
|
+
return cause === undefined ? error.message : `${error.message}: ${errorMessage(cause)}`
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function isSyncReportLike(value: unknown): boolean {
|
|
498
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
499
|
+
return false
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const report = value as Record<string, unknown>
|
|
503
|
+
return (report.command === 'sync' || report.command === 'check') && Array.isArray(report.files)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function isMissingPathError(error: unknown): boolean {
|
|
507
|
+
return (
|
|
508
|
+
error instanceof Error &&
|
|
509
|
+
'code' in error &&
|
|
510
|
+
(error.code === 'ENOENT' || error.code === 'ENOTDIR')
|
|
511
|
+
)
|
|
512
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface I18nProjectConfig {
|
|
2
|
+
include: readonly string[]
|
|
3
|
+
exclude?: readonly string[]
|
|
4
|
+
catalogs: Readonly<Record<string, string>>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface I18nConfig {
|
|
8
|
+
callNames?: readonly string[]
|
|
9
|
+
projects: Readonly<Record<string, I18nProjectConfig>>
|
|
10
|
+
report?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function defineConfig<const Config extends I18nConfig>(config: Config): Config {
|
|
14
|
+
return config
|
|
15
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
|
|
3
|
+
import fg from 'fast-glob'
|
|
4
|
+
|
|
5
|
+
import { scanSource, type MessageOccurrence } from './scanner.ts'
|
|
6
|
+
|
|
7
|
+
export interface LocatedMessageOccurrence extends MessageOccurrence {
|
|
8
|
+
file: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ScanFilesOptions {
|
|
12
|
+
rootDir: string
|
|
13
|
+
include: readonly string[]
|
|
14
|
+
exclude?: readonly string[]
|
|
15
|
+
callNames?: readonly string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ScanFilesResult {
|
|
19
|
+
files: string[]
|
|
20
|
+
keys: Set<string>
|
|
21
|
+
occurrences: LocatedMessageOccurrence[]
|
|
22
|
+
skippedBinaryFiles: string[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const defaultExcludes = [
|
|
26
|
+
'**/.git/**',
|
|
27
|
+
'**/.pnpm-store/**',
|
|
28
|
+
'**/.vite/**',
|
|
29
|
+
'**/build/**',
|
|
30
|
+
'**/coverage/**',
|
|
31
|
+
'**/dist/**',
|
|
32
|
+
'**/node_modules/**',
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
export async function scanFiles(options: ScanFilesOptions): Promise<ScanFilesResult> {
|
|
36
|
+
const files = await fg([...options.include], {
|
|
37
|
+
absolute: true,
|
|
38
|
+
cwd: options.rootDir,
|
|
39
|
+
dot: true,
|
|
40
|
+
followSymbolicLinks: false,
|
|
41
|
+
ignore: [...defaultExcludes, ...(options.exclude ?? [])],
|
|
42
|
+
onlyFiles: true,
|
|
43
|
+
unique: true,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
files.sort((left, right) => left.localeCompare(right))
|
|
47
|
+
|
|
48
|
+
const keys = new Set<string>()
|
|
49
|
+
const occurrences: LocatedMessageOccurrence[] = []
|
|
50
|
+
const skippedBinaryFiles: string[] = []
|
|
51
|
+
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
const source = await readFile(file, 'utf8')
|
|
54
|
+
if (source.includes('\0')) {
|
|
55
|
+
skippedBinaryFiles.push(file)
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const normalizedSource = source.charCodeAt(0) === 0xfe_ff ? source.slice(1) : source
|
|
60
|
+
for (const occurrence of scanSource(normalizedSource, { callNames: options.callNames })) {
|
|
61
|
+
keys.add(occurrence.key)
|
|
62
|
+
occurrences.push({ ...occurrence, file })
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { files, keys, occurrences, skippedBinaryFiles }
|
|
67
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { CliUsageError, main, runCli } from './command.ts'
|
|
2
|
+
export type { CliCommand, CliEnvironment } from './command.ts'
|
|
3
|
+
export { defineConfig } from './config.ts'
|
|
4
|
+
export type { I18nConfig, I18nProjectConfig } from './config.ts'
|
|
5
|
+
export { scanFiles } from './files.ts'
|
|
6
|
+
export type { LocatedMessageOccurrence, ScanFilesOptions, ScanFilesResult } from './files.ts'
|
|
7
|
+
export {
|
|
8
|
+
ConfigLoadError,
|
|
9
|
+
ConfigNotFoundError,
|
|
10
|
+
ConfigValidationError,
|
|
11
|
+
loadConfig,
|
|
12
|
+
} from './load-config.ts'
|
|
13
|
+
export type { LoadConfigOptions, LoadedI18nConfig } from './load-config.ts'
|
|
14
|
+
export { createSyncReport, writeSyncReport } from './report.ts'
|
|
15
|
+
export type { CreateSyncReportOptions, SyncFileReport, SyncReport } from './report.ts'
|
|
16
|
+
export { scanSource } from './scanner.ts'
|
|
17
|
+
export type { MessageOccurrence, ScanOptions } from './scanner.ts'
|
|
18
|
+
export { CatalogValidationError, EmptyScanCleanError, syncCatalog, syncProject } from './sync.ts'
|
|
19
|
+
export type { SyncCatalogOptions, SyncProjectOptions } from './sync.ts'
|