@amritk/mjst 0.7.1 β 0.7.2
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 +153 -16
- package/dist/cli-config.d.ts +7 -0
- package/dist/cli.js +32 -4
- package/package.json +3 -3
- package/src/cli-config.ts +7 -0
- package/src/cli.ts +16 -3
- package/src/parse-cli-args.test.ts +21 -0
- package/src/parse-cli-args.ts +18 -1
package/README.md
CHANGED
|
@@ -95,22 +95,159 @@ npx mjst --config ./mjst.config.json
|
|
|
95
95
|
## Configuration reference
|
|
96
96
|
|
|
97
97
|
<!-- config-table-start -->
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
98
|
+
<table>
|
|
99
|
+
<thead>
|
|
100
|
+
<tr>
|
|
101
|
+
<th>Property</th>
|
|
102
|
+
<th>CLI Flag</th>
|
|
103
|
+
<th>Type</th>
|
|
104
|
+
<th align="center">Required</th>
|
|
105
|
+
<th align="center">Default</th>
|
|
106
|
+
</tr>
|
|
107
|
+
</thead>
|
|
108
|
+
<tbody>
|
|
109
|
+
<tr>
|
|
110
|
+
<td>π <code>schema</code></td>
|
|
111
|
+
<td><code>--schema <path></code></td>
|
|
112
|
+
<td><code>string</code></td>
|
|
113
|
+
<td align="center">β</td>
|
|
114
|
+
<td align="center">β</td>
|
|
115
|
+
</tr>
|
|
116
|
+
<tr>
|
|
117
|
+
<td colspan="5">Path to the schema to process. With the default 'json' input this is a JSON Schema file that is read and parsed. With any other input format it is a JS/TS module that exports a schema, which is loaded and converted to JSON Schema via the matching adapter. Either 'schema' or 'schemaDir' is required.</td>
|
|
118
|
+
</tr>
|
|
119
|
+
<tr>
|
|
120
|
+
<td>ποΈ <code>schemaDir</code></td>
|
|
121
|
+
<td><code>--schema-dir <dir></code></td>
|
|
122
|
+
<td><code>string</code></td>
|
|
123
|
+
<td align="center">β</td>
|
|
124
|
+
<td align="center">β</td>
|
|
125
|
+
</tr>
|
|
126
|
+
<tr>
|
|
127
|
+
<td colspan="5">Path to a directory of JSON Schema files. When set, the CLI walks the directory recursively, generates parsers for every '*.json' schema it finds, and mirrors the directory layout under outDir (each schema lands in its own subdirectory). The runtime helpers are emitted once into a shared outDir/_helpers/ that every nested parser imports from. Mutually exclusive with 'schema'; when both are present 'schemaDir' wins. Only JSON Schema input is supported in this mode.</td>
|
|
128
|
+
</tr>
|
|
129
|
+
<tr>
|
|
130
|
+
<td>π <code>input</code></td>
|
|
131
|
+
<td><code>--input <format></code></td>
|
|
132
|
+
<td><code>string</code></td>
|
|
133
|
+
<td align="center">β</td>
|
|
134
|
+
<td align="center"><code>"json"</code></td>
|
|
135
|
+
</tr>
|
|
136
|
+
<tr>
|
|
137
|
+
<td colspan="5">Source format of the schema. 'json' (default) reads a JSON Schema file directly. Any other format loads 'schema' as a module and converts it to JSON Schema with the matching adapter. Supported: 'typebox', 'zod' (zod v4+), 'valibot' (with @valibot/to-json-schema), and 'effect' β each requires the corresponding library installed in your project.</td>
|
|
138
|
+
</tr>
|
|
139
|
+
<tr>
|
|
140
|
+
<td>π¦ <code>export</code></td>
|
|
141
|
+
<td><code>--export <name></code></td>
|
|
142
|
+
<td><code>string</code></td>
|
|
143
|
+
<td align="center">β</td>
|
|
144
|
+
<td align="center">β</td>
|
|
145
|
+
</tr>
|
|
146
|
+
<tr>
|
|
147
|
+
<td colspan="5">Which export of the schema module to use when 'input' is not 'json'. Defaults to the default export, or the sole named export when the module has exactly one.</td>
|
|
148
|
+
</tr>
|
|
149
|
+
<tr>
|
|
150
|
+
<td>π <code>outDir</code></td>
|
|
151
|
+
<td><code>--out-dir <dir></code></td>
|
|
152
|
+
<td><code>string</code></td>
|
|
153
|
+
<td align="center">β</td>
|
|
154
|
+
<td align="center">β</td>
|
|
155
|
+
</tr>
|
|
156
|
+
<tr>
|
|
157
|
+
<td colspan="5">Output directory for generated TypeScript files. The directory is created automatically if it does not exist. Subdirectories are created as needed when a generated file includes a nested path. Mutually exclusive with 'outFile'.</td>
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td>π <code>outFile</code></td>
|
|
161
|
+
<td><code>--out-file <file></code></td>
|
|
162
|
+
<td><code>string</code></td>
|
|
163
|
+
<td align="center">β</td>
|
|
164
|
+
<td align="center">β</td>
|
|
165
|
+
</tr>
|
|
166
|
+
<tr>
|
|
167
|
+
<td colspan="5">Output everything to a single TypeScript file instead of a directory. Every generated definition is concatenated into one self-contained file and the cross-file imports are dropped. Mutually exclusive with 'outDir'. Currently supported only together with 'typesOnly'.</td>
|
|
168
|
+
</tr>
|
|
169
|
+
<tr>
|
|
170
|
+
<td>π·οΈ <code>typesOnly</code></td>
|
|
171
|
+
<td><code>--types-only</code></td>
|
|
172
|
+
<td><code>boolean</code></td>
|
|
173
|
+
<td align="center">β</td>
|
|
174
|
+
<td align="center"><code>false</code></td>
|
|
175
|
+
</tr>
|
|
176
|
+
<tr>
|
|
177
|
+
<td colspan="5">Generate only TypeScript type definitions without parser functions. Useful when you only need the type shapes and do not need runtime validation.</td>
|
|
178
|
+
</tr>
|
|
179
|
+
<tr>
|
|
180
|
+
<td>π¨ <code>build</code></td>
|
|
181
|
+
<td><code>--build</code></td>
|
|
182
|
+
<td><code>boolean</code></td>
|
|
183
|
+
<td align="center">β</td>
|
|
184
|
+
<td align="center"><code>false</code></td>
|
|
185
|
+
</tr>
|
|
186
|
+
<tr>
|
|
187
|
+
<td colspan="5">Compile the generated TypeScript files to .js and .d.ts output. A temporary tsconfig is written to the output directory, tsc is invoked, and the intermediate .ts source files are removed when compilation succeeds.</td>
|
|
188
|
+
</tr>
|
|
189
|
+
<tr>
|
|
190
|
+
<td>β οΈ <code>logWarnings</code></td>
|
|
191
|
+
<td><code>--log-warnings</code></td>
|
|
192
|
+
<td><code>boolean</code></td>
|
|
193
|
+
<td align="center">β</td>
|
|
194
|
+
<td align="center"><code>false</code></td>
|
|
195
|
+
</tr>
|
|
196
|
+
<tr>
|
|
197
|
+
<td colspan="5">Emit a console.warn in the generated parsers for every input key that is not declared in the schema's properties. Useful for detecting schema drift or unexpected data shapes at runtime.</td>
|
|
198
|
+
</tr>
|
|
199
|
+
<tr>
|
|
200
|
+
<td>π« <code>strict</code></td>
|
|
201
|
+
<td><code>--strict</code></td>
|
|
202
|
+
<td><code>boolean</code></td>
|
|
203
|
+
<td align="center">β</td>
|
|
204
|
+
<td align="center"><code>false</code></td>
|
|
205
|
+
</tr>
|
|
206
|
+
<tr>
|
|
207
|
+
<td colspan="5">Generate parsers that throw on type/shape mismatches (wrong type, missing required property, enum/pattern/min/max violations) instead of coercing invalid input to default values. Unknown extra keys are still allowed.</td>
|
|
208
|
+
</tr>
|
|
209
|
+
<tr>
|
|
210
|
+
<td>π <code>readonly</code></td>
|
|
211
|
+
<td><code>--readonly</code></td>
|
|
212
|
+
<td><code>boolean</code></td>
|
|
213
|
+
<td align="center">β</td>
|
|
214
|
+
<td align="center"><code>false</code></td>
|
|
215
|
+
</tr>
|
|
216
|
+
<tr>
|
|
217
|
+
<td colspan="5">Emit every property, array, and record in the generated type definitions as readonly, producing deeply immutable types. Affects type definitions only; the generated parsers still build and return plain objects.</td>
|
|
218
|
+
</tr>
|
|
219
|
+
<tr>
|
|
220
|
+
<td>π§° <code>helpers</code></td>
|
|
221
|
+
<td><code>--helpers <mode></code></td>
|
|
222
|
+
<td><code>string</code></td>
|
|
223
|
+
<td align="center">β</td>
|
|
224
|
+
<td align="center">β</td>
|
|
225
|
+
</tr>
|
|
226
|
+
<tr>
|
|
227
|
+
<td colspan="5">Controls how generated parsers reference their runtime helpers. 'package' emits imports from @amritk/helpers (requires it to be installed in the consumer project). 'embedded' ships the helper source under outDir/_helpers/ so the output is self-contained. When omitted, the CLI auto-detects: it picks 'package' if @amritk/helpers resolves from outDir, otherwise 'embedded'.</td>
|
|
228
|
+
</tr>
|
|
229
|
+
<tr>
|
|
230
|
+
<td>π·οΈ <code>typeSuffix</code></td>
|
|
231
|
+
<td><code>--type-suffix <suffix></code></td>
|
|
232
|
+
<td><code>string</code></td>
|
|
233
|
+
<td align="center">β</td>
|
|
234
|
+
<td align="center"><code>""</code></td>
|
|
235
|
+
</tr>
|
|
236
|
+
<tr>
|
|
237
|
+
<td colspan="5">Suffix appended to every generated type name derived from a $ref (e.g. 'Object' turns Contact into ContactObject). Defaults to no suffix. The root type name is used verbatim and is unaffected.</td>
|
|
238
|
+
</tr>
|
|
239
|
+
<tr>
|
|
240
|
+
<td>βοΈ <code>config</code></td>
|
|
241
|
+
<td><code>--config <path></code></td>
|
|
242
|
+
<td><code>string</code></td>
|
|
243
|
+
<td align="center">β</td>
|
|
244
|
+
<td align="center">β</td>
|
|
245
|
+
</tr>
|
|
246
|
+
<tr>
|
|
247
|
+
<td colspan="5">Path to a JSON config file. Keys match the option names in this schema (schema, schemaDir, outDir, outFile, typesOnly, build, logWarnings, strict, readonly, helpers, typeSuffix). CLI flags take precedence over config file values.</td>
|
|
248
|
+
</tr>
|
|
249
|
+
</tbody>
|
|
250
|
+
</table>
|
|
114
251
|
<!-- config-table-end -->
|
|
115
252
|
|
|
116
253
|
---
|
package/dist/cli-config.d.ts
CHANGED
|
@@ -73,4 +73,11 @@ export type CliConfig = {
|
|
|
73
73
|
* (no suffix). The root type name is used verbatim and is unaffected.
|
|
74
74
|
*/
|
|
75
75
|
readonly typeSuffix?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Prepends a comment header to every generated file (excluding `_helpers/`).
|
|
78
|
+
* - `true` β use the default message: "This file was auto-generated by @amritk/mjstβ¦"
|
|
79
|
+
* - A string β use that text as the message body (wrapped in a JSDoc block).
|
|
80
|
+
* - `false` / omitted β no header.
|
|
81
|
+
*/
|
|
82
|
+
readonly banner?: boolean | string;
|
|
76
83
|
};
|
package/dist/cli.js
CHANGED
|
@@ -92692,7 +92692,9 @@ var parseCliArgs = (args2) => {
|
|
|
92692
92692
|
if (equalsIndex !== -1) {
|
|
92693
92693
|
const key2 = toCamelCase(arg.slice(2, equalsIndex));
|
|
92694
92694
|
const value10 = arg.slice(equalsIndex + 1);
|
|
92695
|
-
if (
|
|
92695
|
+
if (key2 === "banner") {
|
|
92696
|
+
config3.banner = value10 === "false" ? false : value10 === "true" ? true : value10;
|
|
92697
|
+
} else if (BOOLEAN_KEYS.has(key2)) {
|
|
92696
92698
|
assignBoolean(config3, key2, value10 !== "false");
|
|
92697
92699
|
} else {
|
|
92698
92700
|
assignValue(config3, key2, value10);
|
|
@@ -92700,6 +92702,16 @@ var parseCliArgs = (args2) => {
|
|
|
92700
92702
|
continue;
|
|
92701
92703
|
}
|
|
92702
92704
|
const key = toCamelCase(arg.slice(2));
|
|
92705
|
+
if (key === "banner") {
|
|
92706
|
+
const nextArg = args2[i + 1];
|
|
92707
|
+
if (nextArg && !nextArg.startsWith("--")) {
|
|
92708
|
+
config3.banner = nextArg;
|
|
92709
|
+
i++;
|
|
92710
|
+
} else {
|
|
92711
|
+
config3.banner = true;
|
|
92712
|
+
}
|
|
92713
|
+
continue;
|
|
92714
|
+
}
|
|
92703
92715
|
if (BOOLEAN_KEYS.has(key)) {
|
|
92704
92716
|
assignBoolean(config3, key, true);
|
|
92705
92717
|
continue;
|
|
@@ -92747,6 +92759,18 @@ var loadSchema = async (config3, schemaPath) => {
|
|
|
92747
92759
|
const source = await loadSchemaModule(schemaPath, config3.export);
|
|
92748
92760
|
return getAdapter(inputFormat).toJSONSchema(source);
|
|
92749
92761
|
};
|
|
92762
|
+
var DEFAULT_BANNER_TEXT = `This file was auto-generated by @amritk/mjst.
|
|
92763
|
+
* Do not edit it manually β your changes will be overwritten on the next generation.`;
|
|
92764
|
+
var resolveBanner = (banner) => {
|
|
92765
|
+
if (!banner)
|
|
92766
|
+
return "";
|
|
92767
|
+
const text = banner === true ? DEFAULT_BANNER_TEXT : banner;
|
|
92768
|
+
return `/**
|
|
92769
|
+
* ${text}
|
|
92770
|
+
*/
|
|
92771
|
+
|
|
92772
|
+
`;
|
|
92773
|
+
};
|
|
92750
92774
|
var writeGeneratedFile = async (baseDir, filename, content) => {
|
|
92751
92775
|
const filePath = join8(baseDir, filename);
|
|
92752
92776
|
await mkdir(dirname2(filePath), { recursive: true });
|
|
@@ -92803,7 +92827,9 @@ var runSingle = async (config3, schemaPath, outputDir) => {
|
|
|
92803
92827
|
console.log(`Root type: ${rootTypeName}`);
|
|
92804
92828
|
const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, helpersMode, undefined, config3.readonly, config3.typeSuffix);
|
|
92805
92829
|
for (const file2 of files) {
|
|
92806
|
-
|
|
92830
|
+
const isHelper = file2.filename.startsWith("_helpers/");
|
|
92831
|
+
const content = config3.banner && !isHelper ? resolveBanner(config3.banner) + file2.content : file2.content;
|
|
92832
|
+
await writeGeneratedFile(outputDir, file2.filename, content);
|
|
92807
92833
|
console.log(`Generated: ${file2.filename}`);
|
|
92808
92834
|
}
|
|
92809
92835
|
if (config3.build) {
|
|
@@ -92820,7 +92846,8 @@ var runSingleFile = async (config3, schemaPath, outFilePath) => {
|
|
|
92820
92846
|
const rootTypeName = deriveRootTypeName(schema);
|
|
92821
92847
|
console.log(`Root type: ${rootTypeName}`);
|
|
92822
92848
|
const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, config3.helpers ?? "package", undefined, config3.readonly, config3.typeSuffix);
|
|
92823
|
-
|
|
92849
|
+
const combined = combineGeneratedFiles(files);
|
|
92850
|
+
await writeFile(outFilePath, config3.banner ? resolveBanner(config3.banner) + combined : combined, "utf-8");
|
|
92824
92851
|
console.log(`Generated: ${relative(process.cwd(), outFilePath)}`);
|
|
92825
92852
|
if (config3.build) {
|
|
92826
92853
|
await buildOutput(outputDir, [basename(outFilePath)], config3.typesOnly);
|
|
@@ -92860,7 +92887,8 @@ ${relPath} β ${relNoExt}/ (root type: ${rootTypeName})`);
|
|
|
92860
92887
|
sharedHelpers.set(file2.filename, file2.content);
|
|
92861
92888
|
continue;
|
|
92862
92889
|
}
|
|
92863
|
-
|
|
92890
|
+
const content = config3.banner ? resolveBanner(config3.banner) + file2.content : file2.content;
|
|
92891
|
+
await writeGeneratedFile(schemaSubDir, file2.filename, content);
|
|
92864
92892
|
const relativeFilename = join8(relNoExt, file2.filename);
|
|
92865
92893
|
writtenTsFiles.push(relativeFilename);
|
|
92866
92894
|
console.log(`Generated: ${relativeFilename}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/mjst",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@amritk/adapters": "0.2.4",
|
|
46
|
-
"@amritk/generate-parsers": "0.6.
|
|
47
|
-
"@amritk/generate-markdown": "0.2.
|
|
46
|
+
"@amritk/generate-parsers": "0.6.2",
|
|
47
|
+
"@amritk/generate-markdown": "0.2.2",
|
|
48
48
|
"@amritk/helpers": "0.6.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
package/src/cli-config.ts
CHANGED
|
@@ -74,4 +74,11 @@ export type CliConfig = {
|
|
|
74
74
|
* (no suffix). The root type name is used verbatim and is unaffected.
|
|
75
75
|
*/
|
|
76
76
|
readonly typeSuffix?: string
|
|
77
|
+
/**
|
|
78
|
+
* Prepends a comment header to every generated file (excluding `_helpers/`).
|
|
79
|
+
* - `true` β use the default message: "This file was auto-generated by @amritk/mjstβ¦"
|
|
80
|
+
* - A string β use that text as the message body (wrapped in a JSDoc block).
|
|
81
|
+
* - `false` / omitted β no header.
|
|
82
|
+
*/
|
|
83
|
+
readonly banner?: boolean | string
|
|
77
84
|
}
|
package/src/cli.ts
CHANGED
|
@@ -55,6 +55,15 @@ const loadSchema = async (config: Partial<CliConfig>, schemaPath: string): Promi
|
|
|
55
55
|
return getAdapter(inputFormat).toJSONSchema(source)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
const DEFAULT_BANNER_TEXT =
|
|
59
|
+
'This file was auto-generated by @amritk/mjst.\n * Do not edit it manually β your changes will be overwritten on the next generation.'
|
|
60
|
+
|
|
61
|
+
const resolveBanner = (banner: boolean | string | undefined): string => {
|
|
62
|
+
if (!banner) return ''
|
|
63
|
+
const text = banner === true ? DEFAULT_BANNER_TEXT : banner
|
|
64
|
+
return `/**\n * ${text}\n */\n\n`
|
|
65
|
+
}
|
|
66
|
+
|
|
58
67
|
/** Writes a generated file, creating any parent directories the filename implies. */
|
|
59
68
|
const writeGeneratedFile = async (baseDir: string, filename: string, content: string): Promise<void> => {
|
|
60
69
|
const filePath = join(baseDir, filename)
|
|
@@ -151,7 +160,9 @@ const runSingle = async (config: Partial<CliConfig>, schemaPath: string, outputD
|
|
|
151
160
|
)
|
|
152
161
|
|
|
153
162
|
for (const file of files) {
|
|
154
|
-
|
|
163
|
+
const isHelper = file.filename.startsWith('_helpers/')
|
|
164
|
+
const content = config.banner && !isHelper ? resolveBanner(config.banner) + file.content : file.content
|
|
165
|
+
await writeGeneratedFile(outputDir, file.filename, content)
|
|
155
166
|
console.log(`Generated: ${file.filename}`)
|
|
156
167
|
}
|
|
157
168
|
|
|
@@ -192,7 +203,8 @@ const runSingleFile = async (config: Partial<CliConfig>, schemaPath: string, out
|
|
|
192
203
|
config.typeSuffix,
|
|
193
204
|
)
|
|
194
205
|
|
|
195
|
-
|
|
206
|
+
const combined = combineGeneratedFiles(files)
|
|
207
|
+
await writeFile(outFilePath, config.banner ? resolveBanner(config.banner) + combined : combined, 'utf-8')
|
|
196
208
|
console.log(`Generated: ${relative(process.cwd(), outFilePath)}`)
|
|
197
209
|
|
|
198
210
|
if (config.build) {
|
|
@@ -263,7 +275,8 @@ const runRecursive = async (config: Partial<CliConfig>, schemaDir: string, outpu
|
|
|
263
275
|
continue
|
|
264
276
|
}
|
|
265
277
|
|
|
266
|
-
|
|
278
|
+
const content = config.banner ? resolveBanner(config.banner) + file.content : file.content
|
|
279
|
+
await writeGeneratedFile(schemaSubDir, file.filename, content)
|
|
267
280
|
const relativeFilename = join(relNoExt, file.filename)
|
|
268
281
|
writtenTsFiles.push(relativeFilename)
|
|
269
282
|
console.log(`Generated: ${relativeFilename}`)
|
|
@@ -271,4 +271,25 @@ describe('parse-cli-args', () => {
|
|
|
271
271
|
expect(parseCliArgs(['--readonly=true'])).toEqual({ readonly: true })
|
|
272
272
|
expect(parseCliArgs(['--readonly=false'])).toEqual({ readonly: false })
|
|
273
273
|
})
|
|
274
|
+
|
|
275
|
+
it('parses --banner with no value as true (default message)', () => {
|
|
276
|
+
expect(parseCliArgs(['--banner'])).toEqual({ banner: true })
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('parses --banner=true and --banner=false', () => {
|
|
280
|
+
expect(parseCliArgs(['--banner=true'])).toEqual({ banner: true })
|
|
281
|
+
expect(parseCliArgs(['--banner=false'])).toEqual({ banner: false })
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('parses --banner=<text> as a custom message string', () => {
|
|
285
|
+
expect(parseCliArgs(['--banner=Do not edit this file.'])).toEqual({ banner: 'Do not edit this file.' })
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('parses --banner <text> (space-separated) as a custom message string', () => {
|
|
289
|
+
expect(parseCliArgs(['--banner', 'Do not edit this file.'])).toEqual({ banner: 'Do not edit this file.' })
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('parses --banner followed by a flag as true (default message)', () => {
|
|
293
|
+
expect(parseCliArgs(['--banner', '--out-dir', 'dist'])).toEqual({ banner: true, outDir: 'dist' })
|
|
294
|
+
})
|
|
274
295
|
})
|
package/src/parse-cli-args.ts
CHANGED
|
@@ -19,6 +19,7 @@ type MutableConfig = {
|
|
|
19
19
|
readonly?: boolean
|
|
20
20
|
helpers?: 'package' | 'embedded'
|
|
21
21
|
typeSuffix?: string
|
|
22
|
+
banner?: boolean | string
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
// Boolean flags toggle on by presence and accept `--flag=false` to opt out.
|
|
@@ -127,7 +128,10 @@ export const parseCliArgs = (args: readonly string[]): Partial<CliConfig> => {
|
|
|
127
128
|
if (equalsIndex !== -1) {
|
|
128
129
|
const key = toCamelCase(arg.slice(2, equalsIndex))
|
|
129
130
|
const value = arg.slice(equalsIndex + 1)
|
|
130
|
-
if (
|
|
131
|
+
if (key === 'banner') {
|
|
132
|
+
// --banner=false β false, --banner=true β true, --banner=<text> β custom string
|
|
133
|
+
config.banner = value === 'false' ? false : value === 'true' ? true : value
|
|
134
|
+
} else if (BOOLEAN_KEYS.has(key as keyof MutableConfig)) {
|
|
131
135
|
assignBoolean(config, key, value !== 'false')
|
|
132
136
|
} else {
|
|
133
137
|
assignValue(config, key, value)
|
|
@@ -137,6 +141,19 @@ export const parseCliArgs = (args: readonly string[]): Partial<CliConfig> => {
|
|
|
137
141
|
|
|
138
142
|
const key = toCamelCase(arg.slice(2))
|
|
139
143
|
|
|
144
|
+
// --banner: presence alone enables the default message; an immediately
|
|
145
|
+
// following non-flag argument is treated as a custom message string.
|
|
146
|
+
if (key === 'banner') {
|
|
147
|
+
const nextArg = args[i + 1]
|
|
148
|
+
if (nextArg && !nextArg.startsWith('--')) {
|
|
149
|
+
config.banner = nextArg
|
|
150
|
+
i++
|
|
151
|
+
} else {
|
|
152
|
+
config.banner = true
|
|
153
|
+
}
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
|
|
140
157
|
// Boolean flag: presence alone enables it, no value needed
|
|
141
158
|
if (BOOLEAN_KEYS.has(key as keyof MutableConfig)) {
|
|
142
159
|
assignBoolean(config, key, true)
|