generate-react-cli 8.3.0 → 8.4.1

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.
@@ -6,12 +6,12 @@ const isNotValidNodeVersion = () => {
6
6
  const semver = currentNodeVersion.split('.');
7
7
  const major = semver[0];
8
8
 
9
- if (major < 16) {
9
+ if (major < 18) {
10
10
  console.error(
11
11
  // eslint-disable-next-line
12
12
  'You are running Node ' +
13
13
  currentNodeVersion +
14
- ' Generate React CLI requires Node 16 or higher. Please update your version of Node.'
14
+ ' Generate React CLI requires Node 18 or higher. Please update your version of Node.'
15
15
  );
16
16
 
17
17
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generate-react-cli",
3
- "version": "8.3.0",
3
+ "version": "8.4.1",
4
4
  "description": "A simple React CLI to generate components instantly and more.",
5
5
  "repository": "https://github.com/arminbro/generate-react-cli",
6
6
  "bugs": "https://github.com/arminbro/generate-react-cli/issues",
@@ -38,32 +38,31 @@
38
38
  "prepare": "husky install"
39
39
  },
40
40
  "dependencies": {
41
- "chalk": "5.2.0",
42
- "commander": "9.4.1",
41
+ "chalk": "5.3.0",
42
+ "commander": "12.0.0",
43
43
  "deep-keys": "0.5.0",
44
- "dotenv": "^16.0.3",
45
- "fs-extra": "11.1.0",
46
- "inquirer": "9.1.4",
44
+ "dotenv": "16.4.5",
45
+ "fs-extra": "11.2.0",
46
+ "inquirer": "9.2.15",
47
47
  "lodash": "4.17.21",
48
- "openai": "^3.1.0",
49
48
  "replace": "1.2.2"
50
49
  },
51
50
  "devDependencies": {
52
- "@commitlint/cli": "17.3.0",
53
- "@commitlint/config-conventional": "17.3.0",
54
- "@semantic-release/commit-analyzer": "9.0.2",
51
+ "@commitlint/cli": "18.6.1",
52
+ "@commitlint/config-conventional": "18.6.2",
53
+ "@semantic-release/commit-analyzer": "11.1.0",
55
54
  "@semantic-release/git": "10.0.1",
56
- "@semantic-release/github": "8.0.7",
57
- "@semantic-release/npm": "9.0.1",
58
- "@semantic-release/release-notes-generator": "10.0.3",
59
- "eslint": "8.30.0",
55
+ "@semantic-release/github": "9.2.6",
56
+ "@semantic-release/npm": "11.0.2",
57
+ "@semantic-release/release-notes-generator": "12.1.0",
58
+ "eslint": "8.57.0",
60
59
  "eslint-config-airbnb-base": "15.0.0",
61
- "eslint-config-prettier": "8.5.0",
62
- "eslint-plugin-prettier": "4.2.1",
63
- "husky": "8.0.2",
64
- "prettier": "2.8.1",
65
- "pretty-quick": "3.1.3",
66
- "semantic-release": "19.0.5"
60
+ "eslint-config-prettier": "9.1.0",
61
+ "eslint-plugin-prettier": "5.1.3",
62
+ "husky": "9.0.11",
63
+ "prettier": "3.2.5",
64
+ "pretty-quick": "4.0.0",
65
+ "semantic-release": "23.0.2"
67
66
  },
68
67
  "prettier": {
69
68
  "singleQuote": true,
@@ -90,7 +89,14 @@
90
89
  "commitlint": {
91
90
  "extends": [
92
91
  "@commitlint/config-conventional"
93
- ]
92
+ ],
93
+ "rules": {
94
+ "body-max-line-length": [
95
+ 0,
96
+ "always",
97
+ 200
98
+ ]
99
+ }
94
100
  },
95
101
  "eslintConfig": {
96
102
  "extends": [
package/readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License](https://img.shields.io/npm/l/express.svg)](https://github.com/arminbro/generate-react-cli/blob/master/LICENSE)
4
4
 
5
- <p align="center">
5
+ <p align="center">
6
6
  <img src="https://raw.githubusercontent.com/arminbro/generate-react-cli/master/docs/assets/generate-react-cli.svg?raw=true"/>
7
7
  </p>
8
8
 
@@ -20,8 +20,9 @@ You can also watch an excellent [video](https://www.youtube.com/watch?v=NEvnt3MW
20
20
  - [Generate components](#generate-components)
21
21
  - [Custom component types](#custom-component-types)
22
22
  - [Custom component templates](#custom-component-templates)
23
+ - [Custom component directory](#custom-component-directory)
23
24
  - [Custom component files](#custom-component-files)
24
- - [OpenAi integration (Alpha release)](#openai-integration-alpha-release)
25
+ - [OpenAi integration (Alpha release)](https://github.com/arminbro/generate-react-cli/tree/alpha?tab=readme-ov-file#openai-integration-alpha-release)
25
26
 
26
27
  ## You can run it using npx like this:
27
28
 
@@ -97,10 +98,11 @@ Otherwise, if you don't pass any options, it will just use the default values th
97
98
  <th>Value Type</th>
98
99
  <th>Default Value</th>
99
100
  </tr>
101
+
100
102
  <tr>
101
103
  <td width="20%"><b>--path</b></td>
102
104
  <td width="60%">
103
- Value of the path where you want the component to be generated in (e.g. <b>src/components</b>).
105
+ Value of the path where you want the component to be generated in (e.g. <b>src/components</b>).
104
106
  </td>
105
107
  <td width="20%">String</td>
106
108
  <td width="20%"><code>component.default.path<code></td>
@@ -118,7 +120,7 @@ Otherwise, if you don't pass any options, it will just use the default values th
118
120
  <tr>
119
121
  <td width="20%"><b>--withLazy</b></td>
120
122
  <td width="60%">
121
- Creates a corresponding lazy file (a file that lazy-loads your component out of the box and enables <a href="https://reactjs.org/docs/code-splitting.html#code-splitting">code splitting</a>) with this component.
123
+ Creates a corresponding lazy file (a file that lazy-loads your component out of the box and enables <a href="https://reactjs.org/docs/code-splitting.html#code-splitting">code splitting</a>) with this component.
122
124
  </td>
123
125
  <td width="20%">Boolean</td>
124
126
  <td width="20%"><code>component.default.withLazy<code></td>
@@ -127,7 +129,7 @@ Otherwise, if you don't pass any options, it will just use the default values th
127
129
  <tr>
128
130
  <td width="20%"><b>--withStory</b></td>
129
131
  <td width="60%">
130
- Creates a corresponding (<a href="https://storybook.js.org">storybook</a>) story file with this component.
132
+ Creates a corresponding (<a href="https://storybook.js.org">storybook</a>) story file with this component.
131
133
  </td>
132
134
  <td width="20%">Boolean</td>
133
135
  <td width="20%"><code>component.default.withStory<code></td>
@@ -136,7 +138,7 @@ Otherwise, if you don't pass any options, it will just use the default values th
136
138
  <tr>
137
139
  <td width="20%"><b>--withStyle</b></td>
138
140
  <td width="60%">
139
- Creates a corresponding stylesheet file with this component.
141
+ Creates a corresponding stylesheet file with this component.
140
142
  </td>
141
143
  <td width="20%">Boolean</td>
142
144
  <td width="20%"><code>component.default.withStyle<code></td>
@@ -145,11 +147,12 @@ Otherwise, if you don't pass any options, it will just use the default values th
145
147
  <tr>
146
148
  <td width="20%"><b>--withTest</b></td>
147
149
  <td width="60%">
148
- Creates a corresponding test file with this component.
150
+ Creates a corresponding test file with this component.
149
151
  </td>
150
152
  <td width="20%">Boolean</td>
151
153
  <td width="20%"><code>component.default.withTest<code></td>
152
154
  </tr>
155
+
153
156
  <tr>
154
157
  <td width="20%"><b>--dry-run</b></td>
155
158
  <td width="60%">
@@ -158,25 +161,28 @@ Otherwise, if you don't pass any options, it will just use the default values th
158
161
  <td width="20%">Boolean</td>
159
162
  <td width="20%"><code>false<code></td>
160
163
  </tr>
164
+
161
165
  <tr>
162
166
  <td width="20%"><b>--flat</b></td>
163
167
  <td width="60%">
164
- Generate the files in the mentioned path insted of creating new folder for it
168
+ Generate the files in the mentioned path instead of creating new folder for it
165
169
  </td>
166
170
  <td width="20%">Boolean</td>
167
171
  <td width="20%"><code>false<code></td>
168
172
  </tr>
169
- <tr>
170
- <td width="20%"><b>--describe</b></td>
173
+
174
+ <tr>
175
+ <td width="20%"><b>--customDirectory</b></td>
171
176
  <td width="60%">
172
- Describe the component you're trying to generate, and OpenAI will do its best to render it following your instructions.
177
+ Template value that overrides the name of the directory of the component to be generated in.<br />
178
+ See more under <a href="#custom-component-directory">custom component directory</a>.
173
179
  </td>
174
180
  <td width="20%">String</td>
175
- <td width="20%"><code>null<code></td>
181
+ <td width="20%"><code>null</code></td>
176
182
  </tr>
177
183
  </table>
178
184
 
179
- ### Custom component types:
185
+ ### Custom component types
180
186
 
181
187
  By default, GRC will use the `component.default` configuration rules when running the component command out of the box.
182
188
 
@@ -329,6 +335,93 @@ it('It should mount', () => {
329
335
  });
330
336
  ```
331
337
 
338
+ ### Custom component directory
339
+
340
+ Using the `customDirectory` you can easily override the directory name for the component generated. For instance, if prefixes are required for particular components or if template names will be mixed, the `customDirectory` option will allow you to override the way that GRC generates the name of the directory where the component files will live.
341
+
342
+ The `customDirectory` directive allows all supported casings (see previous section) and can be overridden at the following levels in ascending specific of priority:
343
+
344
+ - top
345
+ - component.default
346
+ - component._type_
347
+ - CLI
348
+
349
+ #### Example:
350
+
351
+ For React Context Providers in a project, the decision has been made to separate Context generation from the visual components.
352
+
353
+ In a typical configuration the configuration would look as following:
354
+
355
+ ```json
356
+ {
357
+ "provider": {
358
+ "path": "src/components/providers",
359
+ "withLazy": false,
360
+ "withStory": true,
361
+ "withStyle": false,
362
+ "withTest": true,
363
+ "withTypes": true,
364
+ "withContext": true,
365
+ "customTemplates": {
366
+ "component": "src/components/templates/provider/TemplateName.tsx",
367
+ "context": "src/components/templates/provider/TemplateName.context.ts",
368
+ "story": "src/components/templates/provider/TemplateName.stories.tsx",
369
+ "test": "src/components/templates/provider/TemplateName.test.tsx",
370
+ "types": "src/components/templates/provider/TemplateName.types.ts"
371
+ }
372
+ }
373
+ }
374
+ ```
375
+
376
+ With the configuration above, the component would be required to either follow a full or a minimalistic naming convention.
377
+ I.e. the component would either need to be generated as `ThemeProvider` and consequently the context name would be generated as `ThemeProviderContext`, or by renaming the files and templates as `TemplateNameProvider` but with the downside of the component path being generated as `src/components/providers/Theme`. This creates inconsistent naming in the directory containg the component files.
378
+
379
+ To work around this, the `customDirectory` option can be used to enforce a particular style.
380
+
381
+ ```json
382
+ {
383
+ ...
384
+ "provider": {
385
+ "path": "src/components/providers",
386
+ "withLazy": false,
387
+ "withStory": true,
388
+ "withStyle": false,
389
+ "withTest": true,
390
+ "withTypes": true,
391
+ "withContext": true,
392
+ "customDirectory": "TemplateNameProvider",
393
+ "customTemplates": {
394
+ "component": "src/components/templates/provider/TemplateNameProvider.tsx",
395
+ "context": "src/components/templates/provider/TemplateName.context.ts",
396
+ "story": "src/components/templates/provider/TemplateNameProvider.stories.tsx",
397
+ "test": "src/components/templates/provider/TemplateNameProvider.test.tsx",
398
+ "types": "src/components/templates/provider/TemplateNameProvider.types.ts"
399
+ }
400
+ }
401
+ ...
402
+ }
403
+ ```
404
+
405
+ The above configuration would allow you to mix and match different template names and keep naming consistent.
406
+
407
+ If we executed GRC with the above configuration (`npx generate-react-cli component Theme --type=provider`), the result would look like this:
408
+
409
+ ```fs
410
+ src/components/providers/ThemeProvider/Theme.context.ts
411
+ src/components/providers/ThemeProvider/ThemeProvider.tsx
412
+ src/components/providers/ThemeProvider/ThemeProvider.stories.tsx
413
+ src/components/providers/ThemeProvider/ThemeProvider.test.tsx
414
+ src/components/providers/ThemeProvider/ThemeProvider.types.ts
415
+ ```
416
+
417
+ Similarly, this construct could be used as a shortcut for generating other named components, like the `BoxLayout` example above, depending on that could be shortened to:
418
+
419
+ ```sh
420
+ npx generate-react-cli component Box --type=layout --customDir=TemplateNameLayout
421
+ ```
422
+
423
+ Or it could be used to generate files with a naming convention with `Test`, `Lazy`, `Context`, `Theme`, or `Provider` suffixes. Or even combined with skeleton CSS
424
+
332
425
  ### Custom component files
333
426
 
334
427
  GRC comes with corresponding built-in files for a given component if you need them (i.e., `withStyle`, `withTest`, `withStory`, and `withLazy`).
@@ -384,106 +477,6 @@ You should also see that we added `index` and `storyStyle` to our `customTemplat
384
477
 
385
478
  Also, we used the `TemplateName` keyword for the `storyStyle` custom file. GRC will generate this corresponding file and replace `TemplateName` with the component name.
386
479
 
387
- ## OpenAI integration (Alpha release)
388
-
389
- Well, the time has come to incorporate OpenAI with GRC.
390
-
391
- I had a chance to experiment with OpenAI's latest GPT-3 natural language model, and I was super impressed by its capabilities. You can read more about OpenAI by visiting their site: https://openai.com/.
392
-
393
- If you've been using GRC, you already know about its component generation capabilities using its internal templates or the custom ones you provide.
394
-
395
- With the help of OpenAI, we can now generate our components intelligently by describing them using the new `--describe` flag, or `-d` for short.
396
-
397
- The plan for this alpha integration will start simple, but I have a few good ideas coming in the near future (and I'm hoping to hear some of yours) on how we can use OpenAI with GRC to improve the developer experience.
398
-
399
- Please remember that this release is still early, and you will run into bugs. So, please report any bugs or issues [here](https://github.com/arminbro/generate-react-cli/issues).
400
-
401
- ### Okay, let's get started.
402
-
403
- 1. If you don't have one, you must create an OpenAI account: https://openai.com/api/.
404
- 2. You'll need to obtain a secret API key from OpenAI. You can do so by visiting https://beta.openai.com/account/api-keys.
405
- 3. Once you have your API key, you'll need to create a `.env.local` file in your react project and store it as a variable as `OPENAI_API_KEY`. Please be sure not to share the key or push it to version control, as it is private.
406
-
407
- GRC will pass the key to OpenAI to communicate with the API on your behalf. You will see the usage reflected on your OpenAI account here: https://beta.openai.com/account/usage.
408
-
409
- GRC uses the DaVinci language model, so you can check out their pricing here: https://openai.com/api/pricing/.
410
-
411
- Let's generate our first component using OpenAI:
412
-
413
- ```sh
414
- npx generate-react-cli@alpha c Counter -d "Create a counter component that increments by one when I click on the increment button"
415
- ```
416
-
417
- GRC should have created a Counter component that looks something like this 🤯:
418
-
419
- ```jsx
420
- import React, { useState } from 'react';
421
- import PropTypes from 'prop-types';
422
- import './Counter.css';
423
-
424
- const Counter = () => {
425
- const [count, setCount] = useState(0);
426
-
427
- return (
428
- <div className="Counter" data-testid="Counter">
429
- <h2> The count is: {count} </h2>
430
- <button onClick={() => setCount(count + 1)}>Increment</button>
431
- </div>
432
- );
433
- };
434
-
435
- Counter.propTypes = {};
436
-
437
- Counter.defaultProps = {};
438
-
439
- export default Counter;
440
- ```
441
-
442
- OpenAI will do its best to generate the component following the instructions provided in the `--describe` flag while using the patterns supplied from the internal or custom component templates.
443
-
444
- Okay, let's try another one.
445
-
446
- ```sh
447
- npx generate-react-cli@alpha c GlobalNav -d "Create a navbar component with 1 logo named 'GRC' and 3 links: 'Home', 'About', 'Contact'"
448
- ```
449
-
450
- and here's the output in src/components/GlobalNav/GlobalNav.js:
451
-
452
- ```jsx
453
- import React from 'react';
454
- import PropTypes from 'prop-types';
455
- import './GlobalNav.css';
456
-
457
- const GlobalNav = () => (
458
- <div className="GlobalNav" data-testid="GlobalNav">
459
- <a href="#">GRC</a>
460
- <ul>
461
- <li>
462
- <a href="#">Home</a>
463
- </li>
464
- <li>
465
- <a href="#">About</a>
466
- </li>
467
- <li>
468
- <a href="#">Contact</a>
469
- </li>
470
- </ul>
471
- </div>
472
- );
473
-
474
- GlobalNav.propTypes = {};
475
-
476
- GlobalNav.defaultProps = {};
477
-
478
- export default GlobalNav;
479
- ```
480
-
481
- That's a wrap. I hope this integration will allow us to generate React components more efficiently, and we can still go in and make the necessary adjustments.
482
-
483
- Again, please provide any feedback if you have any, and I would love to see some of the components that you generate with GRC+OpenAI.
484
-
485
- Please share them with me on Twitter [@arminbro](https://twitter.com/arminbro).
486
-
487
480
  ## License
488
481
 
489
482
  Generate React CLI is an open source software [licensed as MIT](https://github.com/arminbro/generate-react-cli/blob/master/LICENSE).
@@ -29,7 +29,17 @@ export default function initGenerateComponentCommand(args, cliConfigFile, progra
29
29
  'Generate the files in the mentioned path instead of creating new folder for it',
30
30
  selectedComponentType.flat || false
31
31
  )
32
- .option('-dr, --dry-run', 'Show what will be generated without writing to disk');
32
+ .option('-dr, --dry-run', 'Show what will be generated without writing to disk')
33
+ .option(
34
+ '--customDirectory <customDirectory>',
35
+ 'You can pass a cased path template that will be used as the component path for the component being generated.\n' +
36
+ 'E.g. this allows you to add a prefix or suffix to the component path, ' +
37
+ 'or change the case of the name of the directory holding the components to kebab-case.\n' +
38
+ 'Examples:\n' +
39
+ '- TemplateName\n' +
40
+ '- template-name\n' +
41
+ '- TemplateNameSuffix'
42
+ );
33
43
 
34
44
  // Dynamic component command option defaults.
35
45
 
@@ -7,7 +7,6 @@ import snakeCase from 'lodash/snakeCase.js';
7
7
  import startCase from 'lodash/startCase.js';
8
8
  import fsExtra from 'fs-extra';
9
9
 
10
- import { aiComponentGenerator } from '../services/openAiService.js';
11
10
  import componentJsTemplate from '../templates/component/componentJsTemplate.js';
12
11
  import componentTsTemplate from '../templates/component/componentTsTemplate.js';
13
12
  import componentCssTemplate from '../templates/component/componentCssTemplate.js';
@@ -19,6 +18,8 @@ import componentTestEnzymeTemplate from '../templates/component/componentTestEnz
19
18
  import componentTestDefaultTemplate from '../templates/component/componentTestDefaultTemplate.js';
20
19
  import componentTestTestingLibraryTemplate from '../templates/component/componentTestTestingLibraryTemplate.js';
21
20
 
21
+ const templateNameRE = /.*(template[|_-]?name).*/i;
22
+
22
23
  const { existsSync, outputFileSync, readFileSync } = fsExtra;
23
24
 
24
25
  export function getComponentByType(args, cliConfigFile) {
@@ -71,7 +72,7 @@ function getCustomTemplate(componentName, templatePath) {
71
72
  console.error(
72
73
  chalk.red(
73
74
  `
74
- ERROR: The custom template path of "${templatePath}" does not exist.
75
+ ERROR: The custom template path of "${templatePath}" does not exist.
75
76
  Please make sure you're pointing to the right custom template path in your generate-react-cli.json config file.
76
77
  `
77
78
  )
@@ -81,7 +82,52 @@ Please make sure you're pointing to the right custom template path in your gener
81
82
  }
82
83
  }
83
84
 
84
- function componentTemplateGenerator({ cmd, componentName, cliConfigFile }) {
85
+ function componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }) {
86
+ let componentPath = cmd.path;
87
+
88
+ if (cmd.flat !== true) {
89
+ let componentDirectory = componentName;
90
+
91
+ const customDirectoryConfigs = [
92
+ cliConfigFile.customDirectory,
93
+ cliConfigFile.component.default.customDirectory,
94
+ cliConfigFile.component[cmd.type].customDirectory,
95
+ cmd.customDirectory,
96
+ ].filter((e) => Boolean(e) && typeof e === 'string');
97
+
98
+ if (customDirectoryConfigs.length > 0) {
99
+ const customDirectory = customDirectoryConfigs.slice(-1).toString();
100
+
101
+ // Double check if the customDirectory is templatable
102
+ if (templateNameRE.exec(customDirectory) == null) {
103
+ console.error(
104
+ chalk.red(
105
+ `customDirectory [${customDirectory}] for ${componentName} does not contain a templatable value.\nPlease check your configuration!`
106
+ )
107
+ );
108
+
109
+ process.exit(-2);
110
+ }
111
+
112
+ for (const convertor in convertors) {
113
+ const re = new RegExp(`.*${convertor}.*`);
114
+
115
+ if (re.exec(customDirectory) !== null) {
116
+ componentDirectory = customDirectory.replace(convertor, convertors[convertor]);
117
+ }
118
+ }
119
+ }
120
+
121
+ componentPath += `/${componentDirectory}`;
122
+ }
123
+
124
+ componentPath += `/${filename}`;
125
+
126
+ return componentPath;
127
+ }
128
+
129
+ function componentTemplateGenerator({ cmd, componentName, cliConfigFile, convertors }) {
130
+ // @ts-ignore
85
131
  const { usesStyledComponents, cssPreprocessor, testLibrary, usesCssModule, usesTypeScript } = cliConfigFile;
86
132
  const { customTemplates } = cliConfigFile.component[cmd.type];
87
133
  let template = null;
@@ -145,13 +191,13 @@ function componentTemplateGenerator({ cmd, componentName, cliConfigFile }) {
145
191
  }
146
192
 
147
193
  return {
148
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
194
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
149
195
  filename,
150
196
  template,
151
197
  };
152
198
  }
153
199
 
154
- function componentStyleTemplateGenerator({ cliConfigFile, cmd, componentName }) {
200
+ function componentStyleTemplateGenerator({ cliConfigFile, cmd, componentName, convertors }) {
155
201
  const { customTemplates } = cliConfigFile.component[cmd.type];
156
202
  let template = null;
157
203
  let filename = null;
@@ -185,13 +231,13 @@ function componentStyleTemplateGenerator({ cliConfigFile, cmd, componentName })
185
231
  }
186
232
 
187
233
  return {
188
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
234
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
189
235
  filename,
190
236
  template,
191
237
  };
192
238
  }
193
239
 
194
- function componentTestTemplateGenerator({ cliConfigFile, cmd, componentName }) {
240
+ function componentTestTemplateGenerator({ cliConfigFile, cmd, componentName, convertors }) {
195
241
  const { customTemplates } = cliConfigFile.component[cmd.type];
196
242
  const { testLibrary, usesTypeScript } = cliConfigFile;
197
243
  let template = null;
@@ -224,13 +270,13 @@ function componentTestTemplateGenerator({ cliConfigFile, cmd, componentName }) {
224
270
  }
225
271
 
226
272
  return {
227
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
273
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
228
274
  filename,
229
275
  template,
230
276
  };
231
277
  }
232
278
 
233
- function componentStoryTemplateGenerator({ cliConfigFile, cmd, componentName }) {
279
+ function componentStoryTemplateGenerator({ cliConfigFile, cmd, componentName, convertors }) {
234
280
  const { usesTypeScript } = cliConfigFile;
235
281
  const { customTemplates } = cliConfigFile.component[cmd.type];
236
282
  let template = null;
@@ -256,13 +302,13 @@ function componentStoryTemplateGenerator({ cliConfigFile, cmd, componentName })
256
302
  }
257
303
 
258
304
  return {
259
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
305
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
260
306
  filename,
261
307
  template,
262
308
  };
263
309
  }
264
310
 
265
- function componentLazyTemplateGenerator({ cmd, componentName, cliConfigFile }) {
311
+ function componentLazyTemplateGenerator({ cmd, componentName, cliConfigFile, convertors }) {
266
312
  const { usesTypeScript } = cliConfigFile;
267
313
  const { customTemplates } = cliConfigFile.component[cmd.type];
268
314
  let template = null;
@@ -288,13 +334,13 @@ function componentLazyTemplateGenerator({ cmd, componentName, cliConfigFile }) {
288
334
  }
289
335
 
290
336
  return {
291
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
337
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
292
338
  filename,
293
339
  template,
294
340
  };
295
341
  }
296
342
 
297
- function customFileTemplateGenerator({ componentName, cmd, cliConfigFile, componentFileType }) {
343
+ function customFileTemplateGenerator({ componentName, cmd, cliConfigFile, componentFileType, convertors }) {
298
344
  const { customTemplates } = cliConfigFile.component[cmd.type];
299
345
  const fileType = camelCase(componentFileType.split('with')[1]);
300
346
  let filename = null;
@@ -306,7 +352,7 @@ function customFileTemplateGenerator({ componentName, cmd, cliConfigFile, compon
306
352
  console.error(
307
353
  chalk.red(
308
354
  `
309
- ERROR: Custom component files require a valid custom template.
355
+ ERROR: Custom component files require a valid custom template.
310
356
  Please make sure you're pointing to the right custom template path in your generate-react-cli.json config file.
311
357
  `
312
358
  )
@@ -326,7 +372,7 @@ Please make sure you're pointing to the right custom template path in your gener
326
372
  filename = customTemplateFilename;
327
373
 
328
374
  return {
329
- componentPath: `${cmd.path}${cmd.flat ? '' : `/${componentName}`}/${filename}`,
375
+ componentPath: componentDirectoryNameGenerator({ cmd, componentName, cliConfigFile, filename, convertors }),
330
376
  filename,
331
377
  template,
332
378
  };
@@ -365,11 +411,21 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
365
411
  ) {
366
412
  const generateTemplate = componentTemplateGeneratorMap[componentFileType] || customFileTemplateGenerator;
367
413
 
414
+ const convertors = {
415
+ templatename: componentName,
416
+ TemplateName: startCase(camelCase(componentName)).replace(/ /g, ''),
417
+ templateName: camelCase(componentName),
418
+ 'template-name': kebabCase(componentName),
419
+ template_name: snakeCase(componentName),
420
+ TEMPLATE_NAME: snakeCase(componentName).toUpperCase(),
421
+ };
422
+
368
423
  const { componentPath, filename, template } = generateTemplate({
369
424
  cmd,
370
425
  componentName,
371
426
  cliConfigFile,
372
427
  componentFileType,
428
+ convertors,
373
429
  });
374
430
 
375
431
  // --- Make sure the component does not already exist in the path directory.
@@ -384,7 +440,7 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
384
440
  // Will replace the templatename in whichever format the user typed the component name in the command.
385
441
  replace({
386
442
  regex: 'templatename',
387
- replacement: componentName,
443
+ replacement: convertors['templatename'],
388
444
  paths: [componentPath],
389
445
  recursive: false,
390
446
  silent: true,
@@ -393,7 +449,7 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
393
449
  // Will replace the TemplateName in PascalCase
394
450
  replace({
395
451
  regex: 'TemplateName',
396
- replacement: startCase(camelCase(componentName)).replace(/ /g, ''),
452
+ replacement: convertors['TemplateName'],
397
453
  paths: [componentPath],
398
454
  recursive: false,
399
455
  silent: true,
@@ -402,7 +458,7 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
402
458
  // Will replace the templateName in camelCase
403
459
  replace({
404
460
  regex: 'templateName',
405
- replacement: camelCase(componentName),
461
+ replacement: convertors['templateName'],
406
462
  paths: [componentPath],
407
463
  recursive: false,
408
464
  silent: true,
@@ -411,7 +467,7 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
411
467
  // Will replace the template-name in kebab-case
412
468
  replace({
413
469
  regex: 'template-name',
414
- replacement: kebabCase(componentName),
470
+ replacement: convertors['template-name'],
415
471
  paths: [componentPath],
416
472
  recursive: false,
417
473
  silent: true,
@@ -420,7 +476,7 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
420
476
  // Will replace the template_name in snake_case
421
477
  replace({
422
478
  regex: 'template_name',
423
- replacement: snakeCase(componentName),
479
+ replacement: convertors['template_name'],
424
480
  paths: [componentPath],
425
481
  recursive: false,
426
482
  silent: true,
@@ -429,32 +485,13 @@ export function generateComponent(componentName, cmd, cliConfigFile) {
429
485
  // Will replace the TEMPLATE_NAME in uppercase SNAKE_CASE
430
486
  replace({
431
487
  regex: 'TEMPLATE_NAME',
432
- replacement: snakeCase(componentName).toUpperCase(),
488
+ replacement: convertors['TEMPLATE_NAME'],
433
489
  paths: [componentPath],
434
490
  recursive: false,
435
491
  silent: true,
436
492
  });
437
493
  }
438
494
 
439
- // Generate component with openAi, if component description is provided
440
-
441
- if (cmd.describe && componentFileType === buildInComponentFileTypes.COMPONENT) {
442
- aiComponentGenerator(template, cmd.describe)
443
- .then((aiGeneratedComponent) => {
444
- outputFileSync(componentPath, aiGeneratedComponent.trim());
445
- console.log(
446
- chalk.green(`OpenAI Successfully created the ${filename} component with the provided description.`)
447
- );
448
- })
449
- .catch((error) =>
450
- console.log(
451
- chalk.red(`OpenAI failed to create the ${filename} component with the provided description.`, error)
452
- )
453
- );
454
-
455
- return;
456
- }
457
-
458
495
  console.log(chalk.green(`${filename} was successfully created at ${componentPath}`));
459
496
  } catch (error) {
460
497
  console.error(chalk.red(`${filename} failed and was not created.`));
@@ -1,18 +0,0 @@
1
- import { Configuration, OpenAIApi } from 'openai';
2
-
3
- export async function aiComponentGenerator(componentTemplate, prompt) {
4
- const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY });
5
- const openAiApi = new OpenAIApi(configuration);
6
-
7
- const generatedComponent = await openAiApi.createCompletion({
8
- model: 'text-davinci-003',
9
- prompt: `Create a React component using this template "${componentTemplate}", but make the adjustments needed with these instructions as follows "${prompt}"`,
10
- temperature: 0.7,
11
- max_tokens: 2000,
12
- top_p: 1.0,
13
- frequency_penalty: 0.0,
14
- presence_penalty: 1,
15
- });
16
-
17
- return generatedComponent.data.choices[0].text;
18
- }