Mason allows developers to create and consume reusable templates called bricks.
# 🎯 Activate from https://pub.dev
dart pub global activate mason
# 🍺 Or install from https://brew.sh
brew tap felangel/mason
brew install mason
# 🚀 Initialize mason
mason init
# 🧱 Use your first brick
mason make hello
- Overview
- Creating New Bricks
- Adding Bricks
- Removing Bricks
- List all available Brick Templates
- Bundling
- Complete Usage
- Video Tutorial
# 🎯 Activate from https://pub.dev
dart pub global activate mason
# 🍺 Or install from https://brew.sh
brew tap felangel/mason
brew install mason
mason init
mason init
initializes the Mason CLI in the current directory.
Running mason init
generates a mason.yaml
and an example brick
so that you can get started immediately.
bricks:
hello:
path: bricks/hello
To get all bricks registered in mason.yaml
run:
mason get
Then you can use mason make
to generate your first file:
mason make hello
Any variables can be passed as command line args.
mason make hello --name Felix
Any variables which aren't specified as command line args will be prompted.
mason make hello
name: Felix
Any variables can be passed via a config file:
mason make hello -c config.json
where config.json
is:
{
"name": "Felix"
}
The above commands will all generate HELLO.md
in the current directory with the following content:
Hello Felix!
By default mason make
will generate the template in the current working directory but a custom output directory can be specified via the -o
option:
mason make hello --name Felix -o ./path/to/directory
By default, mason make
will prompt on each file conflict and will allow users to specify how the conflict should be resolved via Yyna
:
y - yes, overwrite (default)
Y - yes, overwrite this and all others
n - no, do not overwrite
a - append to existing file
A custom file conflict resolution strategy can be specified via the --on-conflict
option:
# Always prompt when there is a file conflict (default)
mason make hello --name Felix --on-conflict prompt
# Always overwrite when there is a file conflict
mason make hello --name Felix --on-conflict overwrite
# Always skip when there is a file conflict
mason make hello --name Felix --on-conflict skip
# Always append when there is a file conflict
mason make hello --name Felix --on-conflict append
Create a new brick using the mason new
command.
mason new <BRICK_NAME>
The above command will generate a new brick in the bricks
directory with a brick.yaml
and __brick__
template directory.
The brick.yaml
contains metadata for a brick
template.
name: example
description: An example brick
vars:
- name
Write your brick template in the __brick__
directory using mustache templates. See the mustache manual for detailed usage information.
__brick__/example.md
# Hello {{name}}!
❗ Note: __brick__
can contain multiple files and subdirectories
❗ Note: use {{{variable}}}
instead of {{variable}}
when you want the value of variable
to be unescaped
It is possible to have templates nested within other templates. For example, given the follow structure:
├── HELLO.md
├── {{~ footer.md }}
└── {{~ header.md }}
The {{~ header.md }}
and {{~ footer.md }}
are partials (partial brick templates). Partials will not be generated but can be included as part of an existing template.
For example given the contents of {{~ header.md }}
and {{~ footer.md }}
respectively
# 🧱 {{name}}
_made with 💖 by mason_
we can include the partials as part of a template via {{> header.md }}
and {{> footer.md }}
.
In this example, given HELLO.md
:
{{> header.md }}
Hello {{name}}!
{{> footer.md }}
We can use mason make hello --name Felix
to generate HELLO.md
:
# 🧱 Felix
Hello Felix!
_made with 💖 by mason_
❗ Note: Partials can contain variables just like regular templates
It is possible to resolve files based on path input variables using the {{% %}}
tag.
For example, given the following brick.yaml
:
name: app_icon
description: Create an app_icon file from a URL
vars:
- url
And the following brick template:
__brick__/{{% url %}}
Running mason make app_icon --url path/to/icon.png
will generate icon.png
with the contents of path/to/icon.png
where the path/to/icon.png
can be either a local or remote path. Check out the app icon example brick to try it out.
Mason supports a handful of built-in lambdas that can help with customizing generated code:
Name | Example | Usage |
---|---|---|
camelCase |
helloWorld |
{{#camelCase}}{{variable}}{{/camelCase}} |
constantCase |
HELLO_WORLD |
{{#constantCase}}{{variable}}{{/constantCase}} |
dotCase |
hello.world |
{{#dotCase}}{{variable}}{{/dotCase}} |
headerCase |
Hello-World |
{{#headerCase}}{{variable}}{{/headerCase}} |
lowerCase |
hello world |
{{#lowerCase}}{{variable}}{{/lowerCase}} |
pascalCase |
HelloWorld |
{{#pascalCase}}{{variable}}{{/pascalCase}} |
paramCase |
hello-world |
{{#paramCase}}{{variable}}{{/paramCase}} |
pathCase |
hello/world |
{{#pathCase}}{{variable}}{{/pathCase}} |
sentenceCase |
Hello world |
{{#sentenceCase}}{{variable}}{{/sentenceCase}} |
snakeCase |
hello_world |
{{#snakeCase}}{{variable}}{{/snakeCase}} |
titleCase |
Hello World |
{{#titleCase}}{{variable}}{{/titleCase}} |
upperCase |
HELLO WORLD |
{{#upperCase}}{{variable}}{{/upperCase}} |
Example Usage
Given the following example brick:
__brick__
├── {{#snakeCase}}{{name}}{{/snakeCase}}.md
└── {{#pascalCase}}{{name}}{{/pascalCase}}.java
brick.yaml
:
name: example
description: An example brick.
vars:
- name
We can generate code via:
mason make example --name my-name
The output will be:
├── my_name.md
└── MyName.java
Mason supports custom script execution via hooks
. The supported hooks are:
pre_gen
- executed immediately before the generation steppost_gen
- executed immediately after the generation step
Hooks must be defined in the hooks
directory at the root of the brick:
├── __brick__
├── brick.yaml
└── hooks
├── post_gen.dart
└── pre_gen.dart
❗ Currently mason only supports hooks written in Dart.
For example given the following example
brick:
.
├── __brick__
│ └── example.md
├── brick.yaml
└── hooks
└── post_gen.dart
where brick.yaml
looks like:
name: example
description: An example
vars:
- name
And post_gen.dart
contains:
import 'dart:io';
void main() {
print('hello {{name}}!');
print(Directory.current.path);
}
The result of running mason make example --name Dash
would be:
mason make example --name Dash
✓ Made brick example (0.0s)
✓ Generated 1 file:
/Users/dash/mason/example/example.md (new)
hello Dash!
/Users/dash/mason/example
💡 Note: Scripts can contain template variables. In addition, the working directory of the script is the directory in which the code is generated.
Hooks can be disabled using the --no-hooks
flag:
# Disable hook script execution
mason make example --name Dash --no-hooks
The add
command allows developers to add brick templates locally or globally on their machines from either a local path or git url. By default mason add
will add the template locally but bricks can be added globally by providing the --global
(-g
) flag.
# add from path
mason add --source path ./path/to/brick
# add from path (global)
mason add --global --source path ./path/to/brick
# add from path shorthand syntax
mason add ./path/to/brick
# add from path shorthand syntax (global)
mason add -g ./path/to/brick
# add from git url
mason add --source git https://github.com/user/repo
# add from git url (global)
mason add -g --source git https://github.com/user/repo
# add from git url with path
mason add --source git https://github.com/user/repo --path path/to/brick
# add from git url with path and ref
mason add --source git https://github.com/user/repo --path path/to/brick --ref tag-name
Once a brick is added it can be used via the mason make
command:
mason make <BRICK_NAME>
Bricks can be removed by using the remove
command. Use the --global
(-g
) flag to remove global bricks.
# remove brick
mason remove <BRICK_NAME>
# remove brick (global)
mason remove -g <BRICK_NAME>
All available brick templates (local and global) can be seen via the list
(ls
for short) command.
# list all available bricks
mason list
# use alias "ls" instead of "list" for a shorthand syntax
mason ls
You can use mason to generate a bundle for an existing template. Bundles are convenient for cases where you want to include your template as part of a standalone CLI. Very Good CLI is a great example.
There are currently two types of bundles:
- Universal - a platform-agnostic bundle
- Dart - a Dart specific bundle
To generate a bundle:
# Universal Bundle
mason bundle ./path/to/brick -o ./path/to/destination
# Dart Bundle
mason bundle ./path/to/brick -t dart -o ./path/to/destination
A bundle can then be used to generate code from a brick programmatically:
// Create a MasonGenerator from the existing bundle.
final generator = MasonGenerator.fromBundle(...);
// Generate code based on the bundled brick.
await generator.generate(...);
mason
⛏️ mason • lay the foundation!
Usage: mason <command> [arguments]
Global options:
-h, --help Print this usage information.
--version Print the current version.
Available commands:
add Adds a brick from a local or remote source.
bundle Generates a bundle from a brick template.
cache Interact with mason cache.
get Gets all bricks in the nearest mason.yaml.
init Initialize mason in the current directory.
list Lists all available bricks.
make Generate code using an existing brick template.
new Creates a new brick template.
remove Removes a brick.
Run "mason help <command>" for more information about a command.
Say HI to Mason Package! - The Top Tier Code Generation Tool | Complete Tutorial by Flutterly