mirror of
https://github.com/chenasraf/simple-scaffold.git
synced 2026-05-17 17:28:09 +00:00
docs: rewrite docs
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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()
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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()
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user