11#!/usr/bin/env node
22import nanoSpawn from "nano-spawn" ;
3- import minimist from "minimist " ;
3+ import { parseArgs } from "node:util " ;
44import { basename , dirname , join , relative } from "node:path" ;
5- import { cwd , exit as doExit , stdout , argv } from "node:process" ;
5+ import { cwd , exit as doExit , stdout } from "node:process" ;
66import { EOL , platform } from "node:os" ;
77import { readFileSync , writeFileSync , accessSync , truncateSync , statSync } from "node:fs" ;
88import pkg from "./package.json" with { type : "json" } ;
99import { parse } from "smol-toml" ;
10- import type { Opts as MinimistOpts } from "minimist" ;
1110import type { Result } from "nano-spawn" ;
1211
1312export type SemverLevel = "patch" | "minor" | "major" ;
@@ -24,39 +23,6 @@ function uniq<T extends Array<any>>(arr: T): T {
2423 return Array . from ( new Set ( arr ) ) as T ;
2524}
2625
27- const minOpts : MinimistOpts = {
28- boolean : [
29- "a" , "all" ,
30- "D" , "dry" ,
31- "g" , "gitless" ,
32- "h" , "help" ,
33- "P" , "packageless" ,
34- "p" , "prefix" ,
35- "v" , "version" ,
36- ] ,
37- string : [
38- "b" , "base" ,
39- "c" , "command" ,
40- "d" , "date" ,
41- "r" , "replace" ,
42- "m" , "message" ,
43- "_" ,
44- ] ,
45- alias : {
46- a : "all" ,
47- b : "base" ,
48- c : "command" ,
49- d : "date" ,
50- D : "dry" ,
51- g : "gitless" ,
52- h : "help" ,
53- m : "message" ,
54- p : "prefix" ,
55- r : "replace" ,
56- v : "version" ,
57- }
58- } ;
59-
6026function replaceTokens ( str : string , newVersion : string ) : string {
6127 const [ major , minor , patch ] = newVersion . split ( "." ) ;
6228 return str
@@ -177,44 +143,6 @@ function write(file: string, content: string): void {
177143 }
178144}
179145
180- function parseMixedArg ( arg : any ) {
181- if ( arg === "" ) {
182- return true ;
183- } else if ( typeof arg === "string" ) {
184- return arg . includes ( "," ) ? arg . split ( "," ) : [ arg ] ;
185- } else if ( Array . isArray ( arg ) ) {
186- return arg ;
187- } else {
188- return Boolean ( arg ) ;
189- }
190- }
191-
192- // handle minimist parsing issues like '-d patch'
193- function fixArgs ( commands : Set < string > , args : any , minOpts : MinimistOpts ) {
194- for ( const key of Object . keys ( minOpts . alias as object ) ) {
195- delete args [ key ] ;
196- }
197-
198- if ( commands . has ( args . date ) ) {
199- args . _ = [ args . date , ...args . _ ] ;
200- args . date = true ;
201- }
202- if ( commands . has ( args . base ) ) {
203- args . _ = [ args . base , ...args . _ ] ;
204- args . base = true ;
205- }
206- if ( commands . has ( args . command ) ) {
207- args . _ = [ args . command , ...args . _ ] ;
208- args . command = "" ;
209- }
210- if ( commands . has ( args . replace ) ) {
211- args . _ = [ args . replace , ...args . _ ] ;
212- args . replace = "" ;
213- }
214-
215- return args ;
216- }
217-
218146// join strings, ignoring falsy values and trimming the result
219147function joinStrings ( strings : Array < string | undefined > , separator : string ) : string {
220148 const arr : Array < string > = [ ] ;
@@ -245,8 +173,26 @@ function writeResult(result: Result): void {
245173
246174async function main ( ) : Promise < void > {
247175 const commands = new Set ( [ "patch" , "minor" , "major" ] ) ;
248- const args = fixArgs ( commands , minimist ( argv . slice ( 2 ) , minOpts ) , minOpts ) ;
249- let [ level , ...files ] : [ SemverLevel , ...Array < string > ] = args . _ ;
176+ const result = parseArgs ( {
177+ strict : true ,
178+ allowPositionals : true ,
179+ options : {
180+ all : { short : "a" , type : "boolean" } ,
181+ dry : { short : "D" , type : "boolean" } ,
182+ gitless : { short : "g" , type : "boolean" } ,
183+ help : { short : "h" , type : "boolean" } ,
184+ packageless : { short : "P" , type : "boolean" } ,
185+ prefix : { short : "p" , type : "boolean" } ,
186+ version : { short : "v" , type : "boolean" } ,
187+ date : { short : "d" , type : "boolean" } ,
188+ base : { short : "b" , type : "string" } ,
189+ command : { short : "c" , type : "string" } ,
190+ replace : { short : "r" , type : "string" , multiple : true } ,
191+ message : { short : "m" , type : "string" } ,
192+ } ,
193+ } ) ;
194+ const args = result . values ;
195+ let [ level , ...files ] = result . positionals ;
250196 files = uniq ( files ) ;
251197
252198 if ( args . version ) {
@@ -262,7 +208,7 @@ async function main(): Promise<void> {
262208 -b, --base <version> Base version. Default is from latest git tag or 0.0.0
263209 -p, --prefix Prefix version string with a "v" character. Default is none
264210 -c, --command <cmd> Run command after files are updated but before git commit and tag
265- -d, --date [<date>] Replace dates in format YYYY-MM-DD with current or given date
211+ -d, --date Replace dates in format YYYY-MM-DD with current date
266212 -m, --message <str> Custom tag and commit message
267213 -r, --replace <str> Additional replacements in the format "s#regexp#replacement#flags"
268214 -g, --gitless Do not perform any git action like creating commit and tag
@@ -278,17 +224,9 @@ async function main(): Promise<void> {
278224 exit ( ) ;
279225 }
280226
281- let date: any = parseMixedArg(args.date);
282- if (date) {
283- if ( date === true ) {
284- date = ( new Date ( ) ) . toISOString ( ) . substring ( 0 , 10 ) ;
285- } else if (Array.isArray(date)) {
286- date = date [ date . length - 1 ] ;
287- }
288-
289- if (typeof date !== "string" || !/^[0-9]{ 4 } -[0-9]{ 2 } -[0-9]{ 2 } $/.test(date)) {
290- exit ( `Invalid date argument: ${ date } ` ) ;
291- }
227+ let date = "" ;
228+ if ( args . date ) {
229+ date = ( new Date ( ) ) . toISOString ( ) . substring ( 0 , 10 ) ;
292230 }
293231
294232 const pwd = cwd ( ) ;
@@ -314,7 +252,7 @@ async function main(): Promise<void> {
314252 baseVersion = "0.0.0" ;
315253 }
316254 } else {
317- baseVersion = args . base ;
255+ baseVersion = String ( args . base ) ;
318256 }
319257
320258 // chop off "v"
@@ -329,11 +267,11 @@ async function main(): Promise<void> {
329267 files = files . map ( file => relative ( pwd , file ) ) ;
330268
331269 // set new version
332- const newVersion = incrementSemver ( baseVersion , level ) ;
270+ const newVersion = incrementSemver ( baseVersion , level as SemverLevel ) ;
333271
334272 const replacements : Array < { re : RegExp , replacement : string } > = [ ] ;
335273 if ( args . replace ) {
336- args . replace = Array . isArray ( args . replace ) ? args . replace : [ args . replace ] ;
274+ args . replace = ( Array . isArray ( args . replace ) ? args . replace : [ args . replace ] as Array < string > ) ;
337275 for ( const replaceStr of args . replace ) {
338276 let [ _ , re , replacement , flags ] = ( / ^ s # ( .+ ?) # ( .+ ?) # ( .* ) $ / . exec ( replaceStr ) || [ ] ) ;
339277
@@ -371,13 +309,8 @@ async function main(): Promise<void> {
371309 }
372310 if ( args . gitless ) return ; // nothing else to do
373311
374- const messages: Array < string > = parseMixedArg( args.message) as Array < string > ;
312+ const msg = args . message ;
375313 const tagName = args [ "prefix" ] ? `v${ newVersion } ` : newVersion ;
376- const msgs: Array< string > = [];
377-
378- if (messages) {
379- msgs . push ( ...messages . map ( message => replaceTokens ( message , newVersion ) ) ) ;
380- }
381314
382315 // check if base tag exists
383316 let range = "" ;
@@ -411,7 +344,7 @@ async function main(): Promise<void> {
411344 }
412345
413346 // create commit
414- const commitMsg = joinStrings([tagName, ...msgs , changelog], "\n\n");
347+ const commitMsg = joinStrings ( [ tagName , msg , changelog ] . filter ( Boolean ) , "\n\n" ) ;
415348 if ( args . all ) {
416349 writeResult ( await nanoSpawn ( "git" , [ "commit" , "-a" , "--allow-empty" , "-F" , "-" ] , { stdin : { string : commitMsg } } ) ) ;
417350 } else {
@@ -425,7 +358,7 @@ async function main(): Promise<void> {
425358 }
426359
427360 // create tag
428- const tagMsg = joinStrings ( [ ... msgs , changelog ] , "\n\n" ) ;
361+ const tagMsg = joinStrings ( [ msg , changelog ] . filter ( Boolean ) , "\n\n" ) ;
429362 // adding explicit -a here seems to make git no longer sign the tag
430363 writeResult ( await nanoSpawn ( "git" , [ "tag" , "-f" , "-F" , "-" , tagName ] , { stdin : { string : tagMsg } } ) ) ;
431364}
0 commit comments