Git Product home page Git Product logo

maid's Introduction

maid

NPM version NPM downloads CircleCI donate chat

Markdown driven task runner.

Table of Contents

Install

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.

What is a maidfile?

A maidfile is where you define tasks, in Markdown!

📝 maidfile.md:

## lint

It uses ESLint to ensure code quality.

```bash
eslint --fix
```

## build

Build our main app

<!-- Following line is a maid command for running task -->

Run task `build:demo` after this

```bash
# note that you can directly call binaries inside node_modules/.bin
# just like how `npm scripts` works
babel src -d lib
```

## build:demo

You can use JavaScript to write to task script too!

```js
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!.

Now run maid help to display the help for this maidfile:

❯ 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.

Run tasks before/after a task

You can run tasks before or after a task:

## build

Run task `deploy` after this

```bash
webpack --config config/webpack.config.js
```

## deploy

```bash
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: `.

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:

## 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.

## log

```js
console.log(process.argv)
```
Asynchronous task

For asynchonous tasks, you can export a function which returns Promise:

## build

```js
module.exports = async () => {
  const files = await readFiles('./')
  await buildFiles(files)
}
```

py/python

## 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:

## 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'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).

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

test

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.

toc

Generate a table of contents section in the README.md file.

yarn doctoc README.md

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

Author

maid © egoist, Released under the MIT License.
Authored and maintained by egoist with help from contributors (list).

github.com/egoist · GitHub @egoist · Twitter @_egoistlily

maid's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

maid's Issues

[feature request] Add ability to launch a detached process

Eg:

long-running-process &

This would require passing the detached option to spawn, and there is the caveat:

When using the detached option to start a long-running process, the process will not stay running in the background after the parent exits unless it is provided with a stdio configuration that is not connected to the parent. If the parent's stdio is inherited, the child will remain attached to the controlling terminal.

Watch files

## watch

Run task `build` and watch `src/*.js`

Or

## watch

Run task `build` before this and watch `src/*.js`

A new command for running task and rerun it when watched files are changed.

`before this` will be be optional since that will be a default.

This is genial concept

After 25+ years in IT and using many build systems this concept is simply genial. Thank you.

Don't execute certain blocks

I just want to have some blocks be documenting how to use it, and then later define how it works.
So imagine that this would work (note the first blocks don't define a scripting language). Perhaps another thing like <!-- ignore --> would be better, so you can have it look like bash still.

run

Run npm in any apps/app folder, defaults to start. To run every app in dev mode for example just do:

maid run app
maid run desktop
maid run electron

which will end up running:

cd apps/app && npm run start
cd apps/desktop && npm run start
cd apps/electron && npm run start

But you can run any arbitrary npm command inside any package here too by using the fourth argument. So, maid run app build would run npm run build inside apps/app.

echo "hi"
cd apps/$1 || echo "not found" && exit 1
pwd

Should task execution be case-insensitive?

Right now task names are case sensitive. Worried this will cause a lot of confusion in some cases.

Consider the following maidfile:

## Example

```bash
echo "example A"
```

## example

```bash
echo "example B"
```

and I run:

maid example outputs example B

maid Example outputs example A.

rename `beforeAll/afterAll` to `pre/post`?

Hey, thanks for the interesting tool!

I was just gonna make a suggestion. Right now you can have things like postbuild and prebuild which run automatically. But the automatic before/after everything is confusingly named afterAll and beforeAll, which isn't consistent.

It might be nice to allow pre and post tasks that run before/after everything instead, to stay consistent. It feels natural that pre without pre{task} would count for everything.

Support Python

Hello! Nice project you have there! I'd like to know wheter it's possible to write tasks in python as well. Keep up the good work!

Global Variables

In a maidfile, it would be nice to have some variables set so that they can be referenced in the other scripts. Therefore, if the following was at the top:

## global

```bash
destdir='~/.dest'
```

```js
 var destdir='~/.dest'
```

Then the variable $destdir can be used in all the other bash scripts. Have the same thing for js scripts also.

The four spaces won. Using 4 tick didn't help.

Global location for maid file

If there is not a maidfile.md in the current directory then look in the user's root for a file something like .maidfile.md

Add the ability to sync npm scripts

Introduce an argument --update-scripts to write all the maid tasks to the package.json file.

So ## clean -> "scripts: { "clean": "maid clean" }

This will allow users to use yarn clean or npm run clean as they may likely already be doing, but having the source of truth be their maid file. I envision that the --update-scripts arg would be used with something like lint-staged to automatically update the scripts when there were changes. It would only update the scripts whose commands start with maid.

One issue with this approach is the pre, post task hooks that maid supports. These would suddenly be ran twice. Will need to figure out a solution for that.

Reading from paragraphs breaks natural way of listing pre/post tasks:

Eg:

## task

Does task

Run tasks `foo`, `bar` before this
Run tasks `baz`, `yak` after this

foo, bar, baz and yak will all be executed before task because it is parsed like this:

[ 'before',
  index: 38,
  input: 'Run tasks `foo`, `bar` before this\nRun tasks `baz`, `yak` after this' ]

You have to have an additional newline between the Run tasks definitions.

Passing flags to the tasks is conflicting

So.

While implementing #4, i reconsider the #29. And realized that we only should support maidfile.md (from cwd to 5 dirs up) and .maidfile.md (from cwd to 10 dirs up) by default. One more thing that appeared is that we are a bit limited with what flags maid cli can have, because we are passing flags to the tasks e.g. maid lint --fix, so --fix is going to the eslint. I realized that is a bit conflicting while i changed the --path to more meaningful --config-path which ESLint has too.

So, if not another thing, we can rename the --path to, for example, --maidfile which would be the best. Then i can PR the #4 which is pretty fantastic by the way and works.

This issue is more just informatinve and opening the discussion that may appear in future.

[ Feature request ] Connecting code blocks through pipes.

Hello good people of maid,

It would be useful if code blocks could communicate somehow.

Stdin - stdout

In the following pattern the code blocks are connected through the stdin-stdout:

## build 

Builds important stuff 

Snippet 1 

```js
process.stdout.write("hi there from snippet 1");
```

Snippet 2

```js
process.stdin.on('data', console.log); // hi there from snippet 1
```

Next

Another way of allowing communication between code blocks is by injecting a method inside each code block in a similar way of how express.js does it with their middlwares.

## build 

Builds important stuff 

Code block 1 

```js
next('hi there from snippet 1');
```

Code block 2

```js
console.log(maid.result); // hi there from snippet 1
```

This pattern can also be used to control the execution flow:

## build 

Builds important stuff 

Code block 1 

```js
next('hi there from snippet 1');
```

Code block 2

```js
if (true) {
	console.log(maid.result); // hi there from snippet 1
}else {
	next("hi there from snippet 2");
}
```

Code block 3 

```bash
 // This will never get executed 

```

Add extra maintainers

There are a pile of unmerged pull requests, is it possible to add one or more maintainers to this project? I'm super excited about it and want to keep seeing the feature pile in.

Run `N` scripts within task.

Hello good people of maid,

Would it be possible if we could implement the ability to run synchronously N number of scripts within a Task?.

E.j:

## build 

Run task `test` after this

Retrieves the configuration from a website:

```bash
curl https://website.com/myConfiguration > config.json
```

Manipulate somehow the downloaded configuration: 

```js
const config = require('./config.json');
// ....
```

## test 

```bash
jest --config config.json 
```

TypeScript support

Find typescript module in current working directory and use it to compile ts or typescript code blocks.

Show the script of a task in help dialog

Some tasks are self-explanatory if you looked at their script and need no description. I also think knowing what script the task actually runs can be helpful context if only reading from the help dialog and not the maidfile itself.

For instance, I have a clean task that just runs rm -rf build/. If the help dialog outputted this, I wouldn't need to add a description, but since it doesn't I have to add the redundant description of "Cleans the build/ folder".
Tasks without a description also say "No description" instead of not showing anything (potentially a separate issue/PR to address)

nps's help dialog does output the actual script of the task. When no description is given, it will only show the script (never says "No description").

change blockquotes to denote parallelism

Hey! Reading through the docs, I think there are two issues that are kind of inter-related...

  1. That all "comments/description" seem to have to go in blockquotes?
  2. That there's a special (hard to remember) syntax for "Run x after/before this (in parallel)".

I think there might be a simplification that will make writing the files easier, and make running things in parallel or not easier too.

First, I think all of the current use of blockquotes should be removed. Instead, let people write the commenting documentation just as normal paragraphs, since we already have the backticks as delineating code blocks to run. This makes the simple cases easier to remember. So the examples become:

## lint

Run ESLint to ensure code quality

```bash
eslint --fix
```

After that, we now have blockquotes entirely freed up to be used for special syntax. I think they should be used to define parallelism. For things outside of block quotes, everything is run in series as it's encountered. So that instead of writing the "Run x before this", you can just add scripts in series:

## lint

```bash
eslint index.js
```

## test

```bash
maid lint
```

```bash
mocha test/index.js
```

But then anything you put in a blockquote will be run in parallel, so you can easily do things like:

## start

Run the watcher command and the web server.

> ```bash
> babel ./src --out-dir ./public --watch 
> ```
>
> ```bash
> serve ./public
> ```

This would run both the watcher and the web server in parallel, really easily.

You can even specify groups of parallel tasks separated by series tasks, by simply breaking the blockquotes into two with a series task in the middle.

Changing the project name

First things first, I love the concept of this tool. However, because of its gendered name, I'm hesitant to include it in my own projects. Would the maintainers of this library be open to changing the name to something more inclusive?

Any steps, even small ones, that we can take as a community to create a more welcoming environment for new/oldcomers alike enrich our field. We can look to factory_bot for an example of why, even for popular, established projects, such changes are both important and meaningful.

To cast the first line, how about something like doctopus? It draws both on this project's flexible scripting options and on its embedded documentation.

Extract specific part of a markdown file

Let's say you have a README.md:

# project name

> this is cool

## Development

You can use [Maid](https://github.com/egoist/maid) to run following tasks.

### dev

> Start development server

```bash
poi --config poi.config.js
```

### build

> Build as a library

```bash
bili --format cjs,umd --moduleName foo
```

Then you can use CLI flag -i README.md -s Development to use h3 headings under the h2 heading Development as task names.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.