generator-easy-ui5 2.4.6 → 3.1.0

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 (62) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +66 -168
  3. package/generators/app/index.js +392 -171
  4. package/generators/app/postinstall.js +121 -0
  5. package/package.json +23 -18
  6. package/generators/additionalmodules/index.js +0 -222
  7. package/generators/additionalmodules/templates/approuter/package.json +0 -13
  8. package/generators/additionalmodules/templates/deployer/readme.md +0 -3
  9. package/generators/additionalmodules/templates/xs-security.json +0 -20
  10. package/generators/app/templates/_.editorconfig +0 -8
  11. package/generators/app/templates/_.eslintignore +0 -4
  12. package/generators/app/templates/_.eslintrc +0 -48
  13. package/generators/app/templates/_.gitignore +0 -11
  14. package/generators/app/templates/karma-ci.conf.js +0 -21
  15. package/generators/app/templates/karma.conf.js +0 -17
  16. package/generators/app/templates/readme.md +0 -6
  17. package/generators/newcomponent/index.js +0 -82
  18. package/generators/newcontrol/index.js +0 -81
  19. package/generators/newcontrol/templates/webapp/control/template.js +0 -23
  20. package/generators/newmodel/index.js +0 -142
  21. package/generators/newopa5journey/index.js +0 -99
  22. package/generators/newopa5journey/templates/test/integration/$journey.js +0 -23
  23. package/generators/newopa5po/index.js +0 -107
  24. package/generators/newopa5po/templates/test/integration/pages/$poFile.js +0 -43
  25. package/generators/newuiveri5po/index.js +0 -84
  26. package/generators/newuiveri5po/templates/pages/$poFile.js +0 -20
  27. package/generators/newuiveri5spec/index.js +0 -51
  28. package/generators/newuiveri5spec/templates/$specName.spec.js +0 -22
  29. package/generators/newview/index.js +0 -156
  30. package/generators/newview/templates/webapp/controller/$ViewName.controller.js +0 -7
  31. package/generators/newview/templates/webapp/view/$ViewName.view.$ViewEnding +0 -51
  32. package/generators/newwebapp/index.js +0 -239
  33. package/generators/newwebapp/templates/uimodule/ui5.yaml +0 -73
  34. package/generators/newwebapp/templates/uimodule/webapp/Component.js +0 -30
  35. package/generators/newwebapp/templates/uimodule/webapp/controller/BaseController.js +0 -70
  36. package/generators/newwebapp/templates/uimodule/webapp/css/style.css +0 -1
  37. package/generators/newwebapp/templates/uimodule/webapp/flpSandbox.html +0 -66
  38. package/generators/newwebapp/templates/uimodule/webapp/i18n/i18n.properties +0 -3
  39. package/generators/newwebapp/templates/uimodule/webapp/i18n/i18n_en.properties +0 -3
  40. package/generators/newwebapp/templates/uimodule/webapp/index.html +0 -29
  41. package/generators/newwebapp/templates/uimodule/webapp/manifest.json +0 -92
  42. package/generators/newwebapp/templates/uimodule/webapp/model/formatter.js +0 -4
  43. package/generators/newwebapp/templates/uimodule/webapp/model/models.js +0 -14
  44. package/generators/newwebapp/templates/uimodule/webapp/resources/img/favicon.ico +0 -0
  45. package/generators/newwebapp/templates/uimodule/webapp/xs-app.json +0 -11
  46. package/generators/opa5/index.js +0 -114
  47. package/generators/opa5/templates/test/integration/AllJourneys.js +0 -13
  48. package/generators/opa5/templates/test/integration/arrangements/Startup.js +0 -19
  49. package/generators/opa5/templates/test/integration/opaTests.qunit.html +0 -32
  50. package/generators/opa5/templates/test/integration/opaTests.qunit.js +0 -13
  51. package/generators/opa5/templates/test/testsuite.qunit.html +0 -10
  52. package/generators/opa5/templates/test/testsuite.qunit.js +0 -10
  53. package/generators/uiveri5/index.js +0 -144
  54. package/generators/uiveri5/templates/.gitignore +0 -2
  55. package/generators/uiveri5/templates/README.md +0 -11
  56. package/generators/uiveri5/templates/conf.js +0 -16
  57. package/generators/wdi5/index.js +0 -96
  58. package/generators/wdi5/templates/.gitignore +0 -1
  59. package/generators/wdi5/templates/README-wdi5.md +0 -39
  60. package/generators/wdi5/templates/basic.test.js +0 -17
  61. package/generators/wdi5/templates/wdio-wdi5.conf.js +0 -282
  62. package/helpers/fileaccess.js +0 -90
@@ -1,198 +1,419 @@
1
- const Generator = require("yeoman-generator"),
2
- fileaccess = require("../../helpers/fileaccess"),
3
- path = require("path"),
4
- glob = require("glob");
1
+ "use strict";
2
+ const Generator = require("yeoman-generator");
3
+ const chalk = require("chalk");
4
+ const yosay = require("yosay");
5
+ const spawn = require("cross-spawn");
6
+ const { hasYarn } = require("yarn-or-npm");
7
+
8
+ const path = require("path");
9
+ const fs = require("fs");
10
+ const { rmdir } = require("fs").promises;
11
+
12
+ const { Octokit } = require("@octokit/rest");
13
+ const AdmZip = require("adm-zip");
14
+
15
+ const generatorOptions = {
16
+ ghAuthToken: {
17
+ type: String,
18
+ description:
19
+ `GitHub authToken to optionally access private generator repositories`,
20
+ },
21
+ ghOrg: {
22
+ type: String,
23
+ description: `GitHub organization to lookup for available generators`,
24
+ default: "ui5-community",
25
+ hidden: true // we don't want to recommend to use this option
26
+ },
27
+ list: {
28
+ type: Boolean,
29
+ description: `List the available subcommands of the generator`,
30
+ },
31
+ verbose: {
32
+ type: Boolean,
33
+ description: `Enable detailed logging`,
34
+ },
35
+ skipUpdate: {
36
+ type: Boolean,
37
+ description: `Skip the update of the plugin generators`,
38
+ },
39
+ plugins: {
40
+ type: Boolean,
41
+ alias: "p",
42
+ description: `Get detailed version information`,
43
+ }
44
+ };
45
+
46
+ const generatorArgs = {
47
+ generator: {
48
+ type: String,
49
+ required: false,
50
+ description: `Name of the generator to invoke (without the "generator-ui5-" prefix)`,
51
+ },
52
+ subcommand: {
53
+ type: String,
54
+ required: false,
55
+ description: `Name of the subcommand to invoke (without the "generator:" prefix)`,
56
+ },
57
+ };
5
58
 
6
59
  module.exports = class extends Generator {
60
+ constructor(args, opts) {
61
+ super(args, opts);
7
62
 
8
- prompting() {
9
- return this.prompt([{
10
- type: "input",
11
- name: "projectname",
12
- message: "How do you want to name this project?",
13
- validate: (s) => {
14
- if (/^\d*[a-zA-Z][a-zA-Z0-9]*$/g.test(s)) {
15
- return true;
16
- }
17
- return "Please use alpha numeric characters only for the project name.";
18
- },
19
- default: "myUI5App"
20
- }, {
21
- type: "input",
22
- name: "namespace",
23
- message: "Which namespace do you want to use?",
24
- validate: (s) => {
25
- if (/^[a-zA-Z0-9_\.]*$/g.test(s)) {
26
- return true;
27
- }
28
- return "Please use alpha numeric characters and dots only for the namespace.";
29
- },
30
- default: "com.myorg"
31
- }, {
32
- type: "list",
33
- name: "platform",
34
- message: "On which platform would you like to host the application?",
35
- choices: ["Static webserver",
36
- "Application Router @ Cloud Foundry",
37
- "SAP HTML5 Application Repository service for SAP BTP",
38
- "SAP Launchpad service",
39
- "Application Router @ SAP HANA XS Advanced",
40
- "SAP NetWeaver"],
41
- default: "Static webserver"
42
- }, {
43
- type: "list",
44
- name: "viewtype",
45
- message: "Which view type do you want to use?",
46
- choices: ["XML", "JSON", "JS", "HTML"],
47
- default: "XML"
48
- }, {
49
- type: "input",
50
- name: "viewname",
51
- message: "How do you want to name your main view?",
52
- validate: (s) => {
53
- if (/^\d*[a-zA-Z][a-zA-Z0-9]*$/g.test(s)) {
54
- return true;
55
- }
56
- return "Please use alpha numeric characters only for the view name.";
57
- },
58
- default: "MainView"
59
- }, {
60
- type: "list",
61
- name: "ui5libs",
62
- message: "Where should your UI5 libs be served from?",
63
- choices: (props) => {
64
- return (props.platform !== "SAP Launchpad service") ?
65
- ["Content delivery network (OpenUI5)", "Content delivery network (SAPUI5)", "Local resources (OpenUI5)", "Local resources (SAPUI5)"] :
66
- ["Content delivery network (SAPUI5)"];
67
- },
68
- default: (props) => {
69
- return (props.platform !== "SAP Launchpad service") ?
70
- "Content delivery network (OpenUI5)" :
71
- "Content delivery network (SAPUI5)";
72
- },
73
- }, {
74
- type: "confirm",
75
- name: "newdir",
76
- message: "Would you like to create a new directory for the project?",
77
- default: true
78
- }]).then((answers) => {
79
- if (answers.newdir) {
80
- this.destinationRoot(`${answers.namespace}.${answers.projectname}`);
63
+ Object.keys(generatorArgs).forEach((argName) => {
64
+ // register the argument for being displayed in the help
65
+ this.argument(argName, generatorArgs[argName]);
66
+ });
67
+
68
+ Object.keys(generatorOptions).forEach((optionName) => {
69
+ if (!generatorOptions[optionName].hidden) {
70
+ // register the option for being displayed in the help
71
+ this.option(optionName, generatorOptions[optionName]);
72
+ } else {
73
+ // apply the default value for hidden options if needed
74
+ this.options[optionName] = this.options[optionName] || generatorOptions[optionName].default;
81
75
  }
82
- this.config.set(answers);
83
- this.config.set("namespaceURI", answers.namespace.split(".").join("/"));
84
76
  });
85
77
  }
86
78
 
87
- async writing() {
88
- const oConfig = this.config.getAll();
79
+ _showBusy(statusText) {
80
+ this._clearBusy();
81
+ const progressChars = ['\\', '|', '/', '-'];
82
+ let i = 0;
83
+ process.stdout.write(`\r${statusText} `);
84
+ this._busy = {
85
+ text: statusText,
86
+ timer: setInterval(() => {
87
+ process.stdout.write(`\r${statusText} ${progressChars[i++]}`);
88
+ i %= progressChars.length;
89
+ }, 250),
90
+ };
91
+ }
89
92
 
90
- this.sourceRoot(path.join(__dirname, "templates"));
91
- glob.sync("**", {
92
- cwd: this.sourceRoot(),
93
- nodir: true
94
- }).forEach((file) => {
95
- const sOrigin = this.templatePath(file);
96
- const sTarget = this.destinationPath(file.replace(/^_/, "").replace(/\/_/, "/"));
93
+ _clearBusy(newLine) {
94
+ if (this._busy) {
95
+ clearInterval(this._busy.timer);
96
+ process.stdout.write(`\r`.padEnd(this._busy.text.length + 3) + (newLine ? "\n" : ""));
97
+ delete this._busy;
98
+ }
99
+ }
97
100
 
98
- this.fs.copyTpl(sOrigin, sTarget, oConfig);
99
- });
101
+ async prompting() {
102
+
103
+ if (this.options.plugins) {
104
+ const glob = require("glob");
105
+ const yeoman = require("yeoman-environment/package.json");
100
106
 
101
- const oSubGen = Object.assign({}, oConfig);
102
- oSubGen.isSubgeneratorCall = true;
103
- oSubGen.cwd = this.destinationRoot();
104
- oSubGen.modulename = "uimodule";
107
+ const components = {
108
+ 'Node.js': process.version,
109
+ 'home': __dirname.slice(0, -4),
110
+ "yeoman-environment": yeoman.version
111
+ };
112
+ glob.sync("./plugin-generators/*/package.json").forEach(function (plugin) {
113
+ const name = plugin.replace("./plugin-generators/", "").replace("/package.json", "");
114
+ const lib = require(path.join("../../", plugin));
115
+ components[name] = lib.version;
116
+ });
105
117
 
106
- if (oConfig.platform !== "Static webserver" && oConfig.platform !== "SAP NetWeaver") {
107
- this.composeWith(require.resolve("../additionalmodules"), oSubGen);
118
+ const log = this.log;
119
+ return Object.keys(components).forEach(function (component) {
120
+ log(`${chalk.green(component)}: ${components[component]}`);
121
+ })
108
122
  }
109
123
 
110
- this.composeWith(require.resolve("../newwebapp"), oSubGen);
111
- }
124
+ this.log(yosay(`Welcome to the ${chalk.red("easy-ui5")} generator!`));
125
+
126
+ // create the octokit client to retrieve the generators from GH org
127
+ const octokit = new Octokit({
128
+ userAgent: `${this.rootGeneratorName()}:${this.rootGeneratorVersion()}`,
129
+ auth: this.options.ghAuthToken,
130
+ });
112
131
 
113
- async addPackage() {
114
- const oConfig = this.config.getAll();
115
- let packge = {
116
- "name": oConfig.projectname,
117
- "version": "0.0.1",
118
- "scripts": {
119
- "start": "ui5 serve --config=uimodule/ui5.yaml --open index.html",
120
- "build:ui": "run-s ",
121
- "test": "run-s lint karma",
122
- "karma-ci": "karma start karma-ci.conf.js",
123
- "clearCoverage": "shx rm -rf coverage",
124
- "karma": "run-s clearCoverage karma-ci",
125
- "lint": "eslint ."
126
- },
127
- "devDependencies": {
128
- "shx": "^0.3.3",
129
- "@ui5/cli": "^2.8.1",
130
- "ui5-middleware-livereload": "^0.5.1",
131
- "karma": "^6.0.1",
132
- "karma-chrome-launcher": "^3.1.0",
133
- "karma-coverage": "^2.0.3",
134
- "karma-ui5": "^2.3.2",
135
- "npm-run-all": "^4.1.5",
136
- "eslint": "^7.18.0"
137
- },
138
- "ui5": {
139
- "dependencies": [
140
- "ui5-middleware-livereload",
141
- ]
132
+ // retrieve the available repositories
133
+ let reqRepos;
134
+ try {
135
+ reqRepos = await octokit.repos.listForOrg({
136
+ org: this.options.ghOrg,
137
+ });
138
+ } catch (e) {
139
+ console.error(`Failed to connect to GitHub to retrieve available repository for "${this.options.ghOrg}" organization! Run with --verbose for details!`);
140
+ if (this.options.verbose) {
141
+ console.error(e);
142
+ }
143
+ return;
144
+ }
145
+
146
+ // download the generator from GH (or the test generator)
147
+ let generatorPath;
148
+ if (this.options.generator === "test") {
149
+ generatorPath = path.join(
150
+ __dirname,
151
+ "../../plugin-generators/generator-ui5-test"
152
+ );
153
+ } else {
154
+
155
+ // check for provided generator being available on GH
156
+ let generator =
157
+ this.options.generator &&
158
+ reqRepos.data.find(
159
+ (repo) => repo.name === `generator-ui5-${this.options.generator}`
160
+ );
161
+
162
+ // if no generator is provided and doesn't exist, ask for generator name
163
+ if (!generator) {
164
+ if (this.options.generator) {
165
+ this.log(
166
+ `The generator ${chalk.red(
167
+ this.options.generator
168
+ )} was not found. Please select an existing generator!`
169
+ );
170
+ }
171
+ const generatorRepos = reqRepos.data.filter((repo) =>
172
+ /^generator-ui5-.+/.test(repo.name)
173
+ );
174
+ const generatorIdx = (
175
+ await this.prompt([
176
+ {
177
+ type: "list",
178
+ name: "generator",
179
+ message: "Select your generator?",
180
+ choices: generatorRepos.map((repo, idx) => ({
181
+ name: repo.name,
182
+ value: idx,
183
+ })),
184
+ },
185
+ ])
186
+ ).generator;
187
+ generator = generatorRepos[generatorIdx];
188
+ }
189
+
190
+ // fetch the available branches to retrieve the latest commit SHA
191
+ let reqBranch;
192
+ try {
193
+ reqBranch = await octokit.repos.getBranch({
194
+ owner: this.options.ghOrg,
195
+ repo: generator.name,
196
+ branch: generator.default_branch,
197
+ });
198
+ } catch (e) {
199
+ console.error(`Failed to retrieve the default branch for repository "${generator.name}" for "${this.options.ghOrg}" organization! Run with --verbose for details!`);
200
+ if (this.options.verbose) {
201
+ console.error(e);
202
+ }
203
+ return;
142
204
  }
143
- };
144
205
 
145
- if (oConfig.platform !== "Static webserver" && oConfig.platform !== "SAP NetWeaver") {
146
- packge.devDependencies["ui5-middleware-cfdestination"] = "^0.3.1";
147
- packge.devDependencies["ui5-task-zipper"] = "^0.4.2",
148
- packge.devDependencies["cross-var"] = "^1.1.0";
149
- packge.devDependencies["mbt"] = "^1.1.0";
150
- packge.ui5.dependencies.push("ui5-middleware-cfdestination");
151
- packge.ui5.dependencies.push("ui5-task-zipper");
152
-
153
- if (oConfig.platform === "Application Router @ Cloud Foundry" || oConfig.platform === "SAP HTML5 Application Repository service for SAP BTP" || oConfig.platform === "SAP Launchpad service") {
154
- packge.scripts["build:mta"] = "mbt build";
155
- packge.scripts["deploy:cf"] = `cross-var cf deploy mta_archives/${oConfig.projectname}_$npm_package_version.mtar`;
156
- packge.scripts["deploy"] = "run-s build:mta deploy:cf";
157
- } else if (oConfig.platform === "Application Router @ SAP HANA XS Advanced") {
158
- packge.scripts["build:mta"] = "mbt build -p=xsa";
159
- packge.scripts["deploy:cf"] = `cross-var xs deploy mta_archives/${oConfig.projectname}_$npm_package_version.mtar`;
160
- packge.scripts["deploy"] = "run-s build:mta deploy:xs";
206
+ const commitSHA = reqBranch.data.commit.sha;
207
+
208
+ if (this.options.verbose) {
209
+ this.log(
210
+ `Using commit ${commitSHA} from @${this.options.ghOrg}/${generator.name}#${generator.default_branch}...`
211
+ );
212
+ }
213
+ generatorPath = path.join(
214
+ __dirname,
215
+ "../../plugin-generators",
216
+ generator.name
217
+ );
218
+ const shaMarker = path.join(generatorPath, `.${commitSHA}`);
219
+
220
+ if (fs.existsSync(generatorPath) && this.options.skipUpdate) {
221
+ // check if the SHA marker exists to know whether the generator is up-to-date or not
222
+ if (!fs.existsSync(shaMarker)) {
223
+ if (this.options.verbose) {
224
+ this.log(`Generator "${generator.name}" in "${generatorPath}" is outdated...`);
225
+ }
226
+ // remove if the SHA marker doesn't exist => outdated!
227
+ this._showBusy(` Removing old "${generator.name}" templates`);
228
+ await rmdir(generatorPath, { recursive: true });
229
+ }
161
230
  }
162
231
 
163
- if (oConfig.platform === "SAP Launchpad service") {
164
- packge.scripts.start = "ui5 serve --config=uimodule/ui5.yaml --open flpSandbox.html";
232
+ // re-fetch the generator and extract into local plugin folder
233
+ if (!fs.existsSync(generatorPath)) {
234
+ if (this.options.verbose) {
235
+ this.log(`Extracting ZIP to "${generatorPath}"...`);
236
+ }
237
+ this._showBusy(` Downloading and extracting "${generator.name}" templates`);
238
+ const reqZIPArchive = await octokit.repos.downloadZipballArchive({
239
+ owner: this.options.ghOrg,
240
+ repo: generator.name,
241
+ ref: commitSHA,
242
+ });
243
+ const buffer = Buffer.from(new Uint8Array(reqZIPArchive.data));
244
+ const zip = new AdmZip(buffer);
245
+ const zipEntries = zip.getEntries();
246
+ zipEntries.forEach((entry) => {
247
+ const match =
248
+ !entry.isDirectory && entry.entryName.match(/[^\/]+\/(.+)/);
249
+ if (match) {
250
+ const entryPath = match[1].slice(0, entry.name.length * -1);
251
+ zip.extractEntryTo(
252
+ entry,
253
+ path.join(generatorPath, entryPath),
254
+ false,
255
+ true
256
+ );
257
+ }
258
+ });
259
+ fs.writeFileSync(shaMarker, commitSHA);
260
+
261
+ // run yarn/npm install
262
+ if (this.options.verbose) {
263
+ this.log("Installing the plugin dependencies...");
264
+ }
265
+ this._showBusy(` Preparing "${generator.name}"`);
266
+ await new Promise(function (resolve, reject) {
267
+ spawn((hasYarn() ? "yarn" : "npm"), ["install", "--no-progress"], {
268
+ stdio: this.config.verbose ? "inherit" : "ignore",
269
+ cwd: generatorPath,
270
+ env: {
271
+ ...process.env,
272
+ "NO_UPDATE_NOTIFIER": true
273
+ }
274
+ }).on('exit', function (code) {
275
+ resolve(code);
276
+ }).on('error', function (err) {
277
+ reject(err);
278
+ });
279
+ }.bind(this));
165
280
  }
166
281
  }
167
282
 
168
- if (oConfig.platform === "SAP NetWeaver") {
169
- packge.devDependencies["ui5-task-nwabap-deployer"] = "*";
170
- packge.devDependencies["ui5-middleware-route-proxy"] = "*";
171
- packge.ui5.dependencies.push("ui5-task-nwabap-deployer");
172
- packge.ui5.dependencies.push("ui5-middleware-route-proxy");
173
- packge.scripts["deploy"] = "run-s build:ui";
283
+ this._clearBusy(true);
284
+
285
+ // filter the local options and the help command
286
+ const opts = Object.keys(this._options).filter(
287
+ (optionName) =>
288
+ !(generatorOptions.hasOwnProperty(optionName) || optionName === "help")
289
+ );
290
+
291
+ // create the env for the plugin generator
292
+ const yeoman = require("yeoman-environment");
293
+ const env = yeoman.createEnv(this.args, opts);
294
+
295
+ // helper to derive the subcommand
296
+ function deriveSubcommand(namespace) {
297
+ const match = namespace.match(/[^:]+:(.+)/);
298
+ return match ? match[1] : namespace;
174
299
  }
175
300
 
176
- await fileaccess.writeJSON.call(this, "/package.json", packge);
177
- }
301
+ // filter the hidden subgenerators already
302
+ // -> subgenerators must be found in env as they are returned by lookup!
303
+ let subGenerators = env
304
+ .lookup({ localOnly: true, packagePaths: generatorPath })
305
+ .filter((sub) => {
306
+ const subGenerator = env.get(sub.namespace);
307
+ return !subGenerator.hidden;
308
+ });
178
309
 
179
- install() {
180
- this.config.set("setupCompleted", true);
181
- this.installDependencies({
182
- bower: false,
183
- npm: true
184
- });
185
- }
310
+ // list the available subgenerators in the console (as help)
311
+ if (this.options.list) {
312
+ let maxLength = 0;
313
+ this.log(subGenerators
314
+ .map(sub => {
315
+ maxLength = Math.max(sub.namespace.length, maxLength);
316
+ return sub;
317
+ })
318
+ .reduce((output, sub) => {
319
+ const subGenerator = env.get(sub.namespace);
320
+ const displayName = subGenerator.displayName || "";
321
+ let line = ` ${deriveSubcommand(sub.namespace).padEnd(maxLength + 2)}`;
322
+ if (displayName) {
323
+ line += ` # ${subGenerator.displayName}`;
324
+ }
325
+ return `${output}\n${line}`;
326
+ }, `Subcommands (${subGenerators.length}):`));
327
+ return;
328
+ }
329
+
330
+ // if a subcommand is provided as argument, identify the matching subgenerator
331
+ // and remove the rest of the subgenerators from the list for later steps
332
+ if (this.options.subcommand) {
333
+ const selectedSubGenerator = subGenerators
334
+ .filter((sub) => {
335
+ // identify the subgenerator by subcommand
336
+ return new RegExp(`:${this.options.subcommand}$`).test(sub.namespace);
337
+ });
338
+ if (selectedSubGenerator.length == 1) {
339
+ subGenerators = selectedSubGenerator;
340
+ } else {
341
+ this.log(
342
+ `The generator ${chalk.red(
343
+ this.options.generator
344
+ )} has no subcommand ${chalk.red(
345
+ this.options.subcommand
346
+ )}. Please select an existing subcommand!`
347
+ );
348
+ }
349
+ }
350
+
351
+ // transform the list of the subgenerators and identify the
352
+ // default subgenerator for the default selection
353
+ let defaultSubGenerator;
354
+ let maxLength = 0;
355
+ subGenerators = subGenerators
356
+ .map(sub => {
357
+ const generator = env.get(sub.namespace);
358
+ let subcommand = deriveSubcommand(sub.namespace);
359
+ let displayName = generator.displayName || subcommand;
360
+ maxLength = Math.max(displayName.length, maxLength);
361
+ return {
362
+ subcommand,
363
+ displayName,
364
+ sub,
365
+ };
366
+ })
367
+ .map(({ subcommand, displayName, sub }) => {
368
+ const transformed = {
369
+ name: `${displayName.padEnd(maxLength + 2)} [${subcommand}]`,
370
+ value: sub.namespace,
371
+ };
372
+ if (/:app$/.test(sub.namespace)) {
373
+ defaultSubGenerator = transformed;
374
+ }
375
+ return transformed;
376
+ });
377
+
378
+ // at least 1 subgenerator must be present
379
+ if (subGenerators.length >= 1) {
380
+
381
+ // by default the 1st subgenerator is used
382
+ let subGenerator = subGenerators[0].value;
383
+
384
+ // if more than 1 subgenerator is present
385
+ // ask the developer to select one!
386
+ if (subGenerators.length > 1) {
387
+ subGenerator = (
388
+ await this.prompt([
389
+ {
390
+ type: "list",
391
+ name: "subGenerator",
392
+ message: "What do you want to do?",
393
+ default: defaultSubGenerator && defaultSubGenerator.value,
394
+ choices: subGenerators,
395
+ },
396
+ ])
397
+ ).subGenerator;
398
+ }
399
+
400
+ if (this.options.verbose) {
401
+ this.log(`Calling ${chalk.red(subGenerator)}...`);
402
+ }
403
+
404
+ // finally, run the subgenerator
405
+ env.run(subGenerator, {
406
+ verbose: this.options.verbose,
407
+ embedded: true,
408
+ });
409
+
410
+ } else {
411
+ this.log(
412
+ `The generator ${chalk.red(
413
+ this.options.generator
414
+ )} has no visible subgenerators!`
415
+ );
416
+ }
186
417
 
187
- end() {
188
- this.spawnCommandSync("git", ["init", "--quiet"], {
189
- cwd: this.destinationPath()
190
- });
191
- this.spawnCommandSync("git", ["add", "."], {
192
- cwd: this.destinationPath()
193
- });
194
- this.spawnCommandSync("git", ["commit", "--quiet", "--allow-empty", "-m", "Initialize repository with easy-ui5"], {
195
- cwd: this.destinationPath()
196
- });
197
418
  }
198
419
  };