Skip to content

Commit d64dd4f

Browse files
committed
feat: predefined data inputs
1 parent 519ef27 commit d64dd4f

12 files changed

Lines changed: 438 additions & 43 deletions

File tree

.prettierignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
docs/docs/api/
2+
examples/
3+
.github/
4+
CHANGELOG.md

README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313

1414
</h2>
1515

16-
Simple Scaffold is a file scaffolding tool. You define templates once, then generate files from them whenever you need — whether it's a single component or an entire app boilerplate.
16+
Simple Scaffold is a file scaffolding tool. You define templates once, then generate files from them
17+
whenever you need — whether it's a single component or an entire app boilerplate.
1718

18-
Templates use **Handlebars.js** syntax, so you can inject data, loop over lists, use conditionals, and write custom helpers. It works as a CLI or as a Node.js library, and it doesn't care what kind of files you're generating.
19+
Templates use **Handlebars.js** syntax, so you can inject data, loop over lists, use conditionals,
20+
and write custom helpers. It works as a CLI or as a Node.js library, and it doesn't care what kind
21+
of files you're generating.
1922

2023
<div align="center">
2124

@@ -92,6 +95,33 @@ See information about each option and flag using the `--help` flag, or read the
9295
[CLI documentation](https://chenasraf.github.io/simple-scaffold/docs/usage/cli). For information
9396
about how configuration files work, [see below](#configuration-files).
9497

98+
### Interactive Mode
99+
100+
When running in a terminal, Simple Scaffold will interactively prompt for any missing required
101+
values — name, output directory, template paths, and template key (if multiple are available).
102+
103+
Config files can also define **inputs** — custom fields that are prompted interactively and become
104+
template data:
105+
106+
```js
107+
module.exports = {
108+
component: {
109+
templates: ["templates/component"],
110+
output: "src/components",
111+
inputs: {
112+
author: { message: "Author name", required: true },
113+
license: { message: "License", default: "MIT" },
114+
},
115+
},
116+
}
117+
```
118+
119+
Inputs can be pre-provided via `--data` or `-D` to skip the prompt:
120+
121+
```sh
122+
npx simple-scaffold -c scaffold.config.js -k component -D author=John MyComponent
123+
```
124+
95125
### Configuration Files
96126

97127
You can use a config file to more easily maintain all your scaffold definitions.

docs/docs/usage/02-configuration_files.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ module.exports = {
2323
}
2424
```
2525

26-
For the full configuration options, see [ScaffoldConfigFile](../api/type-aliases/ScaffoldConfigFile).
26+
For the full configuration options, see
27+
[ScaffoldConfigFile](../api/type-aliases/ScaffoldConfigFile).
2728

2829
If you want to supply functions inside the configurations, you must use a `.js`/`.cjs`/`.mjs` file
2930
as JSON does not support non-primitives.
@@ -45,6 +46,31 @@ module.exports = (config) => {
4546
}
4647
```
4748

49+
### Template Inputs
50+
51+
You can define **inputs** in your config to prompt users for custom values when scaffolding. Each
52+
input becomes a template data variable:
53+
54+
```js
55+
module.exports = {
56+
component: {
57+
templates: ["templates/component"],
58+
output: "src/components",
59+
inputs: {
60+
author: { message: "Author name", required: true },
61+
license: { message: "License type", default: "MIT" },
62+
description: { message: "Component description" },
63+
},
64+
},
65+
}
66+
```
67+
68+
In your templates, use these as `{{ author }}`, `{{ license }}`, `{{ description }}`.
69+
70+
- **Required** inputs are prompted interactively if not provided via `--data` or `-D`
71+
- **Optional** inputs with a `default` use that value silently if not provided
72+
- In non-interactive environments, only defaults are applied
73+
4874
If you want to provide templates that need no name (such as common config files which are easily
4975
portable between projects), you may provide the `name` property in the config object.
5076

@@ -86,7 +112,6 @@ simple-scaffold -c scaffold.json MyComponentName
86112
```
87113

88114
- When the a directory is given, the following files in the given directory will be tried in order:
89-
90115
- `scaffold.config.*`
91116
- `scaffold.*`
92117

docs/docs/usage/03-cli.md

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,68 @@ To see this and more information anytime, add the `-h` or `--help` flag to your
1313

1414
Options:
1515

16-
| Option/flag \| Alias | Description |
17-
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18-
| `--name` \| `-n` | Name to be passed to the generated files. `{{name}}` and other data parameters inside contents and file names will be replaced accordingly. You may omit the `--name` or `-n` for this specific option. |
19-
| `--config` \| `-c` | Filename or directory to load config from |
20-
| `--git` \| `-g` | Git URL or GitHub path to load a template from. |
21-
| `--key` \| `-k` | Key to load inside the config file. This overwrites the config key provided after the colon in `--config` (e.g. `--config scaffold.cmd.js:component)` |
22-
| `--output` \| `-o` | Path to output to. If `--subdir` is enabled, the subdir will be created inside this path. Default is current working directory. |
23-
| `--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. |
24-
| `--overwrite` \| `-w` \| `--no-overwrite` \| `-W` | Enable to override output files, even if they already exist. (default: false) |
25-
| `--data` \| `-d` | Add custom data to the templates. By default, only your app name is included. |
26-
| `--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` |
27-
| `--subdir` \| `-s` \| `--no-subdir` \| `-S` | Create a parent directory with the input name (and possibly `--subdir-helper` (default: false) |
28-
| `--subdir-helper` \| `-H` | Default helper to apply to subdir name when using `--subdir`. |
29-
| `--quiet` \| `-q` | Suppress output logs (Same as `--log-level none`)(default: false) |
30-
| `--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) |
31-
| `--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. |
32-
| `--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) |
33-
| `--version` \| `-v` | Display version. |
16+
| Option/flag \| Alias | Description |
17+
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18+
| `--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. |
19+
| `--config` \| `-c` | Filename or directory to load config from |
20+
| `--git` \| `-g` | Git URL or GitHub path to load a template from. |
21+
| `--key` \| `-k` | Key to load inside the config file. If omitted and multiple templates are available, you will be prompted to select one. |
22+
| `--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. |
23+
| `--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. |
24+
| `--overwrite` \| `-w` \| `--no-overwrite` \| `-W` | Enable to override output files, even if they already exist. (default: false) |
25+
| `--data` \| `-d` | Add custom data to the templates. By default, only your app name is included. |
26+
| `--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` |
27+
| `--subdir` \| `-s` \| `--no-subdir` \| `-S` | Create a parent directory with the input name (and possibly `--subdir-helper` (default: false) |
28+
| `--subdir-helper` \| `-H` | Default helper to apply to subdir name when using `--subdir`. |
29+
| `--quiet` \| `-q` | Suppress output logs (Same as `--log-level none`)(default: false) |
30+
| `--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) |
31+
| `--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. |
32+
| `--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) |
33+
| `--version` \| `-v` | Display version. |
34+
35+
### Interactive Mode
36+
37+
When running in a terminal (TTY), Simple Scaffold will prompt for any missing required values:
38+
39+
- **Name** — text input if `--name` is not provided
40+
- **Template key** — selectable list if `--key` is not provided and the config file has multiple
41+
templates
42+
- **Output directory** — text input if `--output` is not provided
43+
- **Template paths** — comma-separated text input if `--templates` is not provided
44+
45+
In non-interactive environments (CI, piped input), missing values will cause an error instead of
46+
prompting.
47+
48+
### Template Inputs
49+
50+
Config files can define **inputs** — custom fields that are prompted interactively and injected as
51+
template data. This is useful for templates that need user-specific values like author name,
52+
license, or description.
53+
54+
```js
55+
module.exports = {
56+
component: {
57+
templates: ["templates/component"],
58+
output: "src/components",
59+
inputs: {
60+
author: { message: "Author name", required: true },
61+
license: { message: "License type", default: "MIT" },
62+
description: { message: "Description" },
63+
},
64+
},
65+
}
66+
```
67+
68+
Each input becomes available as a Handlebars variable in your templates (e.g., `{{ author }}`,
69+
`{{ license }}`).
70+
71+
- **Required inputs** without a value will be prompted interactively
72+
- **Optional inputs** with a `default` will use that value if not provided
73+
- All inputs can be pre-provided via `--data` or `-D` to skip the prompt:
74+
75+
```shell
76+
simple-scaffold -c scaffold.config.js -k component -D author=John -D license=Apache-2.0 MyComponent
77+
```
3478

3579
### Before Write option
3680

docs/docs/usage/04-node.md

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,35 @@ title: Node.js Usage
77
You can build the scaffold yourself, if you want to create more complex arguments, scaffold groups,
88
etc - simply pass a config object to the Scaffold function when you are ready to start.
99

10-
The config takes similar arguments to the command line. The full type definitions can be found in
11-
[src/types.ts](https://github.com/chenasraf/simple-scaffold/blob/develop/src/types.ts#L13).
12-
13-
See the full
14-
[documentation](https://chenasraf.github.io/simple-scaffold/interfaces/ScaffoldConfig.html) for the
15-
configuration options and their behavior.
10+
The config takes similar arguments to the command line. See the full
11+
[API documentation](https://chenasraf.github.io/simple-scaffold/docs/api/interfaces/ScaffoldConfig)
12+
for all configuration options and their behavior.
1613

1714
```ts
1815
interface ScaffoldConfig {
1916
name: string
2017
templates: string[]
2118
output: FileResponse<string>
2219
subdir?: boolean
23-
data?: Record<string, any>
20+
data?: Record<string, unknown>
2421
overwrite?: FileResponse<boolean>
25-
quiet?: boolean
26-
verbose?: LogLevel
22+
logLevel?: LogLevel
2723
dryRun?: boolean
2824
helpers?: Record<string, Helper>
2925
subdirHelper?: DefaultHelpers | string
26+
inputs?: Record<string, ScaffoldInput>
3027
beforeWrite?(
3128
content: Buffer,
3229
rawContent: Buffer,
3330
outputPath: string,
3431
): string | Buffer | undefined | Promise<string | Buffer | undefined>
3532
}
33+
34+
interface ScaffoldInput {
35+
message?: string
36+
required?: boolean
37+
default?: string
38+
}
3639
```
3740

3841
### Before Write option
@@ -46,14 +49,39 @@ to be used as the file contents.
4649
Returning `undefined` will keep the file contents as-is, after normal Handlebars.js procesing by
4750
Simple Scaffold.
4851

52+
### Inputs
53+
54+
The `inputs` option lets you define fields that will be prompted interactively (when running in a
55+
TTY) and merged into the template data. This is useful when your templates need user-specific
56+
values.
57+
58+
```typescript
59+
import Scaffold from "simple-scaffold"
60+
61+
await Scaffold({
62+
name: "component",
63+
templates: ["templates/component"],
64+
output: "src/components",
65+
inputs: {
66+
author: { message: "Author name", required: true },
67+
license: { message: "License", default: "MIT" },
68+
},
69+
})
70+
// In templates: {{ author }}, {{ license }}
71+
```
72+
73+
- **Required** inputs are prompted if not already in `data`
74+
- **Optional** inputs with a `default` are applied silently
75+
- Pre-providing values in `data` skips the prompt for that input
76+
4977
## Example
5078

5179
This is an example of loading a complete scaffold via Node.js:
5280

5381
```typescript
5482
import Scaffold from "simple-scaffold"
5583

56-
const config = {
84+
await Scaffold({
5785
name: "component",
5886
templates: [path.join(__dirname, "scaffolds", "component")],
5987
output: path.join(__dirname, "src", "components"),
@@ -65,10 +93,12 @@ const config = {
6593
helpers: {
6694
twice: (text) => [text, text].join(" "),
6795
},
96+
inputs: {
97+
author: { message: "Author name", required: true },
98+
license: { message: "License", default: "MIT" },
99+
},
68100
// return a string to replace the final file contents after pre-processing, or `undefined`
69101
// to keep it as-is
70102
beforeWrite: (content, rawContent, outputPath) => content.toString().toUpperCase(),
71-
}
72-
73-
const scaffold = Scaffold(config)
103+
})
74104
```

docs/docs/usage/05-examples.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ title: Examples
3131
### Output
3232

3333
- Output file path:
34-
3534
- With `subdir = false` (default):
3635

3736
```text

docs/docs/usage/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ title: Usage
33
sidebar_position: 0
44
---
55

6-
- [CLI Usage](cli)
6+
- [Template Files](templates)
77
- [Configuration Files](configuration_files)
8+
- [CLI Usage](cli)
9+
- [Node.js Usage](node)
810
- [Examples](examples)
911
- [Migration](migration)
10-
- [Node.js Usage](node)
11-
- [Template Files](templates)

src/cmd.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { log } from "./logger"
1010
import { MassargCommand } from "massarg/command"
1111
import { getUniqueTmpPath as generateUniqueTmpPath } from "./file"
1212
import { colorize } from "./colors"
13-
import { isInteractive, promptForMissingConfig } from "./prompts"
13+
import { promptForMissingConfig, resolveInputs } from "./prompts"
1414

1515
export async function parseCliArgs(args = process.argv.slice(2)) {
1616
const isProjectRoot = Boolean(await fs.stat(path.join(__dirname, "package.json")).catch(() => false))
@@ -45,7 +45,8 @@ export async function parseCliArgs(args = process.argv.slice(2)) {
4545

4646
log(config, LogLevel.debug, "Parsing config file...", config)
4747
const parsed = await parseConfigFile(config)
48-
await Scaffold(parsed)
48+
const resolved = await resolveInputs(parsed)
49+
await Scaffold(resolved)
4950
} catch (e) {
5051
const message = "message" in (e as object) ? (e as Error).message : e?.toString()
5152
log(config, LogLevel.error, message)

0 commit comments

Comments
 (0)