@coze-arch/cli 0.0.1-alpha.f9be02 → 0.0.1-alpha.fd3d56

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 (84) hide show
  1. package/lib/__templates__/expo/.coze +1 -1
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +19 -82
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +75 -86
  4. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +2 -2
  5. package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +2 -2
  6. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +45 -0
  7. package/lib/__templates__/expo/README.md +68 -7
  8. package/lib/__templates__/expo/client/app/+not-found.tsx +30 -0
  9. package/lib/__templates__/expo/client/{src/app → app}/_layout.tsx +15 -12
  10. package/lib/__templates__/expo/client/app/index.tsx +1 -0
  11. package/lib/__templates__/expo/client/app.config.ts +65 -60
  12. package/lib/__templates__/expo/client/{src/components → components}/Screen.tsx +1 -17
  13. package/lib/__templates__/expo/client/{src/components → components}/ThemedView.tsx +1 -2
  14. package/lib/__templates__/expo/client/constants/theme.ts +177 -0
  15. package/lib/__templates__/expo/client/declarations.d.ts +5 -0
  16. package/lib/__templates__/expo/client/eslint.config.mjs +30 -10
  17. package/lib/__templates__/expo/client/hooks/useColorScheme.tsx +48 -0
  18. package/lib/__templates__/expo/client/hooks/useSafeRouter.ts +152 -0
  19. package/lib/__templates__/expo/client/hooks/useTheme.ts +33 -0
  20. package/lib/__templates__/expo/client/package.json +6 -3
  21. package/lib/__templates__/expo/client/screens/demo/index.tsx +25 -0
  22. package/lib/__templates__/expo/client/screens/demo/styles.ts +28 -0
  23. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +1 -0
  24. package/lib/__templates__/expo/client/tsconfig.json +1 -1
  25. package/lib/__templates__/expo/client/{src/utils → utils}/index.ts +22 -0
  26. package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
  27. package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +1889 -0
  28. package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +174 -0
  29. package/lib/__templates__/expo/eslint-plugins/fontawesome6/v5-only-names.js +388 -0
  30. package/lib/__templates__/expo/eslint-plugins/reanimated/index.js +9 -0
  31. package/lib/__templates__/expo/eslint-plugins/reanimated/rule.js +88 -0
  32. package/lib/__templates__/expo/package.json +7 -98
  33. package/lib/__templates__/expo/patches/expo@54.0.32.patch +44 -0
  34. package/lib/__templates__/expo/pnpm-lock.yaml +2001 -2124
  35. package/lib/__templates__/expo/server/build.js +21 -0
  36. package/lib/__templates__/expo/server/package.json +19 -4
  37. package/lib/__templates__/expo/server/src/index.ts +9 -2
  38. package/lib/__templates__/expo/server/tsconfig.json +24 -0
  39. package/lib/__templates__/expo/template.config.js +1 -0
  40. package/lib/__templates__/nextjs/.babelrc +15 -0
  41. package/lib/__templates__/nextjs/.coze +1 -0
  42. package/lib/__templates__/nextjs/_npmrc +1 -0
  43. package/lib/__templates__/nextjs/next.config.ts +12 -0
  44. package/lib/__templates__/nextjs/package.json +10 -11
  45. package/lib/__templates__/nextjs/pnpm-lock.yaml +2543 -1747
  46. package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
  47. package/lib/__templates__/nextjs/src/app/globals.css +10 -2
  48. package/lib/__templates__/nextjs/src/app/layout.tsx +5 -14
  49. package/lib/__templates__/nextjs/src/app/page.tsx +35 -23
  50. package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
  51. package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
  52. package/lib/__templates__/nextjs/template.config.js +30 -0
  53. package/lib/__templates__/templates.json +61 -43
  54. package/lib/__templates__/vite/.coze +1 -0
  55. package/lib/__templates__/vite/_npmrc +1 -0
  56. package/lib/__templates__/vite/eslint.config.mjs +9 -0
  57. package/lib/__templates__/vite/package.json +10 -1
  58. package/lib/__templates__/vite/pnpm-lock.yaml +3115 -126
  59. package/lib/__templates__/vite/scripts/prepare.sh +9 -0
  60. package/lib/__templates__/vite/src/main.ts +1 -2
  61. package/lib/__templates__/vite/template.config.js +30 -4
  62. package/lib/cli.js +691 -130
  63. package/package.json +5 -3
  64. package/lib/__templates__/expo/client/src/app/index.ts +0 -1
  65. package/lib/__templates__/expo/client/src/constants/theme.ts +0 -850
  66. package/lib/__templates__/expo/client/src/hooks/useColorScheme.ts +0 -1
  67. package/lib/__templates__/expo/client/src/hooks/useTheme.ts +0 -13
  68. package/lib/__templates__/expo/client/src/screens/home/index.tsx +0 -50
  69. package/lib/__templates__/expo/client/src/screens/home/styles.ts +0 -60
  70. package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
  71. package/lib/__templates__/vite/.vscode/settings.json +0 -7
  72. /package/lib/__templates__/expo/client/{src/assets → assets}/fonts/SpaceMono-Regular.ttf +0 -0
  73. /package/lib/__templates__/expo/client/{src/assets → assets}/images/adaptive-icon.png +0 -0
  74. /package/lib/__templates__/expo/client/{src/assets → assets}/images/default-avatar.png +0 -0
  75. /package/lib/__templates__/expo/client/{src/assets → assets}/images/favicon.png +0 -0
  76. /package/lib/__templates__/expo/client/{src/assets → assets}/images/icon.png +0 -0
  77. /package/lib/__templates__/expo/client/{src/assets → assets}/images/partial-react-logo.png +0 -0
  78. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo.png +0 -0
  79. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@2x.png +0 -0
  80. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@3x.png +0 -0
  81. /package/lib/__templates__/expo/client/{src/assets → assets}/images/splash-icon.png +0 -0
  82. /package/lib/__templates__/expo/client/{src/components → components}/SmartDateInput.tsx +0 -0
  83. /package/lib/__templates__/expo/client/{src/components → components}/ThemedText.tsx +0 -0
  84. /package/lib/__templates__/expo/client/{src/contexts → contexts}/AuthContext.tsx +0 -0
@@ -0,0 +1,174 @@
1
+ const names = require('./names')
2
+ const v5OnlyNames = require('./v5-only-names')
3
+ const v5OnlyNamesSet = new Set(v5OnlyNames)
4
+
5
+ const DEFAULTS = {
6
+ whitelist: names,
7
+ componentName: 'FontAwesome6',
8
+ attributeName: 'name',
9
+ };
10
+
11
+ function getJSXAttribute(openingElement, attrName) {
12
+ return openingElement.attributes.find(
13
+ (attr) =>
14
+ attr &&
15
+ attr.type === 'JSXAttribute' &&
16
+ attr.name &&
17
+ attr.name.name === attrName
18
+ );
19
+ }
20
+
21
+ function getStringLiteralValue(attribute) {
22
+ if (!attribute || !attribute.value) return null;
23
+
24
+ const val = attribute.value;
25
+
26
+ // <Comp name="hello" />
27
+ if (val.type === 'Literal' && typeof val.value === 'string') {
28
+ return val.value;
29
+ }
30
+
31
+ // <Comp name={'hello'} />
32
+ if (
33
+ val.type === 'JSXExpressionContainer' &&
34
+ val.expression &&
35
+ val.expression.type === 'Literal' &&
36
+ typeof val.expression.value === 'string'
37
+ ) {
38
+ return val.expression.value;
39
+ }
40
+
41
+ // <Comp name={`hello`} /> template literal without expressions
42
+ if (
43
+ val.type === 'JSXExpressionContainer' &&
44
+ val.expression &&
45
+ val.expression.type === 'TemplateLiteral' &&
46
+ val.expression.expressions.length === 0
47
+ ) {
48
+ return val.expression.quasis[0]?.value?.cooked ?? null;
49
+ }
50
+
51
+ return null;
52
+ }
53
+
54
+ const replacements = {
55
+ 'plus-circle': 'circle-plus',
56
+ }
57
+
58
+ module.exports = {
59
+ meta: {
60
+ type: 'problem',
61
+ docs: {
62
+ description:
63
+ 'Ensure FontAwesome6 name prop is a string literal in whitelist',
64
+ recommended: false,
65
+ },
66
+ schema: [
67
+ {
68
+ type: 'object',
69
+ additionalProperties: false,
70
+ properties: {
71
+ whitelist: {
72
+ type: 'array',
73
+ items: { type: 'string' },
74
+ default: DEFAULTS.whitelist,
75
+ },
76
+ componentName: {
77
+ type: 'string',
78
+ default: DEFAULTS.componentName,
79
+ },
80
+ attributeName: {
81
+ type: 'string',
82
+ default: DEFAULTS.attributeName,
83
+ },
84
+ caseSensitive: {
85
+ type: 'boolean',
86
+ default: true
87
+ }
88
+ },
89
+ },
90
+ ],
91
+ messages: {
92
+ invalidName:
93
+ '{{componentName}} 中不存在图标 {{name}},{{suggestion}}',
94
+ },
95
+ },
96
+
97
+ create(context) {
98
+ const options = context.options && context.options[0] ? context.options[0] : {};
99
+ const componentName = options.componentName || DEFAULTS.componentName;
100
+ const attributeName = options.attributeName || DEFAULTS.attributeName;
101
+ const caseSensitive = options.caseSensitive ?? true;
102
+
103
+ const whitelistRaw = Array.isArray(options.whitelist)
104
+ ? options.whitelist
105
+ : DEFAULTS.whitelist;
106
+
107
+ const normalize = (s) =>
108
+ caseSensitive ? String(s) : String(s).toLowerCase();
109
+
110
+ const whitelist = new Set(whitelistRaw.map(normalize));
111
+
112
+ function isTargetComponent(node) {
113
+ // Supports: <FontAwesome6 />, <NS.FontAwesome6 />
114
+ const nameNode = node.name;
115
+ if (!nameNode) return false;
116
+
117
+ if (nameNode.type === 'JSXIdentifier') {
118
+ return nameNode.name === componentName;
119
+ }
120
+
121
+ if (nameNode.type === 'JSXMemberExpression') {
122
+ // e.g., UI.FontAwesome6
123
+ let base = nameNode;
124
+ while (base.type === 'JSXMemberExpression') {
125
+ if (base.property && base.property.name === componentName) {
126
+ return true;
127
+ }
128
+ base = base.object;
129
+ }
130
+ }
131
+
132
+ return false;
133
+ }
134
+
135
+ return {
136
+ JSXOpeningElement(opening) {
137
+ if (!isTargetComponent(opening)) return;
138
+
139
+ const attrNode = getJSXAttribute(opening, attributeName);
140
+ if (!attrNode) return;
141
+
142
+ const literal = getStringLiteralValue(attrNode);
143
+
144
+ // Only lint when it's a string literal
145
+ if (literal == null) return;
146
+
147
+ const normalized = normalize(literal);
148
+ if (!whitelist.has(normalized)) {
149
+ context.report({
150
+ node: attrNode.value || attrNode,
151
+ messageId: 'invalidName',
152
+ data: {
153
+ componentName,
154
+ name: literal,
155
+ suggestion: getSuggestion(normalized, literal),
156
+ },
157
+ });
158
+ }
159
+ },
160
+ };
161
+ },
162
+ };
163
+
164
+ function getSuggestion(name, originalName) {
165
+ if (replacements[name]) {
166
+ return `请更换为 ${replacements[name]}`
167
+ }
168
+
169
+ if (v5OnlyNamesSet.has(name)) {
170
+ return `${originalName} 只能和 FontAwesome5 组件一起使用`
171
+ }
172
+
173
+ return '请更换为其他图标'
174
+ }
@@ -0,0 +1,388 @@
1
+ const v5names = [
2
+ "acquisitions-incorporated",
3
+ "behance-square",
4
+ "dribbble-square",
5
+ "facebook-square",
6
+ "font-awesome-alt",
7
+ "font-awesome-flag",
8
+ "font-awesome-logo-full",
9
+ "git-square",
10
+ "github-square",
11
+ "google-plus-square",
12
+ "hacker-news-square",
13
+ "innosoft",
14
+ "instagram-square",
15
+ "js-square",
16
+ "lastfm-square",
17
+ "medium-m",
18
+ "odnoklassniki-square",
19
+ "penny-arcade",
20
+ "pied-piper-square",
21
+ "pinterest-square",
22
+ "reddit-square",
23
+ "slack-hash",
24
+ "snapchat-ghost",
25
+ "snapchat-square",
26
+ "steam-square",
27
+ "telegram-plane",
28
+ "tripadvisor",
29
+ "tumblr-square",
30
+ "twitter-square",
31
+ "viadeo-square",
32
+ "vimeo-square",
33
+ "whatsapp-square",
34
+ "xing-square",
35
+ "youtube-square",
36
+ "angry",
37
+ "arrow-alt-circle-down",
38
+ "arrow-alt-circle-left",
39
+ "arrow-alt-circle-right",
40
+ "arrow-alt-circle-up",
41
+ "calendar-alt",
42
+ "calendar-times",
43
+ "caret-square-down",
44
+ "caret-square-left",
45
+ "caret-square-right",
46
+ "caret-square-up",
47
+ "check-circle",
48
+ "check-square",
49
+ "comment-alt",
50
+ "dizzy",
51
+ "dot-circle",
52
+ "edit",
53
+ "file-alt",
54
+ "file-archive",
55
+ "flushed",
56
+ "frown-open",
57
+ "frown",
58
+ "grimace",
59
+ "grin-alt",
60
+ "grin-beam-sweat",
61
+ "grin-beam",
62
+ "grin-hearts",
63
+ "grin-squint-tears",
64
+ "grin-squint",
65
+ "grin-stars",
66
+ "grin-tears",
67
+ "grin-tongue-squint",
68
+ "grin-tongue-wink",
69
+ "grin-tongue",
70
+ "grin-wink",
71
+ "grin",
72
+ "hand-paper",
73
+ "hand-rock",
74
+ "hdd",
75
+ "kiss-beam",
76
+ "kiss-wink-heart",
77
+ "kiss",
78
+ "laugh-beam",
79
+ "laugh-squint",
80
+ "laugh-wink",
81
+ "laugh",
82
+ "list-alt",
83
+ "meh-blank",
84
+ "meh-rolling-eyes",
85
+ "meh",
86
+ "minus-square",
87
+ "money-bill-alt",
88
+ "pause-circle",
89
+ "play-circle",
90
+ "plus-square",
91
+ "question-circle",
92
+ "sad-cry",
93
+ "sad-tear",
94
+ "save",
95
+ "share-square",
96
+ "smile-beam",
97
+ "smile-wink",
98
+ "smile",
99
+ "sticky-note",
100
+ "stop-circle",
101
+ "surprise",
102
+ "times-circle",
103
+ "tired",
104
+ "trash-alt",
105
+ "user-circle",
106
+ "window-close",
107
+ "ad",
108
+ "adjust",
109
+ "air-freshener",
110
+ "allergies",
111
+ "ambulance",
112
+ "american-sign-language-interpreting",
113
+ "angle-double-down",
114
+ "angle-double-left",
115
+ "angle-double-right",
116
+ "angle-double-up",
117
+ "apple-alt",
118
+ "archive",
119
+ "arrow-circle-down",
120
+ "arrow-circle-left",
121
+ "arrow-circle-right",
122
+ "arrow-circle-up",
123
+ "arrows-alt-h",
124
+ "arrows-alt-v",
125
+ "arrows-alt",
126
+ "assistive-listening-systems",
127
+ "atlas",
128
+ "backspace",
129
+ "balance-scale-left",
130
+ "balance-scale-right",
131
+ "balance-scale",
132
+ "band-aid",
133
+ "baseball-ball",
134
+ "basketball-ball",
135
+ "beer",
136
+ "bible",
137
+ "biking",
138
+ "birthday-cake",
139
+ "blind",
140
+ "book-dead",
141
+ "book-reader",
142
+ "border-style",
143
+ "boxes",
144
+ "broadcast-tower",
145
+ "burn",
146
+ "bus-alt",
147
+ "car-alt",
148
+ "car-crash",
149
+ "chalkboard-teacher",
150
+ "chevron-circle-down",
151
+ "chevron-circle-left",
152
+ "chevron-circle-right",
153
+ "chevron-circle-up",
154
+ "clinic-medical",
155
+ "cloud-download-alt",
156
+ "cloud-upload-alt",
157
+ "cocktail",
158
+ "coffee",
159
+ "cog",
160
+ "cogs",
161
+ "columns",
162
+ "compress-alt",
163
+ "compress-arrows-alt",
164
+ "concierge-bell",
165
+ "crop-alt",
166
+ "cut",
167
+ "deaf",
168
+ "diagnoses",
169
+ "digital-tachograph",
170
+ "directions",
171
+ "dolly-flatbed",
172
+ "donate",
173
+ "drafting-compass",
174
+ "ellipsis-h",
175
+ "ellipsis-v",
176
+ "envelope-square",
177
+ "exchange-alt",
178
+ "exclamation-circle",
179
+ "exclamation-triangle",
180
+ "expand-alt",
181
+ "expand-arrows-alt",
182
+ "external-link-alt",
183
+ "external-link-square-alt",
184
+ "fast-backward",
185
+ "fast-forward",
186
+ "feather-alt",
187
+ "female",
188
+ "fighter-jet",
189
+ "file-download",
190
+ "file-medical-alt",
191
+ "file-upload",
192
+ "fire-alt",
193
+ "first-aid",
194
+ "fist-raised",
195
+ "football-ball",
196
+ "funnel-dollar",
197
+ "glass-cheers",
198
+ "glass-martini-alt",
199
+ "glass-martini",
200
+ "glass-whiskey",
201
+ "globe-africa",
202
+ "globe-americas",
203
+ "globe-asia",
204
+ "globe-europe",
205
+ "golf-ball",
206
+ "grip-horizontal",
207
+ "h-square",
208
+ "hamburger",
209
+ "hand-holding-usd",
210
+ "hand-holding-water",
211
+ "hands-helping",
212
+ "hands-wash",
213
+ "handshake-alt-slash",
214
+ "hard-hat",
215
+ "headphones-alt",
216
+ "heart-broken",
217
+ "heartbeat",
218
+ "hiking",
219
+ "history",
220
+ "home",
221
+ "hospital-alt",
222
+ "hospital-symbol",
223
+ "hot-tub",
224
+ "house-damage",
225
+ "hryvnia",
226
+ "id-card-alt",
227
+ "info-circle",
228
+ "journal-whills",
229
+ "laptop-house",
230
+ "level-down-alt",
231
+ "level-up-alt",
232
+ "long-arrow-alt-down",
233
+ "long-arrow-alt-left",
234
+ "long-arrow-alt-right",
235
+ "long-arrow-alt-up",
236
+ "low-vision",
237
+ "luggage-cart",
238
+ "magic",
239
+ "mail-bulk",
240
+ "male",
241
+ "map-marked-alt",
242
+ "map-marked",
243
+ "map-marker-alt",
244
+ "map-marker",
245
+ "map-signs",
246
+ "mars-stroke-h",
247
+ "mars-stroke-v",
248
+ "medkit",
249
+ "microphone-alt-slash",
250
+ "microphone-alt",
251
+ "minus-circle",
252
+ "mobile-alt",
253
+ "money-bill-wave-alt",
254
+ "money-check-alt",
255
+ "mouse-pointer",
256
+ "mouse",
257
+ "paint-brush",
258
+ "parking",
259
+ "pastafarianism",
260
+ "pen-alt",
261
+ "pen-square",
262
+ "pencil-alt",
263
+ "pencil-ruler",
264
+ "people-carry",
265
+ "percentage",
266
+ "phone-alt",
267
+ "phone-square-alt",
268
+ "phone-square",
269
+ "photo-video",
270
+ "plus-circle",
271
+ "poll-h",
272
+ "poll",
273
+ "portrait",
274
+ "pound-sign",
275
+ "pray",
276
+ "praying-hands",
277
+ "prescription-bottle-alt",
278
+ "procedures",
279
+ "project-diagram",
280
+ "quidditch",
281
+ "quran",
282
+ "radiation-alt",
283
+ "random",
284
+ "redo-alt",
285
+ "redo",
286
+ "remove-format",
287
+ "rss-square",
288
+ "running",
289
+ "search-dollar",
290
+ "search-location",
291
+ "search-minus",
292
+ "search-plus",
293
+ "search",
294
+ "share-alt-square",
295
+ "share-alt",
296
+ "shield-alt",
297
+ "shipping-fast",
298
+ "shopping-bag",
299
+ "shopping-basket",
300
+ "shopping-cart",
301
+ "shuttle-van",
302
+ "sign-in-alt",
303
+ "sign-language",
304
+ "sign-out-alt",
305
+ "sign",
306
+ "skating",
307
+ "skiing-nordic",
308
+ "skiing",
309
+ "sliders-h",
310
+ "smoking-ban",
311
+ "sms",
312
+ "snowboarding",
313
+ "sort-alpha-down-alt",
314
+ "sort-alpha-down",
315
+ "sort-alpha-up-alt",
316
+ "sort-alpha-up",
317
+ "sort-amount-down-alt",
318
+ "sort-amount-down",
319
+ "sort-amount-up-alt",
320
+ "sort-amount-up",
321
+ "sort-numeric-down-alt",
322
+ "sort-numeric-down",
323
+ "sort-numeric-up-alt",
324
+ "sort-numeric-up",
325
+ "space-shuttle",
326
+ "square-root-alt",
327
+ "star-half-alt",
328
+ "step-backward",
329
+ "step-forward",
330
+ "store-alt-slash",
331
+ "store-alt",
332
+ "stream",
333
+ "subway",
334
+ "swimmer",
335
+ "swimming-pool",
336
+ "sync-alt",
337
+ "sync",
338
+ "table-tennis",
339
+ "tablet-alt",
340
+ "tachometer-alt",
341
+ "tasks",
342
+ "tenge",
343
+ "th-large",
344
+ "th-list",
345
+ "th",
346
+ "theater-masks",
347
+ "thermometer-empty",
348
+ "thermometer-full",
349
+ "thermometer-half",
350
+ "thermometer-quarter",
351
+ "thermometer-three-quarters",
352
+ "ticket-alt",
353
+ "times",
354
+ "tint-slash",
355
+ "tint",
356
+ "tools",
357
+ "torah",
358
+ "tram",
359
+ "transgender-alt",
360
+ "trash-restore-alt",
361
+ "trash-restore",
362
+ "truck-loading",
363
+ "tshirt",
364
+ "undo-alt",
365
+ "undo",
366
+ "university",
367
+ "unlink",
368
+ "unlock-alt",
369
+ "user-alt-slash",
370
+ "user-alt",
371
+ "user-cog",
372
+ "user-edit",
373
+ "user-friends",
374
+ "user-md",
375
+ "user-times",
376
+ "users-cog",
377
+ "utensil-spoon",
378
+ "volleyball-ball",
379
+ "volume-down",
380
+ "volume-mute",
381
+ "volume-up",
382
+ "vote-yea",
383
+ "walking",
384
+ "weight",
385
+ "wine-glass-alt"
386
+ ]
387
+
388
+ module.exports = v5names
@@ -0,0 +1,9 @@
1
+ const banMixUse = require('./rule')
2
+
3
+ const plugin = {
4
+ rules: {
5
+ 'ban-mix-use': banMixUse,
6
+ },
7
+ };
8
+
9
+ module.exports = plugin
@@ -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
+ };