@ronas-it/nx-generators 0.10.2 → 0.10.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.
Files changed (214) hide show
  1. package/.eslintrc.json +37 -0
  2. package/jest.config.ts +10 -0
  3. package/package.json +2 -2
  4. package/project.json +61 -0
  5. package/src/generators/code-checks/config.ts +17 -0
  6. package/src/generators/code-checks/generator.ts +72 -0
  7. package/src/generators/code-checks/scripts.ts +5 -0
  8. package/src/generators/entity-api/generator.ts +127 -0
  9. package/src/generators/expo-app/generator.ts +152 -0
  10. package/src/generators/expo-app/scripts.ts +12 -0
  11. package/src/generators/form/generator.ts +53 -0
  12. package/src/generators/form/utils/add-form-usage.ts +86 -0
  13. package/src/generators/form/utils/get-app-name.ts +3 -0
  14. package/src/generators/form/utils/get-form-utils-directory.ts +46 -0
  15. package/src/generators/form/utils/update-index.ts +14 -0
  16. package/src/generators/lib-move/generator.ts +57 -0
  17. package/src/generators/lib-remove/generator.ts +25 -0
  18. package/src/generators/lib-rename/generator.ts +25 -0
  19. package/src/generators/lib-tags/generator.ts +68 -0
  20. package/src/generators/lib-tags/interfaces/context.ts +9 -0
  21. package/src/generators/lib-tags/interfaces/index.ts +2 -0
  22. package/src/generators/lib-tags/interfaces/verify-tag-config.ts +12 -0
  23. package/src/generators/lib-tags/types/index.ts +1 -0
  24. package/src/generators/lib-tags/types/tag.ts +1 -0
  25. package/src/generators/lib-tags/utils/check-lib-tags.ts +143 -0
  26. package/src/generators/next-app/generator.ts +99 -0
  27. package/src/generators/react-component/generator.ts +80 -0
  28. package/src/generators/react-lib/generator.ts +86 -0
  29. package/src/generators/repo-config/generator.ts +44 -0
  30. package/src/generators/repo-config/scripts.ts +3 -0
  31. package/src/shared/dependencies.ts +76 -0
  32. package/src/shared/enums/base-generator-type.ts +4 -0
  33. package/src/shared/generators/api-client/generator.ts +49 -0
  34. package/src/shared/generators/app-env/generator.ts +37 -0
  35. package/src/shared/generators/app-env/lib-files/shared/utils/app-env/src/app-env.ts.template +1 -1
  36. package/src/shared/generators/auth/generator.ts +107 -0
  37. package/src/shared/generators/form-utils/generator.ts +23 -0
  38. package/src/shared/generators/rn-styles/generator.ts +49 -0
  39. package/src/shared/generators/storage/generator.ts +34 -0
  40. package/src/shared/generators/store/generator.ts +48 -0
  41. package/src/shared/generators/store/schema.d.ts +1 -1
  42. package/src/shared/generators/ui-kitten/generator.ts +55 -0
  43. package/src/shared/utils/cli-utils.ts +149 -0
  44. package/src/shared/utils/config-utils.ts +146 -0
  45. package/src/shared/utils/constants.ts +3 -0
  46. package/src/shared/utils/dynamic-import.ts +4 -0
  47. package/src/shared/utils/format-utils.ts +16 -0
  48. package/src/shared/utils/get-lib-directory-name.ts +12 -0
  49. package/src/shared/utils/ts-utils.ts +17 -0
  50. package/tsconfig.json +16 -0
  51. package/tsconfig.lib.json +10 -0
  52. package/tsconfig.spec.json +14 -0
  53. package/src/generators/code-checks/config.d.ts +0 -18
  54. package/src/generators/code-checks/config.js +0 -20
  55. package/src/generators/code-checks/config.js.map +0 -1
  56. package/src/generators/code-checks/generator.d.ts +0 -4
  57. package/src/generators/code-checks/generator.js +0 -53
  58. package/src/generators/code-checks/generator.js.map +0 -1
  59. package/src/generators/code-checks/scripts.d.ts +0 -6
  60. package/src/generators/code-checks/scripts.js +0 -8
  61. package/src/generators/code-checks/scripts.js.map +0 -1
  62. package/src/generators/entity-api/generator.d.ts +0 -4
  63. package/src/generators/entity-api/generator.js +0 -84
  64. package/src/generators/entity-api/generator.js.map +0 -1
  65. package/src/generators/expo-app/generator.d.ts +0 -4
  66. package/src/generators/expo-app/generator.js +0 -93
  67. package/src/generators/expo-app/generator.js.map +0 -1
  68. package/src/generators/expo-app/scripts.d.ts +0 -13
  69. package/src/generators/expo-app/scripts.js +0 -15
  70. package/src/generators/expo-app/scripts.js.map +0 -1
  71. package/src/generators/form/generator.d.ts +0 -4
  72. package/src/generators/form/generator.js +0 -48
  73. package/src/generators/form/generator.js.map +0 -1
  74. package/src/generators/form/utils/add-form-usage.d.ts +0 -1
  75. package/src/generators/form/utils/add-form-usage.js +0 -67
  76. package/src/generators/form/utils/add-form-usage.js.map +0 -1
  77. package/src/generators/form/utils/get-app-name.d.ts +0 -1
  78. package/src/generators/form/utils/get-app-name.js +0 -8
  79. package/src/generators/form/utils/get-app-name.js.map +0 -1
  80. package/src/generators/form/utils/get-form-utils-directory.d.ts +0 -2
  81. package/src/generators/form/utils/get-form-utils-directory.js +0 -34
  82. package/src/generators/form/utils/get-form-utils-directory.js.map +0 -1
  83. package/src/generators/form/utils/index.js +0 -8
  84. package/src/generators/form/utils/index.js.map +0 -1
  85. package/src/generators/form/utils/update-index.d.ts +0 -2
  86. package/src/generators/form/utils/update-index.js +0 -18
  87. package/src/generators/form/utils/update-index.js.map +0 -1
  88. package/src/generators/lib-move/generator.d.ts +0 -4
  89. package/src/generators/lib-move/generator.js +0 -34
  90. package/src/generators/lib-move/generator.js.map +0 -1
  91. package/src/generators/lib-remove/generator.d.ts +0 -4
  92. package/src/generators/lib-remove/generator.js +0 -22
  93. package/src/generators/lib-remove/generator.js.map +0 -1
  94. package/src/generators/lib-rename/generator.d.ts +0 -4
  95. package/src/generators/lib-rename/generator.js +0 -24
  96. package/src/generators/lib-rename/generator.js.map +0 -1
  97. package/src/generators/lib-tags/generator.d.ts +0 -4
  98. package/src/generators/lib-tags/generator.js +0 -56
  99. package/src/generators/lib-tags/generator.js.map +0 -1
  100. package/src/generators/lib-tags/interfaces/context.d.ts +0 -8
  101. package/src/generators/lib-tags/interfaces/context.js +0 -3
  102. package/src/generators/lib-tags/interfaces/context.js.map +0 -1
  103. package/src/generators/lib-tags/interfaces/index.d.ts +0 -1
  104. package/src/generators/lib-tags/interfaces/index.js +0 -5
  105. package/src/generators/lib-tags/interfaces/index.js.map +0 -1
  106. package/src/generators/lib-tags/utils/check-lib-tags.d.ts +0 -4
  107. package/src/generators/lib-tags/utils/check-lib-tags.js +0 -99
  108. package/src/generators/lib-tags/utils/check-lib-tags.js.map +0 -1
  109. package/src/generators/lib-tags/utils/index.js +0 -5
  110. package/src/generators/lib-tags/utils/index.js.map +0 -1
  111. package/src/generators/next-app/generator.d.ts +0 -4
  112. package/src/generators/next-app/generator.js +0 -71
  113. package/src/generators/next-app/generator.js.map +0 -1
  114. package/src/generators/react-component/generator.d.ts +0 -4
  115. package/src/generators/react-component/generator.js +0 -55
  116. package/src/generators/react-component/generator.js.map +0 -1
  117. package/src/generators/react-lib/generator.d.ts +0 -4
  118. package/src/generators/react-lib/generator.js +0 -49
  119. package/src/generators/react-lib/generator.js.map +0 -1
  120. package/src/generators/repo-config/generator.d.ts +0 -3
  121. package/src/generators/repo-config/generator.js +0 -36
  122. package/src/generators/repo-config/generator.js.map +0 -1
  123. package/src/generators/repo-config/scripts.d.ts +0 -4
  124. package/src/generators/repo-config/scripts.js +0 -6
  125. package/src/generators/repo-config/scripts.js.map +0 -1
  126. package/src/index.js +0 -1
  127. package/src/index.js.map +0 -1
  128. package/src/shared/dependencies.d.ts +0 -73
  129. package/src/shared/dependencies.js +0 -79
  130. package/src/shared/dependencies.js.map +0 -1
  131. package/src/shared/enums/base-generator-type.d.ts +0 -4
  132. package/src/shared/enums/base-generator-type.js +0 -9
  133. package/src/shared/enums/base-generator-type.js.map +0 -1
  134. package/src/shared/enums/index.js +0 -5
  135. package/src/shared/enums/index.js.map +0 -1
  136. package/src/shared/generators/api-client/generator.d.ts +0 -6
  137. package/src/shared/generators/api-client/generator.js +0 -35
  138. package/src/shared/generators/api-client/generator.js.map +0 -1
  139. package/src/shared/generators/api-client/index.js +0 -5
  140. package/src/shared/generators/api-client/index.js.map +0 -1
  141. package/src/shared/generators/app-env/generator.d.ts +0 -6
  142. package/src/shared/generators/app-env/generator.js +0 -25
  143. package/src/shared/generators/app-env/generator.js.map +0 -1
  144. package/src/shared/generators/app-env/index.js +0 -5
  145. package/src/shared/generators/app-env/index.js.map +0 -1
  146. package/src/shared/generators/auth/generator.d.ts +0 -4
  147. package/src/shared/generators/auth/generator.js +0 -74
  148. package/src/shared/generators/auth/generator.js.map +0 -1
  149. package/src/shared/generators/auth/index.js +0 -5
  150. package/src/shared/generators/auth/index.js.map +0 -1
  151. package/src/shared/generators/form-utils/generator.d.ts +0 -5
  152. package/src/shared/generators/form-utils/generator.js +0 -22
  153. package/src/shared/generators/form-utils/generator.js.map +0 -1
  154. package/src/shared/generators/form-utils/index.js +0 -5
  155. package/src/shared/generators/form-utils/index.js.map +0 -1
  156. package/src/shared/generators/index.js +0 -12
  157. package/src/shared/generators/index.js.map +0 -1
  158. package/src/shared/generators/rn-styles/generator.d.ts +0 -6
  159. package/src/shared/generators/rn-styles/generator.js +0 -36
  160. package/src/shared/generators/rn-styles/generator.js.map +0 -1
  161. package/src/shared/generators/rn-styles/index.js +0 -5
  162. package/src/shared/generators/rn-styles/index.js.map +0 -1
  163. package/src/shared/generators/storage/generator.d.ts +0 -6
  164. package/src/shared/generators/storage/generator.js +0 -25
  165. package/src/shared/generators/storage/generator.js.map +0 -1
  166. package/src/shared/generators/storage/index.js +0 -5
  167. package/src/shared/generators/storage/index.js.map +0 -1
  168. package/src/shared/generators/store/generator.d.ts +0 -4
  169. package/src/shared/generators/store/generator.js +0 -34
  170. package/src/shared/generators/store/generator.js.map +0 -1
  171. package/src/shared/generators/store/index.js +0 -5
  172. package/src/shared/generators/store/index.js.map +0 -1
  173. package/src/shared/generators/ui-kitten/generator.d.ts +0 -6
  174. package/src/shared/generators/ui-kitten/generator.js +0 -40
  175. package/src/shared/generators/ui-kitten/generator.js.map +0 -1
  176. package/src/shared/generators/ui-kitten/index.js +0 -5
  177. package/src/shared/generators/ui-kitten/index.js.map +0 -1
  178. package/src/shared/utils/cli-utils.d.ts +0 -28
  179. package/src/shared/utils/cli-utils.js +0 -125
  180. package/src/shared/utils/cli-utils.js.map +0 -1
  181. package/src/shared/utils/config-utils.d.ts +0 -19
  182. package/src/shared/utils/config-utils.js +0 -115
  183. package/src/shared/utils/config-utils.js.map +0 -1
  184. package/src/shared/utils/constants.d.ts +0 -3
  185. package/src/shared/utils/constants.js +0 -7
  186. package/src/shared/utils/constants.js.map +0 -1
  187. package/src/shared/utils/dynamic-import.d.ts +0 -1
  188. package/src/shared/utils/dynamic-import.js +0 -5
  189. package/src/shared/utils/dynamic-import.js.map +0 -1
  190. package/src/shared/utils/format-utils.d.ts +0 -4
  191. package/src/shared/utils/format-utils.js +0 -18
  192. package/src/shared/utils/format-utils.js.map +0 -1
  193. package/src/shared/utils/get-lib-directory-name.d.ts +0 -1
  194. package/src/shared/utils/get-lib-directory-name.js +0 -15
  195. package/src/shared/utils/get-lib-directory-name.js.map +0 -1
  196. package/src/shared/utils/index.js +0 -11
  197. package/src/shared/utils/index.js.map +0 -1
  198. package/src/shared/utils/ts-utils.d.ts +0 -2
  199. package/src/shared/utils/ts-utils.js +0 -21
  200. package/src/shared/utils/ts-utils.js.map +0 -1
  201. /package/src/generators/form/utils/{index.d.ts → index.ts} +0 -0
  202. /package/src/generators/lib-tags/utils/{index.d.ts → index.ts} +0 -0
  203. /package/src/{index.d.ts → index.ts} +0 -0
  204. /package/src/shared/enums/{index.d.ts → index.ts} +0 -0
  205. /package/src/shared/generators/api-client/{index.d.ts → index.ts} +0 -0
  206. /package/src/shared/generators/app-env/{index.d.ts → index.ts} +0 -0
  207. /package/src/shared/generators/auth/{index.d.ts → index.ts} +0 -0
  208. /package/src/shared/generators/form-utils/{index.d.ts → index.ts} +0 -0
  209. /package/src/shared/generators/{index.d.ts → index.ts} +0 -0
  210. /package/src/shared/generators/rn-styles/{index.d.ts → index.ts} +0 -0
  211. /package/src/shared/generators/storage/{index.d.ts → index.ts} +0 -0
  212. /package/src/shared/generators/store/{index.d.ts → index.ts} +0 -0
  213. /package/src/shared/generators/ui-kitten/{index.d.ts → index.ts} +0 -0
  214. /package/src/shared/utils/{index.d.ts → index.ts} +0 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "extends": ["../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7
+ "rules": {}
8
+ },
9
+ {
10
+ "files": ["*.ts", "*.tsx"],
11
+ "rules": {}
12
+ },
13
+ {
14
+ "files": ["*.js", "*.jsx"],
15
+ "rules": {}
16
+ },
17
+ {
18
+ "files": ["*.json"],
19
+ "parser": "jsonc-eslint-parser",
20
+ "rules": {
21
+ "@nx/dependency-checks": [
22
+ "error",
23
+ {
24
+ "ignoredDependencies": ["@nx/expo"]
25
+ }
26
+ ]
27
+ }
28
+ },
29
+ {
30
+ "files": ["./package.json", "./generators.json"],
31
+ "parser": "jsonc-eslint-parser",
32
+ "rules": {
33
+ "@nx/nx-plugin-checks": "error"
34
+ }
35
+ }
36
+ ]
37
+ }
package/jest.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ /* eslint-disable */
2
+ export default {
3
+ displayName: '@ronas-it/nx-generators',
4
+ preset: '../jest.preset.js',
5
+ transform: {
6
+ '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
7
+ },
8
+ moduleFileExtensions: ['ts', 'js', 'html'],
9
+ coverageDirectory: '../coverage/plugin',
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronas-it/nx-generators",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "NX generators for Ronas IT projects",
5
5
  "license": "MIT",
6
6
  "author": "Ronas IT",
@@ -35,4 +35,4 @@
35
35
  "main": "./src/index.js",
36
36
  "typings": "./src/index.d.ts",
37
37
  "generators": "./generators.json"
38
- }
38
+ }
package/project.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@ronas-it/nx-generators",
3
+ "$schema": "../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "plugin/src",
5
+ "projectType": "library",
6
+ "targets": {
7
+ "build": {
8
+ "executor": "@nx/js:tsc",
9
+ "outputs": ["{options.outputPath}"],
10
+ "options": {
11
+ "outputPath": "dist/plugin",
12
+ "main": "plugin/src/index.ts",
13
+ "tsConfig": "plugin/tsconfig.lib.json",
14
+ "assets": [
15
+ "plugin/*.md",
16
+ {
17
+ "input": "./plugin/src",
18
+ "glob": "**/!(*.ts)",
19
+ "output": "./src"
20
+ },
21
+ {
22
+ "input": "./plugin/src",
23
+ "glob": "**/*.d.ts",
24
+ "output": "./src"
25
+ },
26
+ {
27
+ "input": "./plugin",
28
+ "glob": "generators.json",
29
+ "output": "."
30
+ },
31
+ {
32
+ "input": "./plugin",
33
+ "glob": "executors.json",
34
+ "output": "."
35
+ }
36
+ ]
37
+ }
38
+ },
39
+ "nx-release-publish": {
40
+ "options": {
41
+ "packageRoot": "dist/{projectRoot}"
42
+ }
43
+ },
44
+ "test": {
45
+ "executor": "@nx/jest:jest",
46
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
47
+ "options": {
48
+ "jestConfig": "plugin/jest.config.ts"
49
+ }
50
+ }
51
+ },
52
+ "tags": ["nx", "generator", "monorepo", "expo", "react-native", "typescript"],
53
+ "release": {
54
+ "version": {
55
+ "generatorOptions": {
56
+ "packageRoot": "dist/{projectRoot}",
57
+ "currentVersionResolver": "git-tag"
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,17 @@
1
+ export default {
2
+ 'lint-staged': {
3
+ '*.{ts,tsx}': 'tsc-files --noEmit types.d.ts',
4
+ '*.{ts,tsx,js,html,json,md}': 'prettier --write',
5
+ '*.{ts,tsx,js}': 'eslint --cache --fix',
6
+ },
7
+ tsconfig: {
8
+ jsx: 'react-native',
9
+ allowJs: true,
10
+ noEmit: true,
11
+ strict: true,
12
+ allowSyntheticDefaultImports: true,
13
+ noImplicitAny: true,
14
+ strictPropertyInitialization: false,
15
+ strictNullChecks: true,
16
+ },
17
+ };
@@ -0,0 +1,72 @@
1
+ import { execSync } from 'child_process';
2
+ import * as path from 'path';
3
+ import {
4
+ addDependenciesToPackageJson,
5
+ formatFiles,
6
+ generateFiles,
7
+ installPackagesTask,
8
+ readJson,
9
+ Tree,
10
+ writeJson,
11
+ } from '@nx/devkit';
12
+ import { devDependencies } from '../../shared/dependencies';
13
+ import config from './config';
14
+ import { CodeChecksGeneratorSchema } from './schema';
15
+ import scripts from './scripts';
16
+
17
+ export async function codeChecksGenerator(tree: Tree, options: CodeChecksGeneratorSchema) {
18
+ const projectRoot = '.';
19
+
20
+ // Delete files
21
+ tree.delete('.eslintrc.json');
22
+ tree.delete('eslint.config.cjs');
23
+ tree.delete('.prettierrc');
24
+
25
+ // Configure pre-commit hook
26
+ execSync('npx mrm@2 lint-staged', { stdio: 'inherit' });
27
+
28
+ const packageJson = readJson(tree, 'package.json');
29
+ packageJson['lint-staged'] = config['lint-staged'];
30
+ packageJson.scripts = { ...scripts, ...packageJson.scripts };
31
+ writeJson(tree, 'package.json', packageJson);
32
+
33
+ // Update tsconfig.base.json
34
+ const tsconfigJson = readJson(tree, 'tsconfig.base.json');
35
+ tsconfigJson.compilerOptions = { ...config.tsconfig, ...tsconfigJson.compilerOptions };
36
+ writeJson(tree, 'tsconfig.base.json', tsconfigJson);
37
+
38
+ // Update .gitignore
39
+ const gitignoreContent = tree.read('.gitignore')?.toString() + '\n.eslintcache\n';
40
+ tree.write('.gitignore', gitignoreContent);
41
+
42
+ // Update .eslintignore
43
+ const eslintignoreContent = tree.read('.eslintignore')?.toString() + '\n**/*.js\napps/*/app.config.ts\n';
44
+ tree.write('.eslintignore', eslintignoreContent);
45
+
46
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
47
+ const configTemplate = require('../../shared/templates/config-template.json');
48
+
49
+ // Add files
50
+ generateFiles(tree, path.join(__dirname, 'files'), projectRoot, options);
51
+
52
+ // Add rules to .eslintrc.json
53
+ const esLintConfig = readJson(tree, '.eslintrc.json');
54
+
55
+ esLintConfig.overrides.push(configTemplate);
56
+ writeJson(tree, '.eslintrc.json', esLintConfig);
57
+
58
+ // Install necessary dependencies
59
+ addDependenciesToPackageJson(
60
+ tree,
61
+ {},
62
+ devDependencies['code-checks']
63
+ );
64
+
65
+ await formatFiles(tree);
66
+
67
+ return () => {
68
+ installPackagesTask(tree);
69
+ };
70
+ }
71
+
72
+ export default codeChecksGenerator;
@@ -0,0 +1,5 @@
1
+ export default {
2
+ 'lint': 'npx tsc && cross-env ESLINT_USE_FLAT_CONFIG=false npx eslint ./',
3
+ 'format': 'npx prettier --write . && npm run lint -- --fix',
4
+ 'prepare': 'husky',
5
+ }
@@ -0,0 +1,127 @@
1
+ import * as path from 'path';
2
+ import { formatFiles, generateFiles, Tree } from '@nx/devkit';
3
+ import { camelCase, kebabCase, startCase } from 'lodash';
4
+ import { IndentationText, Project, QuoteKind, StructureKind, SyntaxKind } from 'ts-morph';
5
+ import {
6
+ addNamedImport,
7
+ appendFileContent,
8
+ askQuestion,
9
+ createCliReadline,
10
+ dynamicImport,
11
+ filterSource,
12
+ getNxLibsPaths,
13
+ LibraryType,
14
+ searchAliasPath,
15
+ searchNxLibsPaths
16
+ } from '../../shared/utils';
17
+ import { EntityApiGeneratorSchema } from './schema';
18
+
19
+ export async function entityApiGenerator(tree: Tree, options: EntityApiGeneratorSchema) {
20
+ const { default: autocomplete } = await dynamicImport<typeof import('inquirer-autocomplete-standalone')>(
21
+ 'inquirer-autocomplete-standalone',
22
+ );
23
+ const nxLibsPaths = getNxLibsPaths([LibraryType.DATA_ACCESS]);
24
+ const apiLibsPaths = searchNxLibsPaths(nxLibsPaths, 'data-access/api/src', 'endsWith');
25
+ const apiClientLibsPaths = searchNxLibsPaths(nxLibsPaths, 'data-access/api-client/src', 'endsWith');
26
+
27
+ if (!apiClientLibsPaths.length) {
28
+ throw new Error('Could not find API Client path.');
29
+ }
30
+
31
+ if (!apiLibsPaths.length) {
32
+ throw new Error('Could not find API path.');
33
+ }
34
+
35
+ if (apiClientLibsPaths.length > 1) {
36
+ apiClientLibsPaths[0] = await autocomplete({
37
+ message: 'Select the api client library path:',
38
+ source: (input) => filterSource(input as string, apiClientLibsPaths)
39
+ });
40
+ }
41
+
42
+ if (apiLibsPaths.length > 1) {
43
+ apiLibsPaths[0] = await autocomplete({
44
+ message: 'Select the api library path:',
45
+ source: (input) => filterSource(input as string, apiLibsPaths)
46
+ });
47
+ }
48
+
49
+ const apiDirectory = searchAliasPath(apiLibsPaths[0]) as string;
50
+ const apiClientDirectory = searchAliasPath(apiClientLibsPaths[0]);
51
+
52
+ const libPath = apiLibsPaths[0];
53
+ const libRootPath = `${libPath}/lib`;
54
+
55
+ const cliReadline = createCliReadline();
56
+ options.name =
57
+ options.name || (await askQuestion('Enter the name of the entity (e.g: User): ', undefined, cliReadline));
58
+
59
+ const apiName = kebabCase(options.name);
60
+
61
+ options.baseEndpoint =
62
+ options.baseEndpoint || (await askQuestion('Enter the base endpoint (e.g: /users): ', `/${apiName}`, cliReadline));
63
+ cliReadline.close();
64
+
65
+ const apiPath = `${libRootPath}/${apiName}`;
66
+ const entityName = startCase(camelCase(apiName)).replace(/\s+/g, '');
67
+
68
+ generateFiles(tree, path.join(__dirname, `files`), apiPath, {
69
+ ...options,
70
+ apiName: camelCase(options.name),
71
+ entityName,
72
+ entityFileName: apiName,
73
+ apiClientDirectory,
74
+ baseEndpoint: options.baseEndpoint.startsWith('/') ? options.baseEndpoint : `/${options.baseEndpoint}`
75
+ });
76
+
77
+ tree.rename(`${apiPath}/models/entity.ts`, `${apiPath}/models/${apiName}.ts`);
78
+
79
+ appendFileContent(`${libRootPath}/index.ts`, `export * from './${apiName}';\n`, tree);
80
+
81
+ const storeLibsPaths = searchNxLibsPaths(nxLibsPaths, 'data-access/store/src', 'endsWith');
82
+
83
+ if (!storeLibsPaths.length) {
84
+ await formatFiles(tree);
85
+
86
+ throw new Error('Could not find redux store path.');
87
+ }
88
+
89
+ if (storeLibsPaths.length > 1) {
90
+ storeLibsPaths[0] = await autocomplete({
91
+ message: 'Select the store library path:',
92
+ source: (input) => filterSource(input as string, storeLibsPaths)
93
+ });
94
+ }
95
+
96
+ // Update redux store
97
+ const apiNameDeclaration = camelCase(options.name + 'Api');
98
+ const project = new Project({
99
+ manipulationSettings: {
100
+ indentationText: IndentationText.TwoSpaces,
101
+ quoteKind: QuoteKind.Single
102
+ }
103
+ });
104
+ const store = project.addSourceFileAtPath(`${storeLibsPaths[0]}/store.ts`);
105
+
106
+ addNamedImport(apiNameDeclaration, apiDirectory, store);
107
+
108
+ const rootReducer = store.getVariableDeclarationOrThrow('rootReducer');
109
+
110
+ rootReducer.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression).addProperty({
111
+ name: `[${apiNameDeclaration}.reducerPath]`,
112
+ initializer: `${apiNameDeclaration}.reducer`,
113
+ kind: StructureKind.PropertyAssignment
114
+ });
115
+
116
+ const middlewares = store.getVariableDeclarationOrThrow('middlewares');
117
+
118
+ middlewares
119
+ .getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression)
120
+ .addElement(`${apiNameDeclaration}.middleware`);
121
+
122
+ project.saveSync();
123
+
124
+ await formatFiles(tree);
125
+ }
126
+
127
+ export default entityApiGenerator;
@@ -0,0 +1,152 @@
1
+ import { execSync } from 'child_process';
2
+ import * as path from 'path';
3
+ import {
4
+ addDependenciesToPackageJson,
5
+ formatFiles,
6
+ generateFiles,
7
+ installPackagesTask,
8
+ readJson,
9
+ readProjectConfiguration,
10
+ Tree,
11
+ updateProjectConfiguration,
12
+ writeJson
13
+ } from '@nx/devkit';
14
+ import { ExpoAppGeneratorSchema } from './schema';
15
+ import scripts from './scripts';
16
+ import { existsSync, rmSync } from 'fs';
17
+ import { dependencies, devDependencies } from '../../shared/dependencies';
18
+ import { BaseGeneratorType } from '../../shared/enums';
19
+ import {
20
+ runAppEnvGenerator,
21
+ runApiClientGenerator,
22
+ runStorageGenerator,
23
+ runRNStylesGenerator,
24
+ runFormUtilsGenerator,
25
+ runStoreGenerator,
26
+ runUIKittenGenerator
27
+ } from '../../shared/generators';
28
+ import { formatName, formatAppIdentifier, addNxAppTag, askQuestion, getImportPathPrefix } from '../../shared/utils';
29
+
30
+ export async function expoAppGenerator(
31
+ tree: Tree,
32
+ options: ExpoAppGeneratorSchema
33
+ ) {
34
+ const shouldGenerateStoreLib = await askQuestion('Do you want to create store lib? (y/n): ') === 'y';
35
+ const shouldGenerateApiClientLib = shouldGenerateStoreLib && await askQuestion('Do you want to create api client lib? (y/n): ') === 'y';
36
+ const shouldGenerateAuthLibs = shouldGenerateApiClientLib && await askQuestion('Do you want to create auth lib? (y/n): ') === 'y';
37
+ const shouldGenerateFormUtilsLib = await askQuestion('Do you want to create a lib with the form utils? (y/n): ') === 'y';
38
+ const shouldGenerateUIKittenLib = await askQuestion('Do you want to install @ui-kitten? (y/n): ') === 'y';
39
+
40
+ const appRoot = `apps/${options.directory}`;
41
+ const i18nRoot = `i18n/${options.directory}`;
42
+ const appTestFolder = `apps/${options.directory}-e2e`;
43
+ const libPath = `${getImportPathPrefix(tree)}/${options.directory}`;
44
+ const tags = [`app:${options.directory}`, 'type:app'];
45
+
46
+ // Install @nx/expo plugin
47
+ execSync('npx nx add @nx/expo', { stdio: 'inherit' });
48
+
49
+ if (existsSync(appRoot)) {
50
+ const project = readProjectConfiguration(tree, options.directory);
51
+
52
+ project.tags = [`app:${options.directory}`, 'type:app'];
53
+
54
+ updateProjectConfiguration(tree, project.name as string, project);
55
+ } else {
56
+ execSync(
57
+ `npx nx g @nx/expo:app ${options.name} --directory=apps/${options.directory} --tags="${tags.join(', ')}" --linter=eslint --unitTestRunner=none --e2eTestRunner=none`,
58
+ { stdio: 'inherit' }
59
+ );
60
+ }
61
+
62
+ // Generate shared libs
63
+ await runAppEnvGenerator(tree, { ...options, baseGeneratorType: BaseGeneratorType.EXPO_APP });
64
+ await runStorageGenerator(tree, options);
65
+ await runRNStylesGenerator(tree, options);
66
+
67
+ if (shouldGenerateStoreLib) {
68
+ await runStoreGenerator(tree, { ...options, baseGeneratorType: BaseGeneratorType.EXPO_APP });
69
+ }
70
+
71
+ if (shouldGenerateApiClientLib) {
72
+ await runApiClientGenerator(tree, options);
73
+ }
74
+
75
+ if (shouldGenerateFormUtilsLib) {
76
+ await runFormUtilsGenerator(tree, options);
77
+ }
78
+
79
+ if (shouldGenerateUIKittenLib) {
80
+ await runUIKittenGenerator(tree, options);
81
+ }
82
+
83
+ // Workaround: Even with the '--e2eTestRunner=none' parameter, the test folder is created. We delete it manually.
84
+ if (existsSync(appTestFolder)) {
85
+ rmSync(appTestFolder, { recursive: true, force: true });
86
+ }
87
+
88
+ const appPackagePath = `${appRoot}/package.json`;
89
+
90
+ // Remove unnecessary files and files that will be replaced
91
+ tree.delete(`${appRoot}/src`);
92
+ tree.delete(`${appRoot}/index.js`);
93
+ tree.delete(`${appRoot}/webpack.config.js`);
94
+ tree.delete(`${appRoot}/.eslintrc.json`);
95
+ tree.delete(`${appRoot}/eslint.config.cjs`);
96
+ tree.delete(`${appRoot}/app.json`);
97
+ tree.delete(`${appRoot}/eas.json`);
98
+ tree.delete(`${appRoot}/metro.config.js`);
99
+ tree.delete(`${appRoot}/jest.config.ts`);
100
+ tree.delete(`${appRoot}/tsconfig.app.json`);
101
+
102
+ // Update app package.json
103
+ const appPackageJson = readJson(tree, appPackagePath);
104
+ appPackageJson.main = 'expo-router/entry';
105
+ appPackageJson.scripts = {
106
+ ...scripts,
107
+ ...appPackageJson.scripts,
108
+ };
109
+ writeJson(tree, appPackagePath, appPackageJson);
110
+
111
+ // Add app files
112
+ generateFiles(tree, path.join(__dirname, 'app-files'), appRoot, {
113
+ ...options,
114
+ formatName,
115
+ formatAppIdentifier,
116
+ formatDirectory: () => libPath,
117
+ isUIKittenEnabled: shouldGenerateUIKittenLib,
118
+ isStoreEnabled: shouldGenerateStoreLib,
119
+ appDirectory: options.directory
120
+ });
121
+
122
+ addNxAppTag(tree, options.directory);
123
+ generateFiles(tree, path.join(__dirname, 'i18n'), i18nRoot, {});
124
+
125
+ // Add dependencies
126
+ addDependenciesToPackageJson(
127
+ tree,
128
+ {
129
+ ...dependencies['expo-app'],
130
+ ...dependencies['expo-app-root']
131
+ },
132
+ {
133
+ ...devDependencies['expo-app'],
134
+ ...devDependencies['expo-app-root']
135
+ }
136
+ );
137
+
138
+ addDependenciesToPackageJson(tree, dependencies['expo-app'], devDependencies['expo-app'], appPackagePath);
139
+
140
+ await formatFiles(tree);
141
+
142
+ return () => {
143
+ installPackagesTask(tree);
144
+ execSync('npx expo install --fix', { stdio: 'inherit' });
145
+
146
+ if (shouldGenerateAuthLibs) {
147
+ execSync(`npx nx g auth ${options.name} ${options.directory}`, { stdio: 'inherit' });
148
+ }
149
+ };
150
+ }
151
+
152
+ export default expoAppGenerator;
@@ -0,0 +1,12 @@
1
+ export default {
2
+ 'start': 'cross-env EXPO_PUBLIC_APP_ENV=development npx expo start',
3
+ 'start:prod': 'cross-env EXPO_PUBLIC_APP_ENV=production npx expo start',
4
+ 'build:dev': 'eas build --no-wait -p all --profile=development',
5
+ 'build:internal': 'npm run build:dev -- --profile=internal',
6
+ 'build:debug': 'npm run build:dev -- --profile=debug',
7
+ 'build:prod': 'npm run build:dev -- --profile=production',
8
+ 'update:dev': 'cross-env EXPO_PUBLIC_APP_ENV=development eas update --branch development',
9
+ 'update:prod': 'cross-env EXPO_PUBLIC_APP_ENV=production eas update --branch production',
10
+ 'submit:dev': 'cross-env EXPO_PUBLIC_APP_ENV=development eas submit --no-wait --profile=development',
11
+ 'submit:prod': 'cross-env EXPO_PUBLIC_APP_ENV=production eas submit --no-wait --profile=production',
12
+ };
@@ -0,0 +1,53 @@
1
+ import { addDependenciesToPackageJson, formatFiles, generateFiles, installPackagesTask, Tree } from '@nx/devkit';
2
+ import * as path from 'path';
3
+ import { FormGeneratorSchema } from './schema';
4
+ import { dynamicImport, formatName, getNxLibsPaths, LibraryType, searchNxLibsPaths } from '../../shared/utils';
5
+ import { dependencies } from '../../shared/dependencies';
6
+ import { addFormUsage, getAppName, getFormUtilsDirectory, updateIndex } from './utils';
7
+
8
+ export async function formGenerator(tree: Tree, options: FormGeneratorSchema) {
9
+ // Get input data
10
+ const { default: autocomplete } = await dynamicImport<typeof import('inquirer-autocomplete-standalone')>('inquirer-autocomplete-standalone');
11
+ const availableLibsPaths = getNxLibsPaths([LibraryType.FEATURES, LibraryType.UI]);
12
+ const libPath = await autocomplete({
13
+ message: 'Enter the library path: ',
14
+ source: async (input) => {
15
+ const filteredNxLibsPaths = searchNxLibsPaths(availableLibsPaths, input as string)
16
+
17
+ return filteredNxLibsPaths.map((path) => ({ value: path }))
18
+ }
19
+ });
20
+ const fileName = options.name;
21
+ const placeOfUse = options.placeOfUse;
22
+
23
+ if (!fileName) {
24
+ throw new Error('Form name is required');
25
+ }
26
+
27
+ // Generate form class
28
+ const formsPath = `${libPath}/lib/forms`;
29
+ const formFilePath = `${formsPath}/${fileName}.ts`;
30
+ if (tree.exists(formFilePath)) {
31
+ throw new Error('The form already exists');
32
+ }
33
+
34
+ const formUtilsDirectory = await getFormUtilsDirectory(tree, getAppName(libPath));
35
+ const formClassName = `${formatName(fileName, true)}FormSchema`;
36
+ generateFiles(tree, path.join(__dirname, `files`), formsPath, { className: formClassName, fileName, formUtilsDirectory });
37
+ updateIndex(formsPath, fileName, tree);
38
+
39
+ // Add form usage
40
+ if (placeOfUse) {
41
+ await addFormUsage(libPath, placeOfUse, formClassName);
42
+ }
43
+
44
+ await formatFiles(tree);
45
+
46
+ // Install dependencies
47
+ addDependenciesToPackageJson(tree, dependencies.form, {});
48
+ return () => {
49
+ installPackagesTask(tree);
50
+ };
51
+ }
52
+
53
+ export default formGenerator;
@@ -0,0 +1,86 @@
1
+ import {
2
+ ArrowFunction,
3
+ FunctionDeclaration,
4
+ FunctionExpression,
5
+ IndentationText,
6
+ Project,
7
+ QuoteKind,
8
+ SourceFile,
9
+ SyntaxKind,
10
+ VariableDeclaration
11
+ } from 'ts-morph';
12
+ import { addNamedImport } from '../../../shared/utils';
13
+
14
+ function getFormUsageCode(formClassName: string): string {
15
+ return `const formSchema = new ${formClassName}();
16
+ const form = useForm({
17
+ defaultValues: formSchema.formValues,
18
+ resolver: yupResolver(${formClassName}.validationSchema)
19
+ });\n\n`
20
+ }
21
+
22
+ function getForwardRefFunction(variable: VariableDeclaration): FunctionExpression | ArrowFunction {
23
+ const callExpressionInitializer = variable.getInitializerIfKind(SyntaxKind.CallExpression);
24
+ const hasForwardRef = callExpressionInitializer?.getExpression().getText() === 'forwardRef'
25
+ if (!hasForwardRef) {
26
+ throw new Error('Could not find forwardRef');
27
+ }
28
+
29
+ const argument = callExpressionInitializer.getArguments()[0];
30
+ const hasComponentFunction = argument && [SyntaxKind.FunctionExpression, SyntaxKind.ArrowFunction].includes(argument.getKind())
31
+ if (!hasComponentFunction) {
32
+ throw new Error('Could not find a component function in forwardRef');
33
+ }
34
+
35
+ const functionExpression = argument.asKind(argument.getKind() === SyntaxKind.FunctionExpression ? SyntaxKind.FunctionExpression : SyntaxKind.ArrowFunction);
36
+
37
+ if (!functionExpression) {
38
+ throw new Error('Could not get a component function in forwardRef');
39
+ }
40
+
41
+ return functionExpression;
42
+ }
43
+
44
+ function getPlaceOfUse(file: SourceFile, placeOfUseName: string): FunctionExpression | ArrowFunction | FunctionDeclaration {
45
+ const placeOfUseFunction = file.getFunction(placeOfUseName);
46
+ if (placeOfUseFunction) {
47
+ return placeOfUseFunction;
48
+ }
49
+
50
+ const variable = file.getVariableDeclaration(placeOfUseName);
51
+ if (!variable) {
52
+ throw new Error(`Could not find the place where the form should be used (${placeOfUseName}).`);
53
+ }
54
+
55
+ return variable.getInitializerIfKind(SyntaxKind.FunctionExpression)
56
+ || variable.getInitializerIfKind(SyntaxKind.ArrowFunction)
57
+ || getForwardRefFunction(variable);
58
+ }
59
+
60
+ export async function addFormUsage(libPath: string, placeOfUseName: string, formClassName: string): Promise<void> {
61
+ const project = new Project({
62
+ manipulationSettings: {
63
+ indentationText: IndentationText.TwoSpaces,
64
+ quoteKind: QuoteKind.Single
65
+ }
66
+ });
67
+ const files = project.addSourceFilesAtPaths([`${libPath}/lib/**/*.tsx`, `${libPath}/lib/**/*.ts`]);
68
+ const file = files.find((file) => file.getFunction(placeOfUseName) || file.getVariableDeclaration(placeOfUseName));
69
+ if (!file) {
70
+ throw new Error('Could not find the place where the form should be used.');
71
+ }
72
+
73
+ const pathToForm = file.getFilePath().includes('components')
74
+ ? '../../forms'
75
+ : file.getFilePath().includes('hooks')
76
+ ? '../forms'
77
+ : './forms';
78
+ addNamedImport(formClassName, pathToForm, file);
79
+ addNamedImport('useForm', 'react-hook-form', file);
80
+ addNamedImport('yupResolver', '@hookform/resolvers/yup', file);
81
+
82
+ const placeOfUse = getPlaceOfUse(file, placeOfUseName);
83
+ placeOfUse.setBodyText(`${getFormUsageCode(formClassName)}${placeOfUse.getBodyText()}`);
84
+
85
+ project.saveSync();
86
+ }
@@ -0,0 +1,3 @@
1
+ export function getAppName(path: string): string {
2
+ return path.split('/')[1];
3
+ }