Skip to main content

Generators

Overview​

Create new generator:

$ hygen generator new --name mailer
`-------- just a name you pick.

It will create a corresponing template for us:

Loaded templates: _templates
added: _templates/mailer/new/hello.ejs.t
`------ your template file.

If we don't specify a generator, it's will throw error and available generator list. As you can see below, mailer has been added.

$ hygen

Error: please specify a generator.

Available actions:
generator: new, with-prompt
mailer: new
\
`----------- your new generator is already here!

When a generator under \templates, it's ready to use.

Here's hello.ejs.t that was placed in the template folder for you:

_templates/mailer/new/hello.ejs.t
---
to: app/hello.js
---
const hello = `
Hello!
This is your first hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
`

console.log(hello)
info

hygen doesn't care about file names or file types in your generator folders. It only cares about folder structure and the contents of your files.

Structure​

.
├── _templates/
│ └── mailer/
│ └── new/
│ ├── html.ejs.t
│ └── text.ejs.t
├── app/
│ └── index.js
└── package.json

Every time you call it, hygen mailer new automagically picks up the closest _templates folder, and renders all files in mailer/new. In this case it's html.ejs.t and text.ejs.t.

CLI Arguments​

$ hygen mailer new --name foobar --message hello --version 1

Any double-dash (--) argument becomes a variable we can use later in our templates.

Here's the contents of the template html.ejs.t with the variables in place:

---
to: app/emails/<%= name %>.html
---
<h1>Hello <%= name %></h1>
<%= message %>
(version <%= version %>)

Interactive prompt​

.
└── _templates/
└── mailer/
└── new/ <-- the mailer new generator/
├── prompt.js <-- your prompt file!
├── html.ejs.t
└── text.ejs.t

For example, to ask for the message input variable, add to prompt.js:

_templates/mailer/new/prompt.js
module.exports = [
{
type: "input",
name: "message",
message: "What's your message?",
},
];
info

The format is based on enquirer.

We can render variables like below:

_templates/mailer/new/text.ejs.t
---
to: app/emails/<%= name %>.txt
---
<%= message %>

To generate it, we'll do this:

$ hygen mailer new --name fancy-mailer

Advanced Interactive prompt​

Structure:

.
└── my-generator/
└── my-action/
├── index.js
├── template1.ejs.t
└── template2.ejs.t
info

my-generator, my-action,template1 , template2 are dynamic name. You can put any name you want.

BUT index.js is a special case, hygen will see it as prompt.js to generate templates. So you MUST NOT name other files as index.js

Basic​

Instead of exporting an array of question types as with the prompt.js file, you now need to export an object with a function called prompt:

_templates/my-generator/my-action/index.js
module.exports = {
prompt: ({ prompter, args }) =>
prompter
.prompt({
type: "input",
name: "email",
message: "What's your email?",
})
.then(({ email }) =>
prompter.prompt({
type: "input",
name: "emailConfirmation",
message: `Please type your email [${email}] again:`,
})
),
};

Skipping prompt​

You can return Promise to skip prompt conditionally

_templates/my-generator/my-action/index.js
module.exports = {
prompt: ({ prompter, args }) => {
if (args.age > 18) {
return Promise.resolve({ allow: true });
}
return prompter.prompt({
type: "input",
name: "age",
message: "whats your age?",
});
},
};

Or you can completely skip prompt by using params

_templates/my-generator/my-action/index.js
module.exports = {
params: ({ args }) => {
return { moreConvenientName: args.foobamboozle };
},
};

Argument utils module​

References: Advance prompt improvement - Github

_templates/promptArgsUtil.js
module.exports =
(questions) =>
({ prompter, args }) => {
const providedArgs = questions.reduce((selectedArgs, question) => {
if (args[question.name])
selectedArgs[question.name] = args[question.name];
return selectedArgs;
}, {});
return prompter.prompt(questions.filter(({ name }) => !providedArgs[name]));
};

Usage:

_templates/my-generator/my-action/index.js
const promptArgs = require("../../promptArgsUtil");

const questions = [
{
type: "select",
name: "level",
message: "What is the level of the component?",
choices: [
{ title: "Atoms", value: "atoms" },
{ title: "Molecules", value: "molecules" },
{ title: "Organisms", value: "organisms" },
{ title: "Templates", value: "templates" },
],
},
{
type: "input",
name: "name",
message: "What is the name of the component?",
},
];
module.exports = {
prompt: promptArgs(questions),
};

Document your prompt​

You can use message to build generator help screens.

Looking at our generator layout from before, we add a help action:

Structure:

.
└── _templates/
└── mailer/
├── help/ <-- add new help generator
│ └── index.ejs.t <-- and new template
└── new/
├── prompt.js
├── html.ejs.t
└── text.ejs.t

Our index.ejs.t is simply a blank template, with just a message: prop:

---
message: |
- hygen {bold mailer} new --name [NAME]
---
info

{bold mailer} is a special coloring syntax.

For more styles: chalk.

To see the message, just run:

$ hygen mailer help
warning

In hygen@6.2.11, chalk.template has an error. To fix it, use patch-package and patch diff below:

diff --git a/node_modules/hygen/dist/logger.js b/node_modules/hygen/dist/logger.js
index 312f112..036c45d 100644
--- a/node_modules/hygen/dist/logger.js
+++ b/node_modules/hygen/dist/logger.js
@@ -5,7 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = __importDefault(require("chalk"));
// chalk 4.1.2 doesn't type template property
-const { yellow, red, green, magenta, template } = chalk_1.default;
+const { yellow, red, green, magenta } = chalk_1.default;
+const template = require('chalk/source/templates');
class Logger {
constructor(log) {
this.log = log;

Selecting parts of a Generator​

The complete form is:

$ hygen GENERATOR ACTION:SUBACTION

Where SUBACTION is a regular expression or a simple string hygen uses to pick up the subset of templates you want from a generator.

Since we have a file named text.ejs.t, the string text in new:text will match it.

$ hygen mailer new:text --name textual-mailer

In the same way we could have used a proper regular expression:

$ hygen mailer new:.*xt --name textual-mailer

References​

Hygen official doc