diff --git a/packages/generators/generate/package.json b/packages/generators/generate/package.json index 5ffd56e15c..cbbbd3a5ea 100644 --- a/packages/generators/generate/package.json +++ b/packages/generators/generate/package.json @@ -6,7 +6,6 @@ "license": "MIT", "dependencies": { "fs-extra": "10.0.0", - "inquirer": "8.1.2", "inquirer-recursive": "0.0.7", "node-plop": "0.26.2", "plop": "2.7.4", diff --git a/packages/generators/generate/plopfile.js b/packages/generators/generate/plopfile.js index 66f75a313d..b51906a77b 100644 --- a/packages/generators/generate/plopfile.js +++ b/packages/generators/generate/plopfile.js @@ -1,322 +1,26 @@ 'use strict'; -const { join } = require('path'); -const fs = require('fs-extra'); const pluralize = require('pluralize'); -const rootDir = process.cwd(); - -const getFilePath = destination => { - if (destination === 'api') { - return `api/{{api}}`; - } - - if (destination === 'plugin') { - return `plugins/{{plugin}}`; - } - - return `api/{{id}}`; -}; - -const getDestinationPrompts = action => { - return [ - { - type: 'list', - name: 'destination', - message: `Where do you want to add this ${action}?`, - choices: [ - { - name: `Add ${action} to ${action === 'policy' ? 'root of project' : 'new API'}`, - value: 'new', - }, - { name: `Add ${action} to existing API`, value: 'api' }, - { name: `Add ${action} to existing plugin`, value: 'plugin' }, - ], - }, - { - when: answers => answers.destination === 'api', - type: 'input', - message: 'Which API is this for?', - name: 'api', - validate: async input => { - const exists = await fs.pathExists(join(rootDir, `api/${input}`)); - - return exists || 'That api does not exist, please try again'; - }, - }, - { - when: answers => answers.destination === 'plugin', - type: 'input', - message: 'Which plugin is this for?', - name: 'plugin', - validate: async input => { - const exists = await fs.pathExists(join(rootDir, `plugins/${input}`)); - - return exists || 'That plugin does not exist, please try again'; - }, - }, - ]; -}; +const api = require('./plops/api'); +const controller = require('./plops/controller'); +const model = require('./plops/model'); +const plugin = require('./plops/plugin'); +const policy = require('./plops/policy'); +const service = require('./plops/service'); module.exports = function(plop) { + const rootDir = process.cwd(); + // Plop config plop.setWelcomeMessage('Strapi Generators'); - plop.addHelper('pluralize', text => pluralize(text)); - - // API generator - plop.setGenerator('api', { - description: 'Generate a basic API', - prompts: [ - { - type: 'input', - name: 'id', - message: 'API name', - }, - { - type: 'list', - name: 'kind', - message: 'Please choose the model type', - choices: [ - { name: 'Collection Type', value: 'collectionType' }, - { name: 'Singe Type', value: 'singleType' }, - ], - }, - { - type: 'confirm', - name: 'isPluginApi', - message: 'Is this API for a plugin?', - }, - { - when: answers => answers.isPluginApi, - type: 'input', - name: 'plugin', - message: 'Plugin name', - validate: async input => { - const exists = await fs.pathExists(join(rootDir, `plugins/${input}`)); - - return exists || 'That plugin does not exist, please try again'; - }, - }, - { - type: 'confirm', - name: 'useDraftAndPublish', - message: 'Use draft and publish?', - }, - ], - actions: answers => { - let filePath; - if (answers.isPluginApi && answers.plugin) { - filePath = `plugins/{{plugin}}`; - } else { - filePath = `api/{{id}}`; - } - - const baseActions = [ - { - type: 'add', - path: join(rootDir, `${filePath}/controllers/{{id}}.js`), - templateFile: 'templates/controller.js.hbs', - }, - { - type: 'add', - path: join(rootDir, `${filePath}/models/{{id}}.js`), - templateFile: 'templates/model.js.hbs', - }, - { - type: 'add', - path: join(rootDir, `${filePath}/models/{{id}}.settings.json`), - templateFile: 'templates/model.settings.json.hbs', - }, - { - type: 'add', - path: join(rootDir, `${filePath}/services/{{id}}.js`), - templateFile: 'templates/service.js.hbs', - }, - ]; - - if (answers.isPluginApi) { - return baseActions; - } else { - return [ - { - type: 'add', - path: join(rootDir, `${filePath}/config/routes.json`), - templateFile: 'templates/api-routes.json.hbs', - }, - ...baseActions, - ]; - } - }, - }); - - // Controller generator - plop.setGenerator('controller', { - description: 'Generate a controller for an API', - prompts: [ - { - type: 'input', - name: 'id', - message: 'Controller name', - }, - ...getDestinationPrompts('controller'), - ], - actions: answers => { - const filePath = getFilePath(answers.destination); - - return [ - { - type: 'add', - path: join(rootDir, `${filePath}/controllers/{{id}}.js`), - templateFile: 'templates/controller.js.hbs', - }, - ]; - }, - }); - plop.setPrompt('recursive', require('inquirer-recursive')); - // Model generator - plop.setGenerator('model', { - description: 'Generate a model for an API', - prompts: [ - { - type: 'input', - name: 'id', - message: 'Model name', - }, - { - type: 'list', - name: 'kind', - message: 'Please choose the model type', - choices: [ - { name: 'Collection Type', value: 'collectionType' }, - { name: 'Singe Type', value: 'singleType' }, - ], - }, - ...getDestinationPrompts('model'), - { - type: 'addAttributes', - name: 'attributes', - }, - { - type: 'confirm', - name: 'useDraftAndPublish', - message: 'Use draft and publish?', - }, - ], - actions: answers => { - const filePath = getFilePath(answers.destination); - return [ - { - type: 'add', - path: join(rootDir, `${filePath}/models/{{id}}.js`), - templateFile: 'templates/model.js.hbs', - }, - { - type: 'add', - path: join(rootDir, `${filePath}/models/{{id}}.settings.json`), - templateFile: 'templates/model.settings.json.hbs', - }, - ]; - }, - }); - - const { prompts } = plop.inquirer.prompt; - console.log(prompts); - - // Plugin generator - plop.setGenerator('plugin', { - description: 'Generate a basic plugin', - prompts: [ - { - type: 'input', - name: 'id', - message: 'Plugin name', - }, - ], - actions: answers => { - fs.copySync(join(__dirname, 'files', 'plugin'), join(rootDir, 'plugins', answers.id)); - return [ - { - type: 'add', - path: join(rootDir, 'plugins/{{id}}/services/{{id}}.js'), - templateFile: 'templates/service.js.hbs', - }, - { - type: 'add', - path: join(rootDir, 'plugins/{{id}}/controllers/{{id}}.js'), - templateFile: 'templates/controller.js.hbs', - }, - { - type: 'add', - path: join(rootDir, 'plugins/{{id}}/config/routes.json'), - templateFile: 'templates/plugin-routes.json.hbs', - }, - { - type: 'add', - path: join(rootDir, 'plugins/{{id}}/README.md'), - templateFile: 'templates/README.md.hbs', - }, - { - type: 'add', - path: join(rootDir, 'plugins/{{id}}/package.json'), - templateFile: 'templates/plugin-package.json.hbs', - }, - ]; - }, - }); - - // Policy generator - plop.setGenerator('policy', { - description: 'Generate a policy for an API', - prompts: [ - { - type: 'input', - name: 'id', - message: 'Policy name', - }, - ...getDestinationPrompts('policy'), - ], - actions: answers => { - let filePath; - if (answers.destination === 'api') { - filePath = `api/{{api}}`; - } else if (answers.destination === 'plugin') { - filePath = `plugins/{{plugin}}`; - } else { - filePath = ``; - } - - return [ - { - type: 'add', - path: join(rootDir, `${filePath}/config/policies/{{id}}.js`), - templateFile: 'templates/policy.js.hbs', - }, - ]; - }, - }); - - // Service generator - plop.setGenerator('service', { - description: 'Generate a service for an API', - prompts: [ - { - type: 'input', - name: 'id', - message: 'Service name', - }, - ...getDestinationPrompts('service'), - ], - actions: answers => { - const filePath = getFilePath(answers.destination); - return [ - { - type: 'add', - path: join(rootDir, `${filePath}/services/{{id}}.js`), - templateFile: 'templates/service.js.hbs', - }, - ]; - }, - }); + // Generators + api(plop, rootDir); + controller(plop, rootDir); + model(plop, rootDir); + plugin(plop, rootDir); + policy(plop, rootDir); + service(plop, rootDir); }; diff --git a/packages/generators/generate/plops/api.js b/packages/generators/generate/plops/api.js new file mode 100644 index 0000000000..b0f31ad4bb --- /dev/null +++ b/packages/generators/generate/plops/api.js @@ -0,0 +1,92 @@ +'use strict'; + +const { join } = require('path'); +const fs = require('fs-extra'); + +module.exports = (plop, rootDir) => { + // API generator + plop.setGenerator('api', { + description: 'Generate a basic API', + prompts: [ + { + type: 'input', + name: 'id', + message: 'API name', + }, + { + type: 'list', + name: 'kind', + message: 'Please choose the model type', + choices: [ + { name: 'Collection Type', value: 'collectionType' }, + { name: 'Singe Type', value: 'singleType' }, + ], + }, + { + type: 'confirm', + name: 'isPluginApi', + message: 'Is this API for a plugin?', + }, + { + when: answers => answers.isPluginApi, + type: 'input', + name: 'plugin', + message: 'Plugin name', + validate: async input => { + const exists = await fs.pathExists(join(rootDir, `plugins/${input}`)); + + return exists || 'That plugin does not exist, please try again'; + }, + }, + { + type: 'confirm', + name: 'useDraftAndPublish', + message: 'Use draft and publish?', + }, + ], + actions: answers => { + let filePath; + if (answers.isPluginApi && answers.plugin) { + filePath = `plugins/{{plugin}}`; + } else { + filePath = `api/{{id}}`; + } + + const baseActions = [ + { + type: 'add', + path: join(rootDir, `${filePath}/controllers/{{id}}.js`), + templateFile: 'templates/controller.js.hbs', + }, + { + type: 'add', + path: join(rootDir, `${filePath}/models/{{id}}.js`), + templateFile: 'templates/model.js.hbs', + }, + { + type: 'add', + path: join(rootDir, `${filePath}/models/{{id}}.settings.json`), + templateFile: 'templates/model.settings.json.hbs', + }, + { + type: 'add', + path: join(rootDir, `${filePath}/services/{{id}}.js`), + templateFile: 'templates/service.js.hbs', + }, + ]; + + if (answers.isPluginApi) { + return baseActions; + } else { + return [ + { + type: 'add', + path: join(rootDir, `${filePath}/config/routes.json`), + templateFile: 'templates/api-routes.json.hbs', + }, + ...baseActions, + ]; + } + }, + }); +}; diff --git a/packages/generators/generate/plops/controller.js b/packages/generators/generate/plops/controller.js new file mode 100644 index 0000000000..30ab862d5b --- /dev/null +++ b/packages/generators/generate/plops/controller.js @@ -0,0 +1,31 @@ +'use strict'; + +const { join } = require('path'); +const getDestinationPrompts = require('./utils/get-destination-prompts'); +const getFilePath = require('./utils/get-file-path'); + +module.exports = (plop, rootDir) => { + // Controller generator + plop.setGenerator('controller', { + description: 'Generate a controller for an API', + prompts: [ + { + type: 'input', + name: 'id', + message: 'Controller name', + }, + ...getDestinationPrompts('controller'), + ], + actions: answers => { + const filePath = getFilePath(answers.destination); + + return [ + { + type: 'add', + path: join(rootDir, `${filePath}/controllers/{{id}}.js`), + templateFile: 'templates/controller.js.hbs', + }, + ]; + }, + }); +}; diff --git a/packages/generators/generate/plops/model.js b/packages/generators/generate/plops/model.js new file mode 100644 index 0000000000..27f4811c04 --- /dev/null +++ b/packages/generators/generate/plops/model.js @@ -0,0 +1,115 @@ +'use strict'; + +const { join } = require('path'); +const getDestinationPrompts = require('./utils/get-destination-prompts'); +const getFilePath = require('./utils/get-file-path'); + +const DEFAULT_TYPES = [ + // advanced types + 'media', + + // scalar types + 'string', + 'text', + 'richtext', + 'json', + 'enumeration', + 'password', + 'email', + 'integer', + 'biginteger', + 'float', + 'decimal', + 'date', + 'time', + 'datetime', + 'timestamp', + 'boolean', + + 'relation', +]; + +module.exports = (plop, rootDir) => { + // Model generator + plop.setGenerator('model', { + description: 'Generate a model for an API', + prompts: [ + { + type: 'input', + name: 'id', + message: 'Model name', + }, + { + type: 'list', + name: 'kind', + message: 'Please choose the model type', + choices: [ + { name: 'Collection Type', value: 'collectionType' }, + { name: 'Singe Type', value: 'singleType' }, + ], + }, + ...getDestinationPrompts('model'), + { + type: 'confirm', + name: 'useDraftAndPublish', + message: 'Use draft and publish?', + }, + { + type: 'recursive', + message: 'Add attribute?', + name: 'attributes', + prompts: [ + { + type: 'input', + name: 'attributeName', + message: 'Name of attribute', + }, + { + type: 'list', + name: 'attributeType', + message: 'What type of attribute', + pageSize: DEFAULT_TYPES.length, + choices: DEFAULT_TYPES.map(type => { + return { name: type, value: type }; + }), + }, + ], + }, + ], + actions: answers => { + const attributes = answers.attributes.reduce((object, answer) => { + // Rest/spread properties are not supported until Node.js 8.3.0. + // The configured version range is '>=8.0.0' + return Object.assign( + object, + { [answer.attributeName]: { type: answer.attributeType } }, + {} + ); + }, {}); + + const filePath = getFilePath(answers.destination); + + return [ + { + type: 'add', + path: join(rootDir, `${filePath}/models/{{id}}.js`), + templateFile: 'templates/model.js.hbs', + }, + { + type: 'add', + path: join(rootDir, `${filePath}/models/{{id}}.settings.json`), + templateFile: 'templates/model.settings.json.hbs', + }, + { + type: 'modify', + path: join(rootDir, `${filePath}/models/{{id}}.settings.json`), + transform: template => { + const temp = JSON.parse(template); + temp.attributes = attributes; + return JSON.stringify(temp, null, 2); + }, + }, + ]; + }, + }); +}; diff --git a/packages/generators/generate/plops/plugin.js b/packages/generators/generate/plops/plugin.js new file mode 100644 index 0000000000..4f7c479282 --- /dev/null +++ b/packages/generators/generate/plops/plugin.js @@ -0,0 +1,48 @@ +'use strict'; + +const { join } = require('path'); +const fs = require('fs-extra'); + +module.exports = (plop, rootDir) => { + // Plugin generator + plop.setGenerator('plugin', { + description: 'Generate a basic plugin', + prompts: [ + { + type: 'input', + name: 'id', + message: 'Plugin name', + }, + ], + actions: answers => { + fs.copySync(join(__dirname, 'files', 'plugin'), join(rootDir, 'plugins', answers.id)); + return [ + { + type: 'add', + path: join(rootDir, 'plugins/{{id}}/services/{{id}}.js'), + templateFile: 'templates/service.js.hbs', + }, + { + type: 'add', + path: join(rootDir, 'plugins/{{id}}/controllers/{{id}}.js'), + templateFile: 'templates/controller.js.hbs', + }, + { + type: 'add', + path: join(rootDir, 'plugins/{{id}}/config/routes.json'), + templateFile: 'templates/plugin-routes.json.hbs', + }, + { + type: 'add', + path: join(rootDir, 'plugins/{{id}}/README.md'), + templateFile: 'templates/README.md.hbs', + }, + { + type: 'add', + path: join(rootDir, 'plugins/{{id}}/package.json'), + templateFile: 'templates/plugin-package.json.hbs', + }, + ]; + }, + }); +}; diff --git a/packages/generators/generate/plops/policy.js b/packages/generators/generate/plops/policy.js new file mode 100644 index 0000000000..5e605860a6 --- /dev/null +++ b/packages/generators/generate/plops/policy.js @@ -0,0 +1,37 @@ +'use strict'; + +const { join } = require('path'); +const getDestinationPrompts = require('./utils/get-destination-prompts'); + +module.exports = (plop, rootDir) => { + // Policy generator + plop.setGenerator('policy', { + description: 'Generate a policy for an API', + prompts: [ + { + type: 'input', + name: 'id', + message: 'Policy name', + }, + ...getDestinationPrompts('policy'), + ], + actions: answers => { + let filePath; + if (answers.destination === 'api') { + filePath = `api/{{api}}`; + } else if (answers.destination === 'plugin') { + filePath = `plugins/{{plugin}}`; + } else { + filePath = ``; + } + + return [ + { + type: 'add', + path: join(rootDir, `${filePath}/config/policies/{{id}}.js`), + templateFile: 'templates/policy.js.hbs', + }, + ]; + }, + }); +}; diff --git a/packages/generators/generate/plops/service.js b/packages/generators/generate/plops/service.js new file mode 100644 index 0000000000..6950075e5f --- /dev/null +++ b/packages/generators/generate/plops/service.js @@ -0,0 +1,30 @@ +'use strict'; + +const { join } = require('path'); +const getDestinationPrompts = require('./utils/get-destination-prompts'); +const getFilePath = require('./utils/get-file-path'); + +module.exports = (plop, rootDir) => { + // Service generator + plop.setGenerator('service', { + description: 'Generate a service for an API', + prompts: [ + { + type: 'input', + name: 'id', + message: 'Service name', + }, + ...getDestinationPrompts('service'), + ], + actions: answers => { + const filePath = getFilePath(answers.destination); + return [ + { + type: 'add', + path: join(rootDir, `${filePath}/services/{{id}}.js`), + templateFile: 'templates/service.js.hbs', + }, + ]; + }, + }); +}; diff --git a/packages/generators/generate/plops/utils/get-destination-prompts.js b/packages/generators/generate/plops/utils/get-destination-prompts.js new file mode 100644 index 0000000000..da700b5c72 --- /dev/null +++ b/packages/generators/generate/plops/utils/get-destination-prompts.js @@ -0,0 +1,43 @@ +'use strict'; +const { join } = require('path'); +const fs = require('fs-extra'); + +module.exports = (action, rootDir) => { + return [ + { + type: 'list', + name: 'destination', + message: `Where do you want to add this ${action}?`, + choices: [ + { + name: `Add ${action} to ${action === 'policy' ? 'root of project' : 'new API'}`, + value: 'new', + }, + { name: `Add ${action} to existing API`, value: 'api' }, + { name: `Add ${action} to existing plugin`, value: 'plugin' }, + ], + }, + { + when: answers => answers.destination === 'api', + type: 'input', + message: 'Which API is this for?', + name: 'api', + validate: async input => { + const exists = await fs.pathExists(join(rootDir, `api/${input}`)); + + return exists || 'That api does not exist, please try again'; + }, + }, + { + when: answers => answers.destination === 'plugin', + type: 'input', + message: 'Which plugin is this for?', + name: 'plugin', + validate: async input => { + const exists = await fs.pathExists(join(rootDir, `plugins/${input}`)); + + return exists || 'That plugin does not exist, please try again'; + }, + }, + ]; +}; diff --git a/packages/generators/generate/plops/utils/get-file-path.js b/packages/generators/generate/plops/utils/get-file-path.js new file mode 100644 index 0000000000..9e5775f1c4 --- /dev/null +++ b/packages/generators/generate/plops/utils/get-file-path.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = destination => { + if (destination === 'api') { + return `api/{{api}}`; + } + + if (destination === 'plugin') { + return `plugins/{{plugin}}`; + } + + return `api/{{id}}`; +}; diff --git a/packages/generators/generate/templates/model.settings.json.hbs b/packages/generators/generate/templates/model.settings.json.hbs index c0ddaabb18..c20d27d3b7 100644 --- a/packages/generators/generate/templates/model.settings.json.hbs +++ b/packages/generators/generate/templates/model.settings.json.hbs @@ -8,6 +8,5 @@ "options": { "draftAndPublish": {{useDraftAndPublish}}, "comment": "" - }, - "attributes": {} + } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 8ff04ea032..4823f985f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11187,26 +11187,6 @@ inquirer@8.1.0: strip-ansi "^6.0.0" through "^2.3.6" -inquirer@8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.1.2.tgz#65b204d2cd7fb63400edd925dfe428bafd422e3d" - integrity sha512-DHLKJwLPNgkfwNmsuEUKSejJFbkv0FMO9SMiQbjI3n5NQuCrSIBqP66ggqyz2a6t2qEolKrMjhQ3+W/xXgUQ+Q== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.21" - mute-stream "0.0.8" - ora "^5.3.0" - run-async "^2.4.0" - rxjs "^7.2.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - inquirer@^6.2.0, inquirer@^6.2.1, inquirer@^6.3.1: version "6.5.2" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" @@ -18282,13 +18262,6 @@ rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.6, rxjs@^6.6.7: dependencies: tslib "^1.9.0" -rxjs@^7.2.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.3.0.tgz#39fe4f3461dc1e50be1475b2b85a0a88c1e938c6" - integrity sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw== - dependencies: - tslib "~2.1.0" - safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"