Yeoman: appel de sous générateur avec des arguments fournis par l'utilisateur

J'écris mon premier générateur Yeoman, qui déclenche l'utilisateur pour diverses entrées et crée de manière conditionnelle des fichiers en fonction de leurs réponses. Je dois pouvoir appeler un sous-programme (pourrait être un sous-générateur Yeoman) en fonction de l'entrée de l'utilisateur et lui transmettre des arguments.

La raison pour laquelle je veux utiliser les fonctions nommées (qui ne s'exécute pas automatiquement) est que parfois la réponse de l'utilisateur devrait invoquer un certain nombre de fonctions combinées, et parfois la fonction doit être exécutée seule.

Ce que j'ai essayé:

Je pensais que les sous-générateurs étaient le chemin à parcourir, puisque je crée des jeux de fichiers uniquement si l'utilisateur les demande. Mais j'ai du mal à les appeler conditionnellement et à leur transmettre l'entrée fournie par l'utilisateur. J'ai essayé d'utiliser hookFor , mais je reçois l'erreur d'assertion: hookFor must be used within the constructor only . (Parce que je ne veux pas qu'il soit exécuté par défaut, j'appelle le sous-générateur de mon this.prompt(prompts, function (props) ).

La question:

Comment puis-je appeler une routine uniquement si l'utilisateur la demande (via une invite) et transmet cette routine à certaines informations fournies par l'utilisateur?

Si vous avez la gentillesse de répondre, n'assumez pas que j'ai essayé quelque chose d'évident ;-).

Considérons que vous avez un générateur de generator-blog (BlogGenerator) avec deux sous-générateurs (blog-serveur et blog-client):

 app\index.js client\index.js server\index.js 

Donc, lorsque vous vous dirigez yo blog ce que vous demandez à l'utilisateur pour certaines options et exécutez (éventuellement) les sous-générateurs, n'est-ce pas?

Pour exécuter un sous- this.invoke("generator_namespace", {options: {}}) vous devez appeler this.invoke("generator_namespace", {options: {}}) . Le deuxième argument que nous avons passé peut avoir un champ d' options – c'est l'objet d'options qui sera transmis au générateur.

Dans app \ index.js:

 BlogGenerator.prototype.askFor = function askFor() { var cb = this.async(); // have Yeoman greet the user. console.log(this.yeoman); var prompts = [{ name: 'appName', message: 'Enter your app name', default: 'MyBlog' }, { type: 'confirm', name: 'createServer', message: 'Would you like to create server project?', default: true }, { type: 'confirm', name: 'createClient', message: 'Whould you like to create client project?', default: true }]; this.prompt(prompts, function (props) { this.appName = props.appName; this.createServer = props.createServer; this.createClient = props.createClient; cb(); }.bind(this)); } BlogGenerator.prototype.main = function app() { if (this.createClient) { // Here: we'are calling the nested generator (via 'invoke' with options) this.invoke("blog:client", {options: {nested: true, appName: this.appName}}); } if (this.createServer) { this.invoke("blog:server", {options: {nested: true, appName: this.appName}}); } }; 

Dans client \ index.js:

 var BlogGenerator = module.exports = function BlogGenerator(args, options, config) { var that = this; yeoman.Base.apply(this, arguments); // in this.options we have the object passed to 'invoke' in app/index.js: this.appName = that.options.appName; this.nested = that.options.nested; }; BlogGenerator .prototype.askFor = function askFor() { var cb = this.async(); if (!this.options.nested) { console.log(this.yeoman); } } 

MISE À JOUR 2015-12-21 :
L'utilisation d' invoke est obsolète maintenant et doit être remplacée par une composeWith . Mais ce n'est pas aussi facile que possible. La principale différence entre invoke et composeWith est que maintenant vous n'avez aucune capacité à contrôler les sous-générateurs. Vous ne pouvez que déclarer les utiliser.
Voici comment main méthode main de ci-dessus devrait ressembler à:

 BlogGenerator.prototype.main = function app() { if (this.createClient) { this.composeWith("blog:client", { options: { nested: true, appName: this.appName } }, { local: require.resolve("./../client") }); } if (this.createServer) { this.composeWith("blog:server", { options: { nested: true, appName: this.appName } }, { local: require.resolve("./../server") }); } }; 

J'ai également remplacé yeoman.generators.Base with yeoman.Base .

Mise à jour 2015-04: l'apman Yeoman comprend maintenant this.composeWith comme la méthode préférée pour lier les générateurs.

Docs: http://yeoman.io/authoring/composability.html

Vous pouvez couvrir tous les scénarios d'exécution possibles, la vérification des conditions, les invites lors de la composition des générateurs ensemble si vous découpler les générateurs et utiliser un «générateur principal», la boucle du contexte de l'exécution vous aidera. Utilisez les options de .composeWith('my-genertor', { 'options' : options }) pour passer des configurations aux générateurs composés.

Lors de l'utilisation de .composeWith une fonction de groupe de priorité (p. Ex.: prompting , writing …) sera exécuté pour tous les générateurs, puis le groupe de priorité suivant. Si vous appelez .composeWith au generatorB de l'intérieur d'un generatorA , l'exécution sera, par exemple:

GeneratorA.prompting => generatorB.prompting => generatorA.writing => generatorB.writing

Si vous souhaitez contrôler l'exécution entre différents générateurs, je vous conseille de créer un générateur "principal" qui les compose, comme écrit sur http://yeoman.io/authoring/composability.html#order :

 // In my-generator/generators/turbo/index.js module.exports = require('yeoman-generator').Base.extend({ 'prompting' : function () { console.log('prompting - turbo'); }, 'writing' : function () { console.log('prompting - turbo'); } }); // In my-generator/generators/electric/index.js module.exports = require('yeoman-generator').Base.extend({ 'prompting' : function () { console.log('prompting - zap'); }, 'writing' : function () { console.log('writing - zap'); } }); // In my-generator/generators/app/index.js module.exports = require('yeoman-generator').Base.extend({ 'initializing' : function () { this.composeWith('my-generator:turbo'); this.composeWith('my-generator:electric'); } });