scaffdog is Markdown driven scaffolding tool.
Multiple files can be output in a document, and flexible scaffolding is possible with a simple but powerful template syntax 🐕
- 🐶 Features
- 🐾 Getting Started
- 🛎️ Requirements
- 🔥 Migration
- 🔧 Configuration
- 🐩 Commands
- 📝 Templates
- 🔌 Integration
- 📘 FAQ
- 🐕 Contributing
- 💎 License
- 📝 Markdown driven
- You can define a template with
<h1>
and code block. - It will be a Documetable template !
- Define meta information with extended syntax using Front Matter.
- You can define a template with
- ⚒️ Simple & Powerful template syntax
- A simple syntax similar to mustache.js. (
{{ inputs.value }}
) - Function execution similar to pipe syntax. (
{{ inputs.value | fn }}
) - Provide minimum necessary functions in built-in.
- A simple syntax similar to mustache.js. (
- 🚀 Ready to use
- You can quickly start using
$ scaffdog init
.
- You can quickly start using
- Node.js v12.10 +
scaffdog
can be installed globally, but we recommend installing it locally on the project.
$ npm install --save-dev scaffdog
In the following tutorial you can start using scaffdog
immediately !
By default, it stores the document file and configuration file in the .scaffdog
directory.
Creating directories, configuration file and initial documents can be done with the init
subcommand.
$ npx scaffdog init
? Please enter a document name. hello
Setup of scaffdog 🐶 is complete!
✔ .scaffdog/config.js
✔ .scaffdog/hello.md
Now you can do scaffold by running `$ scaffdog generate`.
Please refer to the following documents and customize it.
https://github.com/cats-oss/scaffdog/#templates
After running the command, the .scaffdog/hello.md
file should have been generated.
Let's scaffold using the hello
document!
$ npx scaffdog generate hello
? Please select the output destination directory. .
? Please enter any text. pretty-dog
🐶 Generated 1 file!
✔ pretty-dog.md
Congratulations 🎉
The first file was generated.
$ cat pretty-dog.md
Let's make a document! See more detail scaffdog repository.
https://github.com/cats-oss/scaffdog/#templates
Please refer to this document and customize the document file 👍
There are important changes in the major update.
See Migration Guide.
scaffdog uses the object exported in .scaffdog/config.js
as the configuration.
In the files
field, specify the path pattern of the document used by scaffdog. The files
field is required.
module.exports = {
files: ['./*'],
};
You can define the global variables available in the template in the variables
field.
module.exports = {
files: ['./*'],
variables: {
key: 'value',
},
};
You can define the custom helpers available in the template in the helpers
field.
module.exports = {
files: ['./*'],
helpers: [
// Using Key-Value
{
trim: (context, value) => value.trim(),
},
// Using Helper Registry
(registry) => {
registry.set('padstart', (context, value, size, str) =>
value.padStart(size, str || ' '),
);
registry.set('padend', (context, value, size, str) =>
value.padEnd(size, str || ' '),
);
},
],
};
The context
passed to the first argument of the helper function has the following structure.
type Variable =
| string
| {
[key in string | number]: Variable;
}
| Variable[];
type VariableMap = Map<string, Variable>;
type Helper = (context: Context, ...args: any[]) => string;
type HelperMap = Map<string, Helper>;
type TagPair = Readonly<[open: string, close: string]>;
type Context = {
cwd: string;
variables: VariableMap;
helpers: HelperMap;
tags: TagPair;
};
The default tag delimiter available in templates is {{
and }}
.
You can change it with tags
.
module.exports = {
files: ['./*'],
tags: ['<%', '%>'],
};
By setting the above config, <%
and %>
will be the tag delimiters in the template.
<% inputs.name %>
Prepare to use scaffdog. Create a .scaffdog
directory by default, and create a first document file.
Options:
-p, --project Directory to load the scaffdog project. [string] [default: ".scaffdog"]
-v, --verbose Enable logging. [boolean]
--help Show help [boolean]
--version Output the version number [boolean]
Build a scaffold using the specified template. If you do not specify the template name and execute it, interactively select the template.
Positionals:
name [string]
Options:
-p, --project Directory to load the scaffdog project. [string] [default: ".scaffdog"]
-v, --verbose Enable logging. [boolean]
--help Show help [boolean]
--version Output the version number [boolean]
-n, --dry-run Output the result to stdout. [boolean]
Create a document file with the specified name.
Positionals:
name Specify a document file name. [string]
Options:
-p, --project Directory to load the scaffdog project. [string] [default: ".scaffdog"]
-v, --verbose Enable logging. [boolean]
--help Show help [boolean]
--version Output the version number [boolean]
-y, --yes Use default options. [boolean]
Print a list of available documents.
Options:
-p, --project Directory to load the scaffdog project. [string] [default: ".scaffdog"]
-v, --verbose Enable logging. [boolean]
--help Show help [boolean]
--version Output the version number [boolean]
Template documents are defined with <h1>
and code blocks. <h1>
is interpreted as the file name and code blocks as the template body.
Meta information is defined using Front Matter.
---
name: 'utility'
root: 'src/utils'
output: '**/*'
ignore: []
questions:
name: 'Please enter a filename.'
---
# Variables
- constant_key: value
- computed_key: `{{ inputs.name | pascal }}`
# `{{ inputs.name }}.js`
```javascript
export const {{ inputs.name | camel }} = () => true;
```
# `__tests__/{{ inputs.name }}.test.js`
```javascript
import { {{ inputs.name | camel }} } from '../{{ inputs.name }}';
describe('{{ inputs.name | camel }}', () => {
test('__TODO__', () => {
expect({{ inputs.name | camel }}()).toBe(true);
});
});
```
The Variables
section is special and is not output to a file. The key-value (key: value
) list allows you to declare variables that can be used in common templates.
This is useful for processing input values that are commonly used in templates.
If you want to define variables in file scope, please see the FAQ.
Between {{
and }}
is interpreted as a tag. Whitespace in tag contents is ignored.
The given variable name is output. See the Variables section for the variables that can be used.
{{ <identifier> }}
Example:
{{ inputs.value }}
Trim the expression to be expanded and the space and line feed around it.
Use {{-
to trim before the tag, and -}}
to trim after the tag.
{{- <expression> -}}
Example:
before {{- "text" }} after
before {{ "text" -}} after
before {{- "text" -}} after
Output:
beforetext after
before textafter
beforetextafter
You can use comment out to keep the template readable. Of course, it is not deployed as a template.
{{ /* a comment */ }}
Execute the helper function with the specified name. Arguments are separated by whitespace. See the Helpers section for the helpers that can be used.
{{ <helper> <argument> ... }}
Example:
{{ relative "../" }}
You can chain output values or helper results with pipes. This is a helper similar to shell.
{{ <identifier> | <helper> }}
{{ <identifier> | <helper> <argument> ... }}
Example:
{{ inputs.value | upper }}
{{ inputs.value | replace "$.ts" ".js" | pascal }}
{{ basename | replace extname ".js" | pascal }}
List of attributes that can be specified with Front Matter.
key | required | type | description |
---|---|---|---|
name |
true |
string |
Name of template. |
root |
true |
string |
The directory as the starting point of the output destination. |
output |
true |
string |
Directory starting from root and being a destination candidate. You can use glob syntax. (see globby document) |
ignore |
false |
string[] |
Directory to exclude from candidate output destination. You can use glob syntax. (see globby document) |
questions |
false |
object |
Message to display when accepting input. |
questions
defines the question to be used in prompt with key-value. The values you answer can be used in a variable called inputs
. (e.g. inputs.key1
, inputs.value
)
---
questions:
# Shortest syntax, using `input` prompt.
key1: 'Message'
# Using `input` prompt.
key2:
message: 'Message'
# Using `input` prompt, with default value.
key3:
message: 'Message'
initial: 'Initial Value'
# Using `list` prompt.
key4:
message: 'Message'
choices: ['A', 'B', 'C']
---
List of variables available in the template. You need to be aware that the file name and the variables available in the template body are different.
key | description | example |
---|---|---|
inputs |
The object value received at the prompt. |
key | description | example |
---|---|---|
inputs |
The object value received at the prompt. | |
output.name |
The name of the output destination file excluding the extension. | scaffdog |
output.base |
The name of the output destination file including the extension. | scaffdog.js |
output.ext |
The destination file name extension. | .js |
output.dir |
The destination directory name. | src |
output.path |
The path of the destination file. | src/scaffdog.js |
output.abs |
The absolute path of the destination file. | /path/to/src/scaffdog.js |
document.name |
The document name. | hello |
document.path |
The path of the document file. | /path/to/.scaffdog/hello.md |
When invoked on a pipe, the previous processing result is passed to the first argument.
name | arguments | description |
---|---|---|
camel |
[value: string] |
Conversion to a camel case. |
snake |
[value: string] |
Conversion to a snake case. |
pascal |
[value: string] |
Conversion to a pascal case. |
kebab |
[value: string] |
Conversion to a kebab case. |
constant |
[value: string] |
Conversion to a constant case. |
upper |
[value: string] |
Conversion to a upper case. |
lower |
[value: string] |
Conversion to a lower case. |
replace |
[value: string, pattern: string, replacement: string] |
Replace pattern withreplacement . pattern is specified as a string, but it is treated as a regular expression. |
trim |
[value: string] |
Alias for String.prototype.trim . |
ltrim |
[value: string] |
Alias for String.prototype.trimStart . |
rtrim |
[value: string] |
Alias for String.prototype.trimEnd . |
eval |
[code: string] |
Executes the specified code and returns the result. |
date |
[format?: string] |
See the dayjs documentation for format details. |
noop |
[] |
Returns an empty string. |
define |
[value: string, key: string] |
Defines a local variable in the template scope. |
relative |
[path: string] |
Convert the path from the template file to the path from the destination file. |
read |
[path: string] |
Read the specified file. The contents of the loaded file are also expanded as a template. |
We provide a Prettier plugin that automatically formats scaffdog templates 🐶 💅
Install via npm:
$ npm install --save-dev prettier-plugin-scaffdog
For more information on this plugin, please refer to here.
Is it possible to define variables in the template?
scaffdog does not support variable definitions syntactically.
However, it is possible to define variables in combination with helper functions 🎉
See the following example.
{{- output.path | replace "^src/" "" | define "out" -}}
{{ output.path }}
{{ out }}
{{ out | replace "/" "-" }}
The output is as follows:
src/utils/input.js
utils/input.js
utils-input.js
Defined a variable called out
which is a processed version of output.path
. This is made up of some magic.
- Save the calculation result to
out
withdefine
helper function. - The variable definition tag trims whitespaces. (use
{{-
and-}}
)
Is it possible to use scaffdog as an API?
Yes, scaffdog consists of a monorepo that is divided into low-level packages so that APIs can be used separately.
If you want to create a custom workflow using scaffdog, consider using @scaffdog/engine, which is the lowest level API.
We are always welcoming your contribution 👏
- Fork (https://github.com/cats-oss/scaffdog) 🎉
- Create a feature branch ☕
- Run test suite with the
$ yarn test
command and confirm that it passes ⚡ - Commit your changes 📝
- Rebase your local changes against the
canary
branch 💡 - Create new Pull Request 💌
Bugs, feature requests and comments are more than welcome in the issues.
Run Unit test with ava.
$ yarn test
Run lint with ESLint.
$ yarn lint
Run formatting with ESLint (--fix
) and Prettier.
$ yarn format