@strapi/generators 4.0.0-beta.12 → 4.0.0-beta.16

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.
@@ -3,7 +3,7 @@
3
3
  module.exports = {
4
4
  index(ctx) {
5
5
  ctx.body = strapi
6
- .plugin('{{ id }}')
6
+ .plugin('{{ pluginName }}')
7
7
  .service('myService')
8
8
  .getWelcomeMessage();
9
9
  },
package/lib/plops/api.js CHANGED
@@ -43,30 +43,9 @@ module.exports = plop => {
43
43
  return pluginsDirContent;
44
44
  },
45
45
  },
46
- {
47
- type: 'list',
48
- name: 'kind',
49
- message: 'Please choose the model type',
50
- default: 'collectionType',
51
- choices: [
52
- { name: 'Collection Type', value: 'collectionType' },
53
- { name: 'Singe Type', value: 'singleType' },
54
- ],
55
- },
56
- {
57
- type: 'confirm',
58
- name: 'useDraftAndPublish',
59
- default: false,
60
- message: 'Use draft and publish?',
61
- },
62
46
  ],
63
47
  actions(answers) {
64
- let filePath;
65
- if (answers.isPluginApi && answers.plugin) {
66
- filePath = `plugins/{{plugin}}`;
67
- } else {
68
- filePath = `api/{{id}}`;
69
- }
48
+ const filePath = answers.isPluginApi && answers.plugin ? 'plugins/{{plugin}}' : 'api/{{id}}';
70
49
 
71
50
  const baseActions = [
72
51
  {
@@ -74,11 +53,6 @@ module.exports = plop => {
74
53
  path: `${filePath}/controllers/{{id}}.js`,
75
54
  templateFile: 'templates/controller.js.hbs',
76
55
  },
77
- {
78
- type: 'add',
79
- path: `${filePath}/content-types/{{id}}/schema.json`,
80
- templateFile: 'templates/content-type.schema.json.hbs',
81
- },
82
56
  {
83
57
  type: 'add',
84
58
  path: `${filePath}/services/{{id}}.js`,
@@ -90,16 +64,11 @@ module.exports = plop => {
90
64
  return baseActions;
91
65
  }
92
66
 
93
- const routeType =
94
- answers.kind === 'singleType'
95
- ? 'single-type-routes.js.hbs'
96
- : 'collection-type-routes.js.hbs';
97
-
98
67
  return [
99
68
  {
100
69
  type: 'add',
101
70
  path: `${filePath}/routes/{{id}}.js`,
102
- templateFile: `templates/${routeType}`,
71
+ templateFile: `templates/single-route.js.hbs`,
103
72
  },
104
73
  ...baseActions,
105
74
  ];
@@ -1,168 +1,66 @@
1
1
  'use strict';
2
2
 
3
- const pluralize = require('pluralize');
3
+ const { join } = require('path');
4
4
  const slugify = require('@sindresorhus/slugify');
5
+ const fs = require('fs-extra');
5
6
  const { isKebabCase } = require('@strapi/utils');
6
7
 
7
- const getDestinationPrompts = require('./utils/get-destination-prompts');
8
+ const getDestinationPrompts = require('./prompts/get-destination-prompts');
8
9
  const getFilePath = require('./utils/get-file-path');
9
- const validateInput = require('./utils/validate-input');
10
-
11
- const DEFAULT_TYPES = [
12
- // advanced types
13
- 'media',
14
-
15
- // scalar types
16
- 'string',
17
- 'text',
18
- 'richtext',
19
- 'json',
20
- 'enumeration',
21
- 'password',
22
- 'email',
23
- 'integer',
24
- 'biginteger',
25
- 'float',
26
- 'decimal',
27
- 'date',
28
- 'time',
29
- 'datetime',
30
- 'timestamp',
31
- 'boolean',
32
- ];
33
-
34
- const promptConfigQuestions = (plop, inquirer) => {
35
- return inquirer.prompt([
36
- {
37
- type: 'input',
38
- name: 'displayName',
39
- message: 'Content type display name',
40
- validate: input => !!input,
41
- },
42
- {
43
- type: 'input',
44
- name: 'singularName',
45
- message: 'Content type singular name',
46
- default: answers => slugify(answers.displayName),
47
- validate(input) {
48
- if (!isKebabCase(input)) {
49
- return 'Value must be in kebab-case';
50
- }
51
-
52
- return true;
53
- },
54
- },
55
- {
56
- type: 'input',
57
- name: 'pluralName',
58
- message: 'Content type plural name',
59
- default: answers => pluralize(answers.singularName),
60
- validate(input, answers) {
61
- if (answers.singularName === input) {
62
- return 'Singular and plural names cannot be the same';
63
- }
64
-
65
- if (!isKebabCase(input)) {
66
- return 'Value must be in kebab-case';
67
- }
68
-
69
- return true;
70
- },
71
- },
72
- {
73
- type: 'list',
74
- name: 'kind',
75
- message: 'Please choose the model type',
76
- default: 'collectionType',
77
- choices: [
78
- { name: 'Collection Type', value: 'collectionType' },
79
- { name: 'Singe Type', value: 'singleType' },
80
- ],
81
- validate: input => validateInput(input),
82
- },
83
- ...getDestinationPrompts('model', plop.getDestBasePath()),
84
- {
85
- type: 'confirm',
86
- name: 'useDraftAndPublish',
87
- default: false,
88
- message: 'Use draft and publish?',
89
- },
90
- {
91
- type: 'confirm',
92
- name: 'addAttributes',
93
- message: 'Do you want to add attributes?',
94
- },
95
- ]);
96
- };
97
-
98
- const promptAttributeQuestions = inquirer => {
99
- return inquirer.prompt([
100
- {
101
- type: 'input',
102
- name: 'attributeName',
103
- message: 'Name of attribute',
104
- validate: input => validateInput(input),
105
- },
106
- {
107
- type: 'list',
108
- name: 'attributeType',
109
- message: 'What type of attribute',
110
- pageSize: DEFAULT_TYPES.length,
111
- choices: DEFAULT_TYPES.map(type => {
112
- return { name: type, value: type };
113
- }),
114
- },
115
- {
116
- when: answers => answers.attributeType === 'enumeration',
117
- type: 'input',
118
- name: 'enum',
119
- message: 'Add values separated by a comma',
120
- },
121
- {
122
- when: answers => answers.attributeType === 'media',
123
- type: 'list',
124
- name: 'multiple',
125
- message: 'Choose media type',
126
- choices: [{ name: 'Multiple', value: true }, { name: 'Single', value: false }],
127
- },
128
- {
129
- type: 'confirm',
130
- name: 'addAttributes',
131
- message: 'Do you want to add another attribute?',
132
- },
133
- ]);
134
- };
10
+ const ctNamesPrompts = require('./prompts/ct-names-prompts');
11
+ const kindPrompts = require('./prompts/kind-prompts');
12
+ const draftAndPublishPrompts = require('./prompts/draft-and-publish-prompts');
13
+ const getAttributesPrompts = require('./prompts/get-attributes-prompts');
14
+ const bootstrapApiPrompts = require('./prompts/bootstrap-api-prompts');
135
15
 
136
16
  module.exports = plop => {
137
17
  // Model generator
138
18
  plop.setGenerator('content-type', {
139
19
  description: 'Generate a content type for an API',
140
20
  async prompts(inquirer) {
141
- const config = await promptConfigQuestions(plop, inquirer);
142
-
143
- if (!config.addAttributes) {
144
- return {
145
- ...config,
146
- attributes: [],
147
- };
148
- }
149
-
150
- const attributes = [];
151
-
152
- const genAttribute = async () => {
153
- const answers = await promptAttributeQuestions(inquirer);
154
-
155
- attributes.push(answers);
156
-
157
- if (answers.addAttributes) {
158
- return genAttribute();
159
- }
160
- };
161
-
162
- await genAttribute();
21
+ const config = await inquirer.prompt([
22
+ ...ctNamesPrompts,
23
+ ...kindPrompts,
24
+ ...draftAndPublishPrompts,
25
+ ]);
26
+ const attributes = await getAttributesPrompts(inquirer);
27
+
28
+ const api = await inquirer.prompt([
29
+ ...getDestinationPrompts('model', plop.getDestBasePath()),
30
+ {
31
+ when: answers => answers.destination === 'new',
32
+ type: 'input',
33
+ name: 'id',
34
+ default: config.singularName,
35
+ message: 'Name of the new API?',
36
+ async validate(input) {
37
+ if (!isKebabCase(input)) {
38
+ return 'Value must be in kebab-case';
39
+ }
40
+
41
+ const apiPath = join(plop.getDestBasePath(), 'api');
42
+ const exists = await fs.pathExists(apiPath);
43
+
44
+ if (!exists) {
45
+ return true;
46
+ }
47
+
48
+ const apiDir = await fs.readdir(apiPath, { withFileTypes: true });
49
+ const apiDirContent = apiDir.filter(fd => fd.isDirectory());
50
+
51
+ if (apiDirContent.findIndex(api => api.name === input) !== -1) {
52
+ throw new Error('This name is already taken.');
53
+ }
54
+
55
+ return true;
56
+ },
57
+ },
58
+ ...bootstrapApiPrompts,
59
+ ]);
163
60
 
164
61
  return {
165
62
  ...config,
63
+ ...api,
166
64
  attributes,
167
65
  };
168
66
  },
@@ -184,17 +82,19 @@ module.exports = plop => {
184
82
 
185
83
  const filePath = getFilePath(answers.destination);
186
84
 
187
- return [
85
+ const baseActions = [
188
86
  {
189
87
  type: 'add',
190
88
  path: `${filePath}/content-types/{{ singularName }}/schema.json`,
191
89
  templateFile: 'templates/content-type.schema.json.hbs',
192
90
  data: {
193
- id: answers.singularName,
194
91
  collectionName: slugify(answers.pluralName, { separator: '_' }),
195
92
  },
196
93
  },
197
- {
94
+ ];
95
+
96
+ if (attributes.lenght > 0) {
97
+ baseActions.push({
198
98
  type: 'modify',
199
99
  path: `${filePath}/content-types/{{ singularName }}/schema.json`,
200
100
  transform(template) {
@@ -202,8 +102,44 @@ module.exports = plop => {
202
102
  parsedTemplate.attributes = attributes;
203
103
  return JSON.stringify(parsedTemplate, null, 2);
204
104
  },
205
- },
206
- ];
105
+ });
106
+ }
107
+
108
+ if (answers.bootstrapApi) {
109
+ const { singularName } = answers;
110
+
111
+ let uid;
112
+ if (answers.destination === 'new') {
113
+ uid = `api::${answers.id}.${singularName}`;
114
+ } else if (answers.api) {
115
+ uid = `api::${answers.api}.${singularName}`;
116
+ } else if (answers.plugin) {
117
+ uid = `plugin::${answers.plugin}.${singularName}`;
118
+ }
119
+
120
+ baseActions.push(
121
+ {
122
+ type: 'add',
123
+ path: `${filePath}/controllers/{{singularName}}.js`,
124
+ templateFile: 'templates/core-controller.js.hbs',
125
+ data: { uid },
126
+ },
127
+ {
128
+ type: 'add',
129
+ path: `${filePath}/services/{{singularName}}.js`,
130
+ templateFile: 'templates/core-service.js.hbs',
131
+ data: { uid },
132
+ },
133
+ {
134
+ type: 'add',
135
+ path: `${filePath}/routes/{{singularName}}.js`,
136
+ templateFile: `templates/core-router.js.hbs`,
137
+ data: { uid },
138
+ }
139
+ );
140
+ }
141
+
142
+ return baseActions;
207
143
  },
208
144
  });
209
145
  };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const getDestinationPrompts = require('./utils/get-destination-prompts');
3
+ const getDestinationPrompts = require('./prompts/get-destination-prompts');
4
4
  const getFilePath = require('./utils/get-file-path');
5
5
  const validateInput = require('./utils/validate-input');
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const getDestinationPrompts = require('./utils/get-destination-prompts');
3
+ const getDestinationPrompts = require('./prompts/get-destination-prompts');
4
4
 
5
5
  module.exports = plop => {
6
6
  // middleware generator
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const getDestinationPrompts = require('./utils/get-destination-prompts');
3
+ const getDestinationPrompts = require('./prompts/get-destination-prompts');
4
4
 
5
5
  module.exports = plop => {
6
6
  // Policy generator
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ module.exports = [
4
+ {
5
+ type: 'confirm',
6
+ name: 'bootstrapApi',
7
+ default: true,
8
+ message: 'Bootstrap API related files?',
9
+ },
10
+ ];
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ const pluralize = require('pluralize');
4
+ const slugify = require('@sindresorhus/slugify');
5
+ const { isKebabCase } = require('@strapi/utils');
6
+
7
+ module.exports = [
8
+ {
9
+ type: 'input',
10
+ name: 'displayName',
11
+ message: 'Content type display name',
12
+ validate: input => !!input,
13
+ },
14
+ {
15
+ type: 'input',
16
+ name: 'singularName',
17
+ message: 'Content type singular name',
18
+ default: answers => slugify(answers.displayName),
19
+ validate(input) {
20
+ if (!isKebabCase(input)) {
21
+ return 'Value must be in kebab-case';
22
+ }
23
+
24
+ return true;
25
+ },
26
+ },
27
+ {
28
+ type: 'input',
29
+ name: 'pluralName',
30
+ message: 'Content type plural name',
31
+ default: answers => pluralize(answers.singularName),
32
+ validate(input, answers) {
33
+ if (answers.singularName === input) {
34
+ return 'Singular and plural names cannot be the same';
35
+ }
36
+
37
+ if (!isKebabCase(input)) {
38
+ return 'Value must be in kebab-case';
39
+ }
40
+
41
+ return true;
42
+ },
43
+ },
44
+ ];
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ module.exports = [
4
+ {
5
+ type: 'confirm',
6
+ name: 'useDraftAndPublish',
7
+ default: false,
8
+ message: 'Use draft and publish?',
9
+ },
10
+ ];
@@ -0,0 +1,102 @@
1
+ 'use strict';
2
+
3
+ const validateInput = require('../utils/validate-input');
4
+
5
+ const DEFAULT_TYPES = [
6
+ // advanced types
7
+ 'media',
8
+
9
+ // scalar types
10
+ 'string',
11
+ 'text',
12
+ 'richtext',
13
+ 'json',
14
+ 'enumeration',
15
+ 'password',
16
+ 'email',
17
+ 'integer',
18
+ 'biginteger',
19
+ 'float',
20
+ 'decimal',
21
+ 'date',
22
+ 'time',
23
+ 'datetime',
24
+ 'timestamp',
25
+ 'boolean',
26
+ ];
27
+
28
+ /**
29
+ * @param {import('inquirer').Inquirer} inquirer
30
+ * @returns {Promise<Record<string, string>[]>}
31
+ */
32
+ module.exports = async inquirer => {
33
+ const { addAttributes } = await inquirer.prompt([
34
+ {
35
+ type: 'confirm',
36
+ name: 'addAttributes',
37
+ message: 'Do you want to add attributes?',
38
+ },
39
+ ]);
40
+
41
+ const attributes = [];
42
+
43
+ /**
44
+ * @param {import('inquirer').Inquirer} inquirer
45
+ * @returns {Promise<void>}
46
+ */
47
+ const createNewAttributes = async inquirer => {
48
+ const answers = await inquirer.prompt([
49
+ {
50
+ type: 'input',
51
+ name: 'attributeName',
52
+ message: 'Name of attribute',
53
+ validate: input => validateInput(input),
54
+ },
55
+ {
56
+ type: 'list',
57
+ name: 'attributeType',
58
+ message: 'What type of attribute',
59
+ pageSize: DEFAULT_TYPES.length,
60
+ choices: DEFAULT_TYPES.map(type => {
61
+ return { name: type, value: type };
62
+ }),
63
+ },
64
+ {
65
+ when: answers => answers.attributeType === 'enumeration',
66
+ type: 'input',
67
+ name: 'enum',
68
+ message: 'Add values separated by a comma',
69
+ },
70
+ {
71
+ when: answers => answers.attributeType === 'media',
72
+ type: 'list',
73
+ name: 'multiple',
74
+ message: 'Choose media type',
75
+ choices: [{ name: 'Multiple', value: true }, { name: 'Single', value: false }],
76
+ },
77
+ {
78
+ type: 'confirm',
79
+ name: 'addAttributes',
80
+ message: 'Do you want to add another attribute?',
81
+ },
82
+ ]);
83
+
84
+ attributes.push(answers);
85
+
86
+ if (!answers.addAttributes) {
87
+ return;
88
+ }
89
+
90
+ await createNewAttributes(inquirer);
91
+ };
92
+
93
+ if (addAttributes) {
94
+ await createNewAttributes(inquirer);
95
+ } else {
96
+ console.warn(
97
+ `You won't be able to manage entries from the admin, you can still add attributes later from the content type builder.`
98
+ );
99
+ }
100
+
101
+ return attributes;
102
+ };
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ const validateInput = require('../utils/validate-input');
4
+
5
+ module.exports = [
6
+ {
7
+ type: 'list',
8
+ name: 'kind',
9
+ message: 'Please choose the model type',
10
+ default: 'collectionType',
11
+ choices: [
12
+ { name: 'Collection Type', value: 'collectionType' },
13
+ { name: 'Single Type', value: 'singleType' },
14
+ ],
15
+ validate: input => validateInput(input),
16
+ },
17
+ ];
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const getDestinationPrompts = require('./utils/get-destination-prompts');
3
+ const getDestinationPrompts = require('./prompts/get-destination-prompts');
4
4
  const getFilePath = require('./utils/get-file-path');
5
5
 
6
6
  module.exports = plop => {
@@ -6,6 +6,7 @@ module.exports = {
6
6
  handler: '{{id}}.find',
7
7
  config: {
8
8
  policies: [],
9
+ middlewares: [],
9
10
  },
10
11
  },
11
12
  {
@@ -14,6 +15,7 @@ module.exports = {
14
15
  handler: '{{id}}.findOne',
15
16
  config: {
16
17
  policies: [],
18
+ middlewares: [],
17
19
  },
18
20
  },
19
21
  {
@@ -22,6 +24,7 @@ module.exports = {
22
24
  handler: '{{id}}.create',
23
25
  config: {
24
26
  policies: [],
27
+ middlewares: [],
25
28
  },
26
29
  },
27
30
  {
@@ -30,6 +33,7 @@ module.exports = {
30
33
  handler: '{{id}}.update',
31
34
  config: {
32
35
  policies: [],
36
+ middlewares: [],
33
37
  },
34
38
  },
35
39
  {
@@ -38,6 +42,7 @@ module.exports = {
38
42
  handler: '{{id}}.delete',
39
43
  config: {
40
44
  policies: [],
45
+ middlewares: [],
41
46
  },
42
47
  },
43
48
  ],
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * {{ id }} controller
5
+ */
6
+
7
+ const { createCoreController } = require('@strapi/strapi').factories;
8
+
9
+ module.exports = createCoreController('{{ uid }}');
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * {{ id }} router.
5
+ */
6
+
7
+ const { createCoreRouter } = require('@strapi/strapi').factories;
8
+
9
+ module.exports = createCoreRouter('{{ uid }}');
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * {{ id }} service.
5
+ */
6
+
7
+ const { createCoreService } = require('@strapi/strapi').factories;
8
+
9
+ module.exports = createCoreService('{{ uid }}');
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ routes: [
3
+ // {
4
+ // method: 'GET',
5
+ // path: '/{{id}}',
6
+ // handler: '{{id}}.exampleAction',
7
+ // config: {
8
+ // policies: [],
9
+ // middlewares: [],
10
+ // },
11
+ // },
12
+ ],
13
+ };
@@ -6,6 +6,7 @@ module.exports = {
6
6
  handler: '{{id}}.find',
7
7
  config: {
8
8
  policies: [],
9
+ middlewares: [],
9
10
  },
10
11
  },
11
12
  {
@@ -14,6 +15,7 @@ module.exports = {
14
15
  handler: '{{id}}.update',
15
16
  config: {
16
17
  policies: [],
18
+ middlewares: [],
17
19
  },
18
20
  },
19
21
  {
@@ -22,6 +24,7 @@ module.exports = {
22
24
  handler: '{{id}}.delete',
23
25
  config: {
24
26
  policies: [],
27
+ middlewares: [],
25
28
  },
26
29
  },
27
30
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/generators",
3
- "version": "4.0.0-beta.12",
3
+ "version": "4.0.0-beta.16",
4
4
  "description": "Interactive API generator.",
5
5
  "keywords": [
6
6
  "strapi",
@@ -30,7 +30,7 @@
30
30
  "main": "lib/index.js",
31
31
  "dependencies": {
32
32
  "@sindresorhus/slugify": "1.1.0",
33
- "@strapi/utils": "4.0.0-beta.12",
33
+ "@strapi/utils": "4.0.0-beta.16",
34
34
  "chalk": "4.1.2",
35
35
  "fs-extra": "10.0.0",
36
36
  "node-plop": "0.26.3",
@@ -41,5 +41,5 @@
41
41
  "node": ">=12.x.x <=16.x.x",
42
42
  "npm": ">=6.0.0"
43
43
  },
44
- "gitHead": "67fee6f3d59df974e8770bb123549f972edda905"
44
+ "gitHead": "71bdfa34637832e8e78a6cf1b57c8c6dbadf133d"
45
45
  }