@qlover/create-app 0.7.15 → 0.8.0

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.
Files changed (340) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/configs/_common/.gitignore.template +6 -0
  3. package/dist/configs/_common/.prettierignore +17 -5
  4. package/dist/configs/_common/.vscode/settings.json +6 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/templates/next-app/.env.template +1 -1
  8. package/dist/templates/next-app/README.en.md +0 -1
  9. package/dist/templates/next-app/README.md +0 -1
  10. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  11. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  12. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  13. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  14. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  15. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  16. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  17. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  18. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  20. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  21. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  22. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  23. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  24. package/dist/templates/next-app/config/common.ts +22 -13
  25. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  26. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  27. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  28. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  29. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  30. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  31. package/dist/templates/next-app/docs/en/index.md +0 -1
  32. package/dist/templates/next-app/docs/en/project-structure.md +0 -1
  33. package/dist/templates/next-app/docs/zh/index.md +0 -1
  34. package/dist/templates/next-app/docs/zh/project-structure.md +0 -1
  35. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  36. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  37. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  38. package/dist/templates/next-app/package.json +7 -3
  39. package/dist/templates/next-app/public/locales/en.json +172 -207
  40. package/dist/templates/next-app/public/locales/zh.json +172 -207
  41. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  42. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  43. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  44. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  45. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  46. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  47. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  48. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  49. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  50. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  51. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  52. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  53. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  54. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  55. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  56. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  57. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  58. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  59. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  60. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  61. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  62. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  63. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  64. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  65. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  66. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  67. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  68. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  69. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  70. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  71. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  72. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  73. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  74. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  75. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  76. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  77. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  78. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  79. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  80. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  81. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  82. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  83. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  84. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  85. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  86. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  87. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  88. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  89. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  90. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  91. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  92. package/dist/templates/react-app/.prettierignore +17 -0
  93. package/dist/templates/react-app/README.en.md +71 -54
  94. package/dist/templates/react-app/README.md +35 -18
  95. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  96. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  97. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  98. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  99. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  100. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  101. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  102. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  103. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  104. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  105. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  106. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  107. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  108. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  109. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  110. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  111. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  112. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  113. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  114. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  115. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  116. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  117. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  118. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  119. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  120. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  121. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  122. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  123. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  124. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  125. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  126. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  127. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  128. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  129. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  130. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  131. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  132. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  133. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  134. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  135. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  136. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  137. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  138. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  139. package/dist/templates/react-app/config/app.router.ts +66 -69
  140. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  141. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  142. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  143. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  144. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  145. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  146. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  147. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  148. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  149. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  150. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  151. package/dist/templates/react-app/config/theme.ts +14 -4
  152. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  153. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  154. package/dist/templates/react-app/docs/en/env.md +1132 -278
  155. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  156. package/dist/templates/react-app/docs/en/index.md +733 -104
  157. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  158. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  159. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  160. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  161. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  162. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  163. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  164. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  165. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  166. package/dist/templates/react-app/docs/en/store.md +1194 -184
  167. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  168. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  169. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  170. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  171. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  172. package/dist/templates/react-app/docs/zh/index.md +717 -104
  173. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  174. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  175. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  176. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  177. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  178. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  179. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  180. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  181. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  182. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  183. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  184. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  185. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  186. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  187. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  188. package/dist/templates/react-app/eslint.config.mjs +247 -0
  189. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  190. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  191. package/dist/templates/react-app/package.json +31 -3
  192. package/dist/templates/react-app/playwright.config.ts +79 -0
  193. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  194. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  195. package/dist/templates/react-app/src/App.tsx +15 -42
  196. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  197. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  198. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  199. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  200. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  201. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  202. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  203. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  204. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  205. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  206. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  207. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  208. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  209. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  210. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  211. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  212. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  213. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  214. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  215. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  216. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  217. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  218. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  219. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  220. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  221. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  222. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  223. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  224. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  225. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  226. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  227. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  228. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  229. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  230. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  231. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  232. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  233. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  234. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  235. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  236. package/dist/templates/react-app/src/core/globals.ts +9 -9
  237. package/dist/templates/react-app/src/main.tsx +4 -4
  238. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  239. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  240. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  241. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  242. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  243. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  244. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  245. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  246. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  247. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  248. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  249. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  250. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  251. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  252. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  253. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  254. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  255. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  256. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  257. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  258. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  259. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  260. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  261. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  262. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  263. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  264. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  265. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  266. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  267. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  268. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  269. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  270. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  271. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  272. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  273. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  274. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  275. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  276. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  277. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  278. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  279. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  280. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  281. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  282. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  283. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  284. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  285. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  286. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  287. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  288. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  289. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  290. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  291. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  292. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  293. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  294. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  295. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  296. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  297. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  298. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  299. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  300. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  301. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  302. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  303. package/dist/templates/react-app/tsconfig.json +8 -1
  304. package/dist/templates/react-app/tsconfig.node.json +1 -1
  305. package/dist/templates/react-app/tsconfig.test.json +3 -1
  306. package/dist/templates/react-app/vite.config.ts +50 -34
  307. package/package.json +2 -1
  308. package/dist/configs/react-app/eslint.config.js +0 -94
  309. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  310. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  311. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  312. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  313. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  314. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  315. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  316. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  317. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  318. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  319. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  320. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  321. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  322. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  323. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  324. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  325. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  326. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  327. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  328. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  329. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  330. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  331. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  332. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  333. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  334. package/dist/templates/react-app/config/i18n.ts +0 -15
  335. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  336. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  337. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  338. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  339. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  340. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -0,0 +1,319 @@
1
+ import { baseNoLocaleRoutes } from '@config/app.router';
2
+ import { useLocaleRoutes } from '@config/common';
3
+ import { i18nConfig } from '@config/i18n/i18nConfig';
4
+ import { themeConfig } from '@config/theme';
5
+ import { test, expect } from './fixtures/base.fixture';
6
+ import {
7
+ createStartWithUrlRegex,
8
+ localeRoutesEach
9
+ } from './utils/test-helpers';
10
+ import type { Page } from '@playwright/test';
11
+
12
+ test.describe('App', () => {
13
+ test('should render the app component', async ({ page }) => {
14
+ await page.goto('/');
15
+ await expect(page.locator('#root')).toBeVisible();
16
+ });
17
+
18
+ test.describe('locale routes', () => {
19
+ test('should handle locale routes correctly(useLocaleRoutes: true)', async ({
20
+ page,
21
+ fullURL
22
+ }) => {
23
+ test.skip(!useLocaleRoutes, 'Locale routes are disabled');
24
+
25
+ // use default locale: i18nConfig.fallbackLng
26
+ await page.goto('/');
27
+ await expect(page).toHaveURL(
28
+ createStartWithUrlRegex(fullURL, i18nConfig.fallbackLng)
29
+ );
30
+
31
+ // 访问所有支持的语言
32
+ for (const locale of i18nConfig.supportedLngs) {
33
+ await page.goto(`/${locale}`);
34
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, locale));
35
+ }
36
+
37
+ // 访问不存在的语言
38
+ await page.goto(`/ena`);
39
+
40
+ // 应该跳转到默认语言
41
+ if (i18nConfig.noValidRedirectFallbackLng) {
42
+ await expect(page).toHaveURL(
43
+ createStartWithUrlRegex(fullURL, i18nConfig.fallbackLng)
44
+ );
45
+ } else {
46
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, '404'));
47
+ }
48
+ });
49
+
50
+ test('should handle locale routes correctly(useLocaleRoutes: false)', async ({
51
+ page,
52
+ fullURL
53
+ }) => {
54
+ test.skip(useLocaleRoutes, 'Locale routes are enabled');
55
+
56
+ await page.goto('/');
57
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, ''));
58
+
59
+ // 访问不存在的语言, 或路由
60
+ await page.goto('/en'); //=> /router-prefix/en/login -> 404
61
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, '404'));
62
+ await expect(page.getByTestId('NotFound')).toBeVisible();
63
+ });
64
+
65
+ test('should render the client routes correctly(LanguageSwitcher.tsx)', async ({
66
+ page,
67
+ fullURL
68
+ }) => {
69
+ const testLocale = async (locale: string, targetLocale: string) => {
70
+ await page.goto(`/${locale}`);
71
+ const languageSwitcher = page.getByTestId('LanguageSwitcher');
72
+ await expect(languageSwitcher).toBeVisible();
73
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, locale));
74
+ await expect(languageSwitcher).toHaveAttribute(
75
+ 'data-testvalue',
76
+ locale
77
+ );
78
+
79
+ // switch to targetLocale
80
+ await page.getByTestId('LanguageSwitcher').click();
81
+ const languageSwitcherSelect = page.getByTestId(
82
+ 'LanguageSwitcherSelect'
83
+ );
84
+ await expect(languageSwitcherSelect).toBeVisible();
85
+
86
+ const targetOption = page.getByTestId(
87
+ `LanguageSwitcherOption-${targetLocale}`
88
+ );
89
+ await expect(targetOption).toBeVisible();
90
+ await targetOption.click();
91
+
92
+ await expect(page).toHaveURL(
93
+ createStartWithUrlRegex(fullURL, targetLocale)
94
+ );
95
+ };
96
+
97
+ const options = [
98
+ { locale: 'zh', targetLocale: 'en' },
99
+ { locale: 'en', targetLocale: 'zh' }
100
+ ];
101
+
102
+ for (const option of options) {
103
+ await testLocale(option.locale, option.targetLocale);
104
+ }
105
+ });
106
+ });
107
+
108
+ test.describe('theme tests', () => {
109
+ test('should handle theme routes correctly(default theme)', async ({
110
+ page
111
+ }) => {
112
+ await page.goto('/');
113
+
114
+ const systemTheme = 'light';
115
+ await expect(
116
+ page.locator(`html[data-theme="${systemTheme}"]`)
117
+ ).toBeVisible();
118
+
119
+ const switchTheme = async (theme: string, targetTheme: string) => {
120
+ const themeSwitcher = page.getByTestId('ThemeSwitcher');
121
+ await expect(themeSwitcher).toBeVisible();
122
+ await expect(themeSwitcher).toHaveAttribute('data-testvalue', theme);
123
+ await themeSwitcher.click();
124
+
125
+ const themeSwitcherSelect = page.getByTestId('ThemeSwitcherSelect');
126
+ await expect(themeSwitcherSelect).toBeVisible();
127
+ const themeOption = page
128
+ .getByTestId(`ThemeSwitcherOption-${targetTheme}`)
129
+ .first();
130
+
131
+ await expect(themeOption).toBeVisible();
132
+ await themeOption.click();
133
+
134
+ await expect(
135
+ page.locator(`html[data-theme="${targetTheme}"]`)
136
+ ).toBeVisible();
137
+ };
138
+
139
+ for (let i = 0; i < themeConfig.supportedThemes.length; i++) {
140
+ const theme = themeConfig.supportedThemes[i];
141
+ const targetTheme =
142
+ themeConfig.supportedThemes[i + 1] || themeConfig.supportedThemes[0];
143
+ await switchTheme(theme, targetTheme);
144
+ }
145
+ });
146
+
147
+ test('should use the real browser default theme(dark mode)', async ({
148
+ page
149
+ }) => {
150
+ // 验证系统检测到暗色模式
151
+ const systemTheme = 'dark';
152
+ // 在测试开始前设置浏览器为暗色模式
153
+ await page.emulateMedia({ colorScheme: systemTheme });
154
+
155
+ await page.goto('/');
156
+
157
+ await expect(
158
+ page.locator(`html[data-theme="${systemTheme}"]`)
159
+ ).toBeVisible();
160
+ });
161
+
162
+ test('should correctly cache the last theme', async ({ page }) => {
163
+ const systemTheme = 'dark';
164
+ await page.emulateMedia({ colorScheme: systemTheme });
165
+
166
+ await page.goto('/');
167
+ await expect(
168
+ page.locator(`html[data-theme="${systemTheme}"]`)
169
+ ).toBeVisible();
170
+
171
+ const switchTheme = async (theme: string, targetTheme: string) => {
172
+ const themeSwitcher = page.getByTestId('ThemeSwitcher');
173
+ await expect(themeSwitcher).toBeVisible();
174
+ await expect(themeSwitcher).toHaveAttribute('data-testvalue', theme);
175
+ await themeSwitcher.click();
176
+
177
+ const themeSwitcherSelect = page.getByTestId('ThemeSwitcherSelect');
178
+ await expect(themeSwitcherSelect).toBeVisible();
179
+ const themeOption = page
180
+ .getByTestId(`ThemeSwitcherOption-${targetTheme}`)
181
+ .first();
182
+
183
+ await expect(themeOption).toBeVisible();
184
+ await themeOption.click();
185
+
186
+ await expect(
187
+ page.locator(`html[data-theme="${targetTheme}"]`)
188
+ ).toBeVisible();
189
+ };
190
+
191
+ const testCachedTheme = async (cachedTheme: string) => {
192
+ await switchTheme(systemTheme, cachedTheme);
193
+ await page.reload();
194
+ await expect(
195
+ page.locator(`html[data-theme="${cachedTheme}"]`)
196
+ ).toBeVisible();
197
+ };
198
+
199
+ await testCachedTheme('pink');
200
+ });
201
+ });
202
+
203
+ test.describe('App bootstrap flow', () => {
204
+ async function testLogin(page: Page, fullURL: string, locale: string) {
205
+ await expect(page.getByTestId('LoginPage')).toBeVisible();
206
+
207
+ // 重定向到登录页
208
+ expect(page.url()).toContain('/login');
209
+
210
+ // 等待登录成功
211
+ const loginButton = page.getByTestId('LoginButton');
212
+ await expect(loginButton).toBeVisible();
213
+ await loginButton.click();
214
+
215
+ // 等待登录 loading 出现
216
+ await loginButton
217
+ .locator('span.ant-btn-loading-icon')
218
+ .waitFor({ state: 'visible' });
219
+
220
+ // 关键:等待登录 loading 消失(表示登录完成)
221
+ await loginButton
222
+ .locator('span.ant-btn-loading-icon')
223
+ .waitFor({ state: 'hidden' });
224
+
225
+ // 等待 LoginPage 消失
226
+ await expect(page.getByTestId('LoginPage')).toBeHidden();
227
+
228
+ // 等待重定向到首页
229
+ await expect(page).toHaveURL(createStartWithUrlRegex(fullURL, locale));
230
+
231
+ // 等待首页显示
232
+ await expect(page.getByTestId('HomePage')).toBeVisible();
233
+ }
234
+
235
+ test('should correctly handle the case of not logged in', async ({
236
+ page
237
+ }) => {
238
+ await page.goto('/');
239
+ await expect(page.locator('#root')).toBeVisible();
240
+ await expect(page.getByTestId('LoginPage')).toBeVisible();
241
+
242
+ // 访问首页和其他登录后才能访问的页面
243
+ await page.goto('/about');
244
+ await expect(page.getByTestId('AboutPage')).toBeHidden();
245
+ await expect(page.getByTestId('LoginPage')).toBeVisible();
246
+
247
+ // 重定向到登录页
248
+ expect(page.url()).toContain('/login');
249
+ });
250
+
251
+ test('should correctly handle the login flow', async ({
252
+ page,
253
+ fullURL
254
+ }) => {
255
+ const testLoginFlow = async (locale: string) => {
256
+ await page.goto(`/${locale}`);
257
+ await expect(page.locator('#root')).toBeVisible();
258
+
259
+ await testLogin(page, fullURL, locale);
260
+
261
+ // 退出
262
+ const logoutButton = page.getByTestId('LogoutButton');
263
+ await expect(logoutButton).toBeVisible();
264
+ await logoutButton.click();
265
+
266
+ const logoutOkButton = page.getByTestId('LogoutButton-OkButton');
267
+ await expect(logoutOkButton).toBeVisible();
268
+ await logoutOkButton.click();
269
+
270
+ await expect(page.getByTestId('LoginPage')).toBeVisible();
271
+ };
272
+
273
+ for (const locale of i18nConfig.supportedLngs) {
274
+ await testLoginFlow(locale);
275
+ }
276
+ });
277
+
278
+ test('should correctly visit all pages after login', async ({
279
+ page,
280
+ fullURL
281
+ }) => {
282
+ await page.goto('/');
283
+
284
+ await testLogin(page, fullURL, i18nConfig.fallbackLng);
285
+
286
+ // 1. 先提取 base/Layout 下的所有子路由
287
+ const baseLayoutRoute = baseNoLocaleRoutes.find(
288
+ (route) => route.element === 'base/Layout'
289
+ );
290
+
291
+ if (!baseLayoutRoute || !baseLayoutRoute.children) {
292
+ throw new Error('base/Layout route or its children not found');
293
+ }
294
+
295
+ // 2. 过滤并构建所有需要访问的页面信息
296
+ const pagesToVisit = baseLayoutRoute.children
297
+ .filter(
298
+ (child) => child.path !== '*' && child.element && child.index !== true
299
+ )
300
+ .map((child) => {
301
+ return {
302
+ visitPath: child.index ? '/' : `/${child.path}`,
303
+ pageName: child.element.split('/').pop()
304
+ };
305
+ });
306
+
307
+ await localeRoutesEach(async (route) => {
308
+ // 3. 访问所有页面
309
+ for (const pageInfo of pagesToVisit) {
310
+ const path = route + pageInfo.visitPath;
311
+ await page.goto(path);
312
+
313
+ // 验证页面可见
314
+ await expect(page.getByTestId(pageInfo.pageName)).toBeVisible();
315
+ }
316
+ });
317
+ });
318
+ });
319
+ });
@@ -0,0 +1,40 @@
1
+ import { test as base } from '@playwright/test';
2
+ import { routerPrefix } from '../../config/common';
3
+
4
+ type CustomFixtures = {
5
+ routerPrefix: string;
6
+ fullURL: string;
7
+ };
8
+
9
+ /**
10
+ * Custom test fixture that can be extended with additional functionality
11
+ * For example: authentication, mock data, custom page objects, etc.
12
+ */
13
+ export const test = base.extend<CustomFixtures>({
14
+ // Provide routerPrefix as a fixture
15
+ routerPrefix: async ({}, use) => {
16
+ await use(routerPrefix);
17
+ },
18
+
19
+ fullURL: async ({ baseURL }, use) => {
20
+ await use(baseURL + routerPrefix);
21
+ },
22
+
23
+ // Override page fixture to automatically add routerPrefix to goto calls
24
+ page: async ({ page }, use) => {
25
+ const originalGoto = page.goto.bind(page);
26
+
27
+ // Override goto method to prepend routerPrefix
28
+ page.goto = async (url, options) => {
29
+ // If url is a relative path (starts with /), prepend routerPrefix
30
+ if (typeof url === 'string' && url.startsWith('/')) {
31
+ url = routerPrefix + url;
32
+ }
33
+ return originalGoto(url, options);
34
+ };
35
+
36
+ await use(page);
37
+ }
38
+ });
39
+
40
+ export { expect } from '@playwright/test';
@@ -0,0 +1,20 @@
1
+ import { test, expect } from './fixtures/base.fixture';
2
+
3
+ test.describe('Main', () => {
4
+ test('should render the main component', async ({ page }) => {
5
+ await page.goto('/');
6
+ await expect(page.locator('#root')).toBeVisible();
7
+ });
8
+
9
+ test('should render the main component with bootstrap loading', async ({
10
+ page
11
+ }) => {
12
+ await page.goto('/');
13
+
14
+ await page.waitForSelector('[data-testid="Loading"]', { state: 'visible' });
15
+ await expect(page.locator('#root')).toBeVisible();
16
+ await page.waitForSelector('[data-testid="Loading"]', { state: 'hidden' });
17
+
18
+ await expect(page.locator('#root')).toBeVisible();
19
+ });
20
+ });
@@ -0,0 +1,19 @@
1
+ import { useLocaleRoutes } from '@config/common';
2
+ import { i18nConfig } from '@config/i18n/i18nConfig';
3
+
4
+ export const createStartWithUrlRegex = (fullURL: string, locale: string) => {
5
+ const url = locale ? `${fullURL}/${locale}` : fullURL;
6
+ return new RegExp(`^${url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`);
7
+ };
8
+
9
+ export async function localeRoutesEach(
10
+ callback: (localePrefix: string) => Promise<void>
11
+ ) {
12
+ if (!useLocaleRoutes) {
13
+ return await callback('');
14
+ }
15
+
16
+ for (const locale of i18nConfig.supportedLngs) {
17
+ await callback(`/${locale}`);
18
+ }
19
+ }
@@ -0,0 +1,247 @@
1
+ import { dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { FlatCompat } from '@eslint/eslintrc';
4
+ import importPlugin from 'eslint-plugin-import';
5
+ import prettierPlugin from 'eslint-plugin-prettier';
6
+ import unusedImports from 'eslint-plugin-unused-imports';
7
+ import qloverEslint from '@qlover/eslint-plugin';
8
+ import tseslint from 'typescript-eslint';
9
+ import globals from 'globals';
10
+ import {
11
+ disableGlobals,
12
+ restrictSpecificGlobals
13
+ } from './makes/eslint-utils.mjs';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+
18
+ const compat = new FlatCompat({ baseDirectory: __dirname });
19
+
20
+ const eslintConfig = [
21
+ ...compat.extends(
22
+ 'plugin:import/recommended',
23
+ 'plugin:import/typescript'
24
+ // 'plugin:prettier/recommended' // 添加 prettier 推荐配置
25
+ ),
26
+ {
27
+ ignores: [
28
+ // dependencies
29
+ 'node_modules/**',
30
+ '.pnp/**',
31
+ '.pnp.js',
32
+
33
+ // testing
34
+ 'coverage/**',
35
+ 'test-results/**',
36
+ 'playwright-report/**',
37
+ '.playwright/**',
38
+
39
+ // next.js
40
+ '.next/**',
41
+ 'out/**',
42
+ 'build/**',
43
+ 'dist/**',
44
+
45
+ // misc
46
+ '*.pem',
47
+
48
+ // debug
49
+ 'npm-debug.log*',
50
+ 'yarn-debug.log*',
51
+ 'yarn-error.log*',
52
+
53
+ // env files
54
+ '.env*',
55
+
56
+ // vercel
57
+ '.vercel/**',
58
+
59
+ // typescript
60
+ '*.tsbuildinfo',
61
+ 'next-env.d.ts',
62
+
63
+ // cache
64
+ '.cache/**',
65
+ '.eslintcache',
66
+
67
+ // IDE
68
+ '.idea/**',
69
+ '.vscode/**',
70
+
71
+ // package manager
72
+ 'package-lock.json',
73
+ 'yarn.lock',
74
+ 'pnpm-lock.yaml',
75
+
76
+ // config files
77
+ '*.config.js',
78
+ '*.config.mjs',
79
+ '*.config.cjs',
80
+ 'postcss.config.*',
81
+ 'tailwind.config.*',
82
+ 'next.config.*',
83
+ 'jest.config.*',
84
+ 'babel.config.*',
85
+ 'playwright.config.*',
86
+
87
+ // static assets
88
+ 'public/**',
89
+ '**/*.min.js',
90
+ '**/*.bundle.js',
91
+ '**/vendor/**',
92
+
93
+ // generated files
94
+ 'coverage/**',
95
+ '.nyc_output/**',
96
+ 'storybook-static/**'
97
+ ]
98
+ },
99
+ {
100
+ files: ['**/*.{js,jsx,ts,tsx}'],
101
+ languageOptions: {
102
+ parser: tseslint.parser,
103
+ parserOptions: {
104
+ project: [
105
+ './tsconfig.app.json',
106
+ './tsconfig.node.json',
107
+ './tsconfig.test.json',
108
+ './tsconfig.e2e.json'
109
+ ],
110
+ tsconfigRootDir: __dirname
111
+ }
112
+ },
113
+ plugins: {
114
+ 'unused-imports': unusedImports,
115
+ import: importPlugin,
116
+ prettier: prettierPlugin,
117
+ '@qlover-eslint': qloverEslint,
118
+ '@typescript-eslint': tseslint.plugin
119
+ },
120
+ rules: {
121
+ '@qlover-eslint/ts-class-method-return': 'error',
122
+ '@qlover-eslint/require-root-testid': 'error',
123
+ // 禁用 import 路径解析检查,TypeScript 编译器会处理
124
+ 'import/no-unresolved': 'off',
125
+ // 禁用原始的 no-unused-vars,使用 unused-imports 的规则替代
126
+ '@typescript-eslint/no-unused-vars': 'off',
127
+ // 强制使用 import type 导入类型
128
+ '@typescript-eslint/consistent-type-imports': [
129
+ 'error',
130
+ {
131
+ prefer: 'type-imports',
132
+ disallowTypeAnnotations: true,
133
+ fixStyle: 'separate-type-imports'
134
+ }
135
+ ],
136
+ // 检查未使用的导入
137
+ 'unused-imports/no-unused-imports': 'error',
138
+ // 检查未使用的变量,但允许以下划线开头的变量
139
+ 'unused-imports/no-unused-vars': [
140
+ 'error',
141
+ {
142
+ vars: 'all',
143
+ varsIgnorePattern: '^_',
144
+ args: 'after-used',
145
+ argsIgnorePattern: '^_'
146
+ }
147
+ ],
148
+ // import 语句排序规则
149
+ 'import/order': [
150
+ 'error',
151
+ {
152
+ groups: [
153
+ 'builtin', // Node.js 内置模块
154
+ 'external', // 第三方模块
155
+ 'internal', // 内部模块(使用 alias 的导入)
156
+ ['parent', 'sibling'], // 父级和同级模块
157
+ 'index', // 当前目录下的模块
158
+ 'object', // 对象导入
159
+ 'type' // 类型导入
160
+ ],
161
+ pathGroups: [
162
+ {
163
+ pattern: '@/**',
164
+ group: 'internal',
165
+ position: 'after'
166
+ },
167
+ {
168
+ pattern: '@migrations/**',
169
+ group: 'internal',
170
+ position: 'after'
171
+ },
172
+ {
173
+ pattern: '@config/**',
174
+ group: 'internal',
175
+ position: 'after'
176
+ }
177
+ ],
178
+ // "newlines-between": "always", // 不同组之间空一行
179
+ alphabetize: {
180
+ order: 'asc', // 按字母顺序排序
181
+ caseInsensitive: true // 排序时忽略大小写
182
+ }
183
+ }
184
+ ],
185
+ // Prettier 配置
186
+ 'prettier/prettier': [
187
+ 'error',
188
+ {
189
+ semi: true,
190
+ singleQuote: true,
191
+ trailingComma: 'none',
192
+ endOfLine: 'lf'
193
+ }
194
+ ],
195
+ // 默认禁用 export default
196
+ 'import/no-default-export': 'error'
197
+ }
198
+ },
199
+ {
200
+ // TODO: antd override theme need use import type
201
+ files: ['src/base/types/deprecated-antd.d.ts'],
202
+ rules: {
203
+ '@typescript-eslint/consistent-type-imports': 'off'
204
+ }
205
+ },
206
+ // 限制 src 目录下不能直接使用特定的浏览器全局变量
207
+ restrictSpecificGlobals(
208
+ {
209
+ files: ['src/**/*.{ts,tsx,js,jsx}'],
210
+ languageOptions: {
211
+ globals: globals.browser
212
+ }
213
+ },
214
+ {
215
+ restrictedGlobals: [
216
+ 'window',
217
+ 'document',
218
+ 'localStorage',
219
+ 'sessionStorage',
220
+ 'navigator',
221
+ 'location',
222
+ 'history'
223
+ ],
224
+ message: '❌ see(./docs/zh/why-no-globals.md)'
225
+ }
226
+ ),
227
+ // 为特定文件允许使用全局变量
228
+ {
229
+ files: ['src/main.tsx', 'src/core/globals.ts'],
230
+ rules: {
231
+ 'no-restricted-globals': 'off'
232
+ }
233
+ },
234
+ // 为特定文件允许 default export
235
+ {
236
+ files: ['src/pages/**/*.tsx', 'src/App.tsx', 'vite.config.ts'],
237
+ rules: {
238
+ 'import/no-default-export': 'off',
239
+ // 强制 pages 必须使用 default export,禁止 named export
240
+ 'import/no-named-export': 'error',
241
+ // 建议使用 default export
242
+ 'import/prefer-default-export': 'error'
243
+ }
244
+ }
245
+ ];
246
+
247
+ export default eslintConfig;