Skip to content

Commit 535a68e

Browse files
author
Pelle Wessman
authored
Reusable consistent flags (#24)
1 parent 980461a commit 535a68e

File tree

8 files changed

+120
-96
lines changed

8 files changed

+120
-96
lines changed

lib/commands/info/index.js

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import chalk from 'chalk'
44
import meow from 'meow'
55
import ora from 'ora'
66

7+
import { outputFlags, validationFlags } from '../../flags/index.js'
78
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
89
import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
910
import { InputError } from '../../utils/errors.js'
@@ -47,17 +48,17 @@ export const info = {
4748
* @returns {void|CommandContext}
4849
*/
4950
function setupCommand (name, description, argv, importMeta) {
51+
const flags = {
52+
...outputFlags,
53+
...validationFlags,
54+
}
55+
5056
const cli = meow(`
5157
Usage
5258
$ ${name} <name>
5359
5460
Options
55-
${printFlagList({
56-
'--all': 'Include all issues',
57-
'--json': 'Output result as json',
58-
'--markdown': 'Output result as markdown',
59-
'--strict': 'Exits with an error code if any matching issues are found',
60-
}, 6)}
61+
${printFlagList(flags, 6)}
6162
6263
Examples
6364
$ ${name} webtorrent
@@ -66,26 +67,7 @@ function setupCommand (name, description, argv, importMeta) {
6667
argv,
6768
description,
6869
importMeta,
69-
flags: {
70-
all: {
71-
type: 'boolean',
72-
default: false,
73-
},
74-
json: {
75-
type: 'boolean',
76-
alias: 'j',
77-
default: false,
78-
},
79-
markdown: {
80-
type: 'boolean',
81-
alias: 'm',
82-
default: false,
83-
},
84-
strict: {
85-
type: 'boolean',
86-
default: false,
87-
},
88-
}
70+
flags
8971
})
9072

9173
const {

lib/commands/report/create.js

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import ora from 'ora'
99
import { ErrorWithCause } from 'pony-cause'
1010

1111
import { fetchReportData, formatReportDataOutput } from './view.js'
12+
import { outputFlags, validationFlags } from '../../flags/index.js'
1213
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
1314
import { ChalkOrMarkdown, logSymbols } from '../../utils/chalk-markdown.js'
1415
import { InputError } from '../../utils/errors.js'
16+
import { prepareFlags } from '../../utils/flags.js'
1517
import { printFlagList } from '../../utils/formatting.js'
1618
import { createDebugLogger } from '../../utils/misc.js'
1719
import { getPackageFiles } from '../../utils/path-resolve.js'
@@ -79,6 +81,28 @@ export const create = {
7981
* @returns {Promise<void|CommandContext>}
8082
*/
8183
async function setupCommand (name, description, argv, importMeta) {
84+
const flags = prepareFlags({
85+
...outputFlags,
86+
...validationFlags,
87+
debug: {
88+
type: 'boolean',
89+
alias: 'd',
90+
default: false,
91+
description: 'Output debug information',
92+
},
93+
dryRun: {
94+
type: 'boolean',
95+
default: false,
96+
description: 'Only output what will be done without actually doing it',
97+
},
98+
view: {
99+
type: 'boolean',
100+
alias: 'v',
101+
default: false,
102+
description: 'Will wait for and return the created report'
103+
},
104+
})
105+
82106
const cli = meow(`
83107
Usage
84108
$ ${name} <paths-to-package-folders-and-files>
@@ -114,40 +138,7 @@ async function setupCommand (name, description, argv, importMeta) {
114138
argv,
115139
description,
116140
importMeta,
117-
flags: {
118-
all: {
119-
type: 'boolean',
120-
default: false,
121-
},
122-
debug: {
123-
type: 'boolean',
124-
alias: 'd',
125-
default: false,
126-
},
127-
dryRun: {
128-
type: 'boolean',
129-
default: false,
130-
},
131-
json: {
132-
type: 'boolean',
133-
alias: 'j',
134-
default: false,
135-
},
136-
markdown: {
137-
type: 'boolean',
138-
alias: 'm',
139-
default: false,
140-
},
141-
strict: {
142-
type: 'boolean',
143-
default: false,
144-
},
145-
view: {
146-
type: 'boolean',
147-
alias: 'v',
148-
default: false,
149-
},
150-
}
141+
flags,
151142
})
152143

153144
const {

lib/commands/report/view.js

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import chalk from 'chalk'
44
import meow from 'meow'
55
import ora from 'ora'
66

7+
import { outputFlags, validationFlags } from '../../flags/index.js'
78
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
89
import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
910
import { InputError } from '../../utils/errors.js'
@@ -28,7 +29,6 @@ export const view = {
2829

2930
// Internal functions
3031

31-
// TODO: Share more of the flag setup inbetween the commands
3232
/**
3333
* @typedef CommandContext
3434
* @property {boolean} includeAllIssues
@@ -46,44 +46,25 @@ export const view = {
4646
* @returns {void|CommandContext}
4747
*/
4848
function setupCommand (name, description, argv, importMeta) {
49+
const flags = {
50+
...outputFlags,
51+
...validationFlags,
52+
}
53+
4954
const cli = meow(`
5055
Usage
5156
$ ${name} <report-identifier>
5257
5358
Options
54-
${printFlagList({
55-
'--all': 'Include all issues',
56-
'--json': 'Output result as json',
57-
'--markdown': 'Output result as markdown',
58-
'--strict': 'Exits with an error code if report result is deemed unhealthy',
59-
}, 6)}
59+
${printFlagList(flags, 6)}
6060
6161
Examples
6262
$ ${name} QXU8PmK7LfH608RAwfIKdbcHgwEd_ZeWJ9QEGv05FJUQ
6363
`, {
6464
argv,
6565
description,
6666
importMeta,
67-
flags: {
68-
all: {
69-
type: 'boolean',
70-
default: false,
71-
},
72-
json: {
73-
type: 'boolean',
74-
alias: 'j',
75-
default: false,
76-
},
77-
markdown: {
78-
type: 'boolean',
79-
alias: 'm',
80-
default: false,
81-
},
82-
strict: {
83-
type: 'boolean',
84-
default: false,
85-
},
86-
}
67+
flags,
8768
})
8869

8970
// Extract the input

lib/flags/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { outputFlags } from './output.js'
2+
export { validationFlags } from './validation.js'

lib/flags/output.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { prepareFlags } from '../utils/flags.js'
2+
3+
export const outputFlags = prepareFlags({
4+
json: {
5+
type: 'boolean',
6+
alias: 'j',
7+
default: false,
8+
description: 'Output result as json',
9+
},
10+
markdown: {
11+
type: 'boolean',
12+
alias: 'm',
13+
default: false,
14+
description: 'Output result as markdown',
15+
},
16+
})

lib/flags/validation.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { prepareFlags } from '../utils/flags.js'
2+
3+
export const validationFlags = prepareFlags({
4+
all: {
5+
type: 'boolean',
6+
default: false,
7+
description: 'Include all issues',
8+
},
9+
strict: {
10+
type: 'boolean',
11+
default: false,
12+
description: 'Exits with an error code if any matching issues are found',
13+
},
14+
})

lib/utils/flags.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @typedef FlagExtensions
3+
* @property {string} description
4+
*/
5+
6+
/**
7+
* @template {import('meow').FlagType} Type
8+
* @template Default
9+
* @template {boolean} [IsMultiple=false]
10+
* @typedef {import('meow').Flag<Type, Default, IsMultiple> & FlagExtensions} Flag
11+
*/
12+
13+
/** @typedef {Flag<'string', string> | Flag<'string', string[], true>} StringFlag */
14+
/** @typedef {Flag<'boolean', boolean> | Flag<'boolean', boolean[], true>} BooleanFlag */
15+
/** @typedef {Flag<'number', number> | Flag<'number', number[], true>} NumberFlag */
16+
/** @typedef {StringFlag | BooleanFlag | NumberFlag} AnyFlag */
17+
/** @typedef {Record<string, AnyFlag>} AnyFlags */
18+
19+
/**
20+
* @template {AnyFlags} Flags
21+
* @param {Flags} flags
22+
* @returns {Readonly<Flags>}
23+
*/
24+
export function prepareFlags (flags) {
25+
// As we can't do "satisfies AnyFlags" in JS yet (+ we add a bonus through Readonly<>)
26+
return flags
27+
}

lib/utils/formatting.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
/** @typedef {string|{ description: string }} ListDescription */
22

3+
/**
4+
* @typedef HelpListOptions
5+
* @property {string} [keyPrefix]
6+
* @property {number} [padName]
7+
*/
8+
39
/**
410
* @param {Record<string,ListDescription>} list
511
* @param {number} indent
6-
* @param {number} padName
12+
* @param {HelpListOptions} options
713
* @returns {string}
814
*/
9-
export function printHelpList (list, indent, padName = 18) {
15+
export function printHelpList (list, indent, options = {}) {
16+
const {
17+
keyPrefix = '',
18+
padName = 18,
19+
} = options
20+
1021
const names = Object.keys(list).sort()
1122

1223
let result = ''
@@ -15,22 +26,22 @@ export function printHelpList (list, indent, padName = 18) {
1526
const rawDescription = list[name]
1627
const description = (typeof rawDescription === 'object' ? rawDescription.description : rawDescription) || ''
1728

18-
result += ''.padEnd(indent) + name.padEnd(padName) + description + '\n'
29+
result += ''.padEnd(indent) + (keyPrefix + name).padEnd(padName) + description + '\n'
1930
}
2031

2132
return result.trim()
2233
}
2334

2435
/**
25-
* @param {Record<string,ListDescription>} list
36+
* @param {Record<string, ListDescription>} list
2637
* @param {number} indent
27-
* @param {number} padName
38+
* @param {HelpListOptions} options
2839
* @returns {string}
2940
*/
30-
export function printFlagList (list, indent, padName = 18) {
41+
export function printFlagList (list, indent, options = {}) {
3142
return printHelpList({
32-
'--help': 'Print this help and exits.',
33-
'--version': 'Prints current version and exits.',
43+
'help': 'Print this help and exits.',
44+
'version': 'Prints current version and exits.',
3445
...list,
35-
}, indent, padName)
46+
}, indent, { keyPrefix: '--', ...options })
3647
}

0 commit comments

Comments
 (0)