UNPKG

15 kBMarkdownView Raw
1<h3 align="center">
2 <img src="https://raw.githubusercontent.com/jondot/hygen/master/media/hygen.png" alt="hygen logo" width=400 />
3</h3>
4
5[![build status](https://img.shields.io/travis/jondot/hygen/master.svg)](https://travis-ci.org/jondot/hygen)
6[![npm version](https://img.shields.io/npm/v/hygen.svg)](https://www.npmjs.com/package/hygen)
7
8`hygen` is the simple, fast, and scalable code generator that lives _in_ your project.
9
10<div align="center">
11 <img src="https://raw.githubusercontent.com/jondot/hygen/master/media/hygen.gif" width=600/>
12</div>
13
14
15## Features
16
17✅ Build ad-hoc generators quickly and full on project scaffolds.
18✅ Local generators per project (and global, if you must)
19✅ Built-in scaffolds to quickly create generators
20✅ Full logic templates and rendering
21✅ Prompts and flows for taking in arguments
22✅ Automatic CLI arguments
23✅ Adding new files
24✅ Injecting into existing files
25✅ Running shell commands
26✅ Super fast, constantly optimized for speed
27
28
29> New in hygen v4.0.0: a positional `NAME` parameter.
30> Now you can use `$ hygen component new MyComponent` instead of `$ hygen component new --name MyComponent`.
31
32## Used By
33
34<Image alt="Wix" height="32" src="https://upload.wikimedia.org/wikipedia/en/7/76/Wix.com_website_logo.svg"/> &nbsp; &nbsp; <Image alt="Airbnb" height="50" src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Airbnb_Logo_B%C3%A9lo.svg/512px-Airbnb_Logo_B%C3%A9lo.svg.png"/> &nbsp; &nbsp; <Image alt="Open Data Institute" height="60" src="https://luminategroup.com/storage/538/c/opendatainstitute%28ODI%29-logo%402x-logo.png"/> &nbsp; &nbsp; <Image alt="Ableneo" height="80" src="https://www.ableneo.com/web/images/logo.svg"/> &nbsp;
35<Image alt="City of Amsterdam" height="70" src="https://avatars3.githubusercontent.com/u/14022058?s=200&v=4"/> &nbsp; &nbsp; <Image alt="Accenture" height="80" src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Accenture.svg/512px-Accenture.svg.png"/> &nbsp; <Image alt="Birdie" height="60" src="https://assets.website-files.com/5d07a11d8195605723dbff07/5d09430b3d6e1c5d28a6e2b6_global%E2%80%94birdie_logo_black.svg"/> &nbsp; &nbsp;
36<Image alt="Kind" height="80" src="https://madebykind.com/dist/images/logos/site-logo-green-e0e983ec46.svg"/> &nbsp; &nbsp; <Image alt="Ackee" height="80" src="https://avatars3.githubusercontent.com/u/1728223?s=400&v=4"/> &nbsp;
37 <Image alt="Aerian Studios" height="80" src="https://www.aerian.com/img/c/aerian-logo.svg"/> &nbsp;<Image alt="Food and Agriculture Organization of the UN" height="100" src="https://avatars2.githubusercontent.com/u/38506195?s=200&v=4"/> <Image alt="Cape Cod Commision" height="70" src="http://www.capecodcommission.org/gfx/home-logo.jpg"/> &nbsp; <Image alt="Tweak Things" height="80" src="https://avatars3.githubusercontent.com/u/49718812?s=400&v=4"/> &nbsp; &nbsp; <Image alt="Crema" height="40" src="https://assets.website-files.com/5b6b50e79e9b6f5948395973/5d88f52b42420350d3e117d2_Asset%201.png"/> &nbsp; &nbsp; <Image alt="Cureon" height="120" src="http://cureon.de/resources/cureon_logo.png"/> &nbsp; &nbsp; <Image alt="Astrocoders" height="50" src="https://d33wubrfki0l68.cloudfront.net/b8f71088a0c9bc92d67476a361f35690d157d0e5/517c2/static/logo-c5d890fb431b53a7c61800feccd65ac2.png"/> &nbsp; &nbsp; <Image alt="Vega/IDL" height="60" src="http://vega.github.io/images/idl-logo.png"/> &nbsp; <Image alt="Sporty Spots" height="60" src="https://www.sportyspots.com/static/sportyspots.svg"/> &nbsp; &nbsp;<Image alt="Thrashplay" height="50" src="https://avatars1.githubusercontent.com/u/55868193?s=200&v=4"/> &nbsp;&nbsp;<Image alt="8base" height="80" src="https://avatars1.githubusercontent.com/u/28789399?s=200&v=4"/> &nbsp;&nbsp; <Image alt="Instamotionh" height="50" src="https://avatars1.githubusercontent.com/u/44466967?s=200&v=4"/> <Image alt="Biotope" height="90" src="https://avatars1.githubusercontent.com/u/34653144?s=400&v=4"/> <Image alt="Frontend Labs" height="50" src="https://avatars1.githubusercontent.com/u/6691550?s=200&v=4"/>
38<Image alt="Swydo" height="90" src="https://avatars1.githubusercontent.com/u/1563883?s=400&v=4"/> <Image alt="Gridsome" height="70" src="https://avatars0.githubusercontent.com/u/17981963?s=200&v=4"/> <Image alt="Rosem Laboratory" height="90" src="https://avatars2.githubusercontent.com/u/22129460?s=200&v=4"/><Image alt="Sheffield Hallam University" height="70" src="https://avatars1.githubusercontent.com/u/46559136?s=400&v=4"/>
39<Image alt="Hackoregon" height="80" src="https://avatars3.githubusercontent.com/u/6343574?s=400&v=4"/> <Image alt="Chilly Design" height="50" src="https://avatars1.githubusercontent.com/u/13002395?s=200&v=4"/>
40
41<Image alt="Scale Leap" height="50" src="https://avatars3.githubusercontent.com/u/41709180?s=200&v=4"/>
42
43<Image alt="Chat Logs" height="50" src="https://avatars1.githubusercontent.com/u/37252774?s=200&v=4"/>
44
45<Image alt="Stelace" height="70" src="https://avatars1.githubusercontent.com/u/32740360?s=400&v=4"/>
46
47## Quick Start
48
49Hygen can be used to supercharge your workflow with [Redux](http://www.hygen.io/redux), [React Native](http://www.hygen.io/react-native), [Express](http://www.hygen.io/express) and more, by allowing you avoid manual work and generate, add, inject and perform custom operations on your codebase.
50
51If you're on macOS and have Homebrew:
52
53```
54$ brew tap jondot/tap
55$ brew install hygen
56```
57
58If you have node.js installed, you can install globally with `npm` (or Yarn):
59
60```
61$ npm i -g hygen
62```
63
64If you like a no-strings-attached approach, you can use `npx` without installing globally:
65
66```
67$ npx hygen ...
68```
69
70For other platforms, see [releases](https://github.com/jondot/hygen/releases).
71
72Initialize `hygen` in your project (do this once per project):
73
74```
75$ cd your-project
76$ hygen init self
77```
78
79Build your first generator, called `mygen`:
80
81```
82$ hygen generator new mygen
83
84Loaded templates: _templates
85 added: _templates/mygen/new/hello.ejs.t
86```
87
88Now you can use it:
89
90```
91$ hygen mygen new
92
93Loaded templates: _templates
94 added: app/hello.js
95```
96
97You've generated content into the current working directory in `app/`. To see how the generator is built, look at `_templates` (which you should check-in to your project from now on, by the way).
98
99You can build a generator that uses an interactive prompt to fill in a variable:
100
101```
102$ hygen generator with-prompt mygen
103
104Loaded templates: _templates
105 added: _templates/mygen/with-prompt/hello.ejs.t
106 added: _templates/mygen/with-prompt/prompt.js
107```
108
109Done! Now let's use `mygen`:
110
111```
112$ hygen mygen with-prompt
113? What's your message? hello
114
115Loaded templates: _templates
116 added: app/hello.js
117```
118
119## What's Next?
120
121Go to the [documentation](http://www.hygen.io/quick-start) to get to know the rest of Hygen and generators.
122
123If you're in a hurry:
124
125* To learn how to edit generator templates, [look here](http://www.hygen.io/templates)
126* To see how to use generators [look here](http://www.hygen.io/generators)
127* Take a look at the [ecosystem](http://www.hygen.io/packages) and tooling built around Hygen.
128
129## A Different Kind of a Generator
130
131`hygen` is a scalable generator. It has developer and team ergonomics as first priority.
132
133It avoids "blessed" or dedicated projects that codifies code generation, which before you know it, become a product you build, needs testing, CI, separate pull request reviews, and ultimately sucks up your time and becomes this super hated thing no one likes to touch anymore.
134
135Plus, since they are not the product you are building they become notoriously hard to reason about.
136
137## Scratch Your Own Itch
138
139Because `hygen` templates live _in_ your project, it cuts the time from having an itch for generating code (Redux, anyone?) in your current
140project to code generated with it and others benefiting from it.
141
142### Template Locality
143
144`hygen` picks up a local `_templates` folder
145at any folder level of your project you're working from.
146
147This is important because:
148
149* Templates are project-local. A git clone of the project fetches all generators as well.
150* Different generators can be tucked in different parts of the project, making it contextual.
151* Template locality is scalable; different teams can maintain different generators.
152* When you change your code, you can make changes in the template and pack in the same commit, to be reviewed and merged in the same PR (as opposed to installing different "plugins" or different templates from out-of-repo places).
153
154And yet, if you don't like project-local templates:
155
156* You can have a global `_templates` folder (maybe a central git repo you maintain?) by populating an environment variable `HYGEN_TMPLS`
157* You can build a [custom generator](#build-your-own) of your own with `hygen` at its core, and pack your own templates with it.
158
159### Folder Structure is Command Structure
160
161The templates folder structure _maps directly_ to the command structure:
162
163```
164$ hygen worker new jobrunner
165```
166
167For this command, `hygen worker new` maps to `_templates/worker/new` and all files within `worker/new` are rendered.
168
169Template parameters are given with `--flag VALUE`, as many as you'd like. In this example we've set a parameter named `name` to the value `jobrunner`.
170
171### Subcommands
172
173A subcommand is a file inside a your folder structure. So if the structure is this:
174
175```
176_templates/
177 worker/
178 new/
179 index.html.ejs
180 setup.html.ejs
181```
182
183And you only want `setup`, you can run:
184
185```
186$ hygen worker new:setup
187```
188
189You can also use the subcommand as a regular expression so, these will do the same:
190
191```
192$ hygen worker new:se
193```
194
195```
196$ hygen worker new:se.*
197```
198
199### Frontmatter for Decluttering
200
201Here's how a template looks like (in our example, `index.ejs.t`). Templates bodies are [ejs](https://github.com/tj/ejs):
202
203```javascript
204---
205to: app/workers/<%=name%>.js
206---
207
208class <%= h.capitalize(name) %> {
209 work(){
210 // your code here!
211 }
212}
213```
214
215The first part of the template is a [front matter](https://jekyllrb.com/docs/frontmatter/), idea borrowed from Markdown, this is the metadata part of a `hygen` template and is part of the reason of why your templates will feel more lightweight and flexible.
216
217All frontmatter metadata _are also run through the template engine_ so feel free to use variables in the frontmatter as you wish.
218
219There's one required metadata variable: `to`.
220`to` points to where this file will be placed (folders are created as needed).
221
222### Case changing
223
224`hygen` provides ability to semantic case changing with `change-case` library, it's simple to use and very easy to understand.
225
226There is a usecase for react based components generation:
227
228```yaml
229---
230to: components/<%= name %>/index.jsx
231---
232import React from 'react'
233
234export const <%= name %> = ({ children }) => (
235 <div className="<%= h.changeCase.paramCase(name) %>">{children}</div>"
236)
237```
238
239With name `HelloWorld` will be compiled to:
240
241```js
242import React from 'react'
243
244export const HelloWorld = ({ children }) => (
245 <div className="hello-world">{children}</div>"
246)
247```
248
249You can see the full list [here](https://github.com/blakeembrey/change-case).
250
251### Addition, Injection, and More
252
253By default templates are 'added' to your project as a new target file, but you can also choose to inject a template _into_ an existing target file.
254
255For this to work, you need to use `inject: true` with the accompanied inject-specific props.
256
257```yaml
258---
259to: package.json
260inject: true
261after: dependencies
262skip_if: react-native-fs
263---
264"react-native-fs":"*",
265```
266
267This template will add the `react-native-fs` dependency into a `package.json` file, but it will not add it twice (see `skip_if`).
268
269Here are the available mutually-exclusive options for where to inject at:
270
271* `before | after` - a regular expression / text to locate. The inject line will appear before or after the located line.
272* `prepend | append` - add a line to start or end of file respectively.
273* `line_at` - add a line at this exact line number.
274
275You can guard against double injection:
276
277* `skip_if` - a regular expression / text. If exists injection is skipped.
278
279Also you can insert or remove empty line to injection body. That feature very useful if your editor or formatter automatically insert blank line at the end of file on save:
280
281* `eof_last` - if falsy - trim blank line from the end of injection body, if truthy - insert it.
282
283### Build Your Own
284
285`hygen` is highly embeddable. You should be able to use it by simply listing it
286as a dependency and having [this kind of workflow](src/bin.js) in your binary.
287
288```javascript
289const { runner } = require('hygen')
290const Logger = require('hygen/lib/logger')
291const path = require('path')
292const defaultTemplates = path.join(__dirname, 'templates')
293
294runner(process.argv.slice(2), {
295 templates: defaultTemplates,
296 cwd: process.cwd(),
297 logger: new Logger(console.log.bind(console)),
298 createPrompter: () => require('enquirer'),
299 exec: (action, body) => {
300 const opts = body && body.length > 0 ? { input: body } : {}
301 return require('execa').shell(action, opts)
302 },
303 debug: !!process.env.DEBUG
304})
305```
306
307# Development
308
309The Hygen codebase has a functional style where possible. This is because naturally, it
310feeds parameters and spits out files. Try to keep it that way.
311
312Running `hygen` locally, rigged to your current codebase (note the additional `--` to allow passing flags)
313
314```
315$ yarn hygen -- mailer new foobar
316```
317
318Running tests in watch mode:
319
320```
321$ yarn watch
322```
323
324## Metaverse Testing
325
326The easiest way to make an impact is to use the built-in [`metaverse`](src/__tests__/metaverse) tests suite, and then add the tests [here](src/__tests__/metaverse.spec.js).
327
328The idea here is to copy templates from any project that use `hygen` and to test that it works at all times. This keeps tabs on the hygen universe / ecosystem (nicknamed metaverse) and makes sure this test suite breaks before `hygen` clients break.
329
330## Internal Testing
331
332## Start Up Speed Testing
333
334Many generators become painfully slow to use as the thing you want to generate grow (because, real life),
335
336This is why `hygen` takes speed as a first class citizen, and sports a dedicated start-up timing suite:
337
338```
339$ yarn test:require
340```
341
342In addition, thought is given to which dependencies to take in, how their file structure fan out and what kind of disk access (due to `require`) would `hygen` ultimately have when we run it. This is recorded with every test run.
343
344Bundling a single file was evaluated (and the infrastructure is still there, using `webpack`) and wasn't faster than what we have right now.
345
346# Contributing
347
348Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :).
349
350### Thanks:
351
352To all [Contributors](https://github.com/jondot/hygen/graphs/contributors) - you make this happen, thanks!
353
354# Copyright
355
356Copyright (c) 2018 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See [LICENSE](LICENSE.txt) for further details.