simple-scaffold 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,181 +28,292 @@ of files you're generating.
28
28
 
29
29
  ---
30
30
 
31
- ## Documentation
32
-
33
- See full documentation [here](https://chenasraf.github.io/simple-scaffold).
34
-
35
- - [Command Line Interface (CLI) usage](https://chenasraf.github.io/simple-scaffold/docs/usage/cli)
36
- - [Node.js usage](https://chenasraf.github.io/simple-scaffold/docs/usage/node)
37
- - [Templates](https://chenasraf.github.io/simple-scaffold/docs/usage/templates)
38
- - [Configuration Files](https://chenasraf.github.io/simple-scaffold/docs/usage/configuration_files)
39
- - [Migration](https://chenasraf.github.io/simple-scaffold/docs/usage/migration)
31
+ > **Full documentation is available at
32
+ > [chenasraf.github.io/simple-scaffold](https://chenasraf.github.io/simple-scaffold)** — including
33
+ > detailed guides on [CLI usage](https://chenasraf.github.io/simple-scaffold/docs/usage/cli),
34
+ > [Node.js API](https://chenasraf.github.io/simple-scaffold/docs/usage/node),
35
+ > [templates](https://chenasraf.github.io/simple-scaffold/docs/usage/templates),
36
+ > [configuration files](https://chenasraf.github.io/simple-scaffold/docs/usage/configuration_files),
37
+ > [examples](https://chenasraf.github.io/simple-scaffold/docs/usage/examples), and
38
+ > [migration from v1/v2](https://chenasraf.github.io/simple-scaffold/docs/usage/migration).
39
+
40
+ ## Table of Contents
41
+
42
+ - [Getting Started](#getting-started)
43
+ - [Configuration Files](#configuration-files)
44
+ - [Templates](#templates)
45
+ - [Interactive Mode & Inputs](#interactive-mode--inputs)
46
+ - [Remote Templates](#remote-templates)
47
+ - [CLI Reference](#cli-reference)
48
+ - [Node.js API](#nodejs-api)
49
+ - [Built-in Helpers](#built-in-helpers)
50
+ - [Contributing](#contributing)
40
51
 
41
52
  ## Getting Started
42
53
 
43
- ### Cheat Sheet
44
-
45
- A quick rundown of common usage scenarios:
46
-
47
- - Remote template config file on GitHub:
54
+ ### Install
48
55
 
49
- ```sh
50
- npx simple-scaffold -g username/repository -c scaffold.js -k component NewComponentName
51
- ```
52
-
53
- - Local template config file:
54
-
55
- ```sh
56
- npx simple-scaffold -c scaffold.js -k component NewComponentName
57
- ```
56
+ ```sh
57
+ npm install -D simple-scaffold
58
+ # or use directly with npx
59
+ npx simple-scaffold
60
+ ```
58
61
 
59
- - Local one-time usage:
62
+ ### Initialize a Project
60
63
 
61
- ```sh
62
- npx simple-scaffold -t templates/component -o src/components NewComponentName
63
- ```
64
+ Run `init` to create a config file and an example template:
64
65
 
65
- ### Remote Configurations
66
+ ```sh
67
+ npx simple-scaffold init
68
+ ```
66
69
 
67
- The fastest way to get started is to is to re-use someone else's (or your own) work using a template
68
- repository.
70
+ This creates `scaffold.config.js` and `templates/default/{{name}}.md`. Now generate files:
69
71
 
70
- A remote config can be loaded in one of these ways:
72
+ ```sh
73
+ npx simple-scaffold MyProject
74
+ ```
71
75
 
72
- - For templates hosted on GitHub, the syntax is `-g user/repository_name`
73
- - For other Git platforms like GitLab, use `-g https://example.com/user/repository_name.git`
76
+ ### One-off Usage (No Config)
74
77
 
75
- These remote configurations support multiple scaffold groups, which can be specified using the
76
- `--key` or `-k` argument:
78
+ Generate files from a template directory without a config file:
77
79
 
78
80
  ```sh
79
- $ npx simple-scaffold \
80
- -g chenasraf/simple-scaffold \
81
- -k component \
82
- PageWrapper
83
-
84
- # equivalent to:
85
- $ npx simple-scaffold \
86
- -g https://github.com/chenasraf/simple-scaffold.git \
87
- -c scaffold.config.js \
88
- -k component \
89
- PageWrapper
81
+ npx simple-scaffold -t templates/component -o src/components MyComponent
90
82
  ```
91
83
 
92
- By default, the template name is set to `default` when the `--key` option is not provided.
84
+ ## Configuration Files
93
85
 
94
- See information about each option and flag using the `--help` flag, or read the
95
- [CLI documentation](https://chenasraf.github.io/simple-scaffold/docs/usage/cli). For information
96
- about how configuration files work, [see below](#configuration-files).
86
+ Config files let you define reusable scaffold definitions. Simple Scaffold **auto-detects** config
87
+ files in the current directory — no `--config` flag needed.
97
88
 
98
- ### Interactive Mode
89
+ It searches for these files in order:
99
90
 
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).
91
+ `scaffold.config.{mjs,cjs,js,json}`, `scaffold.{mjs,cjs,js,json}`, `.scaffold.{mjs,cjs,js,json}`
102
92
 
103
- Config files can also define **inputs** — custom fields that are prompted interactively and become
104
- template data:
93
+ ### Example
105
94
 
106
95
  ```js
96
+ // scaffold.config.js
107
97
  module.exports = {
108
98
  component: {
109
99
  templates: ["templates/component"],
110
100
  output: "src/components",
111
- inputs: {
112
- author: { message: "Author name", required: true },
113
- license: { message: "License", default: "MIT" },
114
- },
101
+ },
102
+ page: {
103
+ templates: ["templates/page"],
104
+ output: "src/pages",
105
+ subdir: true,
115
106
  },
116
107
  }
117
108
  ```
118
109
 
119
- Inputs can be pre-provided via `--data` or `-D` to skip the prompt:
110
+ Then run:
111
+
112
+ ```sh
113
+ npx simple-scaffold -k component MyComponent
114
+ npx simple-scaffold -k page Dashboard
115
+ ```
116
+
117
+ Use the key `default` to skip the `-k` flag entirely.
118
+
119
+ ### Listing Available Templates
120
120
 
121
121
  ```sh
122
- npx simple-scaffold -c scaffold.config.js -k component -D author=John MyComponent
122
+ npx simple-scaffold list
123
+ npx simple-scaffold list -c path/to/config.js
124
+ ```
125
+
126
+ ## Templates
127
+
128
+ Templates are regular files in a directory. Both **file names** and **file contents** support
129
+ Handlebars syntax. Simple Scaffold preserves the directory structure of your template folder.
130
+
131
+ ### Example Template
132
+
133
+ `templates/component/{{pascalCase name}}.tsx`
134
+
135
+ ```tsx
136
+ // Created: {{ now 'yyyy-MM-dd' }}
137
+ import React from "react"
138
+
139
+ export default {{ pascalCase name }}: React.FC = (props) => {
140
+ return (
141
+ <div className="{{ camelCase name }}">{{ pascalCase name }} Component</div>
142
+ )
143
+ }
123
144
  ```
124
145
 
125
- ### Configuration Files
146
+ Running `npx simple-scaffold -t templates/component -o src/components PageWrapper` produces
147
+ `src/components/PageWrapper.tsx` with all tokens replaced.
126
148
 
127
- You can use a config file to more easily maintain all your scaffold definitions. Simple Scaffold
128
- **auto-detects** config files in the current directory — no `--config` flag needed.
149
+ ### Glob Patterns & Exclusions
129
150
 
130
- It searches for these files in order: `scaffold.config.{mjs,cjs,js,json}`,
131
- `scaffold.{mjs,cjs,js,json}`, `.scaffold.{mjs,cjs,js,json}`.
151
+ Template paths support globs and negation:
132
152
 
133
- `scaffold.config.js`
153
+ ```js
154
+ {
155
+ templates: ["templates/component/**", "!templates/component/README.md"]
156
+ }
157
+ ```
158
+
159
+ ### .scaffoldignore
160
+
161
+ Place a `.scaffoldignore` file in your template directory to exclude files. It works like
162
+ `.gitignore` — one pattern per line, `#` for comments.
163
+
164
+ ## Interactive Mode & Inputs
165
+
166
+ When running in a terminal, Simple Scaffold prompts for any missing required values (name, output,
167
+ template key). Config files can also define **inputs** — custom fields that are prompted
168
+ interactively:
134
169
 
135
170
  ```js
136
171
  module.exports = {
137
- // use "default" to avoid needing to specify key
138
- // in this case the key is "component"
139
172
  component: {
140
173
  templates: ["templates/component"],
141
174
  output: "src/components",
142
- data: {
143
- // ...
175
+ inputs: {
176
+ author: { type: "text", message: "Author name", required: true },
177
+ license: { type: "select", message: "License", options: ["MIT", "Apache-2.0", "GPL-3.0"] },
178
+ isPublic: { type: "confirm", message: "Public package?" },
179
+ priority: { type: "number", message: "Priority level", default: 1 },
144
180
  },
145
181
  },
146
182
  }
147
183
  ```
148
184
 
149
- Then just run from the same directory:
185
+ **Input types:** `text` (default), `select`, `confirm`, `number`
186
+
187
+ Pre-fill inputs from the command line to skip prompts:
150
188
 
151
189
  ```sh
152
- $ npx simple-scaffold PageWrapper
153
- # or explicitly: npx simple-scaffold -c scaffold.config.js PageWrapper
190
+ npx simple-scaffold -k component -D author=John -D license=MIT MyComponent
154
191
  ```
155
192
 
156
- This will allow you to avoid needing to remember which configs are needed or to store them in a
157
- one-liner in `package.json` which can get pretty long and messy, and harder to maintain.
158
-
159
- Also, this allows you to define more complex scaffolds with logic without having to use the Node.js
160
- API directly. (Of course you always have the option to still do so if you wish)
161
-
162
- More information can be found at the
163
- [Configuration Files documentation](https://chenasraf.github.io/simple-scaffold/docs/usage/configuration_files).
164
-
165
- ### Templates Structure
193
+ ## Remote Templates
166
194
 
167
- Templates are **any file** in the a directory given to `--templates`.
195
+ Use templates from any Git repository:
168
196
 
169
- Simple Scaffold will maintain any file and directory structure you try to generate, while replacing
170
- any tokens such as `{{ name }}` or other custom-data using
171
- [Handlebars.js](https://handlebarsjs.com/).
197
+ ```sh
198
+ # GitHub shorthand
199
+ npx simple-scaffold -g username/repo -k component MyComponent
172
200
 
173
- `templates/component/{{ pascalName name }}.tsx`
201
+ # Full Git URL (GitLab, Bitbucket, etc.)
202
+ npx simple-scaffold -g https://gitlab.com/user/repo.git -k component MyComponent
203
+ ```
174
204
 
175
- ```tsx
176
- // Created: {{ now 'yyyy-MM-dd' }}
177
- import React from 'react'
205
+ The repository is cloned to a temporary directory, used, and cleaned up automatically.
206
+
207
+ ## CLI Reference
208
+
209
+ ### Commands
210
+
211
+ | Command | Description |
212
+ | ------------- | ---------------------------------------- |
213
+ | `[name]` | Generate files from a template (default) |
214
+ | `init` | Create config file and example template |
215
+ | `list` / `ls` | List available template keys in a config |
216
+
217
+ ### Options
218
+
219
+ | Flag | Short | Description | Default |
220
+ | ------------------------------ | --------- | ---------------------------------------------------- | ----------- |
221
+ | `--config` | `-c` | Path to config file or directory | auto-detect |
222
+ | `--git` | `-g` | Git URL or GitHub shorthand | |
223
+ | `--key` | `-k` | Template key from config | `default` |
224
+ | `--output` | `-o` | Output directory | |
225
+ | `--templates` | `-t` | Template file paths or globs | |
226
+ | `--data` | `-d` | Custom JSON data | |
227
+ | `--append-data` | `-D` | Key-value data (`key=string`, `key:=raw`) | |
228
+ | `--subdir`/`--no-subdir` | `-s`/`-S` | Create parent directory with input name | `false` |
229
+ | `--subdir-helper` | `-H` | Helper to transform subdir name | |
230
+ | `--overwrite`/`--no-overwrite` | `-w`/`-W` | Overwrite existing files | `false` |
231
+ | `--dry-run` | `-dr` | Preview output without writing files | `false` |
232
+ | `--before-write` | `-B` | Script to run before each file is written | |
233
+ | `--after-scaffold` | `-A` | Shell command to run after scaffolding | |
234
+ | `--quiet` | `-q` | Suppress output | |
235
+ | `--log-level` | `-l` | Log level (`none`, `debug`, `info`, `warn`, `error`) | `info` |
236
+ | `--version` | `-v` | Show version | |
237
+ | `--help` | `-h` | Show help | |
238
+
239
+ ## Node.js API
178
240
 
179
- export default {{pascalCase name}}: React.FC = (props) => {
180
- return (
181
- <div className="{{camelCase name}}">{{pascalCase name}} Component</div>
182
- )
183
- }
241
+ ```js
242
+ import Scaffold from "simple-scaffold"
243
+
244
+ // Basic usage
245
+ const scaffold = new Scaffold({
246
+ name: "MyComponent",
247
+ templates: ["templates/component"],
248
+ output: "src/components",
249
+ })
250
+ await scaffold.run()
251
+
252
+ // Load from config file
253
+ const scaffold = await Scaffold.fromConfig("scaffold.config.js", {
254
+ key: "component",
255
+ name: "MyComponent",
256
+ })
257
+ await scaffold.run()
184
258
  ```
185
259
 
186
- To generate the template output once without saving a configuration file, run:
187
-
188
- ```sh
189
- # generate single component
190
- $ npx simple-scaffold \
191
- -t templates/component \
192
- -o src/components \
193
- PageWrapper
260
+ ### Config Options
261
+
262
+ | Option | Type | Description |
263
+ | --------------- | -------------------------- | ------------------------------------- |
264
+ | `name` | `string` | Name for generated files (required) |
265
+ | `templates` | `string[]` | Template paths or globs (required) |
266
+ | `output` | `string \| Function` | Output directory or per-file function |
267
+ | `data` | `Record<string, unknown>` | Custom template data |
268
+ | `inputs` | `Record<string, Input>` | Interactive input definitions |
269
+ | `helpers` | `Record<string, Function>` | Custom Handlebars helpers |
270
+ | `subdir` | `boolean` | Create parent directory with name |
271
+ | `subdirHelper` | `string` | Helper for subdir name transformation |
272
+ | `overwrite` | `boolean \| Function` | Overwrite existing files |
273
+ | `dryRun` | `boolean` | Preview without writing |
274
+ | `logLevel` | `string` | Log verbosity |
275
+ | `beforeWrite` | `Function` | Async hook before each file write |
276
+ | `afterScaffold` | `Function \| string` | Hook after all files are written |
277
+
278
+ ## Built-in Helpers
279
+
280
+ All helpers work in both file names and file contents.
281
+
282
+ ### Case Helpers
283
+
284
+ | Helper | Example Input | Output |
285
+ | ------------ | ------------- | --------- |
286
+ | `camelCase` | `my name` | `myName` |
287
+ | `pascalCase` | `my name` | `MyName` |
288
+ | `snakeCase` | `my name` | `my_name` |
289
+ | `kebabCase` | `my name` | `my-name` |
290
+ | `hyphenCase` | `my name` | `my-name` |
291
+ | `startCase` | `my name` | `My Name` |
292
+ | `upperCase` | `my name` | `MY NAME` |
293
+ | `lowerCase` | `My Name` | `my name` |
294
+
295
+ ### Date Helpers
296
+
297
+ ```handlebars
298
+ {{now "yyyy-MM-dd"}}
299
+ {{now "yyyy-MM-dd HH:mm" -1 "hours"}}
300
+ {{date myDateVar "yyyy-MM-dd"}}
301
+ {{date "2077-01-01T00:00:00Z" "yyyy-MM-dd" 7 "days"}}
194
302
  ```
195
303
 
196
- This will immediately create the following file: `src/components/PageWrapper.tsx`
304
+ ### Custom Helpers
197
305
 
198
- ```tsx
199
- // Created: 2077-01-01
200
- import React from 'react'
306
+ Add your own via config:
201
307
 
202
- export default PageWrapper: React.FC = (props) => {
203
- return (
204
- <div className="pageWrapper">PageWrapper Component</div>
205
- )
308
+ ```js
309
+ module.exports = {
310
+ component: {
311
+ templates: ["templates/component"],
312
+ output: "src/components",
313
+ helpers: {
314
+ shout: (str) => str.toUpperCase() + "!!!",
315
+ },
316
+ },
206
317
  }
207
318
  ```
208
319
 
@@ -216,7 +327,7 @@ just a small amount to help sustain this project, I would be very very thankful!
216
327
  <img
217
328
  height='36'
218
329
  src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3'
219
- alt='Buy Me a Coffee at ko-fi.com'
330
+ alt='Buy Me a Coffee at ko-fi.com'
220
331
  />
221
332
  </a>
222
333
 
package/cmd.js CHANGED
@@ -1,20 +1,110 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_scaffold = require("./scaffold-Ce-rIwy9.js");
3
+ const require_scaffold = require("./scaffold-DOzCgpZT.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_scaffold.__toESM(node_path);
6
6
  let node_fs_promises = require("node:fs/promises");
7
7
  node_fs_promises = require_scaffold.__toESM(node_fs_promises);
8
+ let _inquirer_select = require("@inquirer/select");
9
+ _inquirer_select = require_scaffold.__toESM(_inquirer_select);
8
10
  let massarg = require("massarg");
9
11
  let massarg_command = require("massarg/command");
12
+ //#region src/init.ts
13
+ var CONFIG_EXTENSIONS = {
14
+ js: "scaffold.config.js",
15
+ mjs: "scaffold.config.mjs",
16
+ json: "scaffold.config.json"
17
+ };
18
+ var CONFIG_TEMPLATES = {
19
+ js: `/** @type {import('simple-scaffold').ScaffoldConfigMap} */
20
+ module.exports = {
21
+ default: {
22
+ templates: ["templates/default"],
23
+ output: ".",
24
+ // inputs: {
25
+ // author: { message: "Author name", required: true },
26
+ // license: { message: "License", default: "MIT" },
27
+ // },
28
+ },
29
+ }
30
+ `,
31
+ mjs: `/** @type {import('simple-scaffold').ScaffoldConfigMap} */
32
+ export default {
33
+ default: {
34
+ templates: ["templates/default"],
35
+ output: ".",
36
+ // inputs: {
37
+ // author: { message: "Author name", required: true },
38
+ // license: { message: "License", default: "MIT" },
39
+ // },
40
+ },
41
+ }
42
+ `,
43
+ json: `{
44
+ "default": {
45
+ "templates": ["templates/default"],
46
+ "output": "."
47
+ }
48
+ }
49
+ `
50
+ };
51
+ var EXAMPLE_TEMPLATE_CONTENT = `# {{ name }}
52
+
53
+ Created by Simple Scaffold.
54
+
55
+ {{#if description}}{{ description }}{{/if}}
56
+ `;
57
+ /**
58
+ * Initializes a new Simple Scaffold project by creating a config file
59
+ * and an optional example template directory.
60
+ */
61
+ async function initScaffold(options = {}) {
62
+ const dir = options.dir ?? process.cwd();
63
+ const format = options.format ?? await (0, _inquirer_select.default)({
64
+ message: require_scaffold.colorize.cyan("Config file format:"),
65
+ choices: [
66
+ {
67
+ name: "JavaScript (CommonJS)",
68
+ value: "js"
69
+ },
70
+ {
71
+ name: "JavaScript (ESM)",
72
+ value: "mjs"
73
+ },
74
+ {
75
+ name: "JSON",
76
+ value: "json"
77
+ }
78
+ ]
79
+ });
80
+ const filename = CONFIG_EXTENSIONS[format];
81
+ const configPath = node_path.default.resolve(dir, filename);
82
+ if (await require_scaffold.pathExists(configPath)) console.log(require_scaffold.colorize.yellow(`${filename} already exists, skipping config creation.`));
83
+ else {
84
+ await node_fs_promises.default.writeFile(configPath, CONFIG_TEMPLATES[format]);
85
+ console.log(require_scaffold.colorize.green(`Created ${filename}`));
86
+ }
87
+ if (options.createExample ?? true) {
88
+ const templateDir = node_path.default.resolve(dir, "templates", "default");
89
+ const templateFile = node_path.default.join(templateDir, "{{name}}.md");
90
+ if (await require_scaffold.pathExists(templateDir)) console.log(require_scaffold.colorize.yellow("templates/default/ already exists, skipping example template."));
91
+ else {
92
+ await node_fs_promises.default.mkdir(templateDir, { recursive: true });
93
+ await node_fs_promises.default.writeFile(templateFile, EXAMPLE_TEMPLATE_CONTENT);
94
+ console.log(require_scaffold.colorize.green("Created templates/default/{{name}}.md"));
95
+ }
96
+ }
97
+ console.log();
98
+ console.log(require_scaffold.colorize.dim("Get started:"));
99
+ console.log(require_scaffold.colorize.dim(` npx simple-scaffold MyProject`));
100
+ console.log();
101
+ }
102
+ //#endregion
10
103
  //#region src/cmd.ts
11
104
  async function parseCliArgs(args = process.argv.slice(2)) {
12
105
  const isProjectRoot = Boolean(await node_fs_promises.default.stat(node_path.default.join(__dirname, "package.json")).catch(() => false));
13
106
  const pkgFile = await node_fs_promises.default.readFile(node_path.default.resolve(__dirname, isProjectRoot ? "." : "..", "package.json"));
14
107
  const pkg = JSON.parse(pkgFile.toString());
15
- args.includes("--version") || args.includes("-v");
16
- args.includes("--config") || args.includes("-c");
17
- args.includes("--git") || args.includes("-g");
18
108
  return (0, massarg.massarg)({
19
109
  name: pkg.name,
20
110
  description: pkg.description
@@ -23,19 +113,20 @@ async function parseCliArgs(args = process.argv.slice(2)) {
23
113
  console.log(pkg.version);
24
114
  return;
25
115
  }
26
- require_scaffold.log(config, require_scaffold.LogLevel.info, `Simple Scaffold v${pkg.version}`);
116
+ require_scaffold.log(config, require_scaffold.LogLevel.debug, `Simple Scaffold v${pkg.version}`);
27
117
  config.tmpDir = require_scaffold.getUniqueTmpPath();
28
118
  try {
29
- if (!config.config && !config.git) try {
119
+ const isOneTimeRun = config.templates?.length > 0 || config.output;
120
+ if (!config.config && !config.git && !isOneTimeRun) try {
30
121
  config.config = await require_scaffold.findConfigFile(process.cwd());
31
122
  require_scaffold.log(config, require_scaffold.LogLevel.debug, `Auto-detected config file: ${config.config}`);
32
123
  } catch {}
33
124
  const hasConfigSource = Boolean(config.config || config.git);
34
125
  let configMap;
35
126
  if (hasConfigSource) configMap = await require_scaffold.getConfigFile(config);
36
- config = await require_scaffold.promptForMissingConfig(config, configMap);
127
+ config = await require_scaffold.promptBeforeConfig(config, configMap);
37
128
  require_scaffold.log(config, require_scaffold.LogLevel.debug, "Parsing config file...", config);
38
- await require_scaffold.Scaffold(await require_scaffold.resolveInputs(await require_scaffold.parseConfigFile(config)));
129
+ await require_scaffold.Scaffold(await require_scaffold.resolveInputs(await require_scaffold.promptAfterConfig(await require_scaffold.parseConfigFile(config))));
39
130
  } catch (e) {
40
131
  const message = "message" in e ? e.message : e?.toString();
41
132
  require_scaffold.log(config, require_scaffold.LogLevel.error, message);
@@ -118,6 +209,10 @@ async function parseCliArgs(args = process.argv.slice(2)) {
118
209
  name: "before-write",
119
210
  aliases: ["B"],
120
211
  description: "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."
212
+ }).option({
213
+ name: "after-scaffold",
214
+ aliases: ["A"],
215
+ description: "Run a shell command after all files have been written. The command is executed in the output directory. For example: `--after-scaffold 'npm install'`"
121
216
  }).flag({
122
217
  name: "dry-run",
123
218
  aliases: ["dr"],
@@ -177,6 +272,29 @@ async function parseCliArgs(args = process.argv.slice(2)) {
177
272
  if (!(val in require_scaffold.LogLevel)) throw new Error(`Invalid log level: ${val}, must be one of: ${Object.keys(require_scaffold.LogLevel).join(", ")}`);
178
273
  return val;
179
274
  }
275
+ }).help({ bindOption: true })).command(new massarg_command.MassargCommand({
276
+ name: "init",
277
+ aliases: [],
278
+ description: "Initialize a new scaffold config file and example template in the current directory.",
279
+ run: async (config) => {
280
+ try {
281
+ await initScaffold({
282
+ dir: config.dir,
283
+ format: config.format
284
+ });
285
+ } catch (e) {
286
+ const message = "message" in e ? e.message : e?.toString();
287
+ console.error(require_scaffold.colorize.red(message ?? "Unknown error"));
288
+ }
289
+ }
290
+ }).option({
291
+ name: "dir",
292
+ aliases: ["d"],
293
+ description: "Directory to create the config in. Defaults to current working directory."
294
+ }).option({
295
+ name: "format",
296
+ aliases: ["f"],
297
+ description: "Config file format: js, mjs, or json. If omitted, you will be prompted."
180
298
  }).help({ bindOption: true })).example({
181
299
  description: "Usage with config file",
182
300
  input: "simple-scaffold -c scaffold.cmd.js --key component"