index.d.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /// <reference types="node" />
  2. export type ConfigType = 'number' | 'string' | 'boolean';
  3. /**
  4. * Given a Jack object, get the typeof its ConfigSet
  5. */
  6. export type Unwrap<J> = J extends Jack<infer C> ? C : never;
  7. import { inspect, InspectOptions } from 'node:util';
  8. /**
  9. * Defines the type of value that is valid, given a config definition's
  10. * {@link ConfigType} and boolean multiple setting
  11. */
  12. export type ValidValue<T extends ConfigType = ConfigType, M extends boolean = boolean> = [
  13. T,
  14. M
  15. ] extends ['number', true] ? number[] : [T, M] extends ['string', true] ? string[] : [T, M] extends ['boolean', true] ? boolean[] : [T, M] extends ['number', false] ? number : [T, M] extends ['string', false] ? string : [T, M] extends ['boolean', false] ? boolean : [T, M] extends ['string', boolean] ? string | string[] : [T, M] extends ['boolean', boolean] ? boolean | boolean[] : [T, M] extends ['number', boolean] ? number | number[] : [T, M] extends [ConfigType, false] ? string | number | boolean : [T, M] extends [ConfigType, true] ? string[] | number[] | boolean[] : string | number | boolean | string[] | number[] | boolean[];
  16. /**
  17. * The meta information for a config option definition, when the
  18. * type and multiple values can be inferred by the method being used
  19. */
  20. export type ConfigOptionMeta<T extends ConfigType, M extends boolean = boolean, O extends undefined | (T extends 'boolean' ? never : T extends 'string' ? readonly string[] : T extends 'number' ? readonly number[] : readonly number[] | readonly string[]) = undefined | (T extends 'boolean' ? never : T extends 'string' ? readonly string[] : T extends 'number' ? readonly number[] : readonly number[] | readonly string[])> = {
  21. default?: undefined | (ValidValue<T, M> & (O extends number[] | string[] ? M extends false ? O[number] : O[number][] : unknown));
  22. validOptions?: O;
  23. description?: string;
  24. validate?: ((v: unknown) => v is ValidValue<T, M>) | ((v: unknown) => boolean);
  25. short?: string | undefined;
  26. type?: T;
  27. hint?: T extends 'boolean' ? never : string;
  28. delim?: M extends true ? string : never;
  29. } & (M extends false ? {
  30. multiple?: false | undefined;
  31. } : M extends true ? {
  32. multiple: true;
  33. } : {
  34. multiple?: boolean;
  35. });
  36. /**
  37. * A set of {@link ConfigOptionMeta} fields, referenced by their longOption
  38. * string values.
  39. */
  40. export type ConfigMetaSet<T extends ConfigType, M extends boolean = boolean> = {
  41. [longOption: string]: ConfigOptionMeta<T, M>;
  42. };
  43. /**
  44. * Infer {@link ConfigSet} fields from a given {@link ConfigMetaSet}
  45. */
  46. export type ConfigSetFromMetaSet<T extends ConfigType, M extends boolean, S extends ConfigMetaSet<T, M>> = {
  47. [longOption in keyof S]: ConfigOptionBase<T, M>;
  48. };
  49. /**
  50. * Fields that can be set on a {@link ConfigOptionBase} or
  51. * {@link ConfigOptionMeta} based on whether or not the field is known to be
  52. * multiple.
  53. */
  54. export type MultiType<M extends boolean> = M extends true ? {
  55. multiple: true;
  56. delim?: string | undefined;
  57. } : M extends false ? {
  58. multiple?: false | undefined;
  59. delim?: undefined;
  60. } : {
  61. multiple?: boolean | undefined;
  62. delim?: string | undefined;
  63. };
  64. /**
  65. * A config field definition, in its full representation.
  66. */
  67. export type ConfigOptionBase<T extends ConfigType, M extends boolean = boolean> = {
  68. type: T;
  69. short?: string | undefined;
  70. default?: ValidValue<T, M> | undefined;
  71. description?: string;
  72. hint?: T extends 'boolean' ? undefined : string | undefined;
  73. validate?: (v: unknown) => v is ValidValue<T, M>;
  74. validOptions?: T extends 'boolean' ? undefined : T extends 'string' ? readonly string[] : T extends 'number' ? readonly number[] : readonly number[] | readonly string[];
  75. } & MultiType<M>;
  76. export declare const isConfigType: (t: string) => t is ConfigType;
  77. export declare const isConfigOption: <T extends ConfigType, M extends boolean>(o: any, type: T, multi: M) => o is ConfigOptionBase<T, M>;
  78. /**
  79. * A set of {@link ConfigOptionBase} objects, referenced by their longOption
  80. * string values.
  81. */
  82. export type ConfigSet = {
  83. [longOption: string]: ConfigOptionBase<ConfigType>;
  84. };
  85. /**
  86. * The 'values' field returned by {@link Jack#parse}
  87. */
  88. export type OptionsResults<T extends ConfigSet> = {
  89. [k in keyof T]?: T[k]['validOptions'] extends (readonly string[] | readonly number[]) ? T[k] extends ConfigOptionBase<'string' | 'number', false> ? T[k]['validOptions'][number] : T[k] extends ConfigOptionBase<'string' | 'number', true> ? T[k]['validOptions'][number][] : never : T[k] extends ConfigOptionBase<'string', false> ? string : T[k] extends ConfigOptionBase<'string', true> ? string[] : T[k] extends ConfigOptionBase<'number', false> ? number : T[k] extends ConfigOptionBase<'number', true> ? number[] : T[k] extends ConfigOptionBase<'boolean', false> ? boolean : T[k] extends ConfigOptionBase<'boolean', true> ? boolean[] : never;
  90. };
  91. /**
  92. * The object retured by {@link Jack#parse}
  93. */
  94. export type Parsed<T extends ConfigSet> = {
  95. values: OptionsResults<T>;
  96. positionals: string[];
  97. };
  98. /**
  99. * A row used when generating the {@link Jack#usage} string
  100. */
  101. export interface Row {
  102. left?: string;
  103. text: string;
  104. skipLine?: boolean;
  105. type?: string;
  106. }
  107. /**
  108. * A heading for a section in the usage, created by the jack.heading()
  109. * method.
  110. *
  111. * First heading is always level 1, subsequent headings default to 2.
  112. *
  113. * The level of the nearest heading level sets the indentation of the
  114. * description that follows.
  115. */
  116. export interface Heading extends Row {
  117. type: 'heading';
  118. text: string;
  119. left?: '';
  120. skipLine?: boolean;
  121. level: number;
  122. pre?: boolean;
  123. }
  124. /**
  125. * An arbitrary blob of text describing some stuff, set by the
  126. * jack.description() method.
  127. *
  128. * Indentation determined by level of the nearest header.
  129. */
  130. export interface Description extends Row {
  131. type: 'description';
  132. text: string;
  133. left?: '';
  134. skipLine?: boolean;
  135. pre?: boolean;
  136. }
  137. /**
  138. * A heading or description row used when generating the {@link Jack#usage}
  139. * string
  140. */
  141. export type TextRow = Heading | Description;
  142. /**
  143. * Either a {@link TextRow} or a reference to a {@link ConfigOptionBase}
  144. */
  145. export type UsageField = TextRow | {
  146. type: 'config';
  147. name: string;
  148. value: ConfigOptionBase<ConfigType>;
  149. };
  150. /**
  151. * Options provided to the {@link Jack} constructor
  152. */
  153. export interface JackOptions {
  154. /**
  155. * Whether to allow positional arguments
  156. *
  157. * @default true
  158. */
  159. allowPositionals?: boolean;
  160. /**
  161. * Prefix to use when reading/writing the environment variables
  162. *
  163. * If not specified, environment behavior will not be available.
  164. */
  165. envPrefix?: string;
  166. /**
  167. * Environment object to read/write. Defaults `process.env`.
  168. * No effect if `envPrefix` is not set.
  169. */
  170. env?: {
  171. [k: string]: string | undefined;
  172. };
  173. /**
  174. * A short usage string. If not provided, will be generated from the
  175. * options provided, but that can of course be rather verbose if
  176. * there are a lot of options.
  177. */
  178. usage?: string;
  179. /**
  180. * Stop parsing flags and opts at the first positional argument.
  181. * This is to support cases like `cmd [flags] <subcmd> [options]`, where
  182. * each subcommand may have different options. This effectively treats
  183. * any positional as a `--` argument. Only relevant if `allowPositionals`
  184. * is true.
  185. *
  186. * To do subcommands, set this option, look at the first positional, and
  187. * parse the remaining positionals as appropriate.
  188. *
  189. * @default false
  190. */
  191. stopAtPositional?: boolean;
  192. /**
  193. * Conditional `stopAtPositional`. If set to a `(string)=>boolean` function,
  194. * will be called with each positional argument encountered. If the function
  195. * returns true, then parsing will stop at that point.
  196. */
  197. stopAtPositionalTest?: (arg: string) => boolean;
  198. }
  199. /**
  200. * Class returned by the {@link jack} function and all configuration
  201. * definition methods. This is what gets chained together.
  202. */
  203. export declare class Jack<C extends ConfigSet = {}> {
  204. #private;
  205. constructor(options?: JackOptions);
  206. /**
  207. * Set the default value (which will still be overridden by env or cli)
  208. * as if from a parsed config file. The optional `source` param, if
  209. * provided, will be included in error messages if a value is invalid or
  210. * unknown.
  211. */
  212. setConfigValues(values: OptionsResults<C>, source?: string): this;
  213. /**
  214. * Parse a string of arguments, and return the resulting
  215. * `{ values, positionals }` object.
  216. *
  217. * If an {@link JackOptions#envPrefix} is set, then it will read default
  218. * values from the environment, and write the resulting values back
  219. * to the environment as well.
  220. *
  221. * Environment values always take precedence over any other value, except
  222. * an explicit CLI setting.
  223. */
  224. parse(args?: string[]): Parsed<C>;
  225. loadEnvDefaults(): void;
  226. applyDefaults(p: Parsed<C>): void;
  227. /**
  228. * Only parse the command line arguments passed in.
  229. * Does not strip off the `node script.js` bits, so it must be just the
  230. * arguments you wish to have parsed.
  231. * Does not read from or write to the environment, or set defaults.
  232. */
  233. parseRaw(args: string[]): Parsed<C>;
  234. /**
  235. * Validate that any arbitrary object is a valid configuration `values`
  236. * object. Useful when loading config files or other sources.
  237. */
  238. validate(o: unknown): asserts o is Parsed<C>['values'];
  239. writeEnv(p: Parsed<C>): void;
  240. /**
  241. * Add a heading to the usage output banner
  242. */
  243. heading(text: string, level?: 1 | 2 | 3 | 4 | 5 | 6, { pre }?: {
  244. pre?: boolean;
  245. }): Jack<C>;
  246. /**
  247. * Add a long-form description to the usage output at this position.
  248. */
  249. description(text: string, { pre }?: {
  250. pre?: boolean;
  251. }): Jack<C>;
  252. /**
  253. * Add one or more number fields.
  254. */
  255. num<F extends ConfigMetaSet<'number', false>>(fields: F): Jack<C & ConfigSetFromMetaSet<'number', false, F>>;
  256. /**
  257. * Add one or more multiple number fields.
  258. */
  259. numList<F extends ConfigMetaSet<'number'>>(fields: F): Jack<C & ConfigSetFromMetaSet<'number', true, F>>;
  260. /**
  261. * Add one or more string option fields.
  262. */
  263. opt<F extends ConfigMetaSet<'string', false>>(fields: F): Jack<C & ConfigSetFromMetaSet<'string', false, F>>;
  264. /**
  265. * Add one or more multiple string option fields.
  266. */
  267. optList<F extends ConfigMetaSet<'string'>>(fields: F): Jack<C & ConfigSetFromMetaSet<'string', true, F>>;
  268. /**
  269. * Add one or more flag fields.
  270. */
  271. flag<F extends ConfigMetaSet<'boolean', false>>(fields: F): Jack<C & ConfigSetFromMetaSet<'boolean', false, F>>;
  272. /**
  273. * Add one or more multiple flag fields.
  274. */
  275. flagList<F extends ConfigMetaSet<'boolean'>>(fields: F): Jack<C & ConfigSetFromMetaSet<'boolean', true, F>>;
  276. /**
  277. * Generic field definition method. Similar to flag/flagList/number/etc,
  278. * but you must specify the `type` (and optionally `multiple` and `delim`)
  279. * fields on each one, or Jack won't know how to define them.
  280. */
  281. addFields<F extends ConfigSet>(fields: F): Jack<C & F>;
  282. /**
  283. * Return the usage banner for the given configuration
  284. */
  285. usage(): string;
  286. /**
  287. * Return the usage banner markdown for the given configuration
  288. */
  289. usageMarkdown(): string;
  290. /**
  291. * Return the configuration options as a plain object
  292. */
  293. toJSON(): {
  294. [k: string]: {
  295. hint?: string | undefined;
  296. default?: string | number | boolean | string[] | number[] | boolean[] | undefined;
  297. validOptions?: readonly number[] | readonly string[] | undefined;
  298. validate?: ((v: unknown) => v is string | number | boolean | string[] | number[] | boolean[]) | undefined;
  299. description?: string | undefined;
  300. short?: string | undefined;
  301. delim?: string | undefined;
  302. multiple?: boolean | undefined;
  303. type: ConfigType;
  304. };
  305. };
  306. /**
  307. * Custom printer for `util.inspect`
  308. */
  309. [inspect.custom](_: number, options: InspectOptions): string;
  310. }
  311. /**
  312. * Main entry point. Create and return a {@link Jack} object.
  313. */
  314. export declare const jack: (options?: JackOptions) => Jack<{}>;
  315. //# sourceMappingURL=index.d.ts.map