<p align="center">
  <a href="http://github.com/origin1tech/mustr"><img width="150" src="https://raw.githubusercontent.com/origin1tech/mustr/master/assets/logo.png"></a>
</p>
<br/>

## Description

Minimalistic scaffolding tool using Mustache Templates

Scaffolding can be a time saver and helps in consistency for teams. Yeoman is perhaps the most popular tool for this requirement. However building out your own generators can be cumbersome and time consuming. In the end the need is often no more than passing in some params then rendering those params in your template. Mustr attepts to fill that need in a simplistic and declarative way without the hassle and time investment.

## Installing & Initialization

```sh
$ npm install mustr -g
```

Initialize your project for use with Mustr. This will create a mustr.json configuration file along with a folder called Mustr. This folder is where you'll store your .tpl or template files as well as a file called "register.js".

Register.js is where you'll register your templates. You can register the same template multiple times with unique names keeping your templates DRY (don't repeat yourself). This is done by registering your template with a callback which allows you to do further manipulation before the template is rendered. We'll get to more on that in a min.

Open a terminal at the root of your project and then run:

```sh
$ mu init
```

## Options

The options are pretty minial and mot much to configure. There are basically three properties in your "mustr.json" file. It is not likely that you'll need to change these for most projects but in case you do...

- configDir the configuration directory from root usually "./mustr".
- outputDir the output or where your source files are usually "./src".
- templateExt the extension used for your templates usually ".tpl".

```json
{
  "configDir": "./mustr",
  "outputDir": "./src",
  "templateExt": ".tpl"
}
```

## Defining Templates

Templates are defined using the Mustache templating that you likely already know and yaml front-matter similar to Jekyll or Hugo if you've used either before. The front matter allows for defining a configuration for the template but can be used as you'd expect as the metadata for your template also. At first this may seem a bit redundant however it is needed for the config and also allows for defaults for your template. You'll be able to further modify the metadata for the template as you'll see in a min below.

see: https://www.npmjs.com/package/front-matter
see: https://github.com/janl/mustache.js/

**Example Template**

```hbs
---

config:
  ext: .ts
  suffix: Service
  casing: title

props:
  - key: name
    type: string
  - key: age
    type: number

---

export class {{component}} {

  {{#props}}
  {{key}}: {{type}};
  {{/props}}

  constructor() {

  }

}
```

**The above will result in:**

```js
export class DbService {

  name: string;
  age: number;

  constructor() {

  }

}
```

## Registering Templates

You may notice we did not specify a "component" property in your front matter. You certainly could do that but obviously that kind of defeats the purpose when the desire is to generate a template. This is resolved by injecting the desired component output name you defined in your cli command. We'll get to that here in a minute.

For example consider a template named "base.service.tpl". It might reside in a folder called "services". Mustr ignores folder structures and focuses on the file name itself. Just makes it easier when looking up templates for registration. For this reason it is important to make all your file names regardless of structure uniquely named although this is not required.

**Example Register.js**

```js

module.exports = function (mu) {

  // NAME - the name you wish to register the template under.
  // TEMPLATE - the name, path or static string template to use for the registration.
  // PARTIALS - string, array of strings, object of key value or multi arg of strings.
  // BEFORE_RENDER - callback passing TEMPLATE and done callback.
  // AFTER_RENDER - callback passing TEMPLATE.

  // Usage:
  mu.register(NAME, TEMPLATE)
    .partials('stirng', 'string')
    .beforeRender((template, done) => {  done(); })
    .afterRender((template) => {  /* do something */ });

  /* Simple Register
  *******************************************/

  // Define name and associated template.
  // The first argument is the name you wish to register
  // this name will be used when calling:
  // mu generate <template> where <template> is
  // the registered name.

  // The second arg is the path to the template to
  // associate to your name or the name of a known
  // template (.tpl files are loaded automatically).
  // Known templates can be referenced by file name
  // without extension. Additionally a static template
  // string can be passed directly for inline
  // registrations.

  mu.register('DB', 'service');

  /* Partials Register
  *******************************************/

  // Mustr supports partials as well. You could handle
  // partials manually in the callback (see advanced below)
  // however in most cases it's easiest to just pass
  // the logicless partials in your reigster command.
  // They will then be automatically rendered using your
  // front matter and/or flags passed in cli.

  mu.register('Db', 'service').partials('author');

  // OR

  mu.register('Db', 'service').partials(['author', 'footer'])

  // OR

  mu.register('Db', 'service').partials('header', 'author', 'footer');

  /* Advanced Register
  *******************************************/

  // When registring with a callback the template can
  // be manipulated before rendering.
  // For even greater control of each step see
  // tests folder to see how you can build
  // each step and render manually.

  mu.register('Db', 'service')
    .beforeRender((template, done) => {

      // do something with template
      // then call done to auto render.
      done();

    })
    .afterRender((template) => {

      // The file is rendered and written out.
      // Below is an example of manually calling
      // the .inject() method to inject for example
      // an import for the filed created.

      // NOTE: it is probably easier to inline your
      // injects in your template. see below for more on that.

      mu.inject('path/to/file', 'search expression', 'strategy', 'what to inject', () => {
        done();
      });

    });

};
```

## Generating Templates

Now that we have a template and have registered our templates. We can generate them using the Mustr CLI generate command.

```sh
$ mu g db shared/services/db
```

**The above would create the template at:**

./src/shared/services

**The filename would be:**

db.service.ts

**The component name of the service would be:**

DbService

### How Does That Work?

**suffix**

Because our template front-matter config defines a Suffix generated component names and file names will be automatially suffixed with this value. If you've used angular-cli this will be familiar to you and probably what you want for your conventions. To remove this feature simply remove this value from your configuration.

**output path**

The mustr.json file defines the source root for your projects so all paths are relative to it for template generation. Hence when we generate a template the path you set in your generation command is respected and output to this location.

**component name**

The component name or the ending value you specified in the output path "shared/services/db" in this case "db" is used for the name of the component/template you're generating. You'll notice though that the name is auto suffixed like the file path. This results in this case in "DbService".

The filename is auto cased based on your front-matter config using the property "casing". Valid values are lower, upper, capitalize, title, or camel. Whether you are using suffixes or not Mustr will just figure this out when you specify your desired case. More often than not you want "title" which is essentially titlecase. For anything that is a component/class etc. that's likely what you want.

## Extending Metadata via CLI

Any flags passed in your command line will be respected and overwrite any static metadata used in rendering your template.

```sh
$ mu g db shared/services/db --property value
```

The above will extend or overwrite your metadata object with a key called "property" with the provided "value" as it's value.

Nested values are also possible. You could for example have an object in your metadata such as "user". You override or provide it by doing something like:

```sh
$ mu g db shared/services/db --user name:Bob,age:25
```

OR

```sh
$ mu g db shared/services/db --user.name Bob --user.age 25
```

## Injecting Imports

Usually in the ES6 world you will want create an import of the generated/rendered template into another file. Currently this is done only via a callback in your registration as described above.

```js
mu.register('Db', 'service')
  .afterRender((template) => {

     mu.inject('path/to/file', 'search expression', 'strategy', 'what to inject', () => {
        done();
      });

  });
```

**Inject Inline**

It is also possible to inject inline within your template file. This is done by creating an array in your yaml front-matter. This is very handy as it will create the import to the foriegn file each time a template of this type is created. No fuss no muss just works.

```yaml

config:
  ext: .ts
  suffix: Service
  casing: title
  injects:
    - filename: 'examples/db.example.tsx'
      find: '// INJECT'
      strategy: 'after'
      insert: "import * as _ from 'lodash';"

```

## Wrapping Up

Feel free to comment, create PR's whatever you wish if you have ideas or improvements. Always welcome.

## License

See [LICENSE.md](License.md)






