@nx/react-native 17.0.5 → 17.0.6

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 (181) hide show
  1. package/.eslintrc.json +1 -7
  2. package/LICENSE +1 -1
  3. package/README.md +4 -9
  4. package/executors.json +0 -5
  5. package/generators.json +11 -12
  6. package/migrations.json +0 -126
  7. package/package.json +15 -11
  8. package/plugins/metro-resolver.js +1 -4
  9. package/plugins/with-nx-metro.js +2 -6
  10. package/src/executors/build-android/build-android.impl.js +6 -2
  11. package/src/executors/build-android/build-android.impl.ts +6 -2
  12. package/src/executors/build-android/schema.json +1 -1
  13. package/src/executors/build-ios/schema.json +1 -1
  14. package/src/executors/bundle/schema.d.ts +1 -1
  15. package/src/executors/bundle/schema.json +1 -1
  16. package/src/executors/ensure-symlink/ensure-symlink.impl.d.ts +0 -4
  17. package/src/executors/ensure-symlink/ensure-symlink.impl.js +0 -4
  18. package/src/executors/ensure-symlink/ensure-symlink.impl.ts +0 -4
  19. package/src/executors/ensure-symlink/schema.json +1 -1
  20. package/src/executors/pod-install/schema.json +1 -1
  21. package/src/executors/run-android/run-android.impl.js +17 -5
  22. package/src/executors/run-android/run-android.impl.ts +18 -9
  23. package/src/executors/run-android/schema.json +1 -1
  24. package/src/executors/run-ios/run-ios.impl.js +16 -4
  25. package/src/executors/run-ios/run-ios.impl.ts +18 -9
  26. package/src/executors/run-ios/schema.json +1 -1
  27. package/src/executors/start/schema.d.ts +1 -1
  28. package/src/executors/start/schema.json +1 -1
  29. package/src/executors/start/start.impl.js +26 -11
  30. package/src/executors/start/start.impl.ts +28 -14
  31. package/src/executors/storybook/storybook.impl.d.ts +0 -4
  32. package/src/executors/storybook/storybook.impl.js +2 -15
  33. package/src/executors/storybook/storybook.impl.ts +7 -26
  34. package/src/executors/sync-deps/schema.d.ts +0 -1
  35. package/src/executors/sync-deps/schema.json +1 -6
  36. package/src/executors/sync-deps/sync-deps.impl.d.ts +1 -2
  37. package/src/executors/sync-deps/sync-deps.impl.js +11 -33
  38. package/src/executors/sync-deps/sync-deps.impl.ts +18 -57
  39. package/src/generators/application/application.js +8 -52
  40. package/src/generators/application/application.spec.ts +2 -29
  41. package/src/generators/application/files/app/Gemfile.template +1 -2
  42. package/src/generators/application/files/app/android/app/build.gradle.template +28 -12
  43. package/src/generators/application/files/app/android/app/src/debug/AndroidManifest.xml.template +6 -2
  44. package/src/generators/application/files/app/android/app/src/debug/java/com/__lowerCaseName__/ReactNativeFlipper.java.template +75 -0
  45. package/src/generators/application/files/app/android/app/src/main/java/com/__lowerCaseName__/MainActivity.java.template +32 -0
  46. package/src/generators/application/files/app/android/app/src/main/java/com/__lowerCaseName__/MainApplication.java.template +62 -0
  47. package/src/generators/application/files/app/android/app/src/release/java/com/__lowerCaseName__/ReactNativeFlipper.java.template +20 -0
  48. package/src/generators/application/files/app/android/build.gradle.template +20 -7
  49. package/src/generators/application/files/app/android/gradle/wrapper/gradle-wrapper.properties +1 -2
  50. package/src/generators/application/files/app/android/gradle.properties +3 -0
  51. package/src/generators/application/files/app/android/gradlew.template +7 -12
  52. package/src/generators/application/files/app/android/settings.gradle.template +2 -2
  53. package/src/generators/application/files/app/babel.config.json.template +3 -0
  54. package/src/generators/application/files/app/ios/Podfile.template +7 -0
  55. package/src/generators/application/files/app/ios/__className__/AppDelegate.mm.template +0 -5
  56. package/src/generators/application/files/app/ios/__className__/Info.plist.template +8 -5
  57. package/src/generators/application/files/app/ios/__className__.xcodeproj/project.pbxproj.template +33 -11
  58. package/src/generators/application/files/app/metro.config.js.template +5 -1
  59. package/src/generators/application/files/app/src/app/App.tsx.template +13 -50
  60. package/src/generators/application/lib/add-detox.d.ts +3 -0
  61. package/src/generators/application/lib/add-detox.js +23 -0
  62. package/src/generators/application/lib/add-project.js +18 -18
  63. package/src/generators/application/lib/normalize-options.d.ts +0 -7
  64. package/src/generators/application/lib/normalize-options.js +3 -35
  65. package/src/generators/application/lib/normalize-options.spec.ts +7 -70
  66. package/src/generators/application/schema.d.ts +3 -5
  67. package/src/generators/application/schema.json +6 -14
  68. package/src/generators/component/files/__fileName__.tsx__tmpl__ +1 -1
  69. package/src/generators/component/schema.d.ts +3 -3
  70. package/src/generators/component/schema.json +4 -4
  71. package/src/generators/component-story/component-story.d.ts +8 -5
  72. package/src/generators/component-story/component-story.js +69 -8
  73. package/src/generators/component-story/component-story.spec.ts +428 -0
  74. package/src/generators/component-story/files/__componentFileName__.stories.__fileExt__ +32 -0
  75. package/src/generators/component-story/schema.d.ts +0 -1
  76. package/src/generators/component-story/schema.json +3 -11
  77. package/src/generators/init/init.d.ts +1 -2
  78. package/src/generators/init/init.js +56 -55
  79. package/src/generators/init/init.spec.ts +6 -7
  80. package/src/generators/init/schema.d.ts +3 -3
  81. package/src/generators/init/schema.json +18 -13
  82. package/src/generators/library/files/lib/babel.config.json.template +17 -0
  83. package/src/generators/library/lib/normalize-options.js +0 -5
  84. package/src/generators/library/library.js +38 -48
  85. package/src/generators/library/library.spec.ts +60 -12
  86. package/src/generators/library/schema.d.ts +0 -1
  87. package/src/generators/library/schema.json +2 -2
  88. package/src/generators/stories/schema.d.ts +0 -2
  89. package/src/generators/stories/schema.json +2 -15
  90. package/src/generators/stories/stories-app.spec.ts +128 -0
  91. package/src/generators/stories/stories-lib.spec.ts +105 -0
  92. package/src/generators/stories/stories.d.ts +2 -5
  93. package/src/generators/stories/stories.js +50 -7
  94. package/src/generators/storybook-configuration/configuration.d.ts +2 -7
  95. package/src/generators/storybook-configuration/configuration.js +48 -18
  96. package/src/generators/storybook-configuration/configuration.spec.ts +135 -0
  97. package/src/generators/storybook-configuration/files/app/storybook.ts.template +9 -0
  98. package/src/generators/storybook-configuration/files/app/toggle-storybook.tsx.template +74 -0
  99. package/src/generators/storybook-configuration/files/root/story-loader.ts.template +5 -0
  100. package/src/generators/storybook-configuration/lib/add-resolver-main-fields-to-metro-config.d.ts +6 -0
  101. package/src/generators/storybook-configuration/lib/add-resolver-main-fields-to-metro-config.js +25 -0
  102. package/src/generators/storybook-configuration/lib/add-resolver-main-fields-to-metro-config.spec.ts +161 -0
  103. package/src/generators/storybook-configuration/lib/create-storybook-files.d.ts +6 -0
  104. package/src/generators/storybook-configuration/lib/create-storybook-files.js +42 -0
  105. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.d.ts +7 -0
  106. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.js +29 -0
  107. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.spec.ts +65 -0
  108. package/src/generators/storybook-configuration/schema.d.ts +2 -4
  109. package/src/generators/storybook-configuration/schema.json +12 -22
  110. package/src/generators/upgrade-native/lib/normalize-options.d.ts +1 -1
  111. package/src/generators/upgrade-native/schema.d.ts +1 -1
  112. package/src/generators/upgrade-native/schema.json +3 -3
  113. package/src/generators/upgrade-native/upgrade-native.d.ts +0 -2
  114. package/src/generators/upgrade-native/upgrade-native.js +0 -3
  115. package/src/migrations/update-16-6-0/update-metro-config.js +5 -1
  116. package/src/migrations/update-16-9-0/remove-types-react-native.js +9 -2
  117. package/src/utils/add-jest.d.ts +1 -1
  118. package/src/utils/add-jest.js +1 -13
  119. package/src/utils/add-linting.d.ts +0 -1
  120. package/src/utils/add-linting.js +1 -1
  121. package/src/utils/add-linting.spec.ts +6 -4
  122. package/src/utils/chmod-android-gradle-files.js +2 -6
  123. package/src/utils/find-all-npm-dependencies.js +3 -5
  124. package/src/utils/find-all-npm-dependencies.spec.ts +9 -17
  125. package/src/utils/symlink-task.d.ts +2 -0
  126. package/src/utils/symlink-task.js +18 -0
  127. package/src/utils/testing-generators.js +0 -1
  128. package/src/utils/versions.d.ts +13 -10
  129. package/src/utils/versions.js +14 -11
  130. package/plugin.d.ts +0 -1
  131. package/plugin.js +0 -6
  132. package/plugins/plugin.d.ts +0 -14
  133. package/plugins/plugin.js +0 -162
  134. package/src/executors/upgrade/schema.d.ts +0 -1
  135. package/src/executors/upgrade/schema.json +0 -11
  136. package/src/executors/upgrade/upgrade.impl.d.ts +0 -13
  137. package/src/executors/upgrade/upgrade.impl.js +0 -47
  138. package/src/executors/upgrade/upgrade.impl.ts +0 -64
  139. package/src/generators/application/files/app/.babelrc.js.template +0 -23
  140. package/src/generators/application/files/app/android/app/src/main/java/com/__lowerCaseName__/MainActivity.kt.template +0 -22
  141. package/src/generators/application/files/app/android/app/src/main/java/com/__lowerCaseName__/MainApplication.kt.template +0 -45
  142. package/src/generators/application/lib/add-e2e.d.ts +0 -3
  143. package/src/generators/application/lib/add-e2e.js +0 -46
  144. package/src/generators/library/files/lib/.babelrc.js.template +0 -21
  145. package/src/generators/web-configuration/files/base-vite/.babelrc.js.template +0 -23
  146. package/src/generators/web-configuration/files/base-vite/index.html__tmpl__ +0 -15
  147. package/src/generators/web-configuration/files/base-vite/public/favicon.ico +0 -0
  148. package/src/generators/web-configuration/files/base-vite/src/assets/.gitkeep +0 -0
  149. package/src/generators/web-configuration/files/base-vite/src/main-web.tsx__tmpl__ +0 -9
  150. package/src/generators/web-configuration/files/base-vite/vite.config.ts__tmpl__ +0 -82
  151. package/src/generators/web-configuration/files/base-webpack/.babelrc.js.template +0 -23
  152. package/src/generators/web-configuration/files/base-webpack/src/assets/.gitkeep +0 -0
  153. package/src/generators/web-configuration/files/base-webpack/src/favicon.ico +0 -0
  154. package/src/generators/web-configuration/files/base-webpack/src/index.html__tmpl__ +0 -14
  155. package/src/generators/web-configuration/files/base-webpack/src/main-web.tsx__tmpl__ +0 -9
  156. package/src/generators/web-configuration/files/base-webpack/webpack.config.js__tmpl__ +0 -77
  157. package/src/generators/web-configuration/lib/normalize-schema.d.ts +0 -17
  158. package/src/generators/web-configuration/lib/normalize-schema.js +0 -16
  159. package/src/generators/web-configuration/lib/webpack-targets.d.ts +0 -7
  160. package/src/generators/web-configuration/lib/webpack-targets.js +0 -75
  161. package/src/generators/web-configuration/schema.d.ts +0 -6
  162. package/src/generators/web-configuration/schema.json +0 -42
  163. package/src/generators/web-configuration/web-configuration.d.ts +0 -12
  164. package/src/generators/web-configuration/web-configuration.js +0 -87
  165. package/src/migrations/update-18-0-0/add-upgrade-target.d.ts +0 -6
  166. package/src/migrations/update-18-0-0/add-upgrade-target.js +0 -33
  167. package/src/migrations/update-18-0-0/add-web-configuration.d.ts +0 -8
  168. package/src/migrations/update-18-0-0/add-web-configuration.js +0 -33
  169. package/src/migrations/update-18-0-0/add-web-configuration.spec.ts +0 -39
  170. package/src/migrations/update-18-0-0/change-storybook-targets.d.ts +0 -5
  171. package/src/migrations/update-18-0-0/change-storybook-targets.js +0 -57
  172. package/src/migrations/update-18-0-0/remove-block-list.d.ts +0 -6
  173. package/src/migrations/update-18-0-0/remove-block-list.js +0 -28
  174. package/src/migrations/update-18-0-0/remove-block-list.spec.ts +0 -68
  175. package/src/migrations/update-18-0-0/remove-metro.d.ts +0 -14
  176. package/src/migrations/update-18-0-0/remove-metro.js +0 -29
  177. package/src/migrations/update-18-0-0/remove-symlink-target.d.ts +0 -6
  178. package/src/migrations/update-18-0-0/remove-symlink-target.js +0 -30
  179. package/src/migrations/update-18-0-0/remove-symlink-target.spec.ts +0 -40
  180. package/src/utils/ensure-dependencies.d.ts +0 -2
  181. package/src/utils/ensure-dependencies.js +0 -30
@@ -0,0 +1,428 @@
1
+ import { getProjects, Tree, updateProjectConfiguration } from '@nx/devkit';
2
+ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
3
+ import componentStoryGenerator from './component-story';
4
+ import { Linter } from '@nx/eslint';
5
+
6
+ import { formatFile } from '../../utils/format-file';
7
+ import libraryGenerator from '../library/library';
8
+ import componentGenerator from '../component/component';
9
+
10
+ describe('react-native:component-story', () => {
11
+ let appTree: Tree;
12
+ let cmpPath = 'test-ui-lib/src/lib/test-ui-lib/test-ui-lib.tsx';
13
+ let storyFilePath = 'test-ui-lib/src/lib/test-ui-lib/test-ui-lib.stories.tsx';
14
+
15
+ describe('default setup', () => {
16
+ beforeEach(async () => {
17
+ appTree = await createTestUILib('test-ui-lib');
18
+ });
19
+
20
+ describe('when file does not contain a component', () => {
21
+ beforeEach(() => {
22
+ appTree.write(
23
+ cmpPath,
24
+ `export const add = (a: number, b: number) => a + b;`
25
+ );
26
+ });
27
+
28
+ it('should fail with a descriptive error message', async () => {
29
+ try {
30
+ await componentStoryGenerator(appTree, {
31
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
32
+ project: 'test-ui-lib',
33
+ });
34
+ } catch (e) {
35
+ expect(e.message).toContain(
36
+ 'Could not find any React Native component in file test-ui-lib/src/lib/test-ui-lib/test-ui-lib.tsx'
37
+ );
38
+ }
39
+ });
40
+ });
41
+
42
+ describe('default component setup', () => {
43
+ beforeEach(async () => {
44
+ await componentStoryGenerator(appTree, {
45
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
46
+ project: 'test-ui-lib',
47
+ });
48
+ });
49
+
50
+ it('should create the story file', () => {
51
+ expect(appTree.exists(storyFilePath)).toBeTruthy();
52
+ });
53
+
54
+ it('should properly set up the story', () => {
55
+ expect(
56
+ formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
57
+ ).toContain(formatFile`
58
+ import type { Meta } from '@storybook/react-native';
59
+ import { TestUiLib } from './test-ui-lib';
60
+ const Story: Meta<typeof TestUiLib> = {
61
+ component: TestUiLib,
62
+ title: 'TestUiLib',
63
+ };
64
+ export default Story;
65
+ export const Primary = { args: {} };
66
+ `);
67
+ });
68
+ });
69
+
70
+ describe('when using plain JS components', () => {
71
+ let storyFilePathPlain =
72
+ 'test-ui-lib/src/lib/test-ui-libplain.stories.jsx';
73
+
74
+ beforeEach(async () => {
75
+ appTree.write(
76
+ 'test-ui-lib/src/lib/test-ui-libplain.jsx',
77
+ `import React from 'react';
78
+
79
+ import './test.scss';
80
+
81
+ export const Test = () => {
82
+ return (
83
+ <div>
84
+ <h1>Welcome to test component</h1>
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export default Test;
90
+ `
91
+ );
92
+
93
+ await componentStoryGenerator(appTree, {
94
+ componentPath: 'lib/test-ui-libplain.jsx',
95
+ project: 'test-ui-lib',
96
+ });
97
+ });
98
+
99
+ it('should create the story file', () => {
100
+ expect(appTree.exists(storyFilePathPlain)).toBeTruthy();
101
+ });
102
+
103
+ it('should properly set up the story', () => {
104
+ expect(formatFile`${appTree.read(storyFilePathPlain, 'utf-8')}`)
105
+ .toContain(formatFile`
106
+ import Test from './test-ui-libplain';
107
+ export default { component: Test, title: 'Test' };
108
+ export const Primary = { args: {} };
109
+ `);
110
+ });
111
+ });
112
+
113
+ describe('component without any props defined', () => {
114
+ beforeEach(async () => {
115
+ appTree.write(
116
+ cmpPath,
117
+ `import React from 'react';
118
+
119
+ import { View, Text } from 'react-native';
120
+
121
+ export function Test() {
122
+ return (
123
+ <View>
124
+ <Text>Welcome to test!</Text>
125
+ </View>
126
+ );
127
+ }
128
+
129
+ export default Test;
130
+ `
131
+ );
132
+ await componentStoryGenerator(appTree, {
133
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
134
+ project: 'test-ui-lib',
135
+ });
136
+ });
137
+
138
+ it('should create a story without controls', () => {
139
+ expect(formatFile`${appTree.read(storyFilePath, 'utf-8')}`)
140
+ .toContain(formatFile`
141
+ import type { Meta } from '@storybook/react-native';
142
+ import { Test } from './test-ui-lib';
143
+ const Story: Meta<typeof Test> = { component: Test, title: 'Test' };
144
+ export default Story;
145
+ export const Primary = { args: {} };
146
+ `);
147
+ });
148
+ });
149
+
150
+ describe('component with props', () => {
151
+ beforeEach(async () => {
152
+ await componentStoryGenerator(appTree, {
153
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
154
+ project: 'test-ui-lib',
155
+ });
156
+ });
157
+
158
+ it('should setup controls based on the component props', () => {
159
+ expect(
160
+ formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
161
+ ).toContain(formatFile`
162
+ import type { Meta } from '@storybook/react-native';
163
+ import { TestUiLib } from './test-ui-lib';
164
+ const Story: Meta<typeof TestUiLib> = {
165
+ component: TestUiLib,
166
+ title: 'TestUiLib',
167
+ };
168
+ export default Story;
169
+ export const Primary = { args: {} };
170
+ `);
171
+ });
172
+ });
173
+
174
+ describe('component with props and actions', () => {
175
+ beforeEach(async () => {
176
+ appTree.write(
177
+ cmpPath,
178
+ `import React from 'react';
179
+
180
+ export type ButtonStyle = 'default' | 'primary' | 'warning';
181
+
182
+ export interface TestProps {
183
+ name: string;
184
+ displayAge: boolean;
185
+ someAction: (e: unknown) => void;
186
+ style: ButtonStyle;
187
+ }
188
+
189
+ export const Test = (props: TestProps) => {
190
+ return (
191
+ <div>
192
+ <h1>Welcome to test component, {props.name}</h1>
193
+ <button onClick={props.someAction}>Click me!</button>
194
+ </div>
195
+ );
196
+ };
197
+
198
+ export default Test;
199
+ `
200
+ );
201
+
202
+ await componentStoryGenerator(appTree, {
203
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
204
+ project: 'test-ui-lib',
205
+ });
206
+ });
207
+
208
+ it('should setup controls based on the component props', () => {
209
+ expect(
210
+ formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
211
+ ).toContain(formatFile`
212
+ import type { Meta } from '@storybook/react-native';
213
+ import { Test } from './test-ui-lib';
214
+ const Story: Meta<typeof Test> = {
215
+ component: Test,
216
+ title: 'Test',
217
+ argTypes: { someAction: { action: 'someAction executed!' } },
218
+ };
219
+ export default Story;
220
+ export const Primary = { args: { name: '', displayAge: false } };
221
+ `);
222
+ });
223
+ });
224
+
225
+ [
226
+ {
227
+ name: 'default export function',
228
+ src: `export default function Test(props: TestProps) {
229
+ return (
230
+ <div>
231
+ <h1>Welcome to test component, {props.name}</h1>
232
+ </div>
233
+ );
234
+ };
235
+ `,
236
+ },
237
+ {
238
+ name: 'function and then export',
239
+ src: `
240
+ function Test(props: TestProps) {
241
+ return (
242
+ <div>
243
+ <h1>Welcome to test component, {props.name}</h1>
244
+ </div>
245
+ );
246
+ };
247
+ export default Test;
248
+ `,
249
+ },
250
+ {
251
+ name: 'arrow function',
252
+ src: `
253
+ const Test = (props: TestProps) => {
254
+ return (
255
+ <div>
256
+ <h1>Welcome to test component, {props.name}</h1>
257
+ </div>
258
+ );
259
+ };
260
+ export default Test;
261
+ `,
262
+ },
263
+ {
264
+ name: 'arrow function without {..}',
265
+ src: `
266
+ const Test = (props: TestProps) => <div><h1>Welcome to test component, {props.name}</h1></div>;
267
+ export default Test
268
+ `,
269
+ },
270
+ {
271
+ name: 'direct export of component class',
272
+ src: `
273
+ export default class Test extends React.Component<TestProps> {
274
+ render() {
275
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
276
+ }
277
+ }
278
+ `,
279
+ },
280
+ {
281
+ name: 'component class & then default export',
282
+ src: `
283
+ class Test extends React.Component<TestProps> {
284
+ render() {
285
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
286
+ }
287
+ }
288
+ export default Test
289
+ `,
290
+ },
291
+ {
292
+ name: 'PureComponent class & then default export',
293
+ src: `
294
+ class Test extends React.PureComponent<TestProps> {
295
+ render() {
296
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
297
+ }
298
+ }
299
+ export default Test
300
+ `,
301
+ },
302
+ {
303
+ name: 'direct export of component class new JSX transform',
304
+ src: `
305
+ export default class Test extends Component<TestProps> {
306
+ render() {
307
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
308
+ }
309
+ }
310
+ `,
311
+ },
312
+ {
313
+ name: 'component class & then default export new JSX transform',
314
+ src: `
315
+ class Test extends Component<TestProps> {
316
+ render() {
317
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
318
+ }
319
+ }
320
+ export default Test
321
+ `,
322
+ },
323
+ {
324
+ name: 'PureComponent class & then default export new JSX transform',
325
+ src: `
326
+ class Test extends PureComponent<TestProps> {
327
+ render() {
328
+ return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
329
+ }
330
+ }
331
+ export default Test
332
+ `,
333
+ },
334
+ ].forEach((config) => {
335
+ describe(`React Native component defined as:${config.name}`, () => {
336
+ beforeEach(async () => {
337
+ appTree.write(
338
+ cmpPath,
339
+ `import React from 'react';
340
+
341
+ export interface TestProps {
342
+ name: string;
343
+ displayAge: boolean;
344
+ }
345
+
346
+ ${config.src}
347
+ `
348
+ );
349
+
350
+ await componentStoryGenerator(appTree, {
351
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
352
+ project: 'test-ui-lib',
353
+ });
354
+ });
355
+
356
+ it('should properly setup the controls based on the component props', () => {
357
+ expect(
358
+ formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
359
+ ).toContain(formatFile`
360
+ import type { Meta } from '@storybook/react-native';
361
+ import { Test } from './test-ui-lib';
362
+ const Story: Meta<typeof Test> = { component: Test, title: 'Test' };
363
+ export default Story;
364
+ export const Primary = { args: { name: '', displayAge: false } };
365
+ `);
366
+ });
367
+ });
368
+ });
369
+ });
370
+
371
+ describe('using eslint', () => {
372
+ beforeEach(async () => {
373
+ appTree = await createTestUILib('test-ui-lib');
374
+ await componentGenerator(appTree, {
375
+ name: 'test-ui-lib',
376
+ project: 'test-ui-lib',
377
+ export: true,
378
+ });
379
+ await componentStoryGenerator(appTree, {
380
+ componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
381
+ project: 'test-ui-lib',
382
+ });
383
+ });
384
+
385
+ it('should properly set up the story', () => {
386
+ expect(formatFile`${appTree.read(storyFilePath, 'utf-8')}`)
387
+ .toContain(formatFile`
388
+ import type { Meta } from '@storybook/react-native';
389
+ import { TestUiLib } from './test-ui-lib';
390
+ const Story: Meta<typeof TestUiLib> = {
391
+ component: TestUiLib,
392
+ title: 'TestUiLib',
393
+ };
394
+ export default Story;
395
+ export const Primary = { args: {} };
396
+ `);
397
+ });
398
+ });
399
+ });
400
+
401
+ export async function createTestUILib(libName: string): Promise<Tree> {
402
+ let appTree = createTreeWithEmptyWorkspace();
403
+ appTree.write('.gitignore', '');
404
+
405
+ await libraryGenerator(appTree, {
406
+ name: libName,
407
+ linter: Linter.EsLint,
408
+ skipFormat: true,
409
+ skipTsConfig: false,
410
+ unitTestRunner: 'jest',
411
+ projectNameAndRootFormat: 'as-provided',
412
+ });
413
+
414
+ await componentGenerator(appTree, {
415
+ name: libName,
416
+ project: libName,
417
+ export: true,
418
+ });
419
+
420
+ const currentWorkspaceJson = getProjects(appTree);
421
+
422
+ const projectConfig = currentWorkspaceJson.get(libName);
423
+ projectConfig.targets.lint.options.linter = 'eslint';
424
+
425
+ updateProjectConfiguration(appTree, libName, projectConfig);
426
+
427
+ return appTree;
428
+ }
@@ -0,0 +1,32 @@
1
+ <% if ( !isPlainJs ) { %>import type { Meta } from '@storybook/react-native';<% } %>
2
+ import<% if ( !isPlainJs ) { %> { <% } %> <%= componentName %> <% if ( !isPlainJs ) { %> } <% } %> from './<%= componentImportFileName %>';
3
+
4
+ <% if ( isPlainJs ) { %>
5
+ export default {
6
+ component: <%= componentName %>,
7
+ title: '<%= componentName %>',<% if ( argTypes && argTypes.length > 0 ) { %>
8
+ argTypes: {<% for (let argType of argTypes) { %>
9
+ <%= argType.name %>: { <%- argType.type %> : "<%- argType.actionText %>" },<% } %>
10
+ }
11
+ <% } %>
12
+ };
13
+ <% } %>
14
+
15
+
16
+ <% if ( !isPlainJs ) { %>
17
+ const Story: Meta<typeof <%= componentName %>> = {
18
+ component: <%= componentName %>,
19
+ title: '<%= componentName %>',<% if ( argTypes && argTypes.length > 0 ) { %>
20
+ argTypes: {<% for (let argType of argTypes) { %>
21
+ <%= argType.name %>: { <%- argType.type %> : "<%- argType.actionText %>" },<% } %>
22
+ }
23
+ <% } %>
24
+ };
25
+ export default Story;
26
+ <% } %>
27
+
28
+ export const Primary = {
29
+ args: {<% for (let prop of props) { %>
30
+ <%= prop.name %>: <%- prop.defaultValue %>,<% } %>
31
+ },
32
+ };
@@ -1,6 +1,5 @@
1
1
  export interface CreateComponentStoriesFileSchema {
2
2
  project: string;
3
3
  componentPath: string;
4
- interactionTests?: boolean;
5
4
  skipFormat?: boolean;
6
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://json-schema.org/schema",
2
+ "$schema": "http://json-schema.org/schema",
3
3
  "cli": "nx",
4
4
  "$id": "NxReactNativeComponentStory",
5
5
  "title": "React native component story",
@@ -15,27 +15,19 @@
15
15
  "$source": "projectName",
16
16
  "index": 0
17
17
  },
18
- "x-prompt": "What's name of the project where the component lives?",
19
- "x-priority": "important"
18
+ "x-prompt": "What's the name of the project where the component lives?"
20
19
  },
21
20
  "componentPath": {
22
21
  "type": "string",
23
22
  "description": "Relative path to the component file from the library root.",
24
23
  "examples": ["lib/components"],
25
- "x-prompt": "What's path of the component relative to the project's lib root?",
26
- "x-priority": "important"
24
+ "x-prompt": "What's path of the component relative to the project's lib root?"
27
25
  },
28
26
  "skipFormat": {
29
27
  "description": "Skip formatting files.",
30
28
  "type": "boolean",
31
29
  "default": false,
32
30
  "x-priority": "internal"
33
- },
34
- "interactionTests": {
35
- "type": "boolean",
36
- "description": "Set up Storybook interaction tests.",
37
- "default": true,
38
- "x-priority": "important"
39
31
  }
40
32
  },
41
33
  "required": ["project", "componentPath"]
@@ -1,6 +1,5 @@
1
1
  import { GeneratorCallback, Tree } from '@nx/devkit';
2
2
  import { Schema } from './schema';
3
3
  export declare function reactNativeInitGenerator(host: Tree, schema: Schema): Promise<GeneratorCallback>;
4
- export declare function reactNativeInitGeneratorInternal(host: Tree, schema: Schema): Promise<GeneratorCallback>;
5
- export declare function updateDependencies(host: Tree, schema: Schema): GeneratorCallback;
4
+ export declare function updateDependencies(host: Tree): GeneratorCallback;
6
5
  export default reactNativeInitGenerator;
@@ -1,78 +1,79 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateDependencies = exports.reactNativeInitGeneratorInternal = exports.reactNativeInitGenerator = void 0;
3
+ exports.updateDependencies = exports.reactNativeInitGenerator = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const update_package_scripts_1 = require("@nx/devkit/src/utils/update-package-scripts");
6
- const plugin_1 = require("../../../plugins/plugin");
7
- const versions_1 = require("../../utils/versions");
5
+ const jest_1 = require("@nx/jest");
6
+ const detox_1 = require("@nx/detox");
7
+ const versions_1 = require("@nx/react/src/utils/versions");
8
+ const js_1 = require("@nx/js");
9
+ const versions_2 = require("../../utils/versions");
8
10
  const add_git_ignore_entry_1 = require("./lib/add-git-ignore-entry");
9
- function reactNativeInitGenerator(host, schema) {
10
- return reactNativeInitGeneratorInternal(host, {
11
- addPlugin: false,
12
- ...schema,
13
- });
14
- }
15
- exports.reactNativeInitGenerator = reactNativeInitGenerator;
16
- async function reactNativeInitGeneratorInternal(host, schema) {
11
+ async function reactNativeInitGenerator(host, schema) {
17
12
  (0, add_git_ignore_entry_1.addGitIgnoreEntry)(host);
18
- const nxJson = (0, devkit_1.readNxJson)(host);
19
- const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
20
- nxJson.useInferencePlugins !== false;
21
- schema.addPlugin ??= addPluginDefault;
22
- if (schema.addPlugin) {
23
- addPlugin(host);
24
- }
25
13
  const tasks = [];
14
+ tasks.push(await (0, js_1.initGenerator)(host, {
15
+ ...schema,
16
+ skipFormat: true,
17
+ }));
26
18
  if (!schema.skipPackageJson) {
19
+ const installTask = updateDependencies(host);
27
20
  tasks.push(moveDependency(host));
28
- tasks.push(updateDependencies(host, schema));
21
+ tasks.push(installTask);
29
22
  }
30
- if (schema.updatePackageScripts) {
31
- await (0, update_package_scripts_1.updatePackageScripts)(host, plugin_1.createNodes);
23
+ if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
24
+ const jestTask = await (0, jest_1.jestInitGenerator)(host, schema);
25
+ tasks.push(jestTask);
26
+ }
27
+ if (!schema.e2eTestRunner || schema.e2eTestRunner === 'detox') {
28
+ const detoxTask = await (0, detox_1.detoxInitGenerator)(host, {
29
+ ...schema,
30
+ skipFormat: true,
31
+ });
32
+ tasks.push(detoxTask);
32
33
  }
33
34
  if (!schema.skipFormat) {
34
35
  await (0, devkit_1.formatFiles)(host);
35
36
  }
36
37
  return (0, devkit_1.runTasksInSerial)(...tasks);
37
38
  }
38
- exports.reactNativeInitGeneratorInternal = reactNativeInitGeneratorInternal;
39
- function updateDependencies(host, schema) {
39
+ exports.reactNativeInitGenerator = reactNativeInitGenerator;
40
+ function updateDependencies(host) {
41
+ const isPnpm = (0, devkit_1.detectPackageManager)(host.root) === 'pnpm';
40
42
  return (0, devkit_1.addDependenciesToPackageJson)(host, {
41
- react: versions_1.reactVersion,
42
- 'react-dom': versions_1.reactDomVersion,
43
- 'react-native': versions_1.reactNativeVersion,
43
+ react: versions_2.reactVersion,
44
+ 'react-dom': versions_2.reactDomVersion,
45
+ 'react-native': versions_2.reactNativeVersion,
44
46
  }, {
45
- '@nx/react-native': versions_1.nxVersion,
46
- }, undefined, schema.keepExistingVersions);
47
+ '@nx/react-native': versions_2.nxVersion,
48
+ '@types/node': versions_2.typesNodeVersion,
49
+ '@types/react': versions_2.typesReactVersion,
50
+ '@react-native/metro-config': versions_2.reactNativeMetroConfigVersion,
51
+ '@react-native-community/cli': versions_2.reactNativeCommunityCli,
52
+ '@react-native-community/cli-platform-android': versions_2.reactNativeCommunityCliAndroid,
53
+ '@react-native-community/cli-platform-ios': versions_2.reactNativeCommunityCliIos,
54
+ '@testing-library/react-native': versions_2.testingLibraryReactNativeVersion,
55
+ '@testing-library/jest-native': versions_2.testingLibraryJestNativeVersion,
56
+ 'jest-react-native': versions_2.jestReactNativeVersion,
57
+ metro: versions_2.metroVersion,
58
+ 'metro-config': versions_2.metroVersion,
59
+ 'metro-resolver': versions_2.metroVersion,
60
+ 'metro-babel-register': versions_2.metroVersion,
61
+ 'metro-react-native-babel-preset': versions_2.metroVersion,
62
+ 'metro-react-native-babel-transformer': versions_2.metroVersion,
63
+ 'react-test-renderer': versions_2.reactTestRendererVersion,
64
+ 'react-native-svg-transformer': versions_2.reactNativeSvgTransformerVersion,
65
+ 'react-native-svg': versions_2.reactNativeSvgVersion,
66
+ '@babel/preset-react': versions_1.babelPresetReactVersion,
67
+ '@babel/core': versions_1.babelCoreVersion,
68
+ ...(isPnpm
69
+ ? {
70
+ '@babel/runtime': versions_2.babelRuntimeVersion, // @babel/runtime is used by react-native-svg
71
+ }
72
+ : {}),
73
+ });
47
74
  }
48
75
  exports.updateDependencies = updateDependencies;
49
76
  function moveDependency(host) {
50
77
  return (0, devkit_1.removeDependenciesFromPackageJson)(host, ['@nx/react-native'], []);
51
78
  }
52
- function addPlugin(host) {
53
- const nxJson = (0, devkit_1.readNxJson)(host);
54
- nxJson.plugins ??= [];
55
- for (const plugin of nxJson.plugins) {
56
- if (typeof plugin === 'string'
57
- ? plugin === '@nx/react-native/plugin'
58
- : plugin.plugin === '@nx/react-native/plugin') {
59
- return;
60
- }
61
- }
62
- nxJson.plugins.push({
63
- plugin: '@nx/react-native/plugin',
64
- options: {
65
- startTargetName: 'start',
66
- podInstallTargetName: 'pod-install',
67
- bundleTargetName: 'bundle',
68
- runIosTargetName: 'run-ios',
69
- runAndroidTargetName: 'run-android',
70
- buildIosTargetName: 'build-ios',
71
- buildAndroidTargetName: 'build-android',
72
- syncDepsTargetName: 'sync-deps',
73
- upgradeTargetname: 'upgrade',
74
- },
75
- });
76
- (0, devkit_1.updateNxJson)(host, nxJson);
77
- }
78
79
  exports.default = reactNativeInitGenerator;
@@ -1,4 +1,5 @@
1
- import { Tree, readJson } from '@nx/devkit';
1
+ import { NxJsonConfiguration } from '@nx/devkit';
2
+ import { Tree, readJson, updateJson } from '@nx/devkit';
2
3
  import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
3
4
  import { reactNativeInitGenerator } from './init';
4
5
 
@@ -11,12 +12,12 @@ describe('init', () => {
11
12
  });
12
13
 
13
14
  it('should add react native dependencies', async () => {
14
- await reactNativeInitGenerator(tree, {
15
- addPlugin: true,
16
- });
15
+ await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
17
16
  const packageJson = readJson(tree, 'package.json');
18
17
  expect(packageJson.dependencies['react']).toBeDefined();
19
18
  expect(packageJson.dependencies['react-native']).toBeDefined();
19
+ expect(packageJson.devDependencies['@types/node']).toBeDefined();
20
+ expect(packageJson.devDependencies['@types/react']).toBeDefined();
20
21
  });
21
22
 
22
23
  it('should add .gitignore entries for React native files and directories', async () => {
@@ -26,9 +27,7 @@ describe('init', () => {
26
27
  /node_modules
27
28
  `
28
29
  );
29
- await reactNativeInitGenerator(tree, {
30
- addPlugin: true,
31
- });
30
+ await reactNativeInitGenerator(tree, { e2eTestRunner: 'none' });
32
31
 
33
32
  const content = tree.read('/.gitignore').toString();
34
33