@clerc/core 1.0.0-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,22 +1,8 @@
1
- import { ErrorHandler as ErrorHandler$1 } from "lite-emit";
2
-
3
- //#region ../parser/src/flag-types.d.ts
4
-
5
- /**
6
- * Creates a Choices type function that validates the input against allowed values.
7
- * The display name will be formatted as "value1 | value2 | ..." for help output.
8
- *
9
- * @param values - Array of allowed string values
10
- * @returns A FlagTypeFunction that validates and returns the input value
11
- * @throws {Error} If the value is not in the allowed values list
12
- *
13
- * @example
14
- * ```typescript
15
- * const format = Choices(['json', 'yaml', 'xml']);
16
- * // Help output will show: json | yaml | xml
17
- * ```
18
- */
19
- declare function Choices<T extends string>(...values: T[]): FlagTypeFunction<T>;
1
+ //#endregion
2
+ //#region ../parser/src/errors.d.ts
3
+ declare class InvalidSchemaError extends Error {
4
+ constructor(message: string);
5
+ }
20
6
  //#endregion
21
7
  //#region ../utils/src/types/type-fest.d.ts
22
8
  type LiteralUnion<LiteralType, BaseType> = LiteralType | (BaseType & Record<never, never>);
@@ -29,6 +15,7 @@ type MapsSetsOrArrays = ReadonlyMap<unknown, unknown> | WeakMap<WeakKey, unknown
29
15
  type ConditionalDeepPrettify<T, E = never, I$1 = unknown> = T extends E ? T : T extends I$1 ? { [TypeKey in keyof T]: ConditionalDeepPrettify<T[TypeKey], E, I$1> } : T;
30
16
  type DeepPrettify<T, E = never> = ConditionalDeepPrettify<T, E | NonRecursiveType | MapsSetsOrArrays, object>;
31
17
  type IsAny<T> = 0 extends 1 & T ? true : false;
18
+ type RequireExactlyOneOrNone<T, Keys extends keyof T = keyof T> = ({ [K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, never>> }[Keys] & Omit<T, Keys>) | (Partial<Record<Keys, never>> & Omit<T, Keys>);
32
19
  //#endregion
33
20
  //#region ../utils/src/types/index.d.ts
34
21
  type MaybeArray<T> = T | T[];
@@ -37,19 +24,24 @@ type UnionToIntersection<U$1> = (U$1 extends any ? (k: U$1) => void : never) ext
37
24
  type CamelCase<S extends string> = S extends `${infer Head} ${infer Tail}` ? `${Head}${Capitalize<CamelCase<Tail>>}` : S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize<CamelCase<Tail>>}` : S;
38
25
  //#endregion
39
26
  //#region ../parser/src/types.d.ts
40
- type FlagDefaultValue<T = unknown> = T | (() => T);
27
+ interface FlagDefaultValueFunction<T> {
28
+ (): T;
29
+ display?: string;
30
+ }
31
+ type FlagDefaultValue<T = unknown> = T | FlagDefaultValueFunction<T>;
41
32
  /**
42
33
  * Defines how a string input is converted to the target type T.
43
34
  *
44
35
  * @template T The target type.
45
36
  */
46
- type FlagTypeFunction<T = unknown> = ((value: string) => T) & {
37
+ interface TypeFunction<T = unknown> {
38
+ (value: string): T;
47
39
  /**
48
40
  * Optional display name for the type, useful in help output.
49
41
  * If provided, this will be shown instead of the function name.
50
42
  */
51
- displayName?: string;
52
- };
43
+ display?: string;
44
+ }
53
45
  /**
54
46
  * A callback function to conditionally stop parsing.
55
47
  * When it returns true, parsing stops and remaining arguments are preserved in `ignored`.
@@ -59,19 +51,23 @@ type FlagTypeFunction<T = unknown> = ((value: string) => T) & {
59
51
  * @returns true to stop parsing, false to continue
60
52
  */
61
53
  type IgnoreFunction = (type: typeof KNOWN_FLAG | typeof UNKNOWN_FLAG | typeof PARAMETER, arg: string) => boolean;
62
- type FlagType<T = unknown> = FlagTypeFunction<T> | readonly [FlagTypeFunction<T>];
63
- interface BaseFlagOptions<T extends FlagType = FlagType> {
54
+ type TypeValue<T = unknown> = TypeFunction<T> | readonly [TypeFunction<T>];
55
+ type FlagRequiredOrDefault = RequireExactlyOneOrNone<{
56
+ /** The default value of the flag. */
57
+ default?: unknown;
58
+ /** Whether the flag is required. */
59
+ required?: boolean;
60
+ }, "default" | "required">;
61
+ type BaseFlagOptions<T extends TypeValue = TypeValue> = FlagRequiredOrDefault & {
64
62
  /**
65
63
  * The type constructor or a function to convert the string value.
66
64
  * To support multiple occurrences of a flag (e.g., --file a --file b), wrap the type in an array: [String], [Number].
67
65
  * e.g., String, Number, [String], (val) => val.split(',')
68
66
  */
69
67
  type: T;
70
- /** Aliases for the flag. */
71
- alias?: MaybeArray<string>;
72
- /** The default value of the flag. */
73
- default?: unknown;
74
- }
68
+ /** Short flag alias (single character). */
69
+ short?: string;
70
+ };
75
71
  type FlagOptions = (BaseFlagOptions<BooleanConstructor> & {
76
72
  /**
77
73
  * Whether to enable the `--no-<flag>` syntax to set the value to false.
@@ -84,8 +80,30 @@ type FlagOptions = (BaseFlagOptions<BooleanConstructor> & {
84
80
  }) | (BaseFlagOptions & {
85
81
  negatable?: never;
86
82
  });
87
- type FlagDefinitionValue = FlagOptions | FlagType;
83
+ type FlagDefinitionValue = FlagOptions | TypeValue;
88
84
  type FlagsDefinition = Record<string, FlagDefinitionValue>;
85
+ /**
86
+ * Configuration options for the parser.
87
+ */
88
+ interface ParserOptions<T extends FlagsDefinition = {}> {
89
+ /**
90
+ * Detailed configuration for flags.
91
+ * Supports the full object syntax or a type constructor as a shorthand.
92
+ * The key is the flag name (e.g., "file" for "--file").
93
+ */
94
+ flags?: T;
95
+ /**
96
+ * Delimiters to split flag names and values.
97
+ *
98
+ * @default ['=', ':']
99
+ */
100
+ delimiters?: string[];
101
+ /**
102
+ * A callback function to conditionally stop parsing.
103
+ * When it returns true, parsing stops and remaining arguments are preserved in `ignored`.
104
+ */
105
+ ignore?: IgnoreFunction;
106
+ }
89
107
  type RawInputType = string | boolean;
90
108
  interface ObjectInputType {
91
109
  [key: string]: RawInputType | ObjectInputType;
@@ -110,6 +128,8 @@ interface ParsedResult<TFlags extends Record<string, any>> {
110
128
  unknown: Record<string, RawInputType>;
111
129
  /** Arguments that were not parsed due to ignore callback. */
112
130
  ignored: string[];
131
+ /** List of required flags that were not provided. */
132
+ missingRequiredFlags: string[];
113
133
  }
114
134
  type InferFlagDefault<T extends FlagDefinitionValue, Fallback> = T extends {
115
135
  default: FlagDefaultValue<infer DefaultType>;
@@ -119,13 +139,15 @@ type IsTypeAny<T extends FlagDefinitionValue> = IsAny<T> extends true ? true : T
119
139
  } ? IsAny<Type> extends true ? true : false : false;
120
140
  type _InferFlags<T extends FlagsDefinition> = { [K in keyof T]: IsTypeAny<T[K]> extends true ? any : T[K] extends readonly [BooleanConstructor] | {
121
141
  type: readonly [BooleanConstructor];
122
- } ? number : T[K] extends ObjectConstructor | {
142
+ } ? number | InferFlagDefault<T[K], never> : T[K] extends ObjectConstructor | {
123
143
  type: ObjectConstructor;
124
- } ? ObjectInputType : T[K] extends readonly [FlagType<infer U>] | {
125
- type: readonly [FlagType<infer U>];
126
- } ? U[] | InferFlagDefault<T[K], never> : T[K] extends FlagType<infer U> | {
127
- type: FlagType<infer U>;
128
- } ? U | InferFlagDefault<T[K], [U] extends [boolean] ? never : undefined> : never };
144
+ } ? ObjectInputType | InferFlagDefault<T[K], never> : T[K] extends readonly [TypeValue<infer U>] | {
145
+ type: readonly [TypeValue<infer U>];
146
+ } ? U[] | InferFlagDefault<T[K], never> : T[K] extends TypeValue<infer U> | {
147
+ type: TypeValue<infer U>;
148
+ } ? U | InferFlagDefault<T[K], [U] extends [boolean] ? never : T[K] extends {
149
+ required: true;
150
+ } ? never : undefined> : never };
129
151
  /**
130
152
  * An advanced utility type that infers the exact type of the `flags` object in the parsed result,
131
153
  * based on the provided `flags` configuration object T.
@@ -141,40 +163,95 @@ declare const PARAMETER = "parameter";
141
163
  //#endregion
142
164
  //#region ../parser/src/parse.d.ts
143
165
  declare const DOUBLE_DASH = "--";
166
+ type ParseFunction<T extends FlagsDefinition> = (args: string[]) => ParsedResult<InferFlags<T>>;
167
+ declare function createParser<T extends FlagsDefinition>(options?: ParserOptions<T>): {
168
+ parse: ParseFunction<T>;
169
+ };
170
+ declare const parse: <T extends FlagsDefinition>(args: string[], options?: ParserOptions<T>) => ParsedResult<InferFlags<T>>;
171
+ declare namespace index_d_exports {
172
+ export { BaseFlagOptions, DOUBLE_DASH, FlagDefaultValue, FlagDefaultValueFunction, FlagDefinitionValue, FlagOptions, FlagsDefinition, IgnoreFunction, InferFlags, InvalidSchemaError, KNOWN_FLAG, ObjectInputType, PARAMETER, ParsedResult, ParserOptions, RawInputType, TypeFunction, TypeValue, UNKNOWN_FLAG, createParser, parse };
173
+ }
174
+ //#endregion
175
+ //#region ../advanced-types/src/errors.d.ts
176
+ declare class FlagValidationError extends Error {}
177
+ declare namespace index_d_exports$1 {
178
+ export { Enum, FlagValidationError, Range, Regex };
179
+ }
180
+ /**
181
+ * Creates a Enum type function that validates the input against allowed values.
182
+ * The display name will be formatted as "value1 | value2 | ..." for help output.
183
+ *
184
+ * @param values - Array of allowed string values
185
+ * @returns A TypeFunction that validates and returns the input value
186
+ * @throws {Error} If the value is not in the allowed values list
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * const format = Enum(['json', 'yaml', 'xml']);
191
+ * // Help output will show: json | yaml | xml
192
+ * ```
193
+ */
194
+ declare function Enum<T extends string>(...values: T[]): TypeFunction<T>;
195
+ /**
196
+ * Creates a range type function that validates the input is a number within the specified range.
197
+ *
198
+ * @param min - The minimum acceptable value (inclusive)
199
+ * @param max - The maximum acceptable value (inclusive)
200
+ * @returns A TypeFunction that validates the input value
201
+ * @throws {Error} If the value is not a number or is outside the specified range
202
+ */
203
+ declare function Range(min: number, max: number): TypeFunction<number>;
204
+ /**
205
+ * Creates a regex type function that validates the input against the provided pattern.
206
+ *
207
+ * @param pattern - The regular expression pattern to validate against
208
+ * @param description - Optional description for display purposes
209
+ * @returns A TypeFunction that validates the input value
210
+ * @throws {Error} If the value does not match the regex pattern
211
+ */
212
+ declare function Regex(pattern: RegExp, description?: string): TypeFunction<string>;
144
213
  //#endregion
145
214
  //#region src/types/clerc.d.ts
146
215
  type ErrorHandler = (error: unknown) => void;
147
216
  //#endregion
148
217
  //#region src/types/flag.d.ts
149
218
  interface FlagCustomOptions {}
150
- type ClercFlagOptions = FlagOptions & FlagCustomOptions;
151
- type ClercGlobalFlagDefinitionValue = ClercFlagOptions | FlagType;
152
- type ClercFlagOptionsWithDescription = ClercFlagOptions & {
153
- description: string;
154
- };
155
- type ClercFlagsDefinition = Record<string, ClercFlagOptionsWithDescription>;
219
+ type ClercFlagOptions = FlagOptions & {
220
+ description?: string;
221
+ } & FlagCustomOptions;
222
+ type ClercFlagDefinitionValue = ClercFlagOptions | TypeValue;
223
+ type ClercFlagsDefinition = Record<string, ClercFlagDefinitionValue>;
156
224
  //#endregion
157
- //#region src/types/parameters.d.ts
158
- type InferParameter<T extends string> = T extends `<${infer Name extends string}...>` | `[${infer Name extends string}...]` ? Record<CamelCase<Name>, string[]> : T extends `<${infer Name extends string}>` ? Record<CamelCase<Name>, string> : T extends `[${infer Name extends string}]` ? Record<CamelCase<Name>, string | undefined> : never;
159
- type InferParameters<T extends readonly string[]> = T extends readonly (infer U extends string)[] ? Prettify<UnionToIntersection<InferParameter<U>>> : never;
225
+ //#region src/types/parameter.d.ts
226
+ interface ParameterCustomOptions {}
227
+ type InferStringParameter<T extends string, Type$1 = string> = T extends `<${infer Name extends string}...>` | `[${infer Name extends string}...]` ? Record<CamelCase<Name>, Type$1[]> : T extends `<${infer Name extends string}>` ? Record<CamelCase<Name>, Type$1> : T extends `[${infer Name extends string}]` ? Record<CamelCase<Name>, Type$1 | undefined> : never;
228
+ type InferParameter<T extends ParameterDefinitionValue> = T extends string ? InferStringParameter<T> : T extends ParameterOptions ? T["type"] extends TypeFunction<infer U> ? InferStringParameter<T["key"], U> : InferStringParameter<T["key"]> : never;
229
+ type InferParameters<T extends readonly ParameterDefinitionValue[]> = T extends readonly (infer U extends ParameterDefinitionValue)[] ? Prettify<UnionToIntersection<InferParameter<U>>> : never;
230
+ type ParameterOptions = {
231
+ key: string;
232
+ description?: string;
233
+ type?: TypeFunction;
234
+ } & ParameterCustomOptions;
235
+ type ParameterDefinitionValue = string | ParameterOptions;
160
236
  //#endregion
161
237
  //#region src/types/context.d.ts
162
238
  type AddStringIndex<T> = T & Record<string, any>;
163
- type InferFlagsWithGlobal<C extends Command, GF extends ClercFlagsDefinition> = AddStringIndex<InferFlags<NonNullable<C["flags"]> & Omit<GF, keyof NonNullable<C["flags"]>>>>;
239
+ type KnownKeys<T> = string extends keyof T ? never : keyof T;
240
+ type InferFlagsWithGlobal<C extends Command, GF extends ClercFlagsDefinition> = AddStringIndex<InferFlags<NonNullable<C["flags"]> & Omit<GF, KnownKeys<NonNullable<C["flags"]>>>>>;
241
+ interface ContextStore {}
164
242
  interface BaseContext<C extends Command = Command, GF extends ClercFlagsDefinition = {}> {
165
- resolved: boolean;
166
243
  command?: C;
167
244
  calledAs?: string;
168
245
  parameters: InferParameters<NonNullable<C["parameters"]>>;
169
246
  flags: InferFlagsWithGlobal<C, GF>;
170
247
  ignored: string[];
171
248
  rawParsed: ParsedResult<InferFlagsWithGlobal<C, GF>>;
172
- missingParameters: boolean;
249
+ store: Partial<ContextStore>;
173
250
  }
174
251
  //#endregion
175
252
  //#region src/types/command.d.ts
176
253
  interface CommandCustomOptions {}
177
- interface CommandOptions<Parameters extends readonly string[] = readonly string[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> extends CommandCustomOptions {
254
+ interface CommandOptions<Parameters extends readonly ParameterDefinitionValue[] = readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> extends CommandCustomOptions {
178
255
  alias?: MaybeArray<string>;
179
256
  parameters?: Parameters;
180
257
  flags?: Flags;
@@ -183,11 +260,11 @@ interface CommandOptions<Parameters extends readonly string[] = readonly string[
183
260
  */
184
261
  ignore?: IgnoreFunction;
185
262
  }
186
- interface Command<Name$1 extends string = string, Parameters extends readonly string[] = readonly string[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> extends CommandOptions<Parameters, Flags> {
263
+ interface Command<Name$1 extends string = string, Parameters extends readonly ParameterDefinitionValue[] = readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> extends CommandOptions<Parameters, Flags> {
187
264
  name: Name$1;
188
- description: string;
265
+ description?: string;
189
266
  }
190
- type CommandWithHandler<Name$1 extends string = string, Parameters extends readonly string[] = readonly string[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> = Command<Name$1, Parameters, Flags> & {
267
+ type CommandWithHandler<Name$1 extends string = string, Parameters extends readonly ParameterDefinitionValue[] = readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition = ClercFlagsDefinition> = Command<Name$1, Parameters, Flags> & {
191
268
  handler?: CommandHandler<Command<Name$1, Parameters, Flags>>;
192
269
  };
193
270
  type CommandsRecord = Record<string, Command>;
@@ -237,23 +314,27 @@ declare class Clerc<Commands extends CommandsRecord = {}, GlobalFlags extends Cl
237
314
  get _version(): string;
238
315
  get _commands(): CommandsMap;
239
316
  get _globalFlags(): GlobalFlags;
317
+ get store(): Partial<ContextStore>;
240
318
  static create(options?: CreateOptions): Clerc;
241
319
  name(name: string): this;
242
320
  scriptName(scriptName: string): this;
243
321
  description(description: string): this;
244
322
  version(version: string): this;
245
323
  use(plugin: Plugin): this;
246
- errorHandler(handler: ErrorHandler$1): this;
247
- command<Name$1 extends string, const Parameters extends readonly string[] = readonly [], Flags extends ClercFlagsDefinition = {}>(command: CommandWithHandler<Name$1, Parameters, Flags>): Clerc<Commands & Record<string, CommandWithHandler<Name$1, Parameters, Flags>>, GlobalFlags>;
248
- command<Name$1 extends string, const Parameters extends readonly string[] = readonly [], Flags extends ClercFlagsDefinition = {}>(name: Name$1 extends keyof Commands ? ["COMMAND ALREADY EXISTS"] : Name$1, description: string, options?: CommandOptions<Parameters, Flags>): Clerc<Commands & Record<Name$1, Command<Name$1, Parameters, Flags>>, GlobalFlags>;
249
- globalFlag<Name$1 extends string, Flag extends ClercGlobalFlagDefinitionValue>(name: Name$1, description: string, options: Flag): Clerc<Commands, GlobalFlags & Record<Name$1, Flag>>;
324
+ errorHandler(handler: ErrorHandler): this;
325
+ command(commands: readonly CommandWithHandler<any, any, any>[]): this;
326
+ command<Name$1 extends string, const Parameters extends readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition>(command: CommandWithHandler<Name$1, Parameters, Flags>): Clerc<Commands & Record<string, CommandWithHandler<Name$1, Parameters, Flags>>, GlobalFlags>;
327
+ command<Name$1 extends string, const Parameters extends readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition>(name: Name$1 extends keyof Commands ? ["COMMAND ALREADY EXISTS"] : Name$1, options?: CommandOptions<Parameters, Flags>): Clerc<Commands & Record<Name$1, Command<Name$1, Parameters, Flags>>, GlobalFlags>;
328
+ command<Name$1 extends string, const Parameters extends readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition>(name: Name$1 extends keyof Commands ? ["COMMAND ALREADY EXISTS"] : Name$1, description: string, options?: CommandOptions<Parameters, Flags>): Clerc<Commands & Record<Name$1, Command<Name$1, Parameters, Flags>>, GlobalFlags>;
329
+ globalFlag<Name$1 extends string, Flag extends ClercFlagDefinitionValue>(name: Name$1, description: string, options: Flag): Clerc<Commands, GlobalFlags & Record<Name$1, Flag>>;
330
+ globalFlag<Name$1 extends string, Flag extends ClercFlagDefinitionValue>(name: Name$1, options: Flag): Clerc<Commands, GlobalFlags & Record<Name$1, Flag>>;
250
331
  interceptor(interceptor: Interceptor<Command, GlobalFlags>): this;
251
332
  on<Name$1 extends LiteralUnion<keyof Commands, string>>(name: Name$1, handler: CommandHandler<Commands[Name$1], GlobalFlags>): this;
252
333
  run(): Promise<void>;
253
334
  parse<Run extends boolean = true>(argvOrOptions?: string[] | ParseOptions<Run>): Run extends true ? Promise<void> : this;
254
335
  }
255
336
  //#endregion
256
- //#region src/commands.d.ts
337
+ //#region src/command.d.ts
257
338
  declare function resolveCommand(commandsMap: CommandsMap, parameters: string[]): [Command, string] | [undefined, undefined];
258
339
  //#endregion
259
340
  //#region src/errors.d.ts
@@ -264,23 +345,34 @@ declare class NoSuchCommandError extends Error {
264
345
  declare class NoCommandSpecifiedError extends Error {
265
346
  constructor(text?: string);
266
347
  }
267
- declare class InvalidCommandError extends Error {
268
- constructor(message: string);
269
- }
348
+ declare class InvalidCommandError extends Error {}
270
349
  declare class MissingRequiredMetadataError extends Error {
271
350
  constructor(metadataName: string);
272
351
  }
273
- declare class InvalidParametersError extends Error {
274
- constructor(message: string);
352
+ declare class InvalidParametersError extends Error {}
353
+ declare class MissingRequiredFlagError extends Error {
354
+ constructor(flags: string[]);
275
355
  }
276
356
  //#endregion
277
357
  //#region src/helpers.d.ts
278
- declare const defineCommand: <Name$1 extends string, const Parameters extends readonly string[] = readonly [], Flags extends ClercFlagsDefinition = {}>(command: Command<Name$1, Parameters, Flags>, handler?: NoInfer<CommandHandler<Command<Name$1, Parameters, Flags>>>) => CommandWithHandler<Name$1, Parameters, Flags>;
358
+ declare const defineCommand: <Name$1 extends string, const Parameters extends readonly ParameterDefinitionValue[], Flags extends ClercFlagsDefinition>(command: Command<Name$1, Parameters, Flags>, handler?: NoInfer<CommandHandler<Command<Name$1, Parameters, Flags>>>) => CommandWithHandler<Name$1, Parameters, Flags>;
279
359
  //#endregion
280
360
  //#region src/ignore.d.ts
281
361
  declare function createStopAtFirstParameter(): IgnoreFunction;
282
362
  //#endregion
363
+ //#region src/parameter.d.ts
364
+ interface ParameterInfo {
365
+ name: string;
366
+ isRequired: boolean;
367
+ isVariadic: boolean;
368
+ }
369
+ declare function extractParameterInfo(key: string): ParameterInfo;
370
+ //#endregion
283
371
  //#region src/plugin.d.ts
284
372
  declare const definePlugin: (plugin: Plugin) => Plugin;
285
373
  //#endregion
286
- export { BaseContext, Choices, Clerc, ClercFlagOptions, ClercFlagOptionsWithDescription, ClercFlagsDefinition, ClercGlobalFlagDefinitionValue, Command, CommandCustomOptions, CommandHandler, CommandHandlerContext, CommandOptions, CommandWithHandler, CommandsMap, CommandsRecord, type CreateOptions, DOUBLE_DASH, ErrorHandler, FlagCustomOptions, InferParameters, Interceptor, InterceptorContext, InterceptorHandler, InterceptorNext, InterceptorObject, InvalidCommandError, InvalidParametersError, KNOWN_FLAG, MakeEmitterEvents, MissingRequiredMetadataError, NoCommandSpecifiedError, NoSuchCommandError, PARAMETER, type ParseOptions, Plugin, UNKNOWN_FLAG, createStopAtFirstParameter, defineCommand, definePlugin, resolveCommand };
374
+ //#region src/utils.d.ts
375
+ declare const normalizeFlagValue: (flag: ClercFlagDefinitionValue) => ClercFlagOptions;
376
+ declare const normalizeParameterValue: (parameter: ParameterDefinitionValue) => ParameterOptions;
377
+ //#endregion
378
+ export { BaseContext, Clerc, ClercFlagDefinitionValue, ClercFlagOptions, ClercFlagsDefinition, Command, CommandCustomOptions, CommandHandler, CommandHandlerContext, CommandOptions, CommandWithHandler, CommandsMap, CommandsRecord, ContextStore, type CreateOptions, DOUBLE_DASH, ErrorHandler, FlagCustomOptions, InferParameters, Interceptor, InterceptorContext, InterceptorHandler, InterceptorNext, InterceptorObject, InvalidCommandError, InvalidParametersError, InvalidSchemaError, KNOWN_FLAG, MakeEmitterEvents, MissingRequiredFlagError, MissingRequiredMetadataError, NoCommandSpecifiedError, NoSuchCommandError, PARAMETER, ParameterCustomOptions, ParameterDefinitionValue, ParameterOptions, type ParseOptions, type index_d_exports as Parser, Plugin, index_d_exports$1 as Types, UNKNOWN_FLAG, createStopAtFirstParameter, defineCommand, definePlugin, extractParameterInfo, normalizeFlagValue, normalizeParameterValue, resolveCommand };
package/dist/index.js CHANGED
@@ -1,8 +1,33 @@
1
- import { Choices, DOUBLE_DASH, DOUBLE_DASH as DOUBLE_DASH$1, KNOWN_FLAG, PARAMETER, PARAMETER as PARAMETER$1, UNKNOWN_FLAG, parse } from "@clerc/parser";
2
- import { camelCase, toArray } from "@clerc/utils";
1
+ import * as Types from "@clerc/advanced-types";
2
+ import { DOUBLE_DASH, DOUBLE_DASH as DOUBLE_DASH$1, InvalidSchemaError, KNOWN_FLAG, PARAMETER, PARAMETER as PARAMETER$1, UNKNOWN_FLAG, parse } from "@clerc/parser";
3
3
  import { LiteEmit } from "lite-emit";
4
4
 
5
- //#region src/commands.ts
5
+ //#region ../utils/src/index.ts
6
+ const looseIsArray = (arr) => Array.isArray(arr);
7
+ const toArray = (a) => Array.isArray(a) ? a : [a];
8
+ /**
9
+ * Converts a dash- or space-separated string to camelCase.
10
+ * Not using regexp for better performance, because this function is used in parser.
11
+ */
12
+ function camelCase(str) {
13
+ const firstIdx = Math.min(str.includes("-") ? str.indexOf("-") : Infinity, str.includes(" ") ? str.indexOf(" ") : Infinity);
14
+ if (firstIdx === Infinity) return str;
15
+ let result = str.slice(0, firstIdx);
16
+ for (let i = firstIdx; i < str.length; i++) if ((str[i] === "-" || str[i] === " ") && i + 1 < str.length) {
17
+ const nextChar = str.charCodeAt(i + 1);
18
+ if (nextChar >= 97 && nextChar <= 122) {
19
+ result += String.fromCharCode(nextChar - 32);
20
+ i++;
21
+ } else {
22
+ result += str[i + 1];
23
+ i++;
24
+ }
25
+ } else if (str[i] !== "-" && str[i] !== " ") result += str[i];
26
+ return result;
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/command.ts
6
31
  function resolveCommand(commandsMap, parameters) {
7
32
  for (let i = parameters.length; i >= 0; i--) {
8
33
  const name = parameters.slice(0, i).join(" ");
@@ -24,19 +49,17 @@ var NoCommandSpecifiedError = class extends Error {
24
49
  super(text);
25
50
  }
26
51
  };
27
- var InvalidCommandError = class extends Error {
28
- constructor(message) {
29
- super(message);
30
- }
31
- };
52
+ var InvalidCommandError = class extends Error {};
32
53
  var MissingRequiredMetadataError = class extends Error {
33
54
  constructor(metadataName) {
34
55
  super(`CLI ${metadataName} is required.`);
35
56
  }
36
57
  };
37
- var InvalidParametersError = class extends Error {
38
- constructor(message) {
39
- super(message);
58
+ var InvalidParametersError = class extends Error {};
59
+ var MissingRequiredFlagError = class extends Error {
60
+ constructor(flags) {
61
+ const s = flags.length > 1 ? "s" : "";
62
+ super(`Missing required flag${s}: ${flags.join(", ")}`);
40
63
  }
41
64
  };
42
65
 
@@ -73,7 +96,18 @@ function compose(inspectors) {
73
96
  }
74
97
 
75
98
  //#endregion
76
- //#region src/parameters.ts
99
+ //#region ../../node_modules/.pnpm/is-platform@1.0.0/node_modules/is-platform/dist/index.mjs
100
+ const IS_DENO = typeof Deno !== "undefined";
101
+ const IS_NODE = typeof process !== "undefined" && !IS_DENO;
102
+ const IS_ELECTRON = process.versions.electron && !process.defaultApp;
103
+
104
+ //#endregion
105
+ //#region src/utils.ts
106
+ const normalizeFlagValue = (flag) => typeof flag === "function" || looseIsArray(flag) ? { type: flag } : flag;
107
+ const normalizeParameterValue = (parameter) => typeof parameter === "string" ? { key: parameter } : parameter;
108
+
109
+ //#endregion
110
+ //#region src/parameter.ts
77
111
  function getParametersToResolve(argv) {
78
112
  const parameters = [];
79
113
  for (const arg of argv) {
@@ -84,15 +118,21 @@ function getParametersToResolve(argv) {
84
118
  }
85
119
  const PARAMETER_REGEX = /^(<|\[)([\w ]+)(\.\.\.)?(\]|>)$/;
86
120
  const isParameterDefinitionBracketsValid = (definition) => definition.startsWith("<") && definition.endsWith(">") || definition.startsWith("[") && definition.endsWith("]");
121
+ function extractParameterInfo(key) {
122
+ const match = key.match(PARAMETER_REGEX);
123
+ if (!match || !isParameterDefinitionBracketsValid(key)) throw new InvalidParametersError(`Invalid parameter definition: ${key}`);
124
+ return {
125
+ name: camelCase(match[2]),
126
+ isRequired: key.startsWith("<"),
127
+ isVariadic: !!match[3]
128
+ };
129
+ }
87
130
  function _parseParameters(definitions, parameters) {
88
131
  const result = {};
89
132
  let hasOptional = false;
90
- for (const [i, definition] of definitions.entries()) {
91
- const match = definition.match(PARAMETER_REGEX);
92
- if (!match || !isParameterDefinitionBracketsValid(definition)) throw new InvalidParametersError(`Invalid parameter definition: ${definition}`);
93
- const name = camelCase(match[2]);
94
- const isVariadic = !!match[3];
95
- const isRequired = definition.startsWith("<");
133
+ for (const [i, def] of definitions.entries()) {
134
+ const normalized = normalizeParameterValue(def);
135
+ const { name, isRequired, isVariadic } = extractParameterInfo(normalized.key);
96
136
  if (name in result) throw new InvalidParametersError(`Duplicate parameter name: ${name}`);
97
137
  if (isVariadic && i !== definitions.length - 1) throw new InvalidParametersError("Variadic parameter must be the last parameter in the definition.");
98
138
  if (isRequired) {
@@ -100,7 +140,10 @@ function _parseParameters(definitions, parameters) {
100
140
  } else hasOptional = true;
101
141
  const value = isVariadic ? parameters.slice(i) : parameters[i];
102
142
  if (isRequired && (isVariadic ? value.length === 0 : value === void 0)) throw new InvalidParametersError(`Missing required ${isVariadic ? "variadic " : ""}parameter: ${name}`);
103
- result[name] = value;
143
+ if (normalized.type) if (isVariadic) result[name] = value.map((v) => normalized.type(v));
144
+ else if (value === void 0) result[name] = value;
145
+ else result[name] = normalized.type(value);
146
+ else result[name] = value;
104
147
  }
105
148
  return result;
106
149
  }
@@ -117,12 +160,6 @@ function parseParameters(definitions, parameters, doubleDashParameters) {
117
160
  }
118
161
  }
119
162
 
120
- //#endregion
121
- //#region ../../node_modules/.pnpm/is-platform@1.0.0/node_modules/is-platform/dist/index.mjs
122
- const IS_DENO = typeof Deno !== "undefined";
123
- const IS_NODE = typeof process !== "undefined" && !IS_DENO;
124
- const IS_ELECTRON = process.versions.electron && !process.defaultApp;
125
-
126
163
  //#endregion
127
164
  //#region src/platform.ts
128
165
  const platformArgv = IS_NODE ? process.argv.slice(IS_ELECTRON ? 1 : 2) : IS_DENO ? Deno.args : [];
@@ -132,8 +169,9 @@ const platformArgv = IS_NODE ? process.argv.slice(IS_ELECTRON ? 1 : 2) : IS_DENO
132
169
  var Clerc = class Clerc {
133
170
  #argv = [];
134
171
  #commands = /* @__PURE__ */ new Map();
135
- #emitter = new LiteEmit({ errorHandler: (error) => this.#handleError(error) });
172
+ #emitter = new LiteEmit();
136
173
  #globalFlags = {};
174
+ #store = {};
137
175
  #interceptors = [];
138
176
  #errorHandlers = [];
139
177
  #name = "";
@@ -164,6 +202,9 @@ var Clerc = class Clerc {
164
202
  get _globalFlags() {
165
203
  return this.#globalFlags;
166
204
  }
205
+ get store() {
206
+ return this.#store;
207
+ }
167
208
  static create(options) {
168
209
  return new Clerc(options);
169
210
  }
@@ -211,13 +252,18 @@ var Clerc = class Clerc {
211
252
  if (this.#commands.has(name)) throw new InvalidCommandError(`Command with name "${name}" already exists.`);
212
253
  for (const alias of aliases) if (this.#commands.has(alias)) throw new InvalidCommandError(`Command with name "${alias}" already exists.`);
213
254
  }
214
- command(nameOrCommandObject, description, options) {
215
- const command = typeof nameOrCommandObject === "string" ? {
216
- name: nameOrCommandObject,
217
- description,
218
- ...options
219
- } : nameOrCommandObject;
220
- const aliases = toArray(options?.alias ?? []);
255
+ command(nameOrCommandObjectOrCommandArray, descriptionOrOptions, options) {
256
+ if (Array.isArray(nameOrCommandObjectOrCommandArray)) {
257
+ for (const command$1 of nameOrCommandObjectOrCommandArray) this.command(command$1);
258
+ return this;
259
+ }
260
+ const isDescription = typeof descriptionOrOptions === "string";
261
+ const command = typeof nameOrCommandObjectOrCommandArray === "string" ? {
262
+ name: nameOrCommandObjectOrCommandArray,
263
+ description: isDescription ? descriptionOrOptions : void 0,
264
+ ...isDescription ? options : descriptionOrOptions
265
+ } : nameOrCommandObjectOrCommandArray;
266
+ const aliases = toArray(command?.alias ?? []);
221
267
  this.#callWithErrorHandler(() => this.#validateCommandNameAndAlias(command.name, aliases));
222
268
  this.#commands.set(command.name, command);
223
269
  for (const alias of aliases) this.#commands.set(alias, {
@@ -227,10 +273,11 @@ var Clerc = class Clerc {
227
273
  if (command.handler) this.on(command.name, command.handler);
228
274
  return this;
229
275
  }
230
- globalFlag(name, description, options) {
276
+ globalFlag(name, descriptionOrOptions, options) {
277
+ const isDescription = typeof descriptionOrOptions === "string";
231
278
  this.#globalFlags[name] = {
232
- description,
233
- ...options
279
+ description: isDescription ? descriptionOrOptions : void 0,
280
+ ...isDescription ? options : descriptionOrOptions
234
281
  };
235
282
  return this;
236
283
  }
@@ -244,7 +291,6 @@ var Clerc = class Clerc {
244
291
  }
245
292
  #validate() {
246
293
  if (!this.#scriptName) throw new MissingRequiredMetadataError("script name");
247
- if (!this.#description) throw new MissingRequiredMetadataError("description");
248
294
  if (!this.#version) throw new MissingRequiredMetadataError("version");
249
295
  }
250
296
  #parseArgv(argv, command) {
@@ -270,20 +316,20 @@ var Clerc = class Clerc {
270
316
  parametersError = e;
271
317
  }
272
318
  const context = {
273
- resolved: !!command,
274
319
  command,
275
320
  calledAs,
276
321
  parameters,
277
322
  flags: parsed.flags,
278
323
  ignored: parsed.ignored,
279
324
  rawParsed: parsed,
280
- missingParameters: !!parametersError
325
+ store: { ...this.#store }
281
326
  };
282
327
  const emitInterceptor = {
283
328
  enforce: "post",
284
- handler: (ctx) => {
329
+ handler: async (ctx) => {
330
+ if (parsed.missingRequiredFlags.length > 0) throw new MissingRequiredFlagError(parsed.missingRequiredFlags);
285
331
  if (parametersError) throw parametersError;
286
- if (command) this.#emitter.emit(command.name, ctx);
332
+ if (command) await this.#emitter.emit(command.name, ctx);
287
333
  else throw parametersToResolve.length > 0 ? new NoSuchCommandError(parametersToResolve.join(" ")) : new NoCommandSpecifiedError();
288
334
  }
289
335
  };
@@ -325,4 +371,4 @@ function createStopAtFirstParameter() {
325
371
  const definePlugin = (plugin) => plugin;
326
372
 
327
373
  //#endregion
328
- export { Choices, Clerc, DOUBLE_DASH, InvalidCommandError, InvalidParametersError, KNOWN_FLAG, MissingRequiredMetadataError, NoCommandSpecifiedError, NoSuchCommandError, PARAMETER, UNKNOWN_FLAG, createStopAtFirstParameter, defineCommand, definePlugin, resolveCommand };
374
+ export { Clerc, DOUBLE_DASH, InvalidCommandError, InvalidParametersError, InvalidSchemaError, KNOWN_FLAG, MissingRequiredFlagError, MissingRequiredMetadataError, NoCommandSpecifiedError, NoSuchCommandError, PARAMETER, Types, UNKNOWN_FLAG, createStopAtFirstParameter, defineCommand, definePlugin, extractParameterInfo, normalizeFlagValue, normalizeParameterValue, resolveCommand };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clerc/core",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.0",
4
4
  "author": "Ray <i@mk1.io> (https://github.com/so1ve)",
5
5
  "type": "module",
6
6
  "description": "Clerc core",
@@ -44,15 +44,12 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "lite-emit": "^3.1.0",
48
- "@clerc/parser": "^1.0.0-beta.9",
49
- "@clerc/utils": "1.0.0-beta.9"
47
+ "lite-emit": "^4.0.0",
48
+ "@clerc/advanced-types": "1.0.0",
49
+ "@clerc/parser": "1.0.0"
50
50
  },
51
51
  "devDependencies": {
52
- "is-platform": "^1.0.0"
53
- },
54
- "scripts": {
55
- "build": "tsdown",
56
- "watch": "tsdown --watch"
52
+ "is-platform": "^1.0.0",
53
+ "@clerc/utils": "1.0.0"
57
54
  }
58
55
  }