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 +225 -114
- package/cmd.js +126 -8
- package/cmd.js.map +1 -1
- package/file.d.ts +2 -1
- package/ignore.d.ts +21 -0
- package/index.d.ts +1 -0
- package/index.js +4 -1
- package/index.js.map +1 -1
- package/init.d.ts +20 -0
- package/logger.d.ts +9 -1
- package/package.json +29 -9
- package/prompts.d.ts +11 -2
- package/scaffold-DOzCgpZT.js +1263 -0
- package/scaffold-DOzCgpZT.js.map +1 -0
- package/types.d.ts +76 -2
- package/validate.d.ts +96 -0
- package/scaffold-Ce-rIwy9.js +0 -2636
- package/scaffold-Ce-rIwy9.js.map +0 -1
package/README.md
CHANGED
|
@@ -28,181 +28,292 @@ of files you're generating.
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
###
|
|
44
|
-
|
|
45
|
-
A quick rundown of common usage scenarios:
|
|
46
|
-
|
|
47
|
-
- Remote template config file on GitHub:
|
|
54
|
+
### Install
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
62
|
+
### Initialize a Project
|
|
60
63
|
|
|
61
|
-
|
|
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
|
-
|
|
66
|
+
```sh
|
|
67
|
+
npx simple-scaffold init
|
|
68
|
+
```
|
|
66
69
|
|
|
67
|
-
|
|
68
|
-
repository.
|
|
70
|
+
This creates `scaffold.config.js` and `templates/default/{{name}}.md`. Now generate files:
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
```sh
|
|
73
|
+
npx simple-scaffold MyProject
|
|
74
|
+
```
|
|
71
75
|
|
|
72
|
-
-
|
|
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
|
-
|
|
76
|
-
`--key` or `-k` argument:
|
|
78
|
+
Generate files from a template directory without a config file:
|
|
77
79
|
|
|
78
80
|
```sh
|
|
79
|
-
|
|
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
|
-
|
|
84
|
+
## Configuration Files
|
|
93
85
|
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
89
|
+
It searches for these files in order:
|
|
99
90
|
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
101
|
+
},
|
|
102
|
+
page: {
|
|
103
|
+
templates: ["templates/page"],
|
|
104
|
+
output: "src/pages",
|
|
105
|
+
subdir: true,
|
|
115
106
|
},
|
|
116
107
|
}
|
|
117
108
|
```
|
|
118
109
|
|
|
119
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
128
|
-
**auto-detects** config files in the current directory — no `--config` flag needed.
|
|
149
|
+
### Glob Patterns & Exclusions
|
|
129
150
|
|
|
130
|
-
|
|
131
|
-
`scaffold.{mjs,cjs,js,json}`, `.scaffold.{mjs,cjs,js,json}`.
|
|
151
|
+
Template paths support globs and negation:
|
|
132
152
|
|
|
133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
+
Use templates from any Git repository:
|
|
168
196
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
197
|
+
```sh
|
|
198
|
+
# GitHub shorthand
|
|
199
|
+
npx simple-scaffold -g username/repo -k component MyComponent
|
|
172
200
|
|
|
173
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
304
|
+
### Custom Helpers
|
|
197
305
|
|
|
198
|
-
|
|
199
|
-
// Created: 2077-01-01
|
|
200
|
-
import React from 'react'
|
|
306
|
+
Add your own via config:
|
|
201
307
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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"
|