generator-easy-ui5 3.7.0 → 3.8.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.
@@ -134,6 +134,10 @@ const generatorOptions = {
134
134
  type: Boolean,
135
135
  description: "Preview the next mode to consume subgenerators from bestofui5.org",
136
136
  },
137
+ skipNested: {
138
+ type: Boolean,
139
+ description: "Skips the nested generators and runs only the first subgenerator",
140
+ },
137
141
  };
138
142
 
139
143
  const generatorArgs = {
@@ -149,6 +153,7 @@ const generatorArgs = {
149
153
  },
150
154
  };
151
155
 
156
+ // The Easy UI5 Generator!
152
157
  export default class extends Generator {
153
158
  constructor(args, opts) {
154
159
  super(args, opts, {
@@ -239,6 +244,102 @@ export default class extends Generator {
239
244
  return "Easy UI5";
240
245
  }
241
246
 
247
+ async _getGeneratorMetadata({ env, generatorPath }) {
248
+ // filter the hidden subgenerators already
249
+ // -> subgenerators must be found in env as they are returned by lookup!
250
+ const lookupGeneratorMeta = await env.lookup({ localOnly: true, packagePaths: generatorPath });
251
+ const subGenerators = lookupGeneratorMeta.filter((sub) => {
252
+ const subGenerator = env.get(sub.namespace);
253
+ return !subGenerator.hidden;
254
+ });
255
+ return subGenerators;
256
+ }
257
+
258
+ async _installGenerator({ octokit, generator, generatorPath }) {
259
+ // lookup the default path of the generator if not set
260
+ if (!generator.branch) {
261
+ try {
262
+ const repoInfo = await octokit.repos.get({
263
+ owner: generator.org,
264
+ repo: generator.name,
265
+ });
266
+ generator.branch = repoInfo.data.default_branch;
267
+ } catch (e) {
268
+ console.error(`Generator "${owner}/${repo}!${dir}${branch ? "#" + branch : ""}" not found! Run with --verbose for details!`);
269
+ if (this.options.verbose) {
270
+ console.error(e);
271
+ }
272
+ return;
273
+ }
274
+ }
275
+ // fetch the branch to retrieve the latest commit SHA
276
+ let commitSHA;
277
+ try {
278
+ // determine the commitSHA
279
+ const reqBranch = await octokit.repos.getBranch({
280
+ owner: generator.org,
281
+ repo: generator.name,
282
+ branch: generator.branch,
283
+ });
284
+ commitSHA = reqBranch.data.commit.sha;
285
+ } catch (ex) {
286
+ console.error(chalk.red(`Failed to retrieve the branch "${generator.branch}" for repository "${generator.name}" for "${generator.org}" organization! Run with --verbose for details!`));
287
+ if (this.options.verbose) {
288
+ console.error(chalk.red(ex.message));
289
+ }
290
+ return;
291
+ }
292
+
293
+ if (this.options.verbose) {
294
+ this.log(`Using commit ${commitSHA} from @${generator.org}/${generator.name}#${generator.branch}!`);
295
+ }
296
+ const shaMarker = path.join(generatorPath, `.${commitSHA}`);
297
+
298
+ if (fs.existsSync(generatorPath) && !this.options.skipUpdate) {
299
+ // check if the SHA marker exists to know whether the generator is up-to-date or not
300
+ if (this.options.forceUpdate || !fs.existsSync(shaMarker)) {
301
+ if (this.options.verbose) {
302
+ this.log(`Generator ${chalk.yellow(generator.name)} in "${generatorPath}" is outdated!`);
303
+ }
304
+ // remove if the SHA marker doesn't exist => outdated!
305
+ this._showBusy(` Deleting subgenerator ${chalk.yellow(generator.name)}...`);
306
+ fs.rmSync(generatorPath, { recursive: true });
307
+ }
308
+ }
309
+
310
+ // re-fetch the generator and extract into local plugin folder
311
+ if (!fs.existsSync(generatorPath)) {
312
+ // unzip the archive
313
+ if (this.options.verbose) {
314
+ this.log(`Extracting ZIP to "${generatorPath}"...`);
315
+ }
316
+ this._showBusy(` Downloading subgenerator ${chalk.yellow(generator.name)}...`);
317
+ const reqZIPArchive = await octokit.repos.downloadZipballArchive({
318
+ owner: generator.org,
319
+ repo: generator.name,
320
+ ref: commitSHA,
321
+ });
322
+
323
+ this._showBusy(` Extracting subgenerator ${chalk.yellow(generator.name)}...`);
324
+ const buffer = Buffer.from(new Uint8Array(reqZIPArchive.data));
325
+ this._unzip(buffer, generatorPath, generator.dir);
326
+
327
+ // write the sha marker
328
+ fs.writeFileSync(shaMarker, commitSHA);
329
+ }
330
+
331
+ // run npm install when not embedding the generator (always for self-healing!)
332
+ if (!this.options.embed) {
333
+ if (this.options.verbose) {
334
+ this.log("Installing the subgenerator dependencies...");
335
+ }
336
+ this._showBusy(` Preparing ${chalk.yellow(generator.name)}...`);
337
+ await this._npmInstall(generatorPath, this.options.pluginsWithDevDeps);
338
+ }
339
+
340
+ this._clearBusy(true);
341
+ }
342
+
242
343
  async prompting() {
243
344
  const home = path.join(__dirname, "..", "..");
244
345
  const pkgJson = JSON.parse(fs.readFileSync(path.join(home, "package.json"), "utf8"));
@@ -369,31 +470,28 @@ export default class extends Generator {
369
470
  // determine the generator to be used
370
471
  let generator;
371
472
 
372
- // try to identify whether concrete generator is defined
373
- if (!generator) {
374
- // determine generator by ${owner}/${repo}(!${dir})? syntax, e.g.:
375
- // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial
376
- // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial#1.0
377
- // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial\!/generator
378
- // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial\!/generator#1.0
379
- const reGenerator = /([^\/]+)\/([^\!\#]+)(?:\!([^\#]+))?(?:\#(.+))?/;
380
- const matchGenerator = reGenerator.exec(this.options.generator);
381
- if (matchGenerator) {
382
- // derive and path the generator information from command line
383
- const [owner, repo, dir = "/generator", branch] = matchGenerator.slice(1);
384
- // the plugin path is derived from the owner, repo, dir and branch
385
- const pluginPath = `_/${owner}/${repo}${dir.replace(/[\/\\]/g, "_")}${branch ? `#${branch.replace(/[\/\\]/g, "_")}` : ""}`;
386
- generator = {
387
- org: owner,
388
- name: repo,
389
- branch,
390
- dir,
391
- pluginPath,
392
- };
393
- // log which generator is being used!
394
- if (this.options.verbose) {
395
- this.log(`Using generator ${chalk.green(`${owner}/${repo}!${dir}${branch ? "#" + branch : ""}`)}`);
396
- }
473
+ // determine generator by ${owner}/${repo}(!${dir})? syntax, e.g.:
474
+ // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial
475
+ // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial#1.0
476
+ // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial\!/generator
477
+ // > yo easy-ui5 SAP-samples/ui5-typescript-tutorial\!/generator#1.0
478
+ const reGenerator = /([^\/]+)\/([^\!\#]+)(?:\!([^\#]+))?(?:\#(.+))?/;
479
+ const matchGenerator = reGenerator.exec(this.options.generator);
480
+ if (matchGenerator) {
481
+ // derive and path the generator information from command line
482
+ const [owner, repo, dir = "/generator", branch] = matchGenerator.slice(1);
483
+ // the plugin path is derived from the owner, repo, dir and branch
484
+ const pluginPath = `_/${owner}/${repo}${dir.replace(/[\/\\]/g, "_")}${branch ? `#${branch.replace(/[\/\\]/g, "_")}` : ""}`;
485
+ generator = {
486
+ org: owner,
487
+ name: repo,
488
+ branch,
489
+ dir,
490
+ pluginPath,
491
+ };
492
+ // log which generator is being used!
493
+ if (this.options.verbose) {
494
+ this.log(`Using generator ${chalk.green(`${owner}/${repo}!${dir}${branch ? "#" + branch : ""}`)}`);
397
495
  }
398
496
  }
399
497
 
@@ -527,85 +625,10 @@ export default class extends Generator {
527
625
  }
528
626
  }
529
627
 
530
- let generatorPath = path.join(pluginsHome, generator.pluginPath || generator.name);
628
+ // install the generator if not running in offline mode
629
+ const generatorPath = path.join(pluginsHome, generator.pluginPath || generator.name);
531
630
  if (!this.options.offline) {
532
- // lookup the default path of the generator if not set
533
- if (!generator.branch) {
534
- try {
535
- const repoInfo = await octokit.repos.get({
536
- owner: generator.org,
537
- repo: generator.name,
538
- });
539
- generator.branch = repoInfo.data.default_branch;
540
- } catch (e) {
541
- console.error(`Generator "${owner}/${repo}!${dir}${branch ? "#" + branch : ""}" not found! Run with --verbose for details!`);
542
- if (this.options.verbose) {
543
- console.error(e);
544
- }
545
- return;
546
- }
547
- }
548
- // fetch the branch to retrieve the latest commit SHA
549
- let commitSHA;
550
- try {
551
- // determine the commitSHA
552
- const reqBranch = await octokit.repos.getBranch({
553
- owner: generator.org,
554
- repo: generator.name,
555
- branch: generator.branch,
556
- });
557
- commitSHA = reqBranch.data.commit.sha;
558
- } catch (ex) {
559
- console.error(chalk.red(`Failed to retrieve the branch "${generator.branch}" for repository "${generator.name}" for "${generator.org}" organization! Run with --verbose for details!`));
560
- if (this.options.verbose) {
561
- console.error(chalk.red(ex.message));
562
- }
563
- return;
564
- }
565
-
566
- if (this.options.verbose) {
567
- this.log(`Using commit ${commitSHA} from @${generator.org}/${generator.name}#${generator.branch}!`);
568
- }
569
- const shaMarker = path.join(generatorPath, `.${commitSHA}`);
570
-
571
- if (fs.existsSync(generatorPath) && !this.options.skipUpdate) {
572
- // check if the SHA marker exists to know whether the generator is up-to-date or not
573
- if (this.options.forceUpdate || !fs.existsSync(shaMarker)) {
574
- if (this.options.verbose) {
575
- this.log(`Generator ${chalk.yellow(generator.name)} in "${generatorPath}" is outdated!`);
576
- }
577
- // remove if the SHA marker doesn't exist => outdated!
578
- this._showBusy(` Deleting subgenerator ${chalk.yellow(generator.name)}...`);
579
- fs.rmSync(generatorPath, { recursive: true });
580
- }
581
- }
582
-
583
- // re-fetch the generator and extract into local plugin folder
584
- if (!fs.existsSync(generatorPath)) {
585
- // unzip the archive
586
- if (this.options.verbose) {
587
- this.log(`Extracting ZIP to "${generatorPath}"...`);
588
- }
589
- this._showBusy(` Downloading subgenerator ${chalk.yellow(generator.name)}...`);
590
- const reqZIPArchive = await octokit.repos.downloadZipballArchive({
591
- owner: generator.org,
592
- repo: generator.name,
593
- ref: commitSHA,
594
- });
595
-
596
- this._showBusy(` Extracting subgenerator ${chalk.yellow(generator.name)}...`);
597
- const buffer = Buffer.from(new Uint8Array(reqZIPArchive.data));
598
- this._unzip(buffer, generatorPath, generator.dir);
599
-
600
- // write the sha marker
601
- fs.writeFileSync(shaMarker, commitSHA);
602
- }
603
-
604
- // only when embedding we clear the busy state as otherwise
605
- // the npm install will immediately again show the busy state
606
- if (this.options.embed) {
607
- this._clearBusy(true);
608
- }
631
+ await this._installGenerator({ octokit, generator, generatorPath });
609
632
  }
610
633
 
611
634
  // do not execute the plugin generator during the setup/embed mode
@@ -613,14 +636,6 @@ export default class extends Generator {
613
636
  // filter the local options and the help command
614
637
  const opts = Object.keys(this._options).filter((optionName) => !(generatorOptions.hasOwnProperty(optionName) || optionName === "help"));
615
638
 
616
- // run npm install (always for self-healing!)
617
- if (this.options.verbose) {
618
- this.log("Installing the subgenerator dependencies...");
619
- }
620
- this._showBusy(` Preparing ${chalk.yellow(generator.name)}...`);
621
- await this._npmInstall(generatorPath, this.options.pluginsWithDevDeps);
622
- this._clearBusy(true);
623
-
624
639
  // create the env for the plugin generator
625
640
  let env = this.env; // in case of Yeoman UI the env is injected!
626
641
  if (!env) {
@@ -628,19 +643,20 @@ export default class extends Generator {
628
643
  env = yeoman.createEnv(this.args, opts);
629
644
  }
630
645
 
631
- // helper to derive the subcommand
632
- function deriveSubcommand(namespace) {
633
- const match = namespace.match(/[^:]+:(.+)/);
634
- return match ? match[1] : namespace;
646
+ // read the generator metadata
647
+ let subGenerators = await this._getGeneratorMetadata({ env, generatorPath });
648
+
649
+ // helper to derive the generator from the namespace
650
+ function deriveGenerator(namespace, defaultValue) {
651
+ const match = namespace.match(/([^:]+):.+/);
652
+ return match ? match[1] : defaultValue === undefined ? namespace : defaultValue;
635
653
  }
636
654
 
637
- // filter the hidden subgenerators already
638
- // -> subgenerators must be found in env as they are returned by lookup!
639
- const lookupGeneratorMeta = await env.lookup({ localOnly: true, packagePaths: generatorPath });
640
- let subGenerators = lookupGeneratorMeta.filter((sub) => {
641
- const subGenerator = env.get(sub.namespace);
642
- return !subGenerator.hidden;
643
- });
655
+ // helper to derive the subcommand from the namespace
656
+ function deriveSubcommand(namespace, defaultValue) {
657
+ const match = namespace.match(/^[^:]+:(.+)$/);
658
+ return match ? match[1] : defaultValue === undefined ? namespace : defaultValue;
659
+ }
644
660
 
645
661
  // list the available subgenerators in the console (as help)
646
662
  if (this.options.list) {
@@ -726,16 +742,79 @@ export default class extends Generator {
726
742
  ).subGenerator;
727
743
  }
728
744
 
729
- if (this.options.verbose) {
730
- this.log(`Calling ${chalk.red(subGenerator)}...\n \\_ in "${generatorPath}"`);
745
+ // determine the list of subgenerators to be executed
746
+ const subGensToRun = [subGenerator];
747
+
748
+ // method to resolve nested generators (only once!)
749
+ const resolved = [];
750
+ const resolveNestedGenerator = async (generatorToResolve) => {
751
+ const constructor = await env.get(generatorToResolve);
752
+ await Promise.all(
753
+ constructor.nestedGenerators?.map(async (nestedGenerator) => {
754
+ const theNestedGenerator = deriveGenerator(nestedGenerator);
755
+ if (resolved.indexOf(theNestedGenerator) === -1) {
756
+ resolved.push(theNestedGenerator);
757
+ const nestedGeneratorInfo = availGenerators.find((repo) => repo.subGeneratorName === theNestedGenerator);
758
+ const nestedGeneratorPath = path.join(pluginsHome, nestedGeneratorInfo.pluginPath || nestedGeneratorInfo.name);
759
+ await this._installGenerator({ octokit, generator: nestedGeneratorInfo, generatorPath: nestedGeneratorPath });
760
+ const nestedGens = await this._getGeneratorMetadata({ env, generatorPath: nestedGeneratorPath });
761
+ const subcommand = deriveSubcommand(nestedGenerator, "");
762
+ const theNestedGen = nestedGens.filter((nested) => {
763
+ const nestedSubcommand = deriveSubcommand(nested.namespace, "");
764
+ return subcommand ? nestedSubcommand === subcommand : !nestedSubcommand;
765
+ })?.[0];
766
+ if (theNestedGen) {
767
+ subGensToRun.push(theNestedGen.namespace);
768
+ await resolveNestedGenerator(theNestedGen.namespace);
769
+ } else {
770
+ this.log(`The nested generator "${nestedGeneratorInfo.org}/${nestedGeneratorInfo.name}" has no subgenerator "${subcommand || "default"}"! Ignoring execution...`);
771
+ }
772
+ }
773
+ }) || []
774
+ );
775
+ };
776
+
777
+ // only resolve nested generators when they should not be skipped
778
+ if (!this.options.skipNested) {
779
+ await resolveNestedGenerator(subGenerator);
731
780
  }
732
781
 
733
- // finally, run the subgenerator
734
- env.run(subGenerator, {
735
- verbose: this.options.verbose,
736
- embedded: true,
737
- destinationRoot: this.destinationRoot(),
738
- });
782
+ // intercept the environments runGenerator method to determine
783
+ // and forward the destinationRoot between the generator executions
784
+ const runGenerator = env.runGenerator;
785
+ let cwd;
786
+ env.runGenerator = async function (gen) {
787
+ if (cwd) {
788
+ // apply the cwd to the next gen
789
+ gen.destinationRoot(cwd);
790
+ }
791
+ return runGenerator.apply(this, arguments).then((retval) => {
792
+ // store the cwd from the current gen
793
+ cwd = gen.destinationRoot();
794
+ return retval;
795
+ });
796
+ };
797
+
798
+ // chain the execution of the generators
799
+ let chain = Promise.resolve();
800
+ for (const subGen of subGensToRun) {
801
+ chain = chain.then(
802
+ function () {
803
+ // we need to use env.run and not composeWith
804
+ // to ensure that subgenerators can have different
805
+ // dependencies than the root generator
806
+ return env.run(subGen, {
807
+ verbose: this.options.verbose,
808
+ embedded: true,
809
+ destinationRoot: this.destinationRoot(),
810
+ });
811
+ }.bind(this)
812
+ );
813
+ }
814
+
815
+ if (this.options.verbose) {
816
+ this.log(`Running generators in "${generatorPath}"...`);
817
+ }
739
818
  } else {
740
819
  this.log(`The generator ${chalk.red(this.options.generator)} has no visible subgenerators!`);
741
820
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-easy-ui5",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "Generator for UI5-based project",
5
5
  "main": "generators/app/index.js",
6
6
  "type": "module",
Binary file