docs: rewrite docs

This commit is contained in:
2026-03-26 23:56:54 +02:00
parent 5b5a1fa9a4
commit c797893eb5
7 changed files with 665 additions and 666 deletions

View File

@@ -1,31 +1,40 @@
---
title: Template Files
title: Templates
---
# Preparing template files
# Templates
Put your template files anywhere, and fill them with tokens for replacement.
Templates are regular files in a directory. Both **file names** and **file contents** support
[Handlebars.js](https://handlebarsjs.com/) syntax for token replacement.
Each template (not file) in the config array is parsed individually, and copied to the output
directory. If a single template path contains multiple files (e.g. if you use a folder path or a
glob pattern), the first directory up the tree of that template will become the base inside the
defined output path for that template, while copying files recursively and maintaining their
relative structure.
## How Templates Are Resolved
Examples:
Each path in the `templates` array is resolved individually. If a path points to a directory or glob
pattern containing multiple files, the first directory up the tree becomes the base path — files are
then copied recursively into `output`, preserving their relative structure.
> In the following examples, the config `name` is `AppName`, and the config `output` is `src`.
> In the examples below, `name` is `AppName` and `output` is `src`.
| Input template | Files in template | Output path(s) |
| Template path | Files found | Output |
| ----------------------------- | ------------------------------------------------------ | ------------------------------------------------------------ |
| `./templates/{{ name }}.txt` | `./templates/{{ name }}.txt` | `src/AppName.txt` |
| `./templates/directory` | `outer/{{name}}.txt`,<br />`outer2/inner/{{name}}.txt` | `src/outer/AppName.txt`,<br />`src/outer2/inner/AppName.txt` |
| `./templates/others/**/*.txt` | `outer/{{name}}.jpg`,<br />`outer2/inner/{{name}}.txt` | `src/outer2/inner/AppName.txt` |
## Ignoring files
### Glob Patterns & Exclusions
You can create a `.scaffoldignore` file in your template directory to exclude files from being
copied to the output. It works like `.gitignore` — one pattern per line, comments with `#`.
Template paths support glob patterns and negation with `!`:
```js
{
templates: ["templates/component/**", "!templates/component/README.md"]
}
```
## Ignoring Files
Place a `.scaffoldignore` file in your template directory to exclude files. It works like
`.gitignore` — one pattern per line, `#` for comments.
```text
# .scaffoldignore
@@ -38,120 +47,88 @@ dist/**
The `.scaffoldignore` file itself is never copied to the output.
Patterns are matched against both the file's basename and its path relative to the template
directory, so `README.md` will match at any depth, while `dist/**` only matches a `dist` directory
at the template root.
directory, so `README.md` matches at any depth while `dist/**` only matches a `dist` directory at
the template root.
## Variable/token replacement
## Token Replacement
Scaffolding will replace `{{ varName }}` in both the file name and its contents and put the
transformed files in the output directory.
Handlebars expressions like `{{ name }}` are replaced in both file names and file contents. The
`name` variable is always available — it's the name you pass when running the scaffold.
The data available for the template parser is the data you pass to the `data` config option (or
`--data` argument in CLI).
For example, using the following command:
Any additional data from `--data`, `-D`, `data` config, or [inputs](configuration_files#inputs) is
also available.
```bash
npx simple-scaffold@latest \
--templates templates/components/{{name}}.jsx \
--output src/components \
--create-sub-folder true \
npx simple-scaffold \
-t templates/component/{{name}}.jsx \
-o src/components \
MyComponent
```
Will output a file with the path:
This produces `src/components/MyComponent.jsx`, with all tokens inside the file replaced as well.
```text
<working_dir>/src/components/MyComponent.jsx
```
All standard Handlebars features work — `{{#if}}`, `{{#each}}`, `{{#with}}`, and more. See
[Handlebars.js Language Features](https://handlebarsjs.com/guide/#language-features) for details.
The contents of the file will be transformed in a similar fashion.
## Built-in Helpers
Your `data` will be pre-populated with the following:
Simple Scaffold includes helpers you can use in templates and file names. Helpers can also be
nested: `{{ pascalCase (snakeCase name) }}`.
- `{{name}}`: raw name of the component as you entered it
### Case Helpers
> Simple-Scaffold uses [Handlebars.js](https://handlebarsjs.com/) for outputting the file contents.
> Any `data` you add in the config will be available for use with their names wrapped in `{{` and
> `}}`. Other Handlebars built-ins such as `each`, `if` and `with` are also supported, see
> [Handlebars.js Language Features](https://handlebarsjs.com/guide/#language-features) for more
> information.
| Helper | Usage | `my name` becomes |
| ------------ | ----------------------- | ----------------- |
| _(none)_ | `{{ name }}` | `my name` |
| `camelCase` | `{{ camelCase name }}` | `myName` |
| `pascalCase` | `{{ pascalCase name }}` | `MyName` |
| `snakeCase` | `{{ snakeCase name }}` | `my_name` |
| `kebabCase` | `{{ kebabCase name }}` | `my-name` |
| `hyphenCase` | `{{ hyphenCase name }}` | `my-name` |
| `startCase` | `{{ startCase name }}` | `My Name` |
| `upperCase` | `{{ upperCase name }}` | `MY NAME` |
| `lowerCase` | `{{ lowerCase name }}` | `my name` |
## Helpers
### Date Helpers
### Built-in Helpers
Both `now` and `date` use [`date-fns`](https://date-fns.org/docs/format) format tokens.
Simple-Scaffold provides some built-in text transformation filters usable by Handlebars.
| Helper | Example | Output |
| -------------------- | ---------------------------------------------------------------- | ------------------- |
| `now` | `{{ now "yyyy-MM-dd HH:mm" }}` | `2042-01-01 15:00` |
| `now` (with offset) | `{{ now "yyyy-MM-dd HH:mm" -1 "hours" }}` | `2042-01-01 14:00` |
| `date` | `{{ date "2042-01-01T15:00:00Z" "yyyy-MM-dd HH:mm" }}` | `2042-01-01 15:00` |
| `date` (with offset) | `{{ date "2042-01-01T15:00:00Z" "yyyy-MM-dd HH:mm" -1 "days" }}` | `2041-12-31 15:00` |
| `date` (from data) | `{{ date myCustomDate "yyyy-MM-dd HH:mm" }}` | _(depends on data)_ |
For example, you may use `{{ snakeCase name }}` inside a template file or filename, and it will
replace `My Name` with `my_name` when producing the final value.
#### Capitalization Helpers
| Helper name | Example code | Example output |
| ------------ | ----------------------- | -------------- |
| [None] | `{{ name }}` | my name |
| `camelCase` | `{{ camelCase name }}` | myName |
| `snakeCase` | `{{ snakeCase name }}` | my_name |
| `startCase` | `{{ startCase name }}` | My Name |
| `kebabCase` | `{{ kebabCase name }}` | my-name |
| `hyphenCase` | `{{ hyphenCase name }}` | my-name |
| `pascalCase` | `{{ pascalCase name }}` | MyName |
| `upperCase` | `{{ upperCase name }}` | MY NAME |
| `lowerCase` | `{{ lowerCase name }}` | my name |
#### Date helpers
| Helper name | Description | Example code | Example output |
| -------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------ |
| `now` | Current date with format | `{{ now "yyyy-MM-dd HH:mm" }}` | `2042-01-01 15:00` |
| `now` (with offset) | Current date with format, and with offset | `{{ now "yyyy-MM-dd HH:mm" -1 "hours" }}` | `2042-01-01 14:00` |
| `date` | Custom date with format | `{{ date "2042-01-01T15:00:00Z" "yyyy-MM-dd HH:mm" }}` | `2042-01-01 15:00` |
| `date` (with offset) | Custom date with format, and with offset | `{{ date "2042-01-01T15:00:00Z" "yyyy-MM-dd HH:mm" -1 "days" }}` | `2041-31-12 15:00` |
| `date` (with date from `--data`) | Custom date with format, with data from the `data` config option | `{{ date myCustomDate "yyyy-MM-dd HH:mm" }}` | `2042-01-01 12:00` |
Further details:
- We use [`date-fns`](https://date-fns.org/docs/) for parsing/manipulating the dates. If you want
more information on the date tokens to use, refer to
[their format documentation](https://date-fns.org/docs/format).
- The date helper format takes the following arguments:
```typescript
(
date: string,
format: string,
offsetAmount?: number,
offsetType?: "years" | "months" | "weeks" | "days" | "hours" | "minutes" | "seconds"
)
```
- **The now helper** (for current time) takes the same arguments, minus the first one (`date`) as it
is implicitly the current date:
```typescript
(
format: string,
offsetAmount?: number,
offsetType?: "years" | "months" | "weeks" | "days" | "hours" | "minutes" | "seconds"
)
```
### Custom Helpers
You may also add your own custom helpers using the `helpers` options when using the JS API (rather
than the CLI). The `helpers` option takes an object whose keys are helper names, and values are the
transformation functions. For example, `upperCase` is implemented like so:
**Signatures:**
```typescript
config.helpers = {
upperCase: (text) => text.toUpperCase(),
now(format: string, offsetAmount?: number, offsetType?: "years" | "months" | "weeks" | "days" | "hours" | "minutes" | "seconds")
date(date: string, format: string, offsetAmount?: number, offsetType?: "years" | "months" | "weeks" | "days" | "hours" | "minutes" | "seconds")
```
## Custom Helpers
You can register custom Handlebars helpers via the `helpers` config option:
```js
module.exports = {
component: {
templates: ["templates/component"],
output: "src/components",
helpers: {
shout: (text) => text.toUpperCase() + "!!!",
},
},
}
```
All of the above helpers (built in and custom) will also be available to you when using
`subdirHelper` (`--sub-dir-helper`/`-H`) as a possible value.
Then use in templates: `{{ shout name }}`.
> To see more information on how helpers work and more features, see
> [Handlebars.js docs](https://handlebarsjs.com/guide/#custom-helpers).
All helpers (built-in and custom) are also available as values for `subdirHelper` (`--subdir-helper`
/ `-H`).
For more on Handlebars helpers, see the
[Handlebars.js docs](https://handlebarsjs.com/guide/#custom-helpers).

View File

@@ -2,53 +2,137 @@
title: Configuration Files
---
If you want to have reusable configurations which are complex and don't fit into command lines
easily, or just want to manage your templates easier, you can use configuration files to load your
scaffolding configurations.
# Configuration Files
## Creating config files
Config files let you define reusable scaffold definitions — template paths, output directories,
custom data, inputs, and hooks — all in one place.
Configuration files should be valid `.js`/`.mjs`/`.cjs`/`.json` files that contain valid Scaffold
configurations.
## Creating a Config File
Each file hold multiple scaffolds. Each scaffold is a key, and its value is the configuration. For
example:
The fastest way is to run `init`:
```sh
npx simple-scaffold init
```
This creates a `scaffold.config.js` and an example template in `templates/default/`. See
[`init` command](cli#init) for options.
### Config Structure
A config file exports an object mapping **template keys** to scaffold configurations:
```js
// scaffold.config.js
module.exports = {
component: {
templates: ["templates/component"],
output: "src/components",
},
page: {
templates: ["templates/page"],
output: "src/pages",
subdir: true,
},
}
```
For the full configuration options, see [ScaffoldConfig](../api/interfaces/ScaffoldConfig).
For the full list of options, see [ScaffoldConfig](../api/interfaces/ScaffoldConfig) or the
[Node.js API](node) page.
If you want to supply functions inside the configurations, you must use a `.js`/`.cjs`/`.mjs` file
as JSON does not support non-primitives.
### Dynamic Configs
Another feature of using a JS file is you can export a function which will be loaded with the CMD
config provided to Simple Scaffold. The `extra` key contains any values not consumed by built-in
flags, so you can pre-process your args before outputting a config:
JS config files can export a **function** that receives the CLI config and returns the scaffold map.
This lets you pre-process arguments or add logic:
```js
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
module.exports = (config) => {
console.log("Config:", config)
return {
component: {
templates: ["templates/component"],
output: "src/components",
},
}
module.exports = (config) => ({
component: {
templates: ["templates/component"],
output: "src/components",
data: { timestamp: Date.now() },
},
})
```
The function can also be `async`.
### Supported Formats
- `.js` (CommonJS)
- `.cjs` (CommonJS, explicit)
- `.mjs` (ESM)
- `.json`
:::note The correct extension may depend on your `package.json` `"type"` field. Packages with
`"type": "module"` may require `.mjs` or `.cjs` instead of `.js`. :::
## Using a Config File
### Auto-detection
Simple Scaffold automatically searches the current directory for a config file — no `--config` flag
needed. The following names are tried in order:
1. `scaffold.config.{mjs,cjs,js,json}`
2. `scaffold.{mjs,cjs,js,json}`
3. `.scaffold.{mjs,cjs,js,json}`
```sh
# Just run from the project root — config is found automatically
npx simple-scaffold -k component MyComponent
```
### Explicit Path
Use `--config` (`-c`) to point to a specific file or directory:
```sh
npx simple-scaffold -c path/to/scaffold.config.js -k component MyComponent
```
When a directory is given, the auto-detection order above is used within that directory.
### Default Template Key
If you don't provide `--key`, the `default` key is used:
```js
module.exports = {
default: {
templates: ["templates/default"],
output: "src",
},
}
```
### Template Inputs
```sh
# Uses the "default" key — no -k needed
npx simple-scaffold MyProject
```
You can define **inputs** in your config to prompt users for custom values when scaffolding. Each
input becomes a template data variable:
If multiple keys exist and no `--key` is provided, you'll be prompted to select one interactively.
### Providing a Default Name
If your template doesn't need a dynamic name (e.g. common config files), set `name` in the config:
```js
module.exports = {
eslint: {
name: ".eslintrc",
templates: ["templates/eslint"],
output: ".",
},
}
```
The name can still be overridden with `--name` on the command line.
## Inputs
Inputs define custom fields that are prompted interactively and become template data variables:
```js
module.exports = {
@@ -69,146 +153,53 @@ module.exports = {
}
```
In your templates, use these as `{{ author }}`, `{{ license }}`, `{{ private }}`, `{{ port }}`.
Use them in templates as `{{ author }}`, `{{ license }}`, `{{ private }}`, `{{ port }}`.
Supported input types: `text` (default), `select`, `confirm`, `number`. See
[Template Inputs](cli#template-inputs) for the full reference.
**Input types:**
- **Required** inputs are prompted interactively if not provided via `--data` or `-D`
| Type | Description | Value type |
| --------- | ------------------------------ | ---------- |
| `text` | Free-form text input (default) | `string` |
| `select` | Choose from a list of options | `string` |
| `confirm` | Yes/no prompt | `boolean` |
| `number` | Numeric input | `number` |
**Behavior:**
- **Required** inputs are prompted if not provided via `--data` or `-D`
- **Select and confirm** inputs are always prompted unless pre-provided
- **Optional** inputs with a `default` use that value silently if not provided
- In non-interactive environments, only defaults are applied
- **Optional** inputs with a `default` use that value silently
- In non-interactive environments (CI, piped input), only defaults are applied
If you want to provide templates that need no name (such as common config files which are easily
portable between projects), you may provide the `name` property in the config object.
You will always be able to override it using `--name NewName`, but it will be given a value by
default and therefore it will no longer be required in the CLI arguments.
## Using a config file
### Auto-detection
By default, Simple Scaffold automatically searches the current working directory for a config file.
No `--config` flag is needed if your config file uses one of the standard names.
The following files are tried in order:
1. `scaffold.config.mjs`
2. `scaffold.config.cjs`
3. `scaffold.config.js`
4. `scaffold.config.json`
5. `scaffold.mjs`
6. `scaffold.cjs`
7. `scaffold.js`
8. `scaffold.json`
9. `.scaffold.mjs`
10. `.scaffold.cjs`
11. `.scaffold.js`
12. `.scaffold.json`
If a config file is found, it is loaded automatically. If multiple templates are defined and no
`--key` is provided, you'll be prompted to select one interactively.
Pre-fill inputs from the CLI:
```sh
# Just run from a directory containing scaffold.config.js — no flags needed
simple-scaffold MyComponentName
npx simple-scaffold -k component -D author=John -D license=MIT MyComponent
```
### Explicit config path
## Remote Templates (Git)
You can also provide a specific file or directory path using `--config` (or `-c`), optionally
alongside `--key` or `-k`:
```sh
simple-scaffold -c <file> -k <template_key>
```
For example:
```sh
simple-scaffold -c scaffold.json -k component MyComponentName
```
When a directory is given, the same auto-detection order listed above is used to find a config file
within that directory.
### Default template key
If you don't supply a template key (e.g. `component`), `default` will be used:
```js
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
module.exports = {
default: {
// ...
},
}
```
```sh
# will use 'default' template
simple-scaffold -c scaffold.json MyComponentName
```
If multiple keys exist and no key is specified, you'll be prompted to choose one interactively.
### Supported file types
Any importable file is supported, depending on your build process.
Common extensions:
- `.mjs`
- `.cjs`
- `.js`
- `.json`
Note that you might need to find the correct extension of `.js`, `.cjs` or `.mjs` depending on your
build process and your package type (for example, packages with `"type": "module"` in their
`package.json` might be required to use `.mjs`.)
### Git/GitHub Templates
You may specify a git or GitHub url to use remote templates.
The command line option is `--git` or `-g`.
- You may specify a full git or HTTPS git URL, which will be tried
- You may specify a git username and project if the project is on GitHub
Load config files and templates from any Git repository:
```sh
# GitHub shorthand
simple-scaffold -g <username>/<project_name> [-c <filename>] [-k <template_key>]
npx simple-scaffold -g username/repo -k component MyComponent
# Any git URL, git:// and https:// are supported
simple-scaffold -g git://gitlab.com/<username>/<project_name> [-c <filename>] [-k <template_key>]
simple-scaffold -g https://gitlab.com/<username>/<project_name>.git [-c <filename>] [-k <template_key>]
# Full Git URL (GitLab, Bitbucket, etc.)
npx simple-scaffold -g https://gitlab.com/user/repo.git -k component MyComponent
```
When a config file path is omitted, the files given in the list above will be tried on the root
directory of the git repository.
When `--config` is omitted, the standard auto-detection order is used within the cloned repo. The
repository is cloned to a temporary directory and cleaned up automatically.
**Note:** The repository will be cloned to a temporary directory and removed after the scaffolding
has been done.
## Use In Node.js
You can also start a scaffold from Node.js with a remote file or URL config.
Just use the `Scaffold.fromConfig` function:
### From Node.js
```ts
Scaffold.fromConfig(
"scaffold.config.js", // file or HTTPS git URL
{
// name of the generated component
name: "My Component",
// key to load from the config
key: "component",
},
{
// other config overrides
},
import Scaffold from "simple-scaffold"
const scaffold = await Scaffold.fromConfig(
"https://github.com/user/repo.git", // or a local file path
{ name: "MyComponent", key: "component" },
)
await scaffold.run()
```

View File

@@ -1,243 +1,162 @@
---
title: CLI Usage
title: CLI
---
## Available flags
# CLI
```text
Usage: simple-scaffold [options]
```sh
npx simple-scaffold [options] [name]
```
To see this and more information anytime, add the `-h` or `--help` flag to your call, e.g.
`npx simple-scaffold@latest -h`.
Use `--help` (`-h`) to see all available options at any time.
Options:
## Commands
| Option/flag \| Alias | Description |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name` \| `-n` | Name to be passed to the generated files. `{{name}}` and other data parameters inside contents and file names will be replaced accordingly. If omitted in an interactive terminal, you will be prompted. |
| `--config` \| `-c` | Filename or directory to load config from. If omitted, the current directory is searched automatically for a config file (see [Auto-detection](configuration_files#auto-detection)). |
| `--git` \| `-g` | Git URL or GitHub path to load a template from. |
| `--key` \| `-k` | Key to load inside the config file. If omitted and multiple templates are available, you will be prompted to select one. |
| `--output` \| `-o` | Path to output to. If `--subdir` is enabled, the subdir will be created inside this path. If omitted in an interactive terminal, you will be prompted. |
| `--templates` \| `-t` | Template files to use as input. You may provide multiple files, each of which can be a relative or absolute path, or a glob pattern for multiple file matching easily. If omitted in an interactive terminal, you will be prompted for a comma-separated list. |
| `--overwrite` \| `-w` \| `--no-overwrite` \| `-W` | Enable to override output files, even if they already exist. (default: false) |
| `--data` \| `-d` | Add custom data to the templates. By default, only your app name is included. |
| `--append-data` \| `-D` | Append additional custom data to the templates, which will overwrite `--data`, using an alternate syntax, which is easier to use with CLI: `-D key1=string -D key2:=raw` |
| `--subdir` \| `-s` \| `--no-subdir` \| `-S` | Create a parent directory with the input name (and possibly `--subdir-helper` (default: false) |
| `--subdir-helper` \| `-H` | Default helper to apply to subdir name when using `--subdir`. |
| `--quiet` \| `-q` | Suppress output logs (Same as `--log-level none`)(default: false) |
| `--log-level` \| `-l` | Determine amount of logs to display. The values are: `none, debug, info, warn, error`. The provided level will display messages of the same level or higher. (default: info) |
| `--before-write` \| `-B` | Run a script before writing the files. This can be a command or a path to a file. A temporary file path will be passed to the given command and the command should return a string for the final output. |
| `--after-scaffold` \| `-A` | Run a shell command after all files have been written. The command is executed in the output directory (e.g. `--after-scaffold 'npm install'`). |
| `--dry-run` \| `-dr` | Don't emit files. This is good for testing your scaffolds and making sure they don't fail, without having to write actual file contents or create directories. (default: false) |
| `--version` \| `-v` | Display version. |
### Interactive Mode
When running in a terminal (TTY), Simple Scaffold will prompt for any missing required values:
- **Name** — text input if `--name` is not provided
- **Template key** — selectable list if `--key` is not provided and the config file has multiple
templates
- **Output directory** — text input if `--output` is not provided
- **Template paths** — comma-separated text input if `--templates` is not provided
In non-interactive environments (CI, piped input), missing values will cause an error instead of
prompting.
### Template Inputs
Config files can define **inputs** — custom fields that are prompted interactively and injected as
template data. This is useful for templates that need user-specific values like author name,
license, or description.
```js
module.exports = {
component: {
templates: ["templates/component"],
output: "src/components",
inputs: {
author: { message: "Author name", required: true },
license: {
type: "select",
message: "License",
options: ["MIT", "Apache-2.0", "GPL-3.0"],
},
private: { type: "confirm", message: "Private package?", default: false },
port: { type: "number", message: "Dev server port", default: 3000 },
description: { message: "Description" },
},
},
}
```
Each input becomes available as a Handlebars variable in your templates (e.g., `{{ author }}`,
`{{ license }}`).
**Input types:**
| Type | Description | Value type |
| --------- | ------------------------------ | ---------- |
| `text` | Free-form text input (default) | `string` |
| `select` | Choose from a list of options | `string` |
| `confirm` | Yes/no prompt | `boolean` |
| `number` | Numeric input | `number` |
- **Required inputs** without a value will be prompted interactively
- **Select and confirm** inputs are always prompted (unless pre-provided)
- **Optional text/number inputs** with a `default` will use that value silently
- All inputs can be pre-provided via `--data` or `-D` to skip the prompt:
```shell
simple-scaffold -c scaffold.config.js -k component -D author=John -D license=Apache-2.0 MyComponent
```
### Before Write option
This option allows you to preprocess a file before it is being written, such as running a formatter,
linter or other commands.
To use this option, pass it the command you would like to run. The following tokens will be replaced
in your string:
- `{{path}}` - the temporary file path for you to read from
- `{{rawpath}}` - a different file path containing the raw file contents **before** they were
handled by Handlebars.js.
If none of these tokens are found, the regular (non-raw) path will be appended to the end of the
command.
```shell
simple-scaffold -c . --before-write prettier
# command: prettier /tmp/somefile
simple-scaffold -c . --before-write 'cat {{path}} | my-linter'
# command: cat /tmp/somefile | my-linter
```
The command should return the string to write to the file through standard output (stdout), and not
re-write the tmp file as it is not used for writing. Returning an empty string (after trimming) will
discard the result and write the original file contents.
See
[beforeWrite](https://chenasraf.github.io/simple-scaffold/docs/api/interfaces/ScaffoldConfig#beforewrite)
Node.js API for more details. Instead of returning `undefined` to keep the default behavior, you can
output `''` for the same effect.
### After Scaffold option
This option runs a shell command after all files have been written. The command is executed in the
output directory, making it useful for post-scaffolding tasks like installing dependencies or
initializing a git repo.
```shell
simple-scaffold -c . --after-scaffold 'npm install'
simple-scaffold -c . --after-scaffold 'git init && git add .'
```
In a config file, you can use a function for more control:
```js
module.exports = {
default: {
templates: ["templates/app"],
output: ".",
afterScaffold: async ({ config, files }) => {
console.log(`Created ${files.length} files in ${config.output}`)
// run any post-processing here
},
},
}
```
The function receives a context with the resolved `config` and an array of `files` (absolute paths)
that were written.
## Available Commands:
| Command \| Alias | Description |
| ---------------- | ------------------------------------------------------------------------------------ |
| `init` | Initialize a new scaffold config file and example template in the current directory. |
| `list` \| `ls` | List all available templates for a given config. See `list -h` for more information. |
| Command | Description |
| ------------- | ----------------------------------------- |
| _(default)_ | Generate files from a template |
| `init` | Create a config file and example template |
| `list` / `ls` | List available template keys in a config |
### `init`
Creates a scaffold config file and an example template directory to get you started quickly.
Scaffolds a config file and example template directory to get you started:
```shell
simple-scaffold init
```sh
npx simple-scaffold init
npx simple-scaffold init --format mjs
npx simple-scaffold init --dir packages/my-lib
```
Options:
| Option | Description |
| ----------------- | ----------------------------------------------------------------- |
| `--dir` / `-d` | Directory to create the config in (defaults to current directory) |
| `--format` / `-f` | Config format: `js`, `mjs`, or `json` (prompts if omitted) |
| Option | Description |
| ------------------ | -------------------------------------------------------------------- |
| `--dir` \| `-d` | Directory to create the config in. Defaults to current directory. |
| `--format` \| `-f` | Config format: `js`, `mjs`, or `json`. If omitted, you are prompted. |
The command creates:
Creates:
- A config file (`scaffold.config.js` by default) with a `default` template key
- A `templates/default/` directory with an example `{{name}}.md` template
Existing files are never overwritten.
## Examples:
### `list`
> See
> [Configuration Files](https://chenasraf.github.io/simple-scaffold/docs/usage/configuration_files)
> for organizing multiple scaffold types into easy-to-maintain files
Lists all template keys defined in a config file:
Usage with config file
```shell
$ simple-scaffold -c scaffold.cmd.js -k component MyComponent
```sh
npx simple-scaffold list
npx simple-scaffold list -c path/to/config.js
npx simple-scaffold list -g username/repo
```
Usage with GitHub config file
## Options
```shell
$ simple-scaffold -g chenasraf/simple-scaffold -k component MyComponent
| Flag | Short | Description | Default |
| -------------------------------- | --------- | ----------------------------------------------------- | --------------- |
| `--name` | `-n` | Name for generated files (can also be positional arg) | |
| `--config` | `-c` | Path to config file or directory | _(auto-detect)_ |
| `--git` | `-g` | Git URL or GitHub shorthand (`user/repo`) | |
| `--key` | `-k` | Template key from config | `default` |
| `--output` | `-o` | Output directory | |
| `--templates` | `-t` | Template paths or glob patterns (repeatable) | |
| `--data` | `-d` | Custom data as JSON string | |
| `--append-data` | `-D` | Key-value data (`key=string`, `key:=raw`), repeatable | |
| `--subdir` / `--no-subdir` | `-s`/`-S` | Create parent directory with the input name | `false` |
| `--subdir-helper` | `-H` | Helper to transform subdir name | |
| `--overwrite` / `--no-overwrite` | `-w`/`-W` | Overwrite existing files | `false` |
| `--dry-run` | `-dr` | Preview output without writing files | `false` |
| `--before-write` | `-B` | Command to run before each file is written | |
| `--after-scaffold` | `-A` | Shell command to run after all files are written | |
| `--quiet` | `-q` | Suppress output (same as `--log-level none`) | |
| `--log-level` | `-l` | Log level: `none`, `debug`, `info`, `warn`, `error` | `info` |
| `--version` | `-v` | Show version | |
| `--help` | `-h` | Show help | |
## Interactive Mode
When running in a terminal (TTY), Simple Scaffold prompts for any missing required values:
- **Name** — if `--name` is not provided
- **Template key** — if `--key` is not provided and the config has multiple templates
- **Output directory** — if `--output` is not provided
- **Template paths** — if `--templates` is not provided (comma-separated)
[Inputs](configuration_files#inputs) defined in config files are also prompted interactively.
In non-interactive environments (CI, piped input), missing required values cause an error.
## Hooks
### Before Write
Runs a command before each file is written. The command receives a temporary file path and should
output the final content to stdout.
```sh
# Appends file path automatically
npx simple-scaffold -c . --before-write prettier
# Use tokens for explicit control
npx simple-scaffold -c . --before-write 'cat {{path}} | my-linter'
```
Usage with https git URL (for non-GitHub)
**Tokens:**
```shell
$ simple-scaffold \
-g https://example.com/user/template.git \
-c scaffold.cmd.js \
-k component \
MyComponent
- `{{path}}` — temporary file path with Handlebars-processed contents
- `{{rawpath}}` — temporary file path with raw (unprocessed) contents
If no tokens are found, `{{path}}` is appended automatically. Returning an empty string (after
trimming) discards the result and writes the original contents.
### After Scaffold
Runs a shell command after all files are written. The command executes in the output directory:
```sh
npx simple-scaffold -c . --after-scaffold 'npm install'
npx simple-scaffold -c . --after-scaffold 'git init && git add .'
```
Full syntax with config path and template key (applicable to all above methods)
See the [Node.js API](node#after-scaffold-hook) for the function-based equivalent.
```shell
$ simple-scaffold -c scaffold.cmd.js -k component MyComponent
## CLI Examples
```sh
# Use auto-detected config, default key
npx simple-scaffold MyProject
# Specify config and key
npx simple-scaffold -c scaffold.config.js -k component MyComponent
# GitHub remote template
npx simple-scaffold -g username/repo -k component MyComponent
# Full Git URL
npx simple-scaffold -g https://gitlab.com/user/repo.git -k component MyComponent
# One-off (no config file)
npx simple-scaffold -t templates/component -o src/components MyComponent
# With custom data
npx simple-scaffold -k component -D author=John -D license:='"MIT"' MyComponent
# Dry run
npx simple-scaffold -k component --dry-run MyComponent
```
Excluded template key, assumes 'default' key
```shell
$ simple-scaffold -c scaffold.cmd.js MyComponent
```
Shortest syntax for GitHub, assumes file 'scaffold.cmd.js' and template key 'default'
```shell
$ simple-scaffold -g chenasraf/simple-scaffold MyComponent
```
You can also add this as a script in your `package.json`:
### package.json Scripts
```json
{
"scripts": {
"scaffold-cfg": "npx simple-scaffold -c scaffold.cmd.js -k component",
"scaffold-gh": "npx simple-scaffold -g chenasraf/simple-scaffold -k component",
"scaffold": "npx simple-scaffold@latest -t scaffolds/component/**/* -o src/components -d '{\"myProp\": \"propName\", \"myVal\": 123}'"
"scaffold-component": "npx simple-scaffold -c scaffold.cmd.js -k"
"scaffold": "simple-scaffold -k component",
"scaffold:page": "simple-scaffold -k page"
}
}
```
```sh
npm run scaffold -- MyComponent
npm run scaffold:page -- Dashboard
```

View File

@@ -1,28 +1,54 @@
---
title: Node.js Usage
title: Node.js API
---
## Overview
# Node.js API
You can build the scaffold yourself, if you want to create more complex arguments, scaffold groups,
etc - simply pass a config object to the Scaffold function when you are ready to start.
Use Simple Scaffold programmatically for more complex workflows, custom logic, or integration into
build tools.
The config takes similar arguments to the command line. See the full
[API documentation](https://chenasraf.github.io/simple-scaffold/docs/api/interfaces/ScaffoldConfig)
for all configuration options and their behavior.
## Basic Usage
```ts
```typescript
import Scaffold from "simple-scaffold"
const scaffold = new Scaffold({
name: "MyComponent",
templates: ["templates/component"],
output: "src/components",
})
await scaffold.run()
```
## Loading from a Config File
```typescript
import Scaffold from "simple-scaffold"
const scaffold = await Scaffold.fromConfig(
"scaffold.config.js", // local path or HTTPS Git URL
{ name: "MyComponent", key: "component" },
{
/* optional config overrides */
},
)
await scaffold.run()
```
## Config Interface
```typescript
interface ScaffoldConfig {
name: string
templates: string[]
output: FileResponse<string>
subdir?: boolean
subdirHelper?: string
data?: Record<string, unknown>
overwrite?: FileResponse<boolean>
logLevel?: LogLevel
logLevel?: "none" | "debug" | "info" | "warn" | "error"
dryRun?: boolean
helpers?: Record<string, Helper>
subdirHelper?: DefaultHelpers | string
inputs?: Record<string, ScaffoldInput>
beforeWrite?(
content: Buffer,
@@ -31,43 +57,56 @@ interface ScaffoldConfig {
): string | Buffer | undefined | Promise<string | Buffer | undefined>
afterScaffold?: AfterScaffoldHook
}
interface ScaffoldInput {
type?: "text" | "select" | "confirm" | "number"
message?: string
required?: boolean
default?: string | boolean | number
options?: (string | { name: string; value: string })[] // for type: "select"
}
interface AfterScaffoldContext {
config: ScaffoldConfig
files: string[] // absolute paths of written files
}
type AfterScaffoldHook = ((context: AfterScaffoldContext) => void | Promise<void>) | string
```
### Before Write option
For the full API reference, see [ScaffoldConfig](../api/interfaces/ScaffoldConfig).
This option allows you to preprocess a file before it is being written, such as running a formatter,
linter or other commands.
### Options
To use this option, you can run any async/blocking command, and return a string as the final output
to be used as the file contents.
| Option | Type | Description |
| --------------- | ------------------------------- | ------------------------------------------------------------------------ |
| `name` | `string` | Name for generated files _(required)_ |
| `templates` | `string[]` | Template paths or globs; prefix with `!` to exclude _(required)_ |
| `output` | `string \| Function` | Output directory, or a function for per-file control |
| `data` | `Record<string, unknown>` | Custom data available in templates |
| `inputs` | `Record<string, ScaffoldInput>` | Interactive input definitions (see [Inputs](configuration_files#inputs)) |
| `helpers` | `Record<string, Function>` | Custom Handlebars helpers |
| `subdir` | `boolean` | Create a parent directory with the input name (default: `false`) |
| `subdirHelper` | `string` | Helper to transform the subdir name (e.g. `"pascalCase"`) |
| `overwrite` | `boolean \| Function` | Overwrite existing files (default: `false`); function for per-file logic |
| `dryRun` | `boolean` | Preview without writing files (default: `false`) |
| `logLevel` | `string` | Log verbosity (default: `"info"`) |
| `beforeWrite` | `Function` | Async hook before each file is written |
| `afterScaffold` | `Function \| string` | Hook after all files are written |
Returning `undefined` will keep the file contents as-is, after normal Handlebars.js procesing by
Simple Scaffold.
## Hooks
### After Scaffold hook
### Before Write
The `afterScaffold` option runs after all files have been written. It receives a context object with
the resolved config and the list of files that were created.
Runs before each file is written. Return a `string` or `Buffer` to replace the file contents, or
`undefined` to keep the default (Handlebars-processed) output.
```typescript
import Scaffold from "simple-scaffold"
await new Scaffold({
name: "MyComponent",
templates: ["templates/component"],
output: "src/components",
beforeWrite: async (content, rawContent, outputPath) => {
// Format the output, transform it, or return undefined to keep as-is
return content.toString().trim()
},
}).run()
```
await Scaffold({
### After Scaffold Hook
Runs after all files have been written. Pass a **function** for full control, or a **string** to run
a shell command in the output directory.
**Function:**
```typescript
await new Scaffold({
name: "my-app",
templates: ["templates/app"],
output: ".",
@@ -75,32 +114,37 @@ await Scaffold({
console.log(`Created ${files.length} files`)
// e.g. run npm install, git init, open editor, etc.
},
})
}).run()
```
You can also pass a shell command string, which will be executed in the output directory:
**Shell command:**
```typescript
await Scaffold({
await new Scaffold({
name: "my-app",
templates: ["templates/app"],
output: "my-app",
afterScaffold: "npm install && git init",
})
}).run()
```
The context object:
```typescript
interface AfterScaffoldContext {
config: ScaffoldConfig
files: string[] // absolute paths of written files
}
```
In dry-run mode, the hook is still called but the `files` array will be empty.
### Inputs
## Inputs
The `inputs` option lets you define fields that will be prompted interactively (when running in a
TTY) and merged into the template data. This is useful when your templates need user-specific
values.
Define interactive prompts that merge into template data:
```typescript
import Scaffold from "simple-scaffold"
await Scaffold({
await new Scaffold({
name: "component",
templates: ["templates/component"],
output: "src/components",
@@ -114,27 +158,36 @@ await Scaffold({
private: { type: "confirm", message: "Private package?", default: false },
port: { type: "number", message: "Dev server port", default: 3000 },
},
})
// In templates: {{ author }}, {{ license }}
}).run()
// In templates: {{ author }}, {{ license }}, {{ private }}, {{ port }}
```
```typescript
interface ScaffoldInput {
type?: "text" | "select" | "confirm" | "number"
message?: string
required?: boolean
default?: string | boolean | number
options?: (string | { name: string; value: string })[] // for type: "select"
}
```
- **Required** inputs are prompted if not already in `data`
- **Optional** inputs with a `default` are applied silently
- Pre-providing values in `data` skips the prompt for that input
## Example
This is an example of loading a complete scaffold via Node.js:
## Full Example
```typescript
import path from "path"
import Scaffold from "simple-scaffold"
await Scaffold({
name: "component",
await new Scaffold({
name: "MyComponent",
templates: [path.join(__dirname, "scaffolds", "component")],
output: path.join(__dirname, "src", "components"),
subdir: true,
subdirHelper: "upperCase",
subdirHelper: "pascalCase",
data: {
property: "value",
},
@@ -145,8 +198,11 @@ await Scaffold({
author: { message: "Author name", required: true },
license: { message: "License", default: "MIT" },
},
// return a string to replace the final file contents after pre-processing, or `undefined`
// to keep it as-is
beforeWrite: (content, rawContent, outputPath) => content.toString().toUpperCase(),
})
beforeWrite: (content, rawContent, outputPath) => {
return content.toString().toUpperCase()
},
afterScaffold: async ({ config, files }) => {
console.log(`Created ${files.length} files in ${config.output}`)
},
}).run()
```

View File

@@ -2,139 +2,185 @@
title: Examples
---
## Example files
# Examples
### Input
## React Component
- Input file path:
### Template
```text
project → scaffold → {{Name}}.js → src → components
```
**File:** `templates/component/{{pascalCase name}}.tsx`
- Input file contents:
```tsx
/**
* Author: {{ author }}
* Date: {{ now "yyyy-MM-dd" }}
*/
import React from "react"
```typescript
/**
* Author: {{ author }}
* Date: {{ now "yyyy-MM-dd" }}
*/
import React from 'react'
export default {{ pascalCase name }}: React.FC = (props) => {
return (
<div className="{{ camelCase name }}">{{ pascalCase name }} Component</div>
)
}
```
export default {{camelCase name}}: React.FC = (props) => {
return (
<div className="{{className}}">{{camelCase name}} Component</div>
)
}
```
### Config
```js
// scaffold.config.js
module.exports = {
component: {
templates: ["templates/component"],
output: "src/components",
data: {
author: "My Name",
},
},
}
```
### Running
```sh
npx simple-scaffold -k component MyComponent
```
### Output
- Output file path:
- With `subdir = false` (default):
**File:** `src/components/MyComponent.tsx`
```text
project → src → components → MyComponent.js
```
```tsx
/**
* Author: My Name
* Date: 2077-01-01
*/
import React from "react"
- With `subdir = true`:
```text
project → src → components → MyComponent → MyComponent.js
```
- With `subdir = true` and `subdirHelper = 'upperCase'`:
```text
project → src → components → MYCOMPONENT → MyComponent.js
```
- Output file contents:
```typescript
/**
* Author: My Name
* Date: 2077-01-01
*/
import React from 'react'
export default MyComponent: React.FC = (props) => {
return (
<div className="myClassName">MyComponent Component</div>
)
}
```
## Example run commands
### Command Example
```bash
simple-scaffold \
-t project/scaffold/**/* \
-o src/components \
-d '{"className": "myClassName","author": "My Name"}'
MyComponent
export default MyComponent: React.FC = (props) => {
return (
<div className="myComponent">MyComponent Component</div>
)
}
```
### Equivalent Node Module Example
## Subdir Variations
Given the template and config above, the output path changes based on `subdir` settings:
| Setting | Output path |
| ------------------------------------------- | -------------------------------------------- |
| `subdir: false` (default) | `src/components/MyComponent.tsx` |
| `subdir: true` | `src/components/MyComponent/MyComponent.tsx` |
| `subdir: true`, `subdirHelper: "upperCase"` | `src/components/MYCOMPONENT/MyComponent.tsx` |
## CLI One-liner (No Config)
```sh
npx simple-scaffold \
-t templates/component/**/* \
-o src/components \
-d '{"author": "My Name"}' \
MyComponent
```
## Node.js Equivalent
```typescript
import Scaffold from "simple-scaffold"
async function main() {
await Scaffold({
name: "MyComponent",
templates: ["project/scaffold/**/*"],
output: ["src/components"],
data: {
className: "myClassName",
author: "My Name",
},
})
console.log("Done.")
await new Scaffold({
name: "MyComponent",
templates: ["templates/component"],
output: "src/components",
data: {
author: "My Name",
},
}).run()
```
## Reusable Config Files
### CommonJS (`scaffold.config.js`)
```js
module.exports = {
default: {
templates: ["templates/component"],
output: "src/components",
},
}
```
### Re-usable config
### ESM (`scaffold.config.mjs`)
#### Shell
```bash
# cjs
simple-scaffold -c scaffold.cjs MyComponent \
-d '{"className": "myClassName","author": "My Name"}'
# mjs
simple-scaffold -c scaffold.mjs MyComponent \
-d '{"className": "myClassName","author": "My Name"}'
```js
export default {
default: {
templates: ["templates/component"],
output: "src/components",
},
}
```
#### scaffold.cjs
### Dynamic Config (with function)
```js
module.exports = (config) => ({
default: {
templates: ["project/scaffold/**/*"],
output: ["src/components"],
templates: ["templates/component"],
output: "src/components",
data: {
className: "myClassName",
author: "My Name",
generatedAt: new Date().toISOString(),
},
},
})
```
#### scaffold.mjs
## With Inputs
```js
export default (config) => ({
default: {
templates: ["project/scaffold/**/*"],
output: ["src/components"],
data: {
className: "myClassName",
author: "My Name",
// scaffold.config.js
module.exports = {
package: {
templates: ["templates/package"],
output: "packages",
subdir: true,
inputs: {
description: { message: "Package description", required: true },
author: { message: "Author", default: "Team" },
license: {
type: "select",
message: "License",
options: ["MIT", "Apache-2.0", "ISC"],
},
private: { type: "confirm", message: "Private package?", default: true },
},
},
})
}
```
```sh
# Interactive — prompts for each input
npx simple-scaffold -k package my-lib
# Non-interactive — provide all values upfront
npx simple-scaffold -k package -D description="A utility library" -D author=John my-lib
```
## With Hooks
```js
module.exports = {
app: {
templates: ["templates/app"],
output: ".",
subdir: true,
afterScaffold: "cd {{name}} && npm install && git init",
},
}
```
```sh
npx simple-scaffold -k app my-app
# Files are generated, then npm install and git init run automatically
```

View File

@@ -2,60 +2,63 @@
title: Migration
---
# Migration
## v1.x to v2.x
### CLI option changes
### CLI Changes
- Several changes to how remote configs are loaded via CLI:
- The `:template_key` syntax has been removed. You can still use `-k template_key` to achieve the
same result.
- The `--github` (`-gh`) flag has been replaced by a generic `--git` (`-g`) one, which handles any
git URL. Providing a partial GitHub path will default to trying to find the project on GitHub,
e.g. `-g username/project`
- The `#template_file` syntax has been removed, you may use `--config` or `-c` to tell Simple
Scaffold which file to look for inside the git project. There is a default file priority list
which can find the file for you if it is in one of the supported filenames.
- `verbose` can now take the names `debug`, `info`, `warn`, `error` or `none` (case insensitive).
- `--create-sub-folder` (`-s`) has been renamed to `--subdir` (`-s`) in the CLI. The Node.js names
have been changed as well.
- `--sub-folder-name-helper` (`-sh`) has been renamed to `--subdir-helper` (`-sh`). The Node.js
names have been changed as well.
- All boolean flags no longer take a value. `-q` instead of `-q 1` or `-q true`, `-s` instead of
`-s 1`, `-w` instead of `-w 1`, etc.
**Remote config syntax:**
### Behavior changes
- The `:template_key` suffix syntax has been removed. Use `-k template_key` instead.
- `--github` (`-gh`) is now `--git` (`-g`) and supports any Git URL. GitHub shorthand still works:
`-g username/project`.
- The `#template_file` suffix syntax has been removed. Use `--config` (`-c`) to specify which file
to look for inside the Git project.
- Data is no longer auto-populated with `Name` (PascalCase) by default. You can just use the helper
in your templates contents and file names, simply use `{{ pascalCase name }}` instead of
`{{ Name }}`. `Name` was arbitrary and it is confusing (is it `Title Case`? `PascalCase`? only
reading the docs can tell). Alternatively, you can inject the transformed name into your `data`
manually using a scaffold config file, by using the Node API or by appending the data to the CLI
invocation.
**Renamed flags:**
| v1.x | v2.x |
| ---------------------------------- | -------------------------------------------------------- |
| `--create-sub-folder` / `-s` | `--subdir` / `-s` |
| `--sub-folder-name-helper` / `-sh` | `--subdir-helper` / `-H` |
| `--verbose` (true/false) | `--log-level` (`debug`, `info`, `warn`, `error`, `none`) |
**Boolean flags** no longer take a value. Use `-q` instead of `-q true`, `-s` instead of `-s 1`,
etc.
### Behavior Changes
**`{{ Name }}` removed.** The auto-populated `Name` (PascalCase) variable is gone. Use
`{{ pascalCase name }}` in your templates instead. If you need the old behavior, inject it manually
via `data`:
```js
module.exports = {
default: {
templates: ["templates/default"],
output: "src",
data: { Name: "{{ pascalCase name }}" }, // or set it programmatically
},
}
```
## v0.x to v1.x
In Simple Scaffold v1.0, the entire codebase was overhauled, yet usage remains mostly the same
between versions. With these notable exceptions:
In v1.0, the codebase was overhauled but usage remained mostly the same.
- Some of the argument names have changed
- Template syntax has been improved
- The command to run Scaffold has been simplified from `new SimpleScaffold(opts).run()` to
`SimpleScaffold(opts)`, which now returns a promise that you can await to know when the process
has been completed.
### API Changes
### Argument changes
| v0.x | v1.x |
| -------------------------------- | ------------------------------------------ |
| `new SimpleScaffold(opts).run()` | `SimpleScaffold(opts)` (returns a Promise) |
| `locals` option | `data` option |
| `--locals` / `-l` flag | `--data` / `-d` flag |
- `locals` has been renamed to `data`. The appropriate command line args have been updated as well
to `--data` | `-d`.
- Additional options have been added to both CLI and Node interfaces. See
[Command Line Interface (CLI) usage](https://chenasraf.github.io/simple-scaffold/docs/usage/cli)
and [Node.js usage](https://chenasraf.github.io/simple-scaffold/docs/usage/node) for more
information.
### Template Syntax
### Template syntax changes
Templates still use Handlebars.js. v1.x added **built-in helpers** (case transformations, date
formatting), removing the need to pre-process template data for common operations like `camelCase`,
`snakeCase`, etc.
Simple Scaffold still uses Handlebars.js to handle template content and file names. However, helpers
have been added to remove the need for you to pre-process the template data on simple use-cases such
as case type manipulation (converting to camel case, snake case, etc)
See the readme for the full information on how to use these helpers and which are available.
See [Templates](templates#built-in-helpers) for the full list of available helpers.

View File

@@ -3,9 +3,16 @@ title: Usage
sidebar_position: 0
---
- [Template Files](templates)
- [Configuration Files](configuration_files)
- [CLI Usage](cli)
- [Node.js Usage](node)
- [Examples](examples)
- [Migration](migration)
# Usage
Simple Scaffold can be used as a **CLI tool** or as a **Node.js library**. Both approaches share the
same core concepts: templates, configuration files, and Handlebars-based token replacement.
- [Templates](./usage/templates) — how template files and directories work, built-in helpers, and
custom helpers
- [Configuration Files](./usage/configuration_files) — reusable scaffold definitions,
auto-detection, inputs, and remote Git templates
- [CLI](./usage/cli) — all commands, flags, interactive mode, and hooks
- [Node.js API](./usage/node) — programmatic usage, full config interface, and hooks
- [Examples](./usage/examples) — end-to-end examples for CLI and Node.js
- [Migration](./usage/migration) — upgrading from v1.x or v0.x to the latest version