` | 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()
```
diff --git a/docs/docs/usage/05-examples.md b/docs/docs/usage/05-examples.md
index 90c23d5..899a203 100644
--- a/docs/docs/usage/05-examples.md
+++ b/docs/docs/usage/05-examples.md
@@ -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 (
+ {{ pascalCase name }} Component
+ )
+}
+```
- export default {{camelCase name}}: React.FC = (props) => {
- return (
- {{camelCase name}} Component
- )
- }
- ```
+### 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 (
- MyComponent Component
- )
- }
- ```
-
-## 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 (
+ MyComponent Component
+ )
+}
```
-### 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
```
diff --git a/docs/docs/usage/06-migration.md b/docs/docs/usage/06-migration.md
index b11d13d..c8dd10b 100644
--- a/docs/docs/usage/06-migration.md
+++ b/docs/docs/usage/06-migration.md
@@ -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.
diff --git a/docs/docs/usage/index.md b/docs/docs/usage/index.md
index 64927a5..2b9503c 100644
--- a/docs/docs/usage/index.md
+++ b/docs/docs/usage/index.md
@@ -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