/
githubmirror
/
tailwindcss
Обзор
Документация
Войти
/
githubmirror
/
tailwindcss
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/@tailwindcss-cli/src/utils/args.ts
181 строка
4 KB
Adam Royle
Only use the last value when parsing duplicate cli arguments (#19416)
07 дек 2025, 20:26
Не верифицирован
07 дек 2025, 20:26
563a016
Код
Авторство
О чём код?
import parse from 'mri' // Definition of the arguments for a command in the CLI. export type Arg = { [key: `--${string}`]: { type: keyof Types description: string alias?: `-${string}` default?: Types[keyof Types] values?: string[] } } // Each argument will have a type and we want to convert the incoming raw string // based value to the correct type. We can't use pure TypeScript types because // these don't exist at runtime. Instead, we define a string-based type that // maps to a TypeScript type. type Types = { boolean: boolean number: number | null string: string | null 'boolean | string': boolean | string | null 'number | string': number | string | null 'boolean | number': boolean | number | null 'boolean | number | string': boolean | number | string | null } // Convert the `Arg` type to a type that can be used at runtime. // // E.g.: // // Arg: // ``` // { '--input': { type: 'string', description: 'Input file', alias: '-i' } } // ``` // // Command: // ``` // ./tailwindcss -i input.css // ./tailwindcss --input input.css // ``` // // Result type: // ``` // { // _: string[], // All non-flag arguments // '--input': string | null // The `--input` flag will be filled with `null`, if the flag is not used. // // The `null` type will not be there if `default` is provided. // } // ``` // // Result runtime object: // ``` // { // _: [], // '--input': 'input.css' // } // ``` export type Result<T extends Arg> = { [K in keyof T]: T[K] extends { type: keyof Types; default?: any } ? undefined extends T[K]['default'] ? Types[T[K]['type']] : NonNullable<Types[T[K]['type']]> : never } & { // All non-flag arguments _: string[] } export function args<const T extends Arg>(options: T, argv = process.argv.slice(2)): Result<T> { for (let [idx, value] of argv.entries()) { if (value === '-') { argv[idx] = '__IO_DEFAULT_VALUE__' } } let parsed = parse(argv) for (let key in parsed) { let value = parsed[key] if (key !== '_' && Array.isArray(value)) { value = value[value.length - 1] } if (value === '__IO_DEFAULT_VALUE__') { value = '-' } parsed[key] = value } let result: { _: string[]; [key: string]: unknown } = { _: parsed._, } for (let [ flag, { type, alias, default: defaultValue = type === 'boolean' ? false : null }, ] of Object.entries(options)) { // Start with the default value result[flag] = defaultValue // Try to find the `alias`, and map it to long form `flag` if (alias) { let key = alias.slice(1) if (parsed[key] !== undefined) { result[flag] = convert(parsed[key], type) } } // Try to find the long form `flag` { let key = flag.slice(2) if (parsed[key] !== undefined) { result[flag] = convert(parsed[key], type) } } } return result as Result<T> } // --- type ArgumentType = string | boolean // Try to convert the raw incoming `value` (which will be a string or a boolean, // this is coming from `mri`'s parse function'), to the correct type based on // the `type` of the argument. function convert<T extends keyof Types>(value: string | boolean, type: T) { switch (type) { case 'string': return convertString(value) case 'boolean': return convertBoolean(value) case 'number': return convertNumber(value) case 'boolean | string': return convertBoolean(value) ?? convertString(value) case 'number | string': return convertNumber(value) ?? convertString(value) case 'boolean | number': return convertBoolean(value) ?? convertNumber(value) case 'boolean | number | string': return convertBoolean(value) ?? convertNumber(value) ?? convertString(value) default: throw new Error(`Unhandled type: ${type}`) } } function convertBoolean(value: ArgumentType) { if (value === true || value === false) { return value } if (value === 'true') { return true } if (value === 'false') { return false } } function convertNumber(value: ArgumentType) { if (typeof value === 'number') { return value } { let valueAsNumber = Number(value) if (!Number.isNaN(valueAsNumber)) { return valueAsNumber } } } function convertString(value: ArgumentType) { return `${value}` }