Markdown driven task runner.
You can install Maid globally:
# For npm users
npm i -g maid
# For Yarn users
yarn global add maid
Or if you want to ensure that your teammates are using the same version as you, it's recommended to install Maid locally:
# For npm users
npm i -D maid
# For Yarn users
yarn add maid --dev
PRO TIP: you can use npx
or yarn
command to run any locally installed executable that is inside node_modules/.bin/
, e.g. use yarn maid
to run the locally installed maid command.
A maidfile is where you define tasks, in Markdown!
📝 maidfile.md:
## lint
It uses ESLint to ensure code quality.
```bash
eslint --fix
Build our main app
Run task build:demo
after this
# note that you can directly call binaries inside node_modules/.bin
# just like how `npm scripts` works
babel src -d lib
You can use JavaScript to write to task script too!
const webpack = require('webpack')
// Async task should return a Promise
module.exports = () =>
new Promise((resolve, reject) => {
const compiler = webpack(require('./webpack.config'))
compiler.run((err, stats) => {
if (err) return reject(err)
console.log(stats.toString('minimal'))
resolve()
})
})
Each task is defined using `h2` header and its child contents, the value of `h2` header will be used as task name, its following paragraphs (optional) will be used as task description, and following code block (optional) will be used as task script.
Currently the code block languages are `sh` `bash` `js` `javascript` [and more](#code-block-languages)!.
Now run `maid help` to display the help for this maidfile:
```bash
❯ maid help
lint It uses ESLint to ensure code quality.
build Build our main app
build:demo You can use JavaScript to write to task script too!
❯ maid help "build*"
build Build our main app
build:demo You can use JavaScript to write to task script too!
To run a task, you can directly run maid <task_name>
❯ maid build
[13:46:38] Starting 'build'...
🎉 Successfully compiled 3 files with Babel.
[13:46:38] Finished 'build' after 363 ms...
[13:46:38] Starting 'build:demo'...
webpack compiled in 734ms.
[13:46:38] Finished 'build:demo' after 734 ms...
# to get minimal logs
❯ maid build --quiet
🎉 Successfully compiled 3 files with Babel.
webpack compiled in 734ms.
You can run tasks before or after a task:
## build
Run task `deploy` after this
```bash
webpack --config config/webpack.config.js
gh-pages -d dist
Expressions that start with `Run(s)? task(s)?` are treated specially. In this case if you run `maid build` it will also run the `deploy` task after `build` has finished.
The syntax is simple: `Runs? tasks? <taskNames> (before|after) this (in parallel)?` where each task name is surrounded by a pair of backticks: <code>`</code>.
By default a task will run before the current task. So `` Run task `build` `` would run `build` before the task it was described in. The presence of `after` anywhere in the sentence (after `Run task`) will cause it to be ran after. Commands run synchronously by default. The presence of `in parallel` in the sentence will cause it to be run in parallel.
Examples:
- `` Run task `build`. ``
- `` Run task `build` after this. ``
- `` Run tasks `clean`, `build`, and `lint`. ``
- `` Run tasks `build:app` `start:server` before this. ``
- `` Run tasks `build:server` `build:client` before this in parallel. ``
### Task hooks
Like npm scripts, when you run a command called `build`, when it's finished we will also run `postbuild` task.
Hook syntax:
- `pre<taskName>`: Run before a specific task.
- `post<taskName>`: Run after a specific task.
- `afterAll`: Run after all tasks.
- `beforeAll`: Run before all tasks.
## Advanced
### Code block languages
#### bash/sh
##### Read command line arguments
The CLI arguments are passed to executed script, so you can access it like this:
````markdown
## log
```bash
echo $1
Then run `maid log nice` and it will print `nice` in the console.
#### js/javascript
The JS script will also be evaluated.
````markdown
## log
```js
console.log(process.argv)
##### Asynchronous task
For asynchonous tasks, you can export a function which returns Promise:
````markdown
## build
```js
module.exports = async () => {
const files = await readFiles('./')
await buildFiles(files)
}
#### py/python
````markdown
## log
```py
print("cool")
### Use a custom maidfile
By default, Maid would use `maidfile.md`, `CONTRIBUTING.md` or `README.md` (case-insensitive) in current working directory, when you're using `README.md` you need to manually specify the section of the markdown you wanna use as Maid tasks like below:
````markdown
## My Project
## How to use
Let me explain..
## Development
<!-- maid-tasks -->
### test
```bash
# some test scripts...
Unlike a `maidfile.md` which uses all `h2` headers as tasks, in `README.md` only `h3` headers under the specified `h2` header will be used as tasks. You can add a `<!-- maid-tasks -->` comment right below the desired `h2` header.
Alternatively, if you're not using `maidfile.md`, you can also use `--section h2_header` and `--path foo.md` flags to customize it.
### ZSH completion
Add `FPATH` like following to `.zshrc`:
export FPATH=$(npm root -g)/maid/completion/zsh:$FPATH
## Development
<!-- maid-tasks -->
Maid's own development scripts are powered by itself, run `maid help` or `node bin/cli help` in this project to get more.
### lint
Run ESLint to ensure code quality and code style (via Prettier).
```bash
yarn eslint . "${@:1}"
If you want to automatically fix lint errors, try adding --fix
plugin to the command you run, e.g. maid lint --fix
Use AVA to run unit tests.
yarn ava "${@:1}"
Similar to the lint
task, you can append any flags for ava
command directly when you run the maid command.
Generate a table of contents section in the README.md file.
yarn doctoc README.md
git checkout -b my-new-feature
git commit -am 'Add some feature'
git push origin my-new-feature
maid © egoist, Released under the MIT License.
Authored and maintained by egoist with help from contributors (list).
github.com/egoist · GitHub @egoist · Twitter @_egoistlily