@coze-arch/cli 0.0.1-alpha.e772d9 → 0.0.1-alpha.e89608
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/.cozeproj/scripts/dev_run.sh +8 -5
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +6 -5
- package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
- package/lib/__templates__/expo/client/eslint.config.mjs +8 -1
- package/lib/__templates__/expo/client/metro.config.js +3 -0
- package/lib/__templates__/expo/client/package.json +35 -35
- package/lib/__templates__/expo/client/screens/demo/index.tsx +3 -3
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
- 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/package.json +1 -1
- package/lib/__templates__/expo/patches/{expo@54.0.32.patch → expo@54.0.33.patch} +3 -2
- package/lib/__templates__/expo/pnpm-lock.yaml +340 -1736
- package/lib/__templates__/expo/server/package.json +9 -7
- package/lib/__templates__/expo/server/src/index.ts +1 -0
- package/lib/__templates__/expo/template.config.js +56 -0
- 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/README.md +5 -0
- package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
- package/lib/__templates__/nextjs/next.config.ts +1 -2
- package/lib/__templates__/nextjs/package.json +15 -6
- package/lib/__templates__/nextjs/pnpm-lock.yaml +1859 -736
- package/lib/__templates__/nextjs/scripts/build.sh +4 -1
- package/lib/__templates__/nextjs/scripts/dev.sh +1 -2
- package/lib/__templates__/nextjs/scripts/start.sh +1 -1
- package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
- package/lib/__templates__/nextjs/src/app/page.tsx +18 -60
- package/lib/__templates__/nextjs/src/server.ts +35 -0
- package/lib/__templates__/nextjs/template.config.js +49 -14
- 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 +24 -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 +116 -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 +31 -0
- package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
- package/lib/__templates__/nuxt-vue/scripts/start.sh +15 -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 +751 -0
- package/lib/__templates__/taro/_gitignore +40 -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 +223 -0
- package/lib/__templates__/taro/config/prod.ts +34 -0
- package/lib/__templates__/taro/eslint.config.mjs +80 -0
- package/lib/__templates__/taro/key/private.appid.key +0 -0
- package/lib/__templates__/taro/package.json +107 -0
- package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +23100 -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 +52 -0
- package/lib/__templates__/taro/src/app.tsx +9 -0
- package/lib/__templates__/taro/src/index.html +39 -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 +201 -0
- package/lib/__templates__/taro/src/presets/h5-styles.ts +142 -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 +75 -0
- package/lib/__templates__/vite/README.md +189 -11
- package/lib/__templates__/vite/_gitignore +1 -0
- package/lib/__templates__/vite/eslint.config.mjs +6 -1
- package/lib/__templates__/vite/package.json +20 -3
- package/lib/__templates__/vite/pnpm-lock.yaml +944 -1551
- package/lib/__templates__/vite/scripts/build.sh +4 -1
- package/lib/__templates__/vite/scripts/dev.sh +2 -2
- package/lib/__templates__/vite/scripts/start.sh +3 -3
- package/lib/__templates__/vite/server/index.ts +57 -0
- package/lib/__templates__/vite/server/routes/index.ts +31 -0
- package/lib/__templates__/vite/server/vite.ts +79 -0
- package/lib/__templates__/vite/src/main.ts +17 -47
- package/lib/__templates__/vite/template.config.js +49 -14
- package/lib/__templates__/vite/tsconfig.json +4 -3
- package/lib/__templates__/vite/vite.config.ts +1 -0
- package/lib/cli.js +471 -173
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -89,14 +89,17 @@ ensure_port() {
|
|
|
89
89
|
pipe_to_log() {
|
|
90
90
|
local source="${1:-CLIENT}"
|
|
91
91
|
local raw_log="${2:-}"
|
|
92
|
-
local line timestamp
|
|
92
|
+
local line clean_line timestamp
|
|
93
93
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
94
|
+
clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
|
|
95
|
+
if echo "$clean_line" | grep -qE '(^(Web|iOS|Android) node_modules/.*expo-router.*entry\.js.*%|^(Web|iOS|Android) Bundled [0-9]+ms node_modules/.*expo-router.*entry\.js|Logs will appear in the browser)'; then
|
|
96
|
+
continue
|
|
97
|
+
fi
|
|
94
98
|
if [ -n "$raw_log" ]; then
|
|
95
|
-
|
|
99
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
100
|
+
echo "[$timestamp] $clean_line" >> "$raw_log"
|
|
96
101
|
fi
|
|
97
|
-
|
|
98
|
-
msg="${line}"
|
|
99
|
-
echo "$msg"
|
|
102
|
+
printf '[%s] %s\n' "$source" "$clean_line"
|
|
100
103
|
done
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -11,13 +11,14 @@ mkdir -p "$LOG_DIR"
|
|
|
11
11
|
pipe_to_log() {
|
|
12
12
|
local source="${1:-SERVER}"
|
|
13
13
|
local raw_log="${2:-}"
|
|
14
|
-
local line
|
|
14
|
+
local line clean_line timestamp
|
|
15
15
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
16
|
+
clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
|
|
16
17
|
if [ -n "$raw_log" ]; then
|
|
17
|
-
|
|
18
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
19
|
+
echo "[$timestamp] $clean_line" >> "$raw_log"
|
|
18
20
|
fi
|
|
19
|
-
|
|
20
|
-
echo "$line"
|
|
21
|
+
printf '[%s] %s\n' "$source" "$clean_line"
|
|
21
22
|
done
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -42,4 +43,4 @@ kill_old_server
|
|
|
42
43
|
|
|
43
44
|
echo "启动 server 服务..."
|
|
44
45
|
cd "$SERVER_DIR"
|
|
45
|
-
NODE_ENV=development PORT="$SERVER_PORT" npx tsx ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_SERVER_FILE"
|
|
46
|
+
NODE_ENV=development PORT="$SERVER_PORT" npx tsx watch ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_SERVER_FILE"
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
*
|
|
33
33
|
* ## 2. 沉浸式 Header (推荐)
|
|
34
34
|
* - 场景:Header 背景色/图片需要延伸到状态栏 (如首页、个人中心)。
|
|
35
|
-
* - 用法:`<Screen safeAreaEdges={['left', 'right', 'bottom']}>` (
|
|
35
|
+
* - 用法:`<Screen safeAreaEdges={['left', 'right', 'bottom']}>` (去掉 'top')
|
|
36
36
|
* - 配合:页面内部 Header 组件必须手动添加 paddingTop:
|
|
37
37
|
* ```tsx
|
|
38
38
|
* const insets = useSafeAreaInsets();
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
*
|
|
42
42
|
* ## 3. 底部有 TabBar 或 悬浮按钮
|
|
43
43
|
* - 场景:页面底部有固定导航栏,或者需要精细控制底部留白。
|
|
44
|
-
* - 用法:`<Screen safeAreaEdges={['top', 'left', 'right']}>` (
|
|
44
|
+
* - 用法:`<Screen safeAreaEdges={['top', 'left', 'right']}>` (去掉 'bottom')
|
|
45
45
|
* - 配合:
|
|
46
46
|
* - 若是滚动页:`<ScrollView contentContainerStyle={{ paddingBottom: insets.bottom + 80 }}>`
|
|
47
47
|
* - 若是固定页:`<View style={{ paddingBottom: insets.bottom + 60 }}>`
|
|
@@ -6,7 +6,9 @@ import reactHooks from 'eslint-plugin-react-hooks';
|
|
|
6
6
|
import regexp from 'eslint-plugin-regexp';
|
|
7
7
|
import pluginImport from 'eslint-plugin-import';
|
|
8
8
|
import fontawesome6 from '../eslint-plugins/fontawesome6/index.js';
|
|
9
|
-
import reanimated from '../eslint-plugins/reanimated/index.js'
|
|
9
|
+
import reanimated from '../eslint-plugins/reanimated/index.js';
|
|
10
|
+
import reactnative from '../eslint-plugins/react-native/index.js';
|
|
11
|
+
import forbidEmoji from '../eslint-plugins/forbid-emoji/index.js';
|
|
10
12
|
|
|
11
13
|
export default [
|
|
12
14
|
{
|
|
@@ -19,6 +21,7 @@ export default [
|
|
|
19
21
|
'tailwind.config.js', // 排除 Tailwind 配置文件
|
|
20
22
|
'**/*.d.ts',
|
|
21
23
|
'eslint.config.*',
|
|
24
|
+
'metro.config.*',
|
|
22
25
|
],
|
|
23
26
|
},
|
|
24
27
|
regexp.configs["flat/recommended"],
|
|
@@ -58,6 +61,8 @@ export default [
|
|
|
58
61
|
import: pluginImport,
|
|
59
62
|
fontawesome6,
|
|
60
63
|
reanimated,
|
|
64
|
+
reactnative,
|
|
65
|
+
forbidEmoji,
|
|
61
66
|
},
|
|
62
67
|
rules: {
|
|
63
68
|
// 关闭代码风格规则
|
|
@@ -78,6 +83,7 @@ export default [
|
|
|
78
83
|
'react/jsx-uses-react': 'off',
|
|
79
84
|
'fontawesome6/valid-name': 'error',
|
|
80
85
|
'reanimated/ban-mix-use': 'error',
|
|
86
|
+
'forbidEmoji/no-emoji': 'error',
|
|
81
87
|
// 禁止使用 via.placeholder.com 服务
|
|
82
88
|
'no-restricted-syntax': [
|
|
83
89
|
'error',
|
|
@@ -90,6 +96,7 @@ export default [
|
|
|
90
96
|
'message': 'via.placeholder.com 服务不可用,禁止在代码中使用',
|
|
91
97
|
},
|
|
92
98
|
],
|
|
99
|
+
'reactnative/wrap-horizontal-scrollview-inside-view': ['error'],
|
|
93
100
|
},
|
|
94
101
|
},
|
|
95
102
|
|
|
@@ -15,38 +15,38 @@
|
|
|
15
15
|
"preset": "jest-expo"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@expo/metro-runtime": "
|
|
19
|
-
"@expo/vector-icons": "^15.0.
|
|
20
|
-
"@react-native-async-storage/async-storage": "
|
|
21
|
-
"@react-native-community/datetimepicker": "
|
|
22
|
-
"@react-native-community/slider": "
|
|
23
|
-
"@react-native-masked-view/masked-view": "
|
|
24
|
-
"@react-native-picker/picker": "
|
|
18
|
+
"@expo/metro-runtime": "~6.1.2",
|
|
19
|
+
"@expo/vector-icons": "^15.0.3",
|
|
20
|
+
"@react-native-async-storage/async-storage": "2.2.0",
|
|
21
|
+
"@react-native-community/datetimepicker": "8.4.4",
|
|
22
|
+
"@react-native-community/slider": "5.0.1",
|
|
23
|
+
"@react-native-masked-view/masked-view": "0.3.2",
|
|
24
|
+
"@react-native-picker/picker": "2.11.1",
|
|
25
25
|
"@react-navigation/bottom-tabs": "^7.2.0",
|
|
26
26
|
"@react-navigation/native": "^7.0.14",
|
|
27
27
|
"dayjs": "^1.11.19",
|
|
28
|
-
"expo": "54.0.
|
|
29
|
-
"expo-auth-session": "
|
|
30
|
-
"expo-av": "~16.0.
|
|
31
|
-
"expo-blur": "~15.0.
|
|
28
|
+
"expo": "54.0.33",
|
|
29
|
+
"expo-auth-session": "~7.0.10",
|
|
30
|
+
"expo-av": "~16.0.8",
|
|
31
|
+
"expo-blur": "~15.0.8",
|
|
32
32
|
"expo-camera": "~17.0.10",
|
|
33
|
-
"expo-constants": "~18.0.
|
|
34
|
-
"expo-crypto": "
|
|
33
|
+
"expo-constants": "~18.0.13",
|
|
34
|
+
"expo-crypto": "~15.0.8",
|
|
35
35
|
"expo-file-system": "~19.0.21",
|
|
36
|
-
"expo-font": "~14.0.
|
|
37
|
-
"expo-haptics": "~15.0.
|
|
38
|
-
"expo-image
|
|
39
|
-
"expo-
|
|
40
|
-
"expo-
|
|
41
|
-
"expo-
|
|
42
|
-
"expo-
|
|
43
|
-
"
|
|
44
|
-
"expo-
|
|
45
|
-
"expo-
|
|
46
|
-
"expo-
|
|
47
|
-
"expo-symbols": "~1.0.6",
|
|
36
|
+
"expo-font": "~14.0.11",
|
|
37
|
+
"expo-haptics": "~15.0.8",
|
|
38
|
+
"expo-image": "~3.0.11",
|
|
39
|
+
"expo-image-picker": "~17.0.10",
|
|
40
|
+
"expo-linear-gradient": "~15.0.8",
|
|
41
|
+
"expo-linking": "~8.0.11",
|
|
42
|
+
"expo-location": "~19.0.8",
|
|
43
|
+
"expo-router": "~6.0.23",
|
|
44
|
+
"expo-splash-screen": "~31.0.13",
|
|
45
|
+
"expo-status-bar": "~3.0.9",
|
|
46
|
+
"expo-symbols": "~1.0.8",
|
|
48
47
|
"expo-system-ui": "~6.0.9",
|
|
49
48
|
"expo-web-browser": "~15.0.10",
|
|
49
|
+
"js-base64": "^3.7.7",
|
|
50
50
|
"react": "19.1.0",
|
|
51
51
|
"react-dom": "19.1.0",
|
|
52
52
|
"react-native": "0.81.5",
|
|
@@ -54,25 +54,26 @@
|
|
|
54
54
|
"react-native-gesture-handler": "~2.28.0",
|
|
55
55
|
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
|
56
56
|
"react-native-modal-datetime-picker": "18.0.0",
|
|
57
|
-
"react-native-reanimated": "~4.1.
|
|
57
|
+
"react-native-reanimated": "~4.1.1",
|
|
58
58
|
"react-native-safe-area-context": "~5.6.0",
|
|
59
59
|
"react-native-screens": "~4.16.0",
|
|
60
|
-
"react-native-svg": "15.
|
|
60
|
+
"react-native-svg": "15.12.1",
|
|
61
61
|
"react-native-toast-message": "^2.3.3",
|
|
62
|
-
"react-native-web": "
|
|
63
|
-
"react-native-webview": "
|
|
62
|
+
"react-native-web": "~0.21.0",
|
|
63
|
+
"react-native-webview": "13.15.0",
|
|
64
64
|
"react-native-worklets": "0.5.1",
|
|
65
65
|
"zod": "^4.2.1"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@babel/core": "^7.25.2",
|
|
69
|
-
"babel-plugin-module-resolver": "^5.0.2",
|
|
70
|
-
"babel-preset-expo": "^54.0.9",
|
|
71
69
|
"@eslint/js": "^9.27.0",
|
|
72
70
|
"@types/jest": "^29.5.12",
|
|
73
71
|
"@types/react": "~19.1.0",
|
|
74
72
|
"@types/react-test-renderer": "19.1.0",
|
|
73
|
+
"babel-plugin-module-resolver": "^5.0.2",
|
|
74
|
+
"babel-preset-expo": "^54.0.9",
|
|
75
75
|
"chalk": "^4.1.2",
|
|
76
|
+
"connect": "^3.7.0",
|
|
76
77
|
"depcheck": "^1.4.7",
|
|
77
78
|
"esbuild": "0.27.2",
|
|
78
79
|
"eslint": "^9.39.2",
|
|
@@ -83,13 +84,12 @@
|
|
|
83
84
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
84
85
|
"eslint-plugin-regexp": "^2.10.0",
|
|
85
86
|
"globals": "^16.1.0",
|
|
87
|
+
"http-proxy-middleware": "^3.0.5",
|
|
86
88
|
"jest": "^29.2.1",
|
|
87
|
-
"jest-expo": "~54.0.
|
|
89
|
+
"jest-expo": "~54.0.17",
|
|
88
90
|
"react-test-renderer": "19.1.0",
|
|
89
91
|
"tsx": "^4.21.0",
|
|
90
92
|
"typescript": "^5.8.3",
|
|
91
|
-
"typescript-eslint": "^8.32.1"
|
|
92
|
-
"connect": "^3.7.0",
|
|
93
|
-
"http-proxy-middleware": "^3.0.5"
|
|
93
|
+
"typescript-eslint": "^8.32.1"
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -15,10 +15,10 @@ export default function DemoPage() {
|
|
|
15
15
|
>
|
|
16
16
|
<Image
|
|
17
17
|
style={styles.logo}
|
|
18
|
-
source="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-coding/
|
|
18
|
+
source="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-coding/icon/coze-coding.gif"
|
|
19
19
|
></Image>
|
|
20
|
-
<Text style={{...styles.title, color: theme.textPrimary}}
|
|
21
|
-
<Text style={{...styles.description, color: theme.textSecondary}}
|
|
20
|
+
<Text style={{...styles.title, color: theme.textPrimary}}>应用开发中</Text>
|
|
21
|
+
<Text style={{...styles.description, color: theme.textSecondary}}>请稍候,界面即将呈现</Text>
|
|
22
22
|
</View>
|
|
23
23
|
</Screen>
|
|
24
24
|
);
|
|
@@ -9,7 +9,7 @@ const { execSync } = require('child_process');
|
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const path = require('path');
|
|
11
11
|
|
|
12
|
-
console.log('
|
|
12
|
+
console.log('检测缺失的依赖...\n');
|
|
13
13
|
|
|
14
14
|
try {
|
|
15
15
|
// 运行 depcheck 并获取 JSON 输出
|
|
@@ -61,11 +61,11 @@ try {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
if (missingPackages.length === 0) {
|
|
64
|
-
console.log('
|
|
64
|
+
console.log('没有发现缺失的依赖');
|
|
65
65
|
process.exit(0);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
console.log('
|
|
68
|
+
console.log('发现以下缺失的依赖:');
|
|
69
69
|
missingPackages.forEach((pkg, index) => {
|
|
70
70
|
const files = missing[pkg];
|
|
71
71
|
console.log(` ${index + 1}. ${pkg}`);
|
|
@@ -74,7 +74,7 @@ try {
|
|
|
74
74
|
);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
console.log('\n
|
|
77
|
+
console.log('\n开始安装...\n');
|
|
78
78
|
|
|
79
79
|
// 使用 expo install 安装所有缺失的包
|
|
80
80
|
const packagesToInstall = missingPackages.join(' ');
|
|
@@ -84,22 +84,22 @@ try {
|
|
|
84
84
|
stdio: 'inherit',
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
console.log('\n
|
|
87
|
+
console.log('\n所有缺失的依赖已安装完成');
|
|
88
88
|
} catch (installError) {
|
|
89
|
-
console.log('\
|
|
89
|
+
console.log('\nexpo install 失败,尝试使用 npm install...\n');
|
|
90
90
|
|
|
91
91
|
execSync(`npm install ${packagesToInstall}`, {
|
|
92
92
|
stdio: 'inherit',
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
console.log('\n
|
|
95
|
+
console.log('\n所有缺失的依赖已通过 npm 安装完成');
|
|
96
96
|
}
|
|
97
97
|
} catch (error) {
|
|
98
98
|
if (error.message.includes('depcheck')) {
|
|
99
|
-
console.error('
|
|
100
|
-
console.log('
|
|
99
|
+
console.error('depcheck 未安装或运行失败');
|
|
100
|
+
console.log('尝试运行: npm install -g depcheck');
|
|
101
101
|
} else {
|
|
102
|
-
console.error('
|
|
102
|
+
console.error('发生错误:', error.message);
|
|
103
103
|
}
|
|
104
104
|
process.exit(1);
|
|
105
105
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const DEFAULTS = {
|
|
2
|
+
ignorePatterns: [],
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const RE_EMOJI =
|
|
6
|
+
// 匹配完整 emoji 序列:基础图形 + 可选变体选择符/肤色 + 可选 ZWJ 连接序列;以及国旗与 keycap
|
|
7
|
+
/(?:\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
|
|
8
|
+
|
|
9
|
+
function buildIgnoreRegexes(patterns) {
|
|
10
|
+
if (!Array.isArray(patterns)) return []
|
|
11
|
+
const result = []
|
|
12
|
+
for (const pattern of patterns) {
|
|
13
|
+
if (typeof pattern !== 'string') continue
|
|
14
|
+
try {
|
|
15
|
+
result.push(new RegExp(pattern))
|
|
16
|
+
} catch (_) {
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function shouldIgnore(text, ignoreRegexes) {
|
|
24
|
+
if (!ignoreRegexes.length) return false
|
|
25
|
+
for (const re of ignoreRegexes) {
|
|
26
|
+
if (re.test(text)) return true
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hasEmoji(text) {
|
|
32
|
+
if (!text) return false
|
|
33
|
+
RE_EMOJI.lastIndex = 0
|
|
34
|
+
return RE_EMOJI.test(text)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function collectEmojis(text) {
|
|
38
|
+
if (!text) return []
|
|
39
|
+
RE_EMOJI.lastIndex = 0
|
|
40
|
+
const result = []
|
|
41
|
+
const seen = new Set()
|
|
42
|
+
for (const match of text.matchAll(RE_EMOJI)) {
|
|
43
|
+
if (match[0] && !seen.has(match[0])) {
|
|
44
|
+
seen.add(match[0])
|
|
45
|
+
result.push(match[0])
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
meta: {
|
|
53
|
+
type: 'problem',
|
|
54
|
+
docs: {
|
|
55
|
+
description: 'Disallow emoji in code',
|
|
56
|
+
recommended: 'error',
|
|
57
|
+
},
|
|
58
|
+
schema: [
|
|
59
|
+
{
|
|
60
|
+
type: 'object',
|
|
61
|
+
additionalProperties: false,
|
|
62
|
+
properties: {
|
|
63
|
+
ignorePatterns: {
|
|
64
|
+
type: 'array',
|
|
65
|
+
items: { type: 'string' },
|
|
66
|
+
default: DEFAULTS.ignorePatterns,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
messages: {
|
|
72
|
+
noEmoji: '禁止在代码中使用 emoji:{{emojis}},请移除或者使用 @expo/vector-icons 图标',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
create(context) {
|
|
77
|
+
const options = context.options && context.options[0] ? context.options[0] : {}
|
|
78
|
+
const ignoreRegexes = buildIgnoreRegexes(
|
|
79
|
+
Array.isArray(options.ignorePatterns) ? options.ignorePatterns : DEFAULTS.ignorePatterns
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
function checkText(node, text) {
|
|
83
|
+
if (!text) return
|
|
84
|
+
if (shouldIgnore(text, ignoreRegexes)) return
|
|
85
|
+
if (hasEmoji(text)) {
|
|
86
|
+
const emojis = collectEmojis(text)
|
|
87
|
+
const emojiText = emojis.length ? emojis.join(' ') : ''
|
|
88
|
+
context.report({ node, messageId: 'noEmoji', data: { emojis: emojiText } })
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
Literal(node) {
|
|
94
|
+
if (typeof node.value !== 'string') return
|
|
95
|
+
checkText(node, node.value)
|
|
96
|
+
},
|
|
97
|
+
TemplateLiteral(node) {
|
|
98
|
+
for (const quasi of node.quasis) {
|
|
99
|
+
const cooked = quasi.value && typeof quasi.value.cooked === 'string'
|
|
100
|
+
? quasi.value.cooked
|
|
101
|
+
: quasi.value && typeof quasi.value.raw === 'string'
|
|
102
|
+
? quasi.value.raw
|
|
103
|
+
: ''
|
|
104
|
+
checkText(quasi, cooked)
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
JSXText(node) {
|
|
108
|
+
checkText(node, node.value)
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
diff --git a/src/async-require/hmr.ts b/src/async-require/hmr.ts
|
|
2
|
-
index 33ce50ee2950c40d2b0553b148710f1e24e44f3d..
|
|
2
|
+
index 33ce50ee2950c40d2b0553b148710f1e24e44f3d..3d78cb02dd7e96ac9727a2935d8178f2c7e95982 100644
|
|
3
3
|
--- a/src/async-require/hmr.ts
|
|
4
4
|
+++ b/src/async-require/hmr.ts
|
|
5
|
-
@@ -216,6 +216,
|
|
5
|
+
@@ -216,6 +216,40 @@ const HMRClient: HMRClientNativeInterface = {
|
|
6
6
|
|
|
7
7
|
client.on('update-done', () => {
|
|
8
8
|
hideLoading();
|
|
@@ -39,6 +39,7 @@ index 33ce50ee2950c40d2b0553b148710f1e24e44f3d..a13d6f2da10dea858019cc991c21753f
|
|
|
39
39
|
+ checkServerAndReload(6);
|
|
40
40
|
+ }, 35_000);
|
|
41
41
|
+ }
|
|
42
|
+
+ console.log('[HMR] Update done.');
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
client.on('error', (data: { type: string; message: string }) => {
|