hygenで簡単につくる対話式コードジェネレータCLI

# hygen

Github: https://github.com/jondot/hygen
Docs: http://www.hygen.io/quick-start/

> hygen is the simple, fast, and scalable code generator that lives in your project.

hygenはnode.jsベースに、とっても簡単にテンプレートに沿ったファイルの生成CLIをつくることができます。

今回ReactによるUIコンポーネントを新しく作るときに、決まった構造のファイル群が毎回必要なので活用してみました。

```bash
npm i hygen -D
```

## 生成したいファイル

例えば `Button` コンポーネントを作成する場合。今回は例としてこんな感じのファイルたちを用意したいです。

```bash
/Button
├── Button.stories.tsx
├── Button.test.tsx
├── Button.tsx
├── README.md
├── index.tsx
├── style.css
└── style.css.d.ts
```

## 生成テンプレートを用意

生成したい構造に合わせて、次のようなファイルを用意しました。（※ `prompt.js` は後述）
ちなみにinitコマンドも用意されてます。

```bash
./hygen
└── component
    └── add
        ├── README.md.t
        ├── component.stories.tsx.t
        ├── component.test.tsx.t
        ├── component.tsx.t
        ├── index.tsx.t
        ├── prompt.js
        ├── style.css.d.ts.t
        └── style.css.t
```

`拡張子を含めた出力したいファイル名.t` でファイルを用意します。

hygenではこのテンプレートファイルのディレクトリ構造が、そのまま実行時のコマンド構造に対応しています。そのため実行するためにnpm scriptを同時に準備できます。

```json:package.json
"scripts": {
  "add": "hygen component add"
},
```
```bash
$ npm run add
```

そして同時に設定ファイルも用意します。
これは単純にテンプレートを置く場所を指定してるだけです。今回`./hygen`に作ってみたのでこうしてます。

```js:./.hygen.js
module.exports = {
  templates: `${__dirname}/hygen`,
};
```

## テンプレートを記述

中身は`frontmatter` + `ejs`で書くことになり、CLIから引数を取ってテンプレート内に適用出来ます。
次の例で言うと、`<%= name %>` にコンポーネント名を出力することが出来ます。

```js:index.tsx.t
---
to: src/<%= name %>/index.tsx
unless_exists: true
---
export * from './<%= name %>';
```

```js:component.tsx.t
---
to: src/<%= name %>/<%= name %>.tsx
unless_exists: true
---
import * as React from 'react';

interface I<%= name %>Props {
  text?: string;
}

const <%= name %>: React.FC<I<%= name %>Props> = props => {
  const { text } = props;
  return <div>{text}</div>;
};

export { <%= name %>, I<%= name %>Props };

```

この中身はかなり便利に書くことができるので、是非公式Docsの[Templates](http://www.hygen.io/templates)を参照してみてください。

## CLIに対話式インターフェースを追加

あとはCLI実行時にコンポーネント名を入力できるようにするだけで完成です。
用意したaddフォルダの中に `prompt.js` を作成します。

```js:prompt.js
module.exports = [
  {
    message: 'What is the component name?',
    name: 'name',
    type: 'input',
    validate: answer => {
      if (answer !== '') {
        return true;
      }
    },
  },
];
```

対話式にしたい内容に沿ったobjectを、質問の個数分の配列にして記述しておくだけです。

今回は `name` という名前の変数を入力したいので、こうなりました。空欄で実行できてしまうと変なファイルが出来てしまうので、validateも適当に用意してます。

実行するとこうなります。

```bash
$ npm run add

> hygen component add

? What is the component name? ›
```

コンポーネント名を入れると一気にファイルが出力されます。

```bash
✔ What is the component name? · Button

Loaded templates: hygen
       added: src/Button/Button.stories.tsx
       added: src/Button/Button.test.tsx
       added: src/Button/Button.tsx
       added: src/Button/index.tsx
       added: src/Button/README.md
       added: src/Button/style.css.d.ts
       added: src/Button/style.css
```

空欄でEnterを押すとvalidateがきいて怒られます。

```bash
? What is the component name? ›

❯ Invalid input
```

ちなみにファイルが被ってると（つまり既に作成済みの名前を誤って入力した時）、気を利かせてスキップしてくれます。

```bash
skipped: src/Button/Button.stories.tsx
skipped: src/Button/Button.test.tsx
skipped: src/Button/Button.tsx
skipped: src/Button/index.tsx
skipped: src/Button/README.md
skipped: src/Button/style.css.d.ts
skipped: src/Button/style.css
```

---

今回はやりたいことが超単純だったのでこれだけですが、シンプルなわりには柔軟に作れるので他にもいろいろなことに活用できそうな気がします。

公式には `Redux`, `React Native`, `Express` がユースケースとして紹介されてます。

おわり