archieve-projects/微信机器人/node_modules/cmd-ts/dist/deno_cjs/option.ts

184 lines
5.4 KiB
TypeScript

import {
ArgParser,
ParsingError,
ParsingResult,
ParseContext,
} from './argparser.ts';
import { OutputOf } from './from.ts';
import { findOption } from './newparser/findOption.ts';
import {
ProvidesHelp,
Descriptive,
LongDoc,
EnvDoc,
ShortDoc,
} from './helpdoc.ts';
import { Type, HasType } from './type.ts';
import chalk from 'https://deno.land/std@0.85.0/fmt/colors.ts';
import { Default } from './default.ts';
import { AllOrNothing } from './utils.ts';
import * as Result from './Result.ts';
import { string } from './types.ts';
import { getEnvVar } from './getEnvVar.ts';
type OptionConfig<Decoder extends Type<string, any>> = LongDoc &
HasType<Decoder> &
Partial<Descriptive & EnvDoc & ShortDoc> &
AllOrNothing<Default<OutputOf<Decoder>>>;
function fullOption<Decoder extends Type<string, any>>(
config: OptionConfig<Decoder>
): ArgParser<OutputOf<Decoder>> & ProvidesHelp & Partial<Descriptive> {
return {
description: config.description ?? config.type.description,
helpTopics() {
const displayName = config.type.displayName ?? 'value';
let usage = `--${config.long}`;
if (config.short) {
usage += `, -${config.short}`;
}
usage += ` <${displayName}>`;
const defaults: string[] = [];
if (config.env) {
const envVar = getEnvVar(config.env);
const env = envVar === undefined ? '' : `=${chalk.italic(envVar)}`;
defaults.push(`env: ${config.env}${env}`);
}
const defaultValueFn = config.defaultValue ?? config.type.defaultValue;
if (defaultValueFn) {
try {
const defaultValue = defaultValueFn();
if (
config.defaultValueIsSerializable ??
config.type.defaultValueIsSerializable
) {
defaults.push('default: ' + chalk.italic(defaultValue));
} else {
defaults.push('optional');
}
} catch (e) {}
}
return [
{
category: 'options',
usage,
defaults,
description:
config.description ?? config.type.description ?? 'self explanatory',
},
];
},
register(_opts) {},
async parse({
nodes,
visitedNodes,
}: ParseContext): Promise<ParsingResult<OutputOf<Decoder>>> {
const options = findOption(nodes, {
longNames: [config.long],
shortNames: config.short ? [config.short] : [],
}).filter((x) => !visitedNodes.has(x));
options.forEach((opt) => visitedNodes.add(opt));
if (options.length > 1) {
const error: ParsingError = {
message:
'Too many times provided. Expected 1, got: ' + options.length,
nodes: options,
};
return Result.err({ errors: [error] });
}
const valueFromEnv = config.env ? getEnvVar(config.env) : undefined;
const option = options[0];
let rawValue: string;
let envPrefix = '';
const defaultValueFn = config.defaultValue ?? config.type.defaultValue;
if (option?.value) {
rawValue = option.value.node.raw;
} else if (valueFromEnv !== undefined) {
rawValue = valueFromEnv;
envPrefix = `env[${chalk.italic(config.env)}]: `;
} else if (!option && typeof defaultValueFn === 'function') {
try {
return Result.ok(defaultValueFn());
} catch (e) {
const message = `Default value not found for '--${config.long}': ${e.message}`;
return Result.err({
errors: [
{
nodes: [],
message,
},
],
});
}
} else {
const raw =
option?.type === 'shortOption'
? `-${option?.key}`
: `--${option?.key ?? config.long}`;
return Result.err({
errors: [
{
nodes: options,
message: `No value provided for ${raw}`,
},
],
});
}
const decoded = await Result.safeAsync(config.type.from(rawValue));
if (Result.isErr(decoded)) {
return Result.err({
errors: [
{ nodes: options, message: envPrefix + decoded.error.message },
],
});
}
return Result.ok(decoded.value);
},
};
}
type StringType = Type<string, string>;
/**
* Decodes an argument which is in the form of a key and a value, and allows parsing the following ways:
*
* - `--long=value` where `long` is the provided `long`
* - `--long value` where `long` is the provided `long`
* - `-s=value` where `s` is the provided `short`
* - `-s value` where `s` is the provided `short`
* @param config flag configurations
*/
export function option<Decoder extends Type<string, any>>(
config: LongDoc &
HasType<Decoder> &
Partial<Descriptive & EnvDoc & ShortDoc> &
AllOrNothing<Default<OutputOf<Decoder>>>
): ArgParser<OutputOf<Decoder>> & ProvidesHelp & Partial<Descriptive>;
export function option(
config: LongDoc &
Partial<HasType<never> & Descriptive & EnvDoc & ShortDoc> &
AllOrNothing<Default<OutputOf<StringType>>>
): ArgParser<OutputOf<StringType>> & ProvidesHelp & Partial<Descriptive>;
export function option(
config: LongDoc &
Partial<HasType<any>> &
Partial<Descriptive & EnvDoc & ShortDoc>
): ArgParser<OutputOf<any>> & ProvidesHelp & Partial<Descriptive> {
return fullOption({
type: string,
...config,
});
}