@benev/argv
Advanced tools
Comparing version 0.3.1 to 0.3.2
{ | ||
"name": "@benev/argv", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"description": "command line argument parser", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -323,3 +323,20 @@ | ||
- `asTypes` will use your object's property names as the type `name` | ||
- your custom types can throw errors and it works as validation | ||
```ts | ||
const integer = asType({ | ||
name: "integer", | ||
coerce: string => { | ||
const n = Number(string) | ||
if (isNaN(n)) | ||
throw new Error("not a number") | ||
if (!Number.isSafeInteger(n)) | ||
throw new Error("not a safe integer") | ||
return n | ||
}, | ||
}) | ||
``` | ||
<br/> | ||
@@ -326,0 +343,0 @@ |
@@ -5,6 +5,8 @@ | ||
import {Command, CommandOptions} from "./types/commands.js" | ||
import {tnConnect, tnString} from "../../tooling/text/tn.js" | ||
import {InvalidFlagError} from "../../errors/kinds/config.js" | ||
import {Arg, CoerceFn, Param, Type, Opts, Args, Params, ValidateFn} from "./types/units.js" | ||
import * as tn from "../../tooling/text/tn.js" | ||
import * as fmt from "../../tooling/text/formatting.js" | ||
export function command< | ||
@@ -157,8 +159,11 @@ A extends Args, | ||
else if (allowable.length === 1) | ||
message = `must be "${allowable[0]}"` | ||
message = `can be "${allowable[0]}"` | ||
else | ||
message = allowable.map(c => JSON.stringify(c)).join(", ") | ||
message = `choose one: ${allowable.map(c => c).join(", ")}` | ||
return { | ||
help: tnString(tnConnect("\n", [message, help])), | ||
help: tn.str(tn.connect("\n", [ | ||
help ? fmt.normalize(help) : null, | ||
message, | ||
])), | ||
validate: item => { | ||
@@ -172,5 +177,36 @@ if (!allowable.includes(item)) | ||
export function multipleChoice<T>( | ||
allowable: T[], | ||
{zeroAllowed = false, help}: {zeroAllowed?: boolean, help?: string} = {}, | ||
): Opts<T[]> { | ||
let message: string | ||
if (allowable.length === 0) | ||
throw new ConfigError(`zero choices doesn't make sense`) | ||
else if (allowable.length === 1) | ||
message = `can be "${allowable[0]}"` | ||
else | ||
message = zeroAllowed | ||
? `choose zero or more: ${allowable.map(c => c).join(", ")}.` | ||
: `choose one or more: ${allowable.map(c => c).join(", ")}.` | ||
return { | ||
help: tn.str(tn.connect("\n", [ | ||
help ? fmt.normalize(help) : null, | ||
message, | ||
])), | ||
validate: list => { | ||
if (!zeroAllowed && list.length === 0) | ||
throw new Error(`must choose at least one`) | ||
for (const item of list) | ||
if (!allowable.includes(item)) | ||
throw new Error(`invalid choice`) | ||
return list | ||
}, | ||
} | ||
} | ||
export function list<T>({name: type, coerce}: Type<T>): Type<T[]> { | ||
return { | ||
name: `list-${type}`, | ||
name: `${type}-list`, | ||
coerce: string => string | ||
@@ -177,0 +213,0 @@ .split(",") |
@@ -12,2 +12,3 @@ | ||
help?: string | ||
extraArgs?: {name: string, help?: string} | ||
execute?: (analysis: CommandAnalysis<Command<A, P>>) => Promise<void> | ||
@@ -20,2 +21,3 @@ } | ||
help: string | undefined | ||
extraArgs?: {name: string, help?: string} | ||
execute: (analysis: CommandAnalysis<Command<A, P>>) => Promise<void> | ||
@@ -27,2 +29,3 @@ | ||
this.help = o.help | ||
this.extraArgs = o.extraArgs | ||
this.execute = o.execute ?? (async() => {}) | ||
@@ -29,0 +32,0 @@ validateCommand(this as Command<any, any>) |
@@ -7,3 +7,3 @@ | ||
import {checkHelp} from "../parsing/check-help.js" | ||
import {tnFinal} from "../../tooling/text/tn.js" | ||
import {final} from "../../tooling/text/tn.js" | ||
import {makePalette} from "../../tooling/text/theming.js" | ||
@@ -56,3 +56,3 @@ import {CommandTree} from "../analysis/types/commands.js" | ||
const help = printHelp({...config, selectedCommand, relevantCommands, palette}) | ||
const formatted = tnFinal(columns, indent, help) | ||
const formatted = final(columns, indent, help) | ||
onHelp(formatted + "\n") | ||
@@ -59,0 +59,0 @@ return exit(0) |
@@ -7,5 +7,6 @@ | ||
import {Cmd} from "../../analysis/utils/list-all-commands.js" | ||
import {normalize} from "../../../tooling/text/formatting.js" | ||
import {tnConnect, tnIndent} from "../../../tooling/text/tn.js" | ||
import * as tn from "../../../tooling/text/tn.js" | ||
import * as fmt from "../../../tooling/text/formatting.js" | ||
export function helpWiz(palette: Palette<ArgvTheme>) { | ||
@@ -18,3 +19,3 @@ | ||
) { | ||
return tnConnect(" ", [ | ||
return tn.connect(" ", [ | ||
@@ -26,10 +27,16 @@ // program name | ||
(path.length > 0) | ||
&& tnConnect(" ", path.map(palette.command)), | ||
&& tn.connect(" ", path.map(palette.command)), | ||
// args | ||
command.args | ||
.map(arg => arg.name) | ||
.map(n => palette.arg(`${n}`)) | ||
.join(" "), | ||
command.args.length > 0 | ||
? command.args | ||
.map(arg => arg.name) | ||
.map(n => palette.arg(n)) | ||
.join(" ") | ||
: null, | ||
command.extraArgs | ||
? palette.arg(`...${command.extraArgs.name}`) | ||
: null, | ||
// params | ||
@@ -46,10 +53,10 @@ summarize | ||
return command.help | ||
&& palette.plain(normalize(command.help)) | ||
&& palette.plain(fmt.normalize(command.help)) | ||
} | ||
function commandArgs(args: Args) { | ||
return tnConnect("\n\n", args.map(arg => tnConnect("\n", [ | ||
function commandArgs({args, extraArgs}: Command) { | ||
const argsHelp = args.map(arg => tn.connect("\n", [ | ||
// arg header | ||
tnConnect(" ", [ | ||
tn.connect(" ", [ | ||
@@ -74,12 +81,20 @@ // arg name | ||
arg.help | ||
&& tnIndent(1, palette.plain(normalize(arg.help))), | ||
]))) | ||
&& tn.indent(1, palette.plain(fmt.normalize(arg.help))), | ||
])) | ||
const extraArgsHelp = extraArgs | ||
? tn.connect("\n", [ | ||
palette.arg(`...${extraArgs.name},`), | ||
extraArgs.help | ||
&& tn.indent(1, palette.plain(fmt.normalize(extraArgs.help))), | ||
]) | ||
: null | ||
return tn.connect("\n\n", [...argsHelp, extraArgsHelp]) | ||
} | ||
function commandParams(params: Params) { | ||
return tnConnect("\n\n", Object.entries(params) | ||
.map(([name, param]) => tnConnect("\n", [ | ||
return tn.connect("\n\n", Object.entries(params) | ||
.map(([name, param]) => tn.connect("\n", [ | ||
// param header | ||
tnConnect(" ", [ | ||
tn.connect(" ", [ | ||
@@ -108,3 +123,3 @@ // param name | ||
param.help | ||
&& tnIndent(1, palette.plain(normalize(param.help))), | ||
&& tn.indent(1, palette.plain(fmt.normalize(param.help))), | ||
])) | ||
@@ -115,3 +130,3 @@ ) | ||
function programHeadline(name: string, commandList: Cmd[]) { | ||
return tnConnect(" ", [ | ||
return tn.connect(" ", [ | ||
palette.program(name), | ||
@@ -124,5 +139,5 @@ (commandList.length > 1) | ||
function programHelp(help?: string, readme?: string) { | ||
return tnConnect("\n", [ | ||
return tn.connect("\n", [ | ||
readme && `${palette.property("readme")} ${palette.link(readme.trim())}`, | ||
help && palette.plain(normalize(help)), | ||
help && palette.plain(fmt.normalize(help)), | ||
]) | ||
@@ -129,0 +144,0 @@ } |
@@ -6,3 +6,2 @@ | ||
import {Palette} from "../../../tooling/text/theming.js" | ||
import {tnConnect, tnIndent} from "../../../tooling/text/tn.js" | ||
import {SelectedCommand} from "../../analysis/types/analysis.js" | ||
@@ -12,2 +11,4 @@ import {Command, CommandTree} from "../../analysis/types/commands.js" | ||
import * as tn from "../../../tooling/text/tn.js" | ||
export function printHelp({ | ||
@@ -37,6 +38,6 @@ readme, | ||
const {command} = selectedCommand | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, selectedCommand, false), | ||
tnIndent(1, tnConnect("\n", [ | ||
tn.indent(1, tn.connect("\n", [ | ||
wiz.programHelp(programHelp, readme), | ||
@@ -46,4 +47,4 @@ wiz.commandHelp(command), | ||
]), | ||
tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(command.args), | ||
tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(command), | ||
wiz.commandParams(command.params), | ||
@@ -57,9 +58,9 @@ ])), | ||
const {command} = selectedCommand | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, selectedCommand, false), | ||
tnIndent(1, wiz.commandHelp(command)), | ||
tn.indent(1, wiz.commandHelp(command)), | ||
]), | ||
tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(command.args), | ||
tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(command), | ||
wiz.commandParams(command.params), | ||
@@ -73,17 +74,17 @@ ])) | ||
const actuallySummarize = summarize && relevantCommands.length > 1 | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.programHeadline(programName, relevantCommands), | ||
tnIndent(1, wiz.programHelp(programHelp)) | ||
tn.indent(1, wiz.programHelp(programHelp)) | ||
]), | ||
...relevantCommands | ||
.map(cmd => tnIndent(1, tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
.map(cmd => tn.indent(1, tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, cmd, actuallySummarize), | ||
tnIndent(1, wiz.commandHelp(cmd.command)), | ||
tn.indent(1, wiz.commandHelp(cmd.command)), | ||
]), | ||
actuallySummarize | ||
? null | ||
: tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(cmd.command.args), | ||
: tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(cmd.command), | ||
wiz.commandParams(cmd.command.params), | ||
@@ -98,12 +99,12 @@ ])), | ||
const actuallySummarize = summarize && relevantCommands.length > 1 | ||
return tnConnect("\n\n", relevantCommands | ||
.map(cmd => tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", relevantCommands | ||
.map(cmd => tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, cmd, actuallySummarize), | ||
tnIndent(1, wiz.commandHelp(cmd.command)), | ||
tn.indent(1, wiz.commandHelp(cmd.command)), | ||
]), | ||
actuallySummarize | ||
? null | ||
: tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(cmd.command.args), | ||
: tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(cmd.command), | ||
wiz.commandParams(cmd.command.params), | ||
@@ -110,0 +111,0 @@ ])), |
#!/usr/bin/env node | ||
import {cli} from "../areas/cli/cli.js" | ||
import {themes} from "../areas/cli/themes.js" | ||
import {arg, choice, command, number, param, string} from "../areas/analysis/helpers.js" | ||
@@ -6,0 +5,0 @@ |
#!/usr/bin/env node | ||
import {cli} from "../areas/cli/cli.js" | ||
import {themes} from "../areas/cli/themes.js" | ||
import {arg, choice, command, param, type} from "../areas/analysis/helpers.js" | ||
@@ -6,0 +5,0 @@ |
@@ -14,5 +14,6 @@ | ||
export * from "./areas/analysis/helpers.js" | ||
export * from "./areas/analysis/types/units.js" | ||
export * from "./areas/analysis/types/commands.js" | ||
export * as helpers from "./areas/analysis/helpers.js" | ||
export * as validators from "./areas/analysis/validators.js" | ||
export {Command, CommandTree} from "./areas/analysis/types/commands.js" | ||
@@ -23,2 +24,4 @@ // exporting useful tools for making a cli | ||
export * from "./tooling/death-with-dignity.js" | ||
export * as tn from "./tooling/text/tn.js" | ||
export * as fmt from "./tooling/text/formatting.js" | ||
@@ -105,17 +105,38 @@ | ||
const [whitespace, content] = extractLeadingWhitespace(line) | ||
const words = content.split(/\s+/) | ||
const sublines: string[] = [] | ||
let current = whitespace | ||
let word = '' | ||
for (const word of words) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length + 1 | ||
for (const char of content) { | ||
if (/\s/.test(char) || /[.,!?;:()\-]/.test(char)) { | ||
if (word.length > 0) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length | ||
if (proposedLength > columns) { | ||
sublines.push(current) | ||
current = whitespace + word | ||
} else { | ||
current += word | ||
} | ||
word = '' | ||
} | ||
const proposedLength = uncolor(current).length + uncolor(char).length | ||
if (proposedLength > columns) { | ||
sublines.push(current) | ||
current = whitespace + char | ||
} else { | ||
current += char | ||
} | ||
} else { | ||
word += char | ||
} | ||
} | ||
if (word.length > 0) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length | ||
if (proposedLength > columns) { | ||
sublines.push(current) | ||
current = whitespace + word | ||
} else { | ||
current += word | ||
} | ||
else { | ||
current += (current.length > whitespace.length) | ||
? " " + word | ||
: word | ||
} | ||
} | ||
@@ -128,2 +149,27 @@ | ||
// function breakLinesBasedOnLength(columns: number) { | ||
// return (line: string) => { | ||
// const [whitespace, content] = extractLeadingWhitespace(line) | ||
// const words = content.split(/[\s.,!?;:()-]+/) | ||
// const sublines: string[] = [] | ||
// let current = whitespace | ||
// for (const word of words) { | ||
// const proposedLength = uncolor(current).length + uncolor(word).length + 1 | ||
// if (proposedLength > columns) { | ||
// sublines.push(current) | ||
// current = whitespace + word | ||
// } | ||
// else { | ||
// current += (current.length > whitespace.length) | ||
// ? " " + word | ||
// : word | ||
// } | ||
// } | ||
// sublines.push(current) | ||
// return sublines | ||
// } | ||
// } | ||
function extractLeadingWhitespace(s: string) { | ||
@@ -130,0 +176,0 @@ const match = s.match(/^\s*/) |
import {indent, isString, replaceTabs, wrap} from "./formatting.js" | ||
import * as fmt from "./formatting.js" | ||
export type Tn = string | null | undefined | false | ||
export function tnIndent(depth: number, tn: Tn) { | ||
return isString(tn) && indent(depth, tn) | ||
export function indent(depth: number, tn: Tn) { | ||
return fmt.isString(tn) && fmt.indent(depth, tn) | ||
} | ||
export function tnConnect(glue: string, tns: Tn[]) { | ||
const processed = tns.flat(Infinity).filter(isString) | ||
export function connect(glue: string, tns: Tn[]) { | ||
const processed = tns.flat(Infinity).filter(fmt.isString) | ||
return processed.length | ||
@@ -17,11 +17,11 @@ ? processed.join(glue) | ||
export function tnString(tn: Tn) { | ||
export function str(tn: Tn) { | ||
return tn || "" | ||
} | ||
export function tnFinal(columns: number, indent: string, tn: Tn) { | ||
return isString(tn) | ||
? wrap(columns, replaceTabs(tn, indent)) | ||
export function final(columns: number, indent: string, tn: Tn) { | ||
return fmt.isString(tn) | ||
? fmt.wrap(columns, fmt.replaceTabs(tn, indent)) | ||
: "" | ||
} | ||
@@ -38,2 +38,6 @@ import { Command, CommandOptions } from "./types/commands.js"; | ||
}): Opts<T>; | ||
export declare function multipleChoice<T>(allowable: T[], { zeroAllowed, help }?: { | ||
zeroAllowed?: boolean; | ||
help?: string; | ||
}): Opts<T[]>; | ||
export declare function list<T>({ name: type, coerce }: Type<T>): Type<T[]>; |
import { obmap } from "../../tooling/obmap.js"; | ||
import { ConfigError } from "../../errors/basic.js"; | ||
import { Command } from "./types/commands.js"; | ||
import { tnConnect, tnString } from "../../tooling/text/tn.js"; | ||
import { InvalidFlagError } from "../../errors/kinds/config.js"; | ||
import * as tn from "../../tooling/text/tn.js"; | ||
import * as fmt from "../../tooling/text/formatting.js"; | ||
export function command(o) { | ||
@@ -114,7 +115,10 @@ return new Command(o); | ||
else if (allowable.length === 1) | ||
message = `must be "${allowable[0]}"`; | ||
message = `can be "${allowable[0]}"`; | ||
else | ||
message = allowable.map(c => JSON.stringify(c)).join(", "); | ||
message = `choose one: ${allowable.map(c => c).join(", ")}`; | ||
return { | ||
help: tnString(tnConnect("\n", [message, help])), | ||
help: tn.str(tn.connect("\n", [ | ||
help ? fmt.normalize(help) : null, | ||
message, | ||
])), | ||
validate: item => { | ||
@@ -127,5 +131,30 @@ if (!allowable.includes(item)) | ||
} | ||
export function multipleChoice(allowable, { zeroAllowed = false, help } = {}) { | ||
let message; | ||
if (allowable.length === 0) | ||
throw new ConfigError(`zero choices doesn't make sense`); | ||
else if (allowable.length === 1) | ||
message = `can be "${allowable[0]}"`; | ||
else | ||
message = zeroAllowed | ||
? `choose zero or more: ${allowable.map(c => c).join(", ")}.` | ||
: `choose one or more: ${allowable.map(c => c).join(", ")}.`; | ||
return { | ||
help: tn.str(tn.connect("\n", [ | ||
help ? fmt.normalize(help) : null, | ||
message, | ||
])), | ||
validate: list => { | ||
if (!zeroAllowed && list.length === 0) | ||
throw new Error(`must choose at least one`); | ||
for (const item of list) | ||
if (!allowable.includes(item)) | ||
throw new Error(`invalid choice`); | ||
return list; | ||
}, | ||
}; | ||
} | ||
export function list({ name: type, coerce }) { | ||
return { | ||
name: `list-${type}`, | ||
name: `${type}-list`, | ||
coerce: string => string | ||
@@ -132,0 +161,0 @@ .split(",") |
@@ -10,2 +10,6 @@ import { Args, Params } from "./units.js"; | ||
help?: string; | ||
extraArgs?: { | ||
name: string; | ||
help?: string; | ||
}; | ||
execute?: (analysis: CommandAnalysis<Command<A, P>>) => Promise<void>; | ||
@@ -17,4 +21,8 @@ }; | ||
help: string | undefined; | ||
extraArgs?: { | ||
name: string; | ||
help?: string; | ||
}; | ||
execute: (analysis: CommandAnalysis<Command<A, P>>) => Promise<void>; | ||
constructor(o: CommandOptions<A, P>); | ||
} |
@@ -7,2 +7,3 @@ import { validateCommand } from "../utils/validate-command.js"; | ||
this.help = o.help; | ||
this.extraArgs = o.extraArgs; | ||
this.execute = o.execute ?? (async () => { }); | ||
@@ -9,0 +10,0 @@ validateCommand(this); |
@@ -5,3 +5,3 @@ import { themes } from "./themes.js"; | ||
import { checkHelp } from "../parsing/check-help.js"; | ||
import { tnFinal } from "../../tooling/text/tn.js"; | ||
import { final } from "../../tooling/text/tn.js"; | ||
import { makePalette } from "../../tooling/text/theming.js"; | ||
@@ -34,3 +34,3 @@ import { CommandNotFoundError } from "../../errors/kinds/mistakes.js"; | ||
const help = printHelp({ ...config, selectedCommand, relevantCommands, palette }); | ||
const formatted = tnFinal(columns, indent, help); | ||
const formatted = final(columns, indent, help); | ||
onHelp(formatted + "\n"); | ||
@@ -37,0 +37,0 @@ return exit(0); |
import { ArgvTheme } from "../themes.js"; | ||
import { Palette } from "../../../tooling/text/theming.js"; | ||
import { Command } from "../../analysis/types/commands.js"; | ||
import { Args, Params } from "../../analysis/types/units.js"; | ||
import { Params } from "../../analysis/types/units.js"; | ||
import { Cmd } from "../../analysis/utils/list-all-commands.js"; | ||
@@ -11,4 +11,4 @@ export declare function helpWiz(palette: Palette<ArgvTheme>): { | ||
commandHelp: (command: Command) => string | undefined; | ||
commandArgs: (args: Args) => string | null; | ||
commandArgs: ({ args, extraArgs }: Command) => string | null; | ||
commandParams: (params: Params) => string | null; | ||
}; |
@@ -1,6 +0,6 @@ | ||
import { normalize } from "../../../tooling/text/formatting.js"; | ||
import { tnConnect, tnIndent } from "../../../tooling/text/tn.js"; | ||
import * as tn from "../../../tooling/text/tn.js"; | ||
import * as fmt from "../../../tooling/text/formatting.js"; | ||
export function helpWiz(palette) { | ||
function commandHeadline(programName, { command, path }, summarize) { | ||
return tnConnect(" ", [ | ||
return tn.connect(" ", [ | ||
// program name | ||
@@ -10,8 +10,13 @@ palette.program(programName), | ||
(path.length > 0) | ||
&& tnConnect(" ", path.map(palette.command)), | ||
&& tn.connect(" ", path.map(palette.command)), | ||
// args | ||
command.args | ||
.map(arg => arg.name) | ||
.map(n => palette.arg(`${n}`)) | ||
.join(" "), | ||
command.args.length > 0 | ||
? command.args | ||
.map(arg => arg.name) | ||
.map(n => palette.arg(n)) | ||
.join(" ") | ||
: null, | ||
command.extraArgs | ||
? palette.arg(`...${command.extraArgs.name}`) | ||
: null, | ||
// params | ||
@@ -27,8 +32,8 @@ summarize | ||
return command.help | ||
&& palette.plain(normalize(command.help)); | ||
&& palette.plain(fmt.normalize(command.help)); | ||
} | ||
function commandArgs(args) { | ||
return tnConnect("\n\n", args.map(arg => tnConnect("\n", [ | ||
function commandArgs({ args, extraArgs }) { | ||
const argsHelp = args.map(arg => tn.connect("\n", [ | ||
// arg header | ||
tnConnect(" ", [ | ||
tn.connect(" ", [ | ||
// arg name | ||
@@ -48,10 +53,18 @@ palette.arg(arg.name + ","), | ||
arg.help | ||
&& tnIndent(1, palette.plain(normalize(arg.help))), | ||
]))); | ||
&& tn.indent(1, palette.plain(fmt.normalize(arg.help))), | ||
])); | ||
const extraArgsHelp = extraArgs | ||
? tn.connect("\n", [ | ||
palette.arg(`...${extraArgs.name},`), | ||
extraArgs.help | ||
&& tn.indent(1, palette.plain(fmt.normalize(extraArgs.help))), | ||
]) | ||
: null; | ||
return tn.connect("\n\n", [...argsHelp, extraArgsHelp]); | ||
} | ||
function commandParams(params) { | ||
return tnConnect("\n\n", Object.entries(params) | ||
.map(([name, param]) => tnConnect("\n", [ | ||
return tn.connect("\n\n", Object.entries(params) | ||
.map(([name, param]) => tn.connect("\n", [ | ||
// param header | ||
tnConnect(" ", [ | ||
tn.connect(" ", [ | ||
// param name | ||
@@ -74,7 +87,7 @@ palette.param(`--${name},`), | ||
param.help | ||
&& tnIndent(1, palette.plain(normalize(param.help))), | ||
&& tn.indent(1, palette.plain(fmt.normalize(param.help))), | ||
]))); | ||
} | ||
function programHeadline(name, commandList) { | ||
return tnConnect(" ", [ | ||
return tn.connect(" ", [ | ||
palette.program(name), | ||
@@ -86,5 +99,5 @@ (commandList.length > 1) | ||
function programHelp(help, readme) { | ||
return tnConnect("\n", [ | ||
return tn.connect("\n", [ | ||
readme && `${palette.property("readme")} ${palette.link(readme.trim())}`, | ||
help && palette.plain(normalize(help)), | ||
help && palette.plain(fmt.normalize(help)), | ||
]); | ||
@@ -91,0 +104,0 @@ } |
import { helpWiz } from "./help-wiz.js"; | ||
import { tnConnect, tnIndent } from "../../../tooling/text/tn.js"; | ||
import { Command } from "../../analysis/types/commands.js"; | ||
import { listAllCommands } from "../../analysis/utils/list-all-commands.js"; | ||
import * as tn from "../../../tooling/text/tn.js"; | ||
export function printHelp({ readme, palette, commands, selectedCommand, relevantCommands, name: programName, help: programHelp, summarize = true, }) { | ||
@@ -13,6 +13,6 @@ const wiz = helpWiz(palette); | ||
const { command } = selectedCommand; | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, selectedCommand, false), | ||
tnIndent(1, tnConnect("\n", [ | ||
tn.indent(1, tn.connect("\n", [ | ||
wiz.programHelp(programHelp, readme), | ||
@@ -22,4 +22,4 @@ wiz.commandHelp(command), | ||
]), | ||
tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(command.args), | ||
tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(command), | ||
wiz.commandParams(command.params), | ||
@@ -32,9 +32,9 @@ ])), | ||
const { command } = selectedCommand; | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, selectedCommand, false), | ||
tnIndent(1, wiz.commandHelp(command)), | ||
tn.indent(1, wiz.commandHelp(command)), | ||
]), | ||
tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(command.args), | ||
tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(command), | ||
wiz.commandParams(command.params), | ||
@@ -47,17 +47,17 @@ ])) | ||
const actuallySummarize = summarize && relevantCommands.length > 1; | ||
return tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.programHeadline(programName, relevantCommands), | ||
tnIndent(1, wiz.programHelp(programHelp)) | ||
tn.indent(1, wiz.programHelp(programHelp)) | ||
]), | ||
...relevantCommands | ||
.map(cmd => tnIndent(1, tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
.map(cmd => tn.indent(1, tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, cmd, actuallySummarize), | ||
tnIndent(1, wiz.commandHelp(cmd.command)), | ||
tn.indent(1, wiz.commandHelp(cmd.command)), | ||
]), | ||
actuallySummarize | ||
? null | ||
: tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(cmd.command.args), | ||
: tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(cmd.command), | ||
wiz.commandParams(cmd.command.params), | ||
@@ -71,12 +71,12 @@ ])), | ||
const actuallySummarize = summarize && relevantCommands.length > 1; | ||
return tnConnect("\n\n", relevantCommands | ||
.map(cmd => tnConnect("\n\n", [ | ||
tnConnect("\n", [ | ||
return tn.connect("\n\n", relevantCommands | ||
.map(cmd => tn.connect("\n\n", [ | ||
tn.connect("\n", [ | ||
wiz.commandHeadline(programName, cmd, actuallySummarize), | ||
tnIndent(1, wiz.commandHelp(cmd.command)), | ||
tn.indent(1, wiz.commandHelp(cmd.command)), | ||
]), | ||
actuallySummarize | ||
? null | ||
: tnIndent(1, tnConnect("\n\n", [ | ||
wiz.commandArgs(cmd.command.args), | ||
: tn.indent(1, tn.connect("\n\n", [ | ||
wiz.commandArgs(cmd.command), | ||
wiz.commandParams(cmd.command.params), | ||
@@ -83,0 +83,0 @@ ])), |
@@ -8,7 +8,10 @@ export * from "./errors/basic.js"; | ||
export * from "./areas/analysis/helpers.js"; | ||
export * from "./areas/analysis/types/units.js"; | ||
export * from "./areas/analysis/types/commands.js"; | ||
export * as helpers from "./areas/analysis/helpers.js"; | ||
export * as validators from "./areas/analysis/validators.js"; | ||
export { Command, CommandTree } from "./areas/analysis/types/commands.js"; | ||
export * from "./tooling/logger.js"; | ||
export * from "./tooling/text/coloring.js"; | ||
export * from "./tooling/death-with-dignity.js"; | ||
export * as tn from "./tooling/text/tn.js"; | ||
export * as fmt from "./tooling/text/formatting.js"; |
@@ -11,5 +11,6 @@ // all errors | ||
export * from "./areas/analysis/helpers.js"; | ||
export * from "./areas/analysis/types/units.js"; | ||
export * from "./areas/analysis/types/commands.js"; | ||
export * as helpers from "./areas/analysis/helpers.js"; | ||
export * as validators from "./areas/analysis/validators.js"; | ||
export { Command } from "./areas/analysis/types/commands.js"; | ||
// exporting useful tools for making a cli | ||
@@ -19,2 +20,4 @@ export * from "./tooling/logger.js"; | ||
export * from "./tooling/death-with-dignity.js"; | ||
export * as tn from "./tooling/text/tn.js"; | ||
export * as fmt from "./tooling/text/formatting.js"; | ||
//# sourceMappingURL=index.js.map |
@@ -87,7 +87,33 @@ import { uncolor } from "./coloring.js"; | ||
const [whitespace, content] = extractLeadingWhitespace(line); | ||
const words = content.split(/\s+/); | ||
const sublines = []; | ||
let current = whitespace; | ||
for (const word of words) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length + 1; | ||
let word = ''; | ||
for (const char of content) { | ||
if (/\s/.test(char) || /[.,!?;:()\-]/.test(char)) { | ||
if (word.length > 0) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length; | ||
if (proposedLength > columns) { | ||
sublines.push(current); | ||
current = whitespace + word; | ||
} | ||
else { | ||
current += word; | ||
} | ||
word = ''; | ||
} | ||
const proposedLength = uncolor(current).length + uncolor(char).length; | ||
if (proposedLength > columns) { | ||
sublines.push(current); | ||
current = whitespace + char; | ||
} | ||
else { | ||
current += char; | ||
} | ||
} | ||
else { | ||
word += char; | ||
} | ||
} | ||
if (word.length > 0) { | ||
const proposedLength = uncolor(current).length + uncolor(word).length; | ||
if (proposedLength > columns) { | ||
@@ -98,5 +124,3 @@ sublines.push(current); | ||
else { | ||
current += (current.length > whitespace.length) | ||
? " " + word | ||
: word; | ||
current += word; | ||
} | ||
@@ -108,2 +132,24 @@ } | ||
} | ||
// function breakLinesBasedOnLength(columns: number) { | ||
// return (line: string) => { | ||
// const [whitespace, content] = extractLeadingWhitespace(line) | ||
// const words = content.split(/[\s.,!?;:()-]+/) | ||
// const sublines: string[] = [] | ||
// let current = whitespace | ||
// for (const word of words) { | ||
// const proposedLength = uncolor(current).length + uncolor(word).length + 1 | ||
// if (proposedLength > columns) { | ||
// sublines.push(current) | ||
// current = whitespace + word | ||
// } | ||
// else { | ||
// current += (current.length > whitespace.length) | ||
// ? " " + word | ||
// : word | ||
// } | ||
// } | ||
// sublines.push(current) | ||
// return sublines | ||
// } | ||
// } | ||
function extractLeadingWhitespace(s) { | ||
@@ -110,0 +156,0 @@ const match = s.match(/^\s*/); |
export type Tn = string | null | undefined | false; | ||
export declare function tnIndent(depth: number, tn: Tn): string | false; | ||
export declare function tnConnect(glue: string, tns: Tn[]): string | null; | ||
export declare function tnString(tn: Tn): string; | ||
export declare function tnFinal(columns: number, indent: string, tn: Tn): string; | ||
export declare function indent(depth: number, tn: Tn): string | false; | ||
export declare function connect(glue: string, tns: Tn[]): string | null; | ||
export declare function str(tn: Tn): string; | ||
export declare function final(columns: number, indent: string, tn: Tn): string; |
@@ -1,7 +0,7 @@ | ||
import { indent, isString, replaceTabs, wrap } from "./formatting.js"; | ||
export function tnIndent(depth, tn) { | ||
return isString(tn) && indent(depth, tn); | ||
import * as fmt from "./formatting.js"; | ||
export function indent(depth, tn) { | ||
return fmt.isString(tn) && fmt.indent(depth, tn); | ||
} | ||
export function tnConnect(glue, tns) { | ||
const processed = tns.flat(Infinity).filter(isString); | ||
export function connect(glue, tns) { | ||
const processed = tns.flat(Infinity).filter(fmt.isString); | ||
return processed.length | ||
@@ -11,10 +11,10 @@ ? processed.join(glue) | ||
} | ||
export function tnString(tn) { | ||
export function str(tn) { | ||
return tn || ""; | ||
} | ||
export function tnFinal(columns, indent, tn) { | ||
return isString(tn) | ||
? wrap(columns, replaceTabs(tn, indent)) | ||
export function final(columns, indent, tn) { | ||
return fmt.isString(tn) | ||
? fmt.wrap(columns, fmt.replaceTabs(tn, indent)) | ||
: ""; | ||
} | ||
//# sourceMappingURL=tn.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
227540
4367
387