@coze-arch/cli 0.0.1-beta.6 → 0.0.3
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/README.md +1 -0
- package/lib/__templates__/expo/.coze +7 -2
- package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +46 -0
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +229 -0
- package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +47 -0
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +34 -0
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +46 -0
- package/lib/__templates__/expo/README.md +68 -7
- package/lib/__templates__/expo/_gitignore +2 -1
- package/lib/__templates__/expo/_npmrc +4 -5
- package/lib/__templates__/expo/client/app/+not-found.tsx +15 -64
- package/lib/__templates__/expo/client/app/_layout.tsx +15 -12
- package/lib/__templates__/expo/client/app/index.tsx +1 -0
- package/lib/__templates__/expo/client/app.config.ts +76 -0
- package/lib/__templates__/expo/client/components/Screen.tsx +3 -19
- package/lib/__templates__/expo/client/components/ThemedText.tsx +33 -0
- package/lib/__templates__/expo/client/components/ThemedView.tsx +37 -0
- package/lib/__templates__/expo/client/constants/theme.ts +117 -58
- package/lib/__templates__/expo/client/contexts/AuthContext.tsx +14 -107
- package/lib/__templates__/expo/client/declarations.d.ts +5 -0
- package/lib/__templates__/expo/{eslint.config.mjs → client/eslint.config.mjs} +40 -10
- package/lib/__templates__/expo/client/hooks/useColorScheme.tsx +48 -0
- package/lib/__templates__/expo/client/hooks/useSafeRouter.ts +152 -0
- package/lib/__templates__/expo/client/hooks/useTheme.ts +26 -6
- package/lib/__templates__/expo/client/metro.config.js +124 -0
- package/lib/__templates__/expo/client/package.json +95 -0
- package/lib/__templates__/expo/client/screens/demo/index.tsx +25 -0
- package/lib/__templates__/expo/client/screens/demo/styles.ts +28 -0
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +11 -10
- package/lib/__templates__/expo/client/tsconfig.json +24 -0
- package/lib/__templates__/expo/client/utils/index.ts +23 -2
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +1889 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +174 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/v5-only-names.js +388 -0
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
- package/lib/__templates__/expo/eslint-plugins/react-native/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/react-native/rule.js +64 -0
- package/lib/__templates__/expo/eslint-plugins/reanimated/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/reanimated/rule.js +88 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
- package/lib/__templates__/expo/package.json +16 -101
- package/lib/__templates__/expo/patches/expo@54.0.33.patch +45 -0
- package/lib/__templates__/expo/pnpm-lock.yaml +1622 -3274
- package/lib/__templates__/expo/pnpm-workspace.yaml +3 -0
- package/lib/__templates__/expo/server/build.js +21 -0
- package/lib/__templates__/expo/server/package.json +34 -0
- package/lib/__templates__/expo/server/src/index.ts +20 -0
- package/lib/__templates__/expo/server/tsconfig.json +24 -0
- package/lib/__templates__/expo/template.config.js +58 -1
- package/lib/__templates__/expo/tsconfig.json +1 -24
- package/lib/__templates__/native-static/.coze +11 -0
- package/lib/__templates__/native-static/index.html +33 -0
- package/lib/__templates__/native-static/styles/main.css +136 -0
- package/lib/__templates__/native-static/template.config.js +22 -0
- package/lib/__templates__/nextjs/.coze +4 -3
- package/lib/__templates__/nextjs/README.md +5 -0
- package/lib/__templates__/nextjs/_gitignore +1 -0
- package/lib/__templates__/nextjs/_npmrc +2 -1
- package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
- package/lib/__templates__/nextjs/next.config.ts +11 -0
- package/lib/__templates__/nextjs/package.json +15 -1
- package/lib/__templates__/nextjs/pnpm-lock.yaml +7694 -4394
- package/lib/__templates__/nextjs/scripts/build.sh +4 -1
- package/lib/__templates__/nextjs/scripts/dev.sh +15 -28
- package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
- package/lib/__templates__/nextjs/scripts/start.sh +7 -1
- package/lib/__templates__/nextjs/src/app/globals.css +109 -89
- package/lib/__templates__/nextjs/src/app/layout.tsx +20 -33
- package/lib/__templates__/nextjs/src/app/page.tsx +18 -49
- package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
- package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
- package/lib/__templates__/nextjs/src/server.ts +35 -0
- package/lib/__templates__/nextjs/template.config.js +68 -3
- package/lib/__templates__/nextjs/tsconfig.json +1 -1
- package/lib/__templates__/nuxt-vue/.coze +12 -0
- package/lib/__templates__/nuxt-vue/README.md +73 -0
- package/lib/__templates__/nuxt-vue/_gitignore +25 -0
- package/lib/__templates__/nuxt-vue/_npmrc +23 -0
- package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
- package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
- package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
- package/lib/__templates__/nuxt-vue/nuxt.config.ts +126 -0
- package/lib/__templates__/nuxt-vue/package.json +35 -0
- package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
- package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
- package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
- package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
- package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
- package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
- package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
- package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
- package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
- package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
- package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
- package/lib/__templates__/nuxt-vue/template.config.js +87 -0
- package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
- package/lib/__templates__/taro/.coze +14 -0
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +19 -0
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +14 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +2 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +151 -0
- package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +5 -0
- package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -0
- package/lib/__templates__/taro/README.md +763 -0
- package/lib/__templates__/taro/_gitignore +41 -0
- package/lib/__templates__/taro/_npmrc +18 -0
- package/lib/__templates__/taro/babel.config.js +12 -0
- package/lib/__templates__/taro/config/dev.ts +9 -0
- package/lib/__templates__/taro/config/index.ts +238 -0
- package/lib/__templates__/taro/config/prod.ts +34 -0
- package/lib/__templates__/taro/eslint.config.mjs +135 -0
- package/lib/__templates__/taro/key/private.appid.key +0 -0
- package/lib/__templates__/taro/package.json +112 -0
- package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +23412 -0
- package/lib/__templates__/taro/pnpm-workspace.yaml +2 -0
- package/lib/__templates__/taro/project.config.json +15 -0
- package/lib/__templates__/taro/server/nest-cli.json +10 -0
- package/lib/__templates__/taro/server/package.json +40 -0
- package/lib/__templates__/taro/server/src/app.controller.ts +23 -0
- package/lib/__templates__/taro/server/src/app.module.ts +10 -0
- package/lib/__templates__/taro/server/src/app.service.ts +8 -0
- package/lib/__templates__/taro/server/src/interceptors/http-status.interceptor.ts +23 -0
- package/lib/__templates__/taro/server/src/main.ts +49 -0
- package/lib/__templates__/taro/server/tsconfig.json +24 -0
- package/lib/__templates__/taro/src/app.config.ts +11 -0
- package/lib/__templates__/taro/src/app.css +156 -0
- package/lib/__templates__/taro/src/app.tsx +9 -0
- package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
- package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
- package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
- package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
- package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
- package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
- package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
- package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
- package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
- package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
- package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
- package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
- package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
- package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
- package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
- package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
- package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
- package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
- package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
- package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
- package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
- package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
- package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
- package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
- package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
- package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
- package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
- package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
- package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
- package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
- package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
- package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
- package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
- package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
- package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
- package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
- package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
- package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
- package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
- package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
- package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
- package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
- package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
- package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
- package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
- package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
- package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
- package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
- package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
- package/lib/__templates__/taro/src/index.html +39 -0
- package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
- package/lib/__templates__/taro/src/lib/measure.ts +115 -0
- package/lib/__templates__/taro/src/lib/platform.ts +12 -0
- package/lib/__templates__/taro/src/lib/utils.ts +6 -0
- package/lib/__templates__/taro/src/network.ts +39 -0
- package/lib/__templates__/taro/src/pages/index/index.config.ts +3 -0
- package/lib/__templates__/taro/src/pages/index/index.css +1 -0
- package/lib/__templates__/taro/src/pages/index/index.tsx +33 -0
- package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
- package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
- package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
- package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
- package/lib/__templates__/taro/src/presets/index.tsx +18 -0
- package/lib/__templates__/taro/stylelint.config.mjs +4 -0
- package/lib/__templates__/taro/template.config.js +68 -0
- package/lib/__templates__/taro/tsconfig.json +29 -0
- package/lib/__templates__/taro/types/global.d.ts +32 -0
- package/lib/__templates__/templates.json +173 -36
- package/lib/__templates__/vite/.coze +4 -3
- package/lib/__templates__/vite/README.md +383 -26
- package/lib/__templates__/vite/_gitignore +2 -0
- package/lib/__templates__/vite/_npmrc +2 -1
- package/lib/__templates__/vite/eslint.config.mjs +14 -0
- package/lib/__templates__/vite/package.json +23 -3
- package/lib/__templates__/vite/pnpm-lock.yaml +2509 -293
- package/lib/__templates__/vite/scripts/build.sh +4 -1
- package/lib/__templates__/vite/scripts/dev.sh +16 -28
- package/lib/__templates__/vite/scripts/prepare.sh +9 -0
- package/lib/__templates__/vite/scripts/start.sh +9 -3
- package/lib/__templates__/vite/server/routes/index.ts +31 -0
- package/lib/__templates__/vite/server/server.ts +65 -0
- package/lib/__templates__/vite/server/vite.ts +67 -0
- package/lib/__templates__/vite/src/main.ts +17 -48
- package/lib/__templates__/vite/template.config.js +77 -7
- package/lib/__templates__/vite/tsconfig.json +4 -3
- package/lib/__templates__/vite/vite.config.ts +8 -3
- package/lib/cli.js +1545 -526
- package/package.json +20 -7
- package/lib/__templates__/expo/.cozeproj/scripts/deploy_build.sh +0 -109
- package/lib/__templates__/expo/.cozeproj/scripts/deploy_run.sh +0 -257
- package/lib/__templates__/expo/app.json +0 -63
- package/lib/__templates__/expo/babel.config.js +0 -9
- package/lib/__templates__/expo/client/app/(tabs)/_layout.tsx +0 -43
- package/lib/__templates__/expo/client/app/(tabs)/home.tsx +0 -1
- package/lib/__templates__/expo/client/app/(tabs)/index.tsx +0 -7
- package/lib/__templates__/expo/client/hooks/useColorScheme.ts +0 -1
- package/lib/__templates__/expo/client/index.js +0 -12
- package/lib/__templates__/expo/client/screens/home/index.tsx +0 -54
- package/lib/__templates__/expo/client/screens/home/styles.ts +0 -332
- package/lib/__templates__/expo/metro.config.js +0 -53
- package/lib/__templates__/expo/src/index.ts +0 -12
- package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
- package/lib/__templates__/nextjs/server.mjs +0 -50
- package/lib/__templates__/vite/.vscode/settings.json +0 -7
- /package/lib/__templates__/expo/{eslint-formatter-simple.mjs → client/eslint-formatter-simple.mjs} +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# forbid-emoji 技术设计
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
- 在代码中检测并禁止使用 emoji
|
|
5
|
+
- 覆盖常见的字符串与 JSX 场景,避免明显漏报
|
|
6
|
+
- 保持实现简单、可维护,避免引入新依赖
|
|
7
|
+
|
|
8
|
+
## 规则命名与对外形态
|
|
9
|
+
- 插件目录:demo/eslint-plugins/forbid-emoji
|
|
10
|
+
- 规则名:forbid-emoji/no-emoji
|
|
11
|
+
- 规则类型:problem
|
|
12
|
+
- 默认等级:error
|
|
13
|
+
|
|
14
|
+
## 规则行为定义
|
|
15
|
+
### 报错
|
|
16
|
+
当以下任一位置包含 emoji 时,报错:
|
|
17
|
+
- 字符串字面量
|
|
18
|
+
- 模板字符串的静态片段
|
|
19
|
+
- JSXText 文本
|
|
20
|
+
- JSXAttribute 中可静态解析为字符串的值
|
|
21
|
+
|
|
22
|
+
### 不报错
|
|
23
|
+
以下场景不触发:
|
|
24
|
+
- 标识符、对象键名、属性名中的字符
|
|
25
|
+
- 数值、正则字面量、BigInt
|
|
26
|
+
- 模板字符串的表达式部分(仅检测静态片段)
|
|
27
|
+
- 被用户显式忽略的路径或内容
|
|
28
|
+
|
|
29
|
+
## 配置项
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"ignorePatterns": []
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
- ignorePatterns:字符串数组,命中任一正则则跳过该文本片段
|
|
36
|
+
|
|
37
|
+
## 检测策略
|
|
38
|
+
### AST 访问节点
|
|
39
|
+
- Literal:仅处理 typeof value === 'string'
|
|
40
|
+
- TemplateLiteral:遍历 quasis,使用 cooked 值
|
|
41
|
+
- JSXText:使用 node.value
|
|
42
|
+
- JSXAttribute:可静态解析为字符串时处理
|
|
43
|
+
|
|
44
|
+
### 忽略策略
|
|
45
|
+
当文本命中 ignorePatterns 的任一正则时,不再做 emoji 检测,减少误报与白名单配置成本。
|
|
46
|
+
|
|
47
|
+
## Emoji 识别方案
|
|
48
|
+
### 组合序列处理
|
|
49
|
+
考虑到真实文本中的 emoji 组合形式,需要识别以下组合序列并保证命中:
|
|
50
|
+
- 变体选择符:U+FE0F
|
|
51
|
+
- 皮肤色修饰符:U+1F3FB–U+1F3FF
|
|
52
|
+
- ZWJ 组合:U+200D
|
|
53
|
+
- 区域指示符组成的国旗:U+1F1E6–U+1F1FF 的成对序列
|
|
54
|
+
- Keycap 组合:[#*0-9] + U+FE0F? + U+20E3
|
|
55
|
+
|
|
56
|
+
实现上直接使用完整序列正则匹配,覆盖 ZWJ 连接序列、国旗与 keycap。
|
|
57
|
+
|
|
58
|
+
### 正则示意
|
|
59
|
+
```
|
|
60
|
+
const RE_EMOJI =
|
|
61
|
+
/(?:\p{Extended_Pictographic}(?:\uFE0F|[\u{1F3FB}-\u{1F3FF}])?(?:\u200D\p{Extended_Pictographic}(?:\uFE0F|[\u{1F3FB}-\u{1F3FF}])?)*)|(?:[\u{1F1E6}-\u{1F1FF}]{2})|(?:[#*0-9]\uFE0F?\u20E3)/gu
|
|
62
|
+
```
|
|
63
|
+
命中即判定为 emoji。
|
|
64
|
+
|
|
65
|
+
## 报错信息
|
|
66
|
+
- messageId: noEmoji
|
|
67
|
+
- 文案:禁止在代码中使用 emoji
|
|
68
|
+
|
|
69
|
+
## 典型示例
|
|
70
|
+
### 触发
|
|
71
|
+
- "hello🙂"
|
|
72
|
+
- `title: "Nice 👍"`
|
|
73
|
+
- <Text>欢迎🎉</Text>
|
|
74
|
+
|
|
75
|
+
### 不触发
|
|
76
|
+
- const icon = "face-smile"
|
|
77
|
+
- <Text>{user.name}</Text>
|
|
78
|
+
- "hello" + emojiName
|
|
79
|
+
|
|
80
|
+
## 边界与决策
|
|
81
|
+
- 模板字符串表达式部分:不深入解析,避免执行风险与复杂度
|
|
82
|
+
- 正则字面量:不扫描,避免干扰正则语义
|
|
83
|
+
- 注释:默认不扫描
|
|
84
|
+
- 误报控制:提供 ignorePatterns,由使用者按文件或内容片段进行排除
|
|
85
|
+
|
|
86
|
+
## 性能考虑
|
|
87
|
+
- 仅在字符串节点上进行扫描
|
|
88
|
+
- 正则预编译并复用
|
|
89
|
+
- 对空字符串与短文本快速返回
|
|
90
|
+
|
|
91
|
+
## 测试计划
|
|
92
|
+
- 覆盖 Literal、TemplateLiteral、JSXText、JSXAttribute 四类节点
|
|
93
|
+
- 覆盖 ZWJ 组合、变体选择符、国旗、keycap、皮肤色修饰符
|
|
94
|
+
- 覆盖 ignorePatterns 行为
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
meta: {
|
|
3
|
+
type: 'problem',
|
|
4
|
+
docs: {
|
|
5
|
+
description: '禁止带有 horizontal: true 属性的 ScrollView 单独使用',
|
|
6
|
+
recommended: false,
|
|
7
|
+
},
|
|
8
|
+
schema: [],
|
|
9
|
+
messages: {
|
|
10
|
+
noSiblings: '禁止带有 props.horizontal: true 的 ScrollView 单独使用,需要在 ScrollView 外层使用一个单独的 View 组件进行包裹',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create(context) {
|
|
14
|
+
return {
|
|
15
|
+
JSXElement(node) {
|
|
16
|
+
const isScrollView = node.openingElement.name.name === 'ScrollView';
|
|
17
|
+
|
|
18
|
+
if (!isScrollView) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const hasHorizontalProp = node.openingElement.attributes.some(attr => {
|
|
23
|
+
if (attr.type === 'JSXAttribute' && attr.name.name === 'horizontal') {
|
|
24
|
+
if (!attr.value) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (
|
|
28
|
+
attr.value.type === 'JSXExpressionContainer' &&
|
|
29
|
+
attr.value.expression.value === true
|
|
30
|
+
) {
|
|
31
|
+
return true; // horizontal={true}
|
|
32
|
+
}
|
|
33
|
+
if (attr.value.type === 'Literal' && attr.value.value === true) {
|
|
34
|
+
return true; // horizontal={true} 的另一种形式
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!hasHorizontalProp) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const parent = node.parent;
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
parent.type === 'JSXFragment' ||
|
|
48
|
+
parent.type === 'JSXElement'
|
|
49
|
+
) {
|
|
50
|
+
const siblings = parent.children.filter(
|
|
51
|
+
child => child.type === 'JSXElement' && child !== node
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (siblings.length > 0) {
|
|
55
|
+
context.report({
|
|
56
|
+
node,
|
|
57
|
+
messageId: 'noSiblings',
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
meta: {
|
|
3
|
+
type: 'problem',
|
|
4
|
+
docs: {
|
|
5
|
+
description:
|
|
6
|
+
'Disallow passing useAnimatedScrollHandler return value to ScrollView',
|
|
7
|
+
recommended: 'error',
|
|
8
|
+
},
|
|
9
|
+
schema: [],
|
|
10
|
+
messages: {
|
|
11
|
+
noUseAnimatedScrollHandlerOnScroll:
|
|
12
|
+
'Do not pass useAnimatedScrollHandler return value to ScrollView, pass to Animated.ScrollView instead.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
create(context) {
|
|
17
|
+
// 记录 useAnimatedScrollHandler 的本地名字
|
|
18
|
+
let useAnimatedScrollHandlerImportName = null;
|
|
19
|
+
// 记录 ScrollView 的本地名字
|
|
20
|
+
let scrollViewImportName = null;
|
|
21
|
+
// 记录调用 useAnimatedScrollHandler 返回值的变量名
|
|
22
|
+
const animatedScrollHandlerVars = new Set();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
ImportDeclaration(node) {
|
|
26
|
+
if (node.source.value === 'react-native-reanimated') {
|
|
27
|
+
for (const specifier of node.specifiers) {
|
|
28
|
+
if (
|
|
29
|
+
specifier.type === 'ImportSpecifier' &&
|
|
30
|
+
specifier.imported.name === 'useAnimatedScrollHandler'
|
|
31
|
+
) {
|
|
32
|
+
useAnimatedScrollHandlerImportName = specifier.local.name;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (node.source.value === 'react-native') {
|
|
38
|
+
for (const specifier of node.specifiers) {
|
|
39
|
+
if (
|
|
40
|
+
specifier.type === 'ImportSpecifier' &&
|
|
41
|
+
specifier.imported.name === 'ScrollView'
|
|
42
|
+
) {
|
|
43
|
+
scrollViewImportName = specifier.local.name;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
VariableDeclarator(node) {
|
|
50
|
+
if (
|
|
51
|
+
node.init &&
|
|
52
|
+
node.init.type === 'CallExpression' &&
|
|
53
|
+
node.init.callee.type === 'Identifier' &&
|
|
54
|
+
node.init.callee.name === useAnimatedScrollHandlerImportName
|
|
55
|
+
) {
|
|
56
|
+
if (node.id.type === 'Identifier') {
|
|
57
|
+
animatedScrollHandlerVars.add(node.id.name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
JSXOpeningElement(node) {
|
|
63
|
+
if (
|
|
64
|
+
node.name.type === 'JSXIdentifier' &&
|
|
65
|
+
node.name.name === scrollViewImportName
|
|
66
|
+
) {
|
|
67
|
+
for (const attr of node.attributes) {
|
|
68
|
+
if (
|
|
69
|
+
attr.type === 'JSXAttribute' &&
|
|
70
|
+
attr.name.name === 'onScroll' &&
|
|
71
|
+
attr.value &&
|
|
72
|
+
attr.value.type === 'JSXExpressionContainer' &&
|
|
73
|
+
attr.value.expression.type === 'Identifier'
|
|
74
|
+
) {
|
|
75
|
+
const varName = attr.value.expression.name;
|
|
76
|
+
if (animatedScrollHandlerVars.has(varName)) {
|
|
77
|
+
context.report({
|
|
78
|
+
node: attr,
|
|
79
|
+
messageId: 'noUseAnimatedScrollHandlerOnScroll',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const LINEAR_GRADIENT_RE = /linear-gradient/i
|
|
2
|
+
|
|
3
|
+
function getPropertyKeyName(property) {
|
|
4
|
+
if (!property || property.type !== 'Property') return null
|
|
5
|
+
if (property.key.type === 'Identifier') return property.key.name
|
|
6
|
+
if (property.key.type === 'Literal' && typeof property.key.value === 'string') {
|
|
7
|
+
return property.key.value
|
|
8
|
+
}
|
|
9
|
+
return null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getStaticStringValue(node) {
|
|
13
|
+
if (!node) return null
|
|
14
|
+
if (node.type === 'Literal' && typeof node.value === 'string') return node.value
|
|
15
|
+
if (node.type === 'TemplateLiteral') {
|
|
16
|
+
return node.quasis.map(quasi => quasi.value?.cooked || '').join('')
|
|
17
|
+
}
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isLinearGradientString(text) {
|
|
22
|
+
if (!text) return false
|
|
23
|
+
return LINEAR_GRADIENT_RE.test(text)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function checkStyleObjectExpression(objectExpression, report) {
|
|
27
|
+
if (!objectExpression || objectExpression.type !== 'ObjectExpression') return
|
|
28
|
+
for (const property of objectExpression.properties) {
|
|
29
|
+
if (!property || property.type !== 'Property') continue
|
|
30
|
+
const keyName = getPropertyKeyName(property)
|
|
31
|
+
if (keyName !== 'backgroundColor') continue
|
|
32
|
+
const valueText = getStaticStringValue(property.value)
|
|
33
|
+
if (isLinearGradientString(valueText)) {
|
|
34
|
+
report(property.key || property)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isStyleSheetMethodCall(node, methodName) {
|
|
40
|
+
if (!node || node.type !== 'CallExpression') return false
|
|
41
|
+
const callee = node.callee
|
|
42
|
+
if (!callee || callee.type !== 'MemberExpression') return false
|
|
43
|
+
if (callee.object.type !== 'Identifier' || callee.object.name !== 'StyleSheet') return false
|
|
44
|
+
if (callee.property.type === 'Identifier') return callee.property.name === methodName
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function checkStyleExpression(expression, report) {
|
|
49
|
+
if (!expression) return
|
|
50
|
+
if (expression.type === 'ObjectExpression') {
|
|
51
|
+
checkStyleObjectExpression(expression, report)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
if (expression.type === 'ArrayExpression') {
|
|
55
|
+
for (const element of expression.elements) {
|
|
56
|
+
if (!element) continue
|
|
57
|
+
if (element.type === 'SpreadElement') {
|
|
58
|
+
checkStyleExpression(element.argument, report)
|
|
59
|
+
} else {
|
|
60
|
+
checkStyleExpression(element, report)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
// 例:StyleSheet.flatten([styles.a, { backgroundColor: 'linear-gradient(...)' }])
|
|
66
|
+
if (isStyleSheetMethodCall(expression, 'flatten')) {
|
|
67
|
+
const arg = expression.arguments[0]
|
|
68
|
+
checkStyleExpression(arg, report)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
// 例:StyleSheet.compose(styles.a, { backgroundColor: `linear-gradient(${angle},#fff,#000)` })
|
|
72
|
+
if (isStyleSheetMethodCall(expression, 'compose')) {
|
|
73
|
+
const [first, second] = expression.arguments
|
|
74
|
+
checkStyleExpression(first, report)
|
|
75
|
+
checkStyleExpression(second, report)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
meta: {
|
|
81
|
+
type: 'problem',
|
|
82
|
+
docs: {
|
|
83
|
+
description: 'Disallow linear-gradient string in backgroundColor',
|
|
84
|
+
recommended: 'error',
|
|
85
|
+
},
|
|
86
|
+
schema: [],
|
|
87
|
+
messages: {
|
|
88
|
+
noLinearGradientBackgroundColor:
|
|
89
|
+
'backgroundColor 和 linear-gradient 无法一起使用,请将 backgroundColor 改为 experimental_backgroundImage',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
create(context) {
|
|
94
|
+
function report(node) {
|
|
95
|
+
context.report({ node, messageId: 'noLinearGradientBackgroundColor' })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
CallExpression(node) {
|
|
100
|
+
if (!isStyleSheetMethodCall(node, 'create')) return
|
|
101
|
+
const firstArg = node.arguments[0]
|
|
102
|
+
if (!firstArg || firstArg.type !== 'ObjectExpression') return
|
|
103
|
+
|
|
104
|
+
checkStyleObjectExpression(firstArg, report)
|
|
105
|
+
|
|
106
|
+
for (const property of firstArg.properties) {
|
|
107
|
+
if (!property || property.type !== 'Property') continue
|
|
108
|
+
if (!property.value || property.value.type !== 'ObjectExpression') continue
|
|
109
|
+
checkStyleObjectExpression(property.value, report)
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
JSXAttribute(node) {
|
|
114
|
+
if (!node.name || node.name.name !== 'style') return
|
|
115
|
+
if (!node.value || node.value.type !== 'JSXExpressionContainer') return
|
|
116
|
+
checkStyleExpression(node.value.expression, report)
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# restrict-linear-gradient 技术设计
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
- 禁止在 backgroundColor 中使用 linear-gradient 字符串
|
|
5
|
+
- 覆盖 StyleSheet.create 与 JSX style 的常见写法
|
|
6
|
+
- 实现轻量、易维护,不引入新依赖
|
|
7
|
+
|
|
8
|
+
## 规则命名与对外形态
|
|
9
|
+
- 插件目录:expo/eslint-plugins/restrict-linear-gradient
|
|
10
|
+
- 规则名:restrict-linear-gradient/no-linear-gradient-backgroundcolor
|
|
11
|
+
- 规则类型:problem
|
|
12
|
+
- 默认等级:error
|
|
13
|
+
|
|
14
|
+
## 规则行为定义
|
|
15
|
+
### 报错
|
|
16
|
+
当以下任一位置出现 backgroundColor 且值包含 linear-gradient( 时,报错:
|
|
17
|
+
- StyleSheet.create 的样式对象中
|
|
18
|
+
- JSX 元素 style 属性内的对象或数组成员
|
|
19
|
+
|
|
20
|
+
### 不报错
|
|
21
|
+
以下场景不触发:
|
|
22
|
+
- 非 backgroundColor 的属性
|
|
23
|
+
- backgroundColor 的非字符串值
|
|
24
|
+
- 模板字符串包含表达式的动态值
|
|
25
|
+
- 与 style 无关的对象字面量
|
|
26
|
+
|
|
27
|
+
## 检测策略
|
|
28
|
+
### StyleSheet.create
|
|
29
|
+
遍历 StyleSheet.create 的首个参数对象,检查:
|
|
30
|
+
- 顶层 backgroundColor
|
|
31
|
+
- 每个样式项对应的对象内的 backgroundColor
|
|
32
|
+
|
|
33
|
+
### JSX style
|
|
34
|
+
定位 JSXAttribute(name=style) 后,检查表达式:
|
|
35
|
+
- ObjectExpression
|
|
36
|
+
- ArrayExpression 的各元素
|
|
37
|
+
- StyleSheet.flatten / StyleSheet.compose 的参数
|
|
38
|
+
|
|
39
|
+
## 线性渐变识别
|
|
40
|
+
使用正则 /linear-gradient/i 检测字符串字面量与模板字符串静态片段。
|
|
41
|
+
|
|
42
|
+
## 报错信息
|
|
43
|
+
- messageId: noLinearGradientBackgroundColor
|
|
44
|
+
- 文案:backgroundColor 和 linear-gradient 无法一起使用,请将 backgroundColor 改为 experimental_backgroundImage
|
|
45
|
+
|
|
46
|
+
## 典型示例
|
|
47
|
+
### 触发
|
|
48
|
+
- StyleSheet.create({ a: { backgroundColor: 'linear-gradient(135deg,#F97316 0%,#FB923C 100%)' } })
|
|
49
|
+
- <View style={{ backgroundColor: "linear-gradient(135deg,#F97316 0%,#FB923C 100%)" }} />
|
|
50
|
+
- <View style={[{ backgroundColor: `linear-gradient(135deg,#F97316 0%,#FB923C 100%)` }]} />
|
|
51
|
+
|
|
52
|
+
### 不触发
|
|
53
|
+
- { background: 'linear-gradient(...)' }
|
|
54
|
+
- { backgroundColor: someVar }
|
|
55
|
+
|
|
56
|
+
## 性能考虑
|
|
57
|
+
- 仅扫描目标节点与静态字符串
|
|
58
|
+
- 早返回空节点与非字符串值
|
|
@@ -1,110 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
3
|
-
"version": "1.0.0",
|
|
2
|
+
"name": "expo-express-monorepo",
|
|
4
3
|
"private": true,
|
|
5
|
-
"
|
|
4
|
+
"version": "0.0.0",
|
|
6
5
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"preinstall": "npx only-allow pnpm"
|
|
11
|
-
"postinstall": "node ./client/scripts/install-missing-deps.js",
|
|
12
|
-
"install-missing": "node ./client/scripts/install-missing-deps.js",
|
|
13
|
-
"lint": "expo lint",
|
|
14
|
-
"server": "NODE_ENV=development tsx ./src/index.ts",
|
|
15
|
-
"start": "expo start --web",
|
|
16
|
-
"test": "jest --watchAll"
|
|
17
|
-
},
|
|
18
|
-
"jest": {
|
|
19
|
-
"preset": "jest-expo"
|
|
20
|
-
},
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"@aws-sdk/client-s3": "^3.958.0",
|
|
23
|
-
"@aws-sdk/lib-storage": "^3.958.0",
|
|
24
|
-
"@expo/metro-runtime": "^6.1.2",
|
|
25
|
-
"@expo/vector-icons": "^15.0.0",
|
|
26
|
-
"@react-native-async-storage/async-storage": "^2.2.0",
|
|
27
|
-
"@react-native-community/datetimepicker": "^8.5.0",
|
|
28
|
-
"@react-native-community/slider": "^5.0.1",
|
|
29
|
-
"@react-native-masked-view/masked-view": "^0.3.2",
|
|
30
|
-
"@react-native-picker/picker": "^2.11.0",
|
|
31
|
-
"@react-navigation/bottom-tabs": "^7.2.0",
|
|
32
|
-
"@react-navigation/native": "^7.0.14",
|
|
33
|
-
"ajv": "^8.17.1",
|
|
34
|
-
"ajv-formats": "^3.0.1",
|
|
35
|
-
"connect": "^3.7.0",
|
|
36
|
-
"coze-coding-dev-sdk": "0.5.0",
|
|
37
|
-
"dayjs": "^1.11.19",
|
|
38
|
-
"drizzle-kit": "^0.31.8",
|
|
39
|
-
"drizzle-orm": "^0.45.1",
|
|
40
|
-
"drizzle-zod": "^0.8.3",
|
|
41
|
-
"expo": "^54.0.7",
|
|
42
|
-
"expo-auth-session": "^7.0.9",
|
|
43
|
-
"expo-av": "~16.0.6",
|
|
44
|
-
"expo-blur": "~15.0.6",
|
|
45
|
-
"expo-camera": "~17.0.10",
|
|
46
|
-
"expo-constants": "~18.0.8",
|
|
47
|
-
"expo-crypto": "^15.0.7",
|
|
48
|
-
"expo-font": "~14.0.7",
|
|
49
|
-
"expo-haptics": "~15.0.6",
|
|
50
|
-
"expo-image-picker": "~17.0.7",
|
|
51
|
-
"expo-linear-gradient": "~15.0.6",
|
|
52
|
-
"expo-linking": "~8.0.7",
|
|
53
|
-
"expo-location": "~19.0.7",
|
|
54
|
-
"expo-router": "~6.0.0",
|
|
55
|
-
"expo-splash-screen": "~31.0.8",
|
|
56
|
-
"expo-status-bar": "~3.0.7",
|
|
57
|
-
"expo-symbols": "~1.0.6",
|
|
58
|
-
"expo-system-ui": "~6.0.9",
|
|
59
|
-
"expo-web-browser": "~15.0.10",
|
|
60
|
-
"express": "^4.22.1",
|
|
61
|
-
"pg": "^8.16.3",
|
|
62
|
-
"react": "19.1.0",
|
|
63
|
-
"react-dom": "19.1.0",
|
|
64
|
-
"react-native": "0.81.5",
|
|
65
|
-
"react-native-chart-kit": "^6.12.0",
|
|
66
|
-
"react-native-gesture-handler": "~2.28.0",
|
|
67
|
-
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
|
68
|
-
"react-native-modal-datetime-picker": "18.0.0",
|
|
69
|
-
"react-native-reanimated": "~4.1.0",
|
|
70
|
-
"react-native-safe-area-context": "~5.6.0",
|
|
71
|
-
"react-native-screens": "~4.16.0",
|
|
72
|
-
"react-native-svg": "15.15.0",
|
|
73
|
-
"react-native-toast-message": "^2.3.3",
|
|
74
|
-
"react-native-web": "^0.21.2",
|
|
75
|
-
"react-native-webview": "~13.15.0",
|
|
76
|
-
"react-native-worklets": "0.5.1",
|
|
77
|
-
"zod": "^4.2.1"
|
|
78
|
-
},
|
|
79
|
-
"devDependencies": {
|
|
80
|
-
"@babel/core": "^7.25.2",
|
|
81
|
-
"@eslint/js": "^9.27.0",
|
|
82
|
-
"@types/express": "^5.0.6",
|
|
83
|
-
"@types/jest": "^29.5.12",
|
|
84
|
-
"@types/pg": "^8.16.0",
|
|
85
|
-
"@types/react": "~19.1.0",
|
|
86
|
-
"@types/react-test-renderer": "19.1.0",
|
|
87
|
-
"babel-plugin-module-resolver": "^5.0.2",
|
|
88
|
-
"babel-preset-expo": "^54.0.9",
|
|
89
|
-
"chalk": "^4.1.2",
|
|
90
|
-
"depcheck": "^1.4.7",
|
|
91
|
-
"eslint": "^9.27.0",
|
|
92
|
-
"eslint-formatter-compact": "^9.0.1",
|
|
93
|
-
"eslint-import-resolver-typescript": "^4.4.4",
|
|
94
|
-
"eslint-plugin-import": "^2.32.0",
|
|
95
|
-
"eslint-plugin-react": "^7.37.5",
|
|
96
|
-
"eslint-plugin-react-hooks": "^7.0.1",
|
|
97
|
-
"eslint-plugin-regexp": "^2.10.0",
|
|
98
|
-
"globals": "^16.1.0",
|
|
99
|
-
"jest": "^29.2.1",
|
|
100
|
-
"jest-expo": "~54.0.10",
|
|
101
|
-
"react-test-renderer": "19.1.0",
|
|
102
|
-
"tsx": "^4.21.0",
|
|
103
|
-
"typescript": "^5.8.3",
|
|
104
|
-
"typescript-eslint": "^8.32.1"
|
|
6
|
+
"dev": "bash .cozeproj/scripts/dev_run.sh",
|
|
7
|
+
"build": "bash .cozeproj/scripts/prod_build.sh",
|
|
8
|
+
"start": "bash .cozeproj/scripts/prod_run.sh",
|
|
9
|
+
"preinstall": "npx only-allow pnpm"
|
|
105
10
|
},
|
|
11
|
+
"dependencies": {},
|
|
12
|
+
"devDependencies": {},
|
|
106
13
|
"packageManager": "pnpm@9.0.0",
|
|
107
14
|
"engines": {
|
|
108
15
|
"pnpm": ">=9.0.0"
|
|
16
|
+
},
|
|
17
|
+
"pnpm": {
|
|
18
|
+
"overrides": {
|
|
19
|
+
"esbuild": "0.27.2"
|
|
20
|
+
},
|
|
21
|
+
"patchedDependencies": {
|
|
22
|
+
"expo@54.0.33": "patches/expo@54.0.33.patch"
|
|
23
|
+
}
|
|
109
24
|
}
|
|
110
25
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
diff --git a/src/async-require/hmr.ts b/src/async-require/hmr.ts
|
|
2
|
+
index 33ce50ee2950c40d2b0553b148710f1e24e44f3d..3d78cb02dd7e96ac9727a2935d8178f2c7e95982 100644
|
|
3
|
+
--- a/src/async-require/hmr.ts
|
|
4
|
+
+++ b/src/async-require/hmr.ts
|
|
5
|
+
@@ -216,6 +216,40 @@ const HMRClient: HMRClientNativeInterface = {
|
|
6
|
+
|
|
7
|
+
client.on('update-done', () => {
|
|
8
|
+
hideLoading();
|
|
9
|
+
+ if (process.env.EXPO_PUBLIC_COZE_PROJECT_ID && typeof window !== 'undefined' && window.location) {
|
|
10
|
+
+ if((window as any).__updateTimeoutId) {
|
|
11
|
+
+ clearTimeout((window as any).__updateTimeoutId);
|
|
12
|
+
+ }
|
|
13
|
+
+ const updateDoneTime = Date.now();
|
|
14
|
+
+ (window as any).__updateDoneTime = updateDoneTime;
|
|
15
|
+
+ (window as any).__updateTimeoutId = setTimeout(() => {
|
|
16
|
+
+ const lastUpdateTime = (window as any).__updateDoneTime;
|
|
17
|
+
+ if (lastUpdateTime !== updateDoneTime) return;
|
|
18
|
+
+ const checkServerAndReload = (retriesLeft: number) => {
|
|
19
|
+
+ if ((window as any).__updateDoneTime !== updateDoneTime) return;
|
|
20
|
+
+ fetch(`/favicon.ico?_t=${Date.now()}`)
|
|
21
|
+
+ .then((response) => {
|
|
22
|
+
+ if (response.status === 200) {
|
|
23
|
+
+ console.warn('[HMR] Server is ready (200), reloading now.');
|
|
24
|
+
+ window.location.reload();
|
|
25
|
+
+ } else {
|
|
26
|
+
+ throw new Error(`Server status: ${response.status}`);
|
|
27
|
+
+ }
|
|
28
|
+
+ }).catch((error) => {
|
|
29
|
+
+ console.warn(`[HMR] Check failed (${error.message}). Retries left: ${retriesLeft}`);
|
|
30
|
+
+ if (retriesLeft > 0) {
|
|
31
|
+
+ setTimeout(() => {
|
|
32
|
+
+ checkServerAndReload(retriesLeft - 1);
|
|
33
|
+
+ }, 5000);
|
|
34
|
+
+ } else {
|
|
35
|
+
+ console.error('[HMR] Server unreachable after 6 attempts. Abort reload.');
|
|
36
|
+
+ }
|
|
37
|
+
+ });
|
|
38
|
+
+ };
|
|
39
|
+
+ checkServerAndReload(6);
|
|
40
|
+
+ }, 35_000);
|
|
41
|
+
+ }
|
|
42
|
+
+ console.log('[HMR] Update done.');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
client.on('error', (data: { type: string; message: string }) => {
|