@optique/core 1.2.0-dev.2180 → 1.2.0-dev.2188

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.
@@ -2,6 +2,7 @@ import { Message } from "./message.cjs";
2
2
  import { HiddenVisibility, OptionName, Usage } from "./usage.cjs";
3
3
  import { ValueParser, ValueParserResult } from "./valueparser.cjs";
4
4
  import { Mode, Parser } from "./internal/parser.cjs";
5
+ import { FluentParser } from "./modifiers.cjs";
5
6
 
6
7
  //#region src/primitives.d.ts
7
8
  /** @internal */
@@ -11,7 +12,7 @@ type OptionState<T> = ValueParserResult<T> | undefined;
11
12
  * produces a constant value of the type {@link T}.
12
13
  * @template T The type of the constant value produced by the parser.
13
14
  */
14
- declare function constant<const T>(value: T): Parser<"sync", T, T>;
15
+ declare function constant<const T>(value: T): FluentParser<"sync", T, T>;
15
16
  /**
16
17
  * Creates a parser that always fails without consuming any input.
17
18
  *
@@ -31,7 +32,7 @@ declare function constant<const T>(value: T): Parser<"sync", T, T>;
31
32
  * complete time.
32
33
  * @since 1.0.0
33
34
  */
34
- declare function fail<T>(): Parser<"sync", T, undefined>;
35
+ declare function fail<T>(): FluentParser<"sync", T, undefined>;
35
36
  /**
36
37
  * Options for the {@link option} parser.
37
38
  */
@@ -113,7 +114,7 @@ interface OptionErrorOptions {
113
114
  * @returns A {@link Parser} that can parse the specified options and their
114
115
  * values.
115
116
  */
116
- declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>]): Parser<M, T, ValueParserResult<T> | undefined>;
117
+ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>]): FluentParser<M, T, ValueParserResult<T> | undefined>;
117
118
  /**
118
119
  * Creates a parser for various styles of command-line options that take an
119
120
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
@@ -127,7 +128,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
127
128
  * @returns A {@link Parser} that can parse the specified options and their
128
129
  * values.
129
130
  */
130
- declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>, OptionOptions]): Parser<M, T, ValueParserResult<T> | undefined>;
131
+ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>, OptionOptions]): FluentParser<M, T, ValueParserResult<T> | undefined>;
131
132
  /**
132
133
  * Creates a parser for various styles of command-line options that do not
133
134
  * take an argument value, such as `--option`, `-o`, or `/option`.
@@ -135,7 +136,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
135
136
  * @return A {@link Parser} that can parse the specified options as Boolean
136
137
  * flags, producing `true` if the option is present.
137
138
  */
138
- declare function option(...optionNames: readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", boolean, ValueParserResult<boolean> | undefined>;
139
+ declare function option(...optionNames: readonly [OptionName, ...readonly OptionName[]]): FluentParser<"sync", boolean, ValueParserResult<boolean> | undefined>;
139
140
  /**
140
141
  * Creates a parser for various styles of command-line options that take an
141
142
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
@@ -146,7 +147,7 @@ declare function option(...optionNames: readonly [OptionName, ...readonly Option
146
147
  * @returns A {@link Parser} that can parse the specified options and their
147
148
  * values.
148
149
  */
149
- declare function option(...args: readonly [OptionName, ...readonly OptionName[], OptionOptions]): Parser<"sync", boolean, ValueParserResult<boolean> | undefined>;
150
+ declare function option(...args: readonly [OptionName, ...readonly OptionName[], OptionOptions]): FluentParser<"sync", boolean, ValueParserResult<boolean> | undefined>;
150
151
  /**
151
152
  * Options for the {@link flag} parser.
152
153
  */
@@ -236,7 +237,7 @@ interface FlagErrorOptions {
236
237
  * });
237
238
  * ```
238
239
  */
239
- declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", true, ValueParserResult<true> | undefined>;
240
+ declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): FluentParser<"sync", true, ValueParserResult<true> | undefined>;
240
241
  /**
241
242
  * A non-empty list of option names, or a single option name.
242
243
  * @since 1.1.0
@@ -340,7 +341,7 @@ interface NegatableFlagState {
340
341
  * side, or shared by the positive and negative sides.
341
342
  * @since 1.1.0
342
343
  */
343
- declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): Parser<"sync", boolean, NegatableFlagState | undefined>;
344
+ declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): FluentParser<"sync", boolean, NegatableFlagState | undefined>;
344
345
  /**
345
346
  * Options for the {@link argument} parser.
346
347
  */
@@ -399,7 +400,7 @@ interface ArgumentErrorOptions {
399
400
  * @returns A {@link Parser} that expects a single argument value and produces
400
401
  * the parsed value of type {@link T}.
401
402
  */
402
- declare function argument<M extends Mode, T>(valueParser: ValueParser<M, T>, options?: ArgumentOptions): Parser<M, T, ValueParserResult<T> | undefined>;
403
+ declare function argument<M extends Mode, T>(valueParser: ValueParser<M, T>, options?: ArgumentOptions): FluentParser<M, T, ValueParserResult<T> | undefined>;
403
404
  /**
404
405
  * Options for the {@link command} parser.
405
406
  * @since 0.5.0
@@ -507,7 +508,7 @@ type CommandState<TState> = undefined | ["matched", string] | ["parsing", TState
507
508
  * @throws {TypeError} If `name` is empty, whitespace-only, contains
508
509
  * embedded whitespace, or contains control characters.
509
510
  */
510
- declare function command<M extends Mode, T, TState>(name: string, parser: Parser<M, T, TState>, options?: CommandOptions): Parser<M, T, CommandState<TState>>;
511
+ declare function command<M extends Mode, T, TState>(name: string, parser: Parser<M, T, TState>, options?: CommandOptions): FluentParser<M, T, CommandState<TState>>;
511
512
  /**
512
513
  * Format options for how {@link passThrough} captures options.
513
514
  * @since 0.8.0
@@ -595,6 +596,6 @@ interface PassThroughOptions {
595
596
  *
596
597
  * @since 0.8.0
597
598
  */
598
- declare function passThrough(options?: PassThroughOptions): Parser<"sync", readonly string[], readonly string[]>;
599
+ declare function passThrough(options?: PassThroughOptions): FluentParser<"sync", readonly string[], readonly string[]>;
599
600
  //#endregion
600
601
  export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough };
@@ -2,6 +2,7 @@ import { Message } from "./message.js";
2
2
  import { HiddenVisibility, OptionName, Usage } from "./usage.js";
3
3
  import { ValueParser, ValueParserResult } from "./valueparser.js";
4
4
  import { Mode, Parser } from "./internal/parser.js";
5
+ import { FluentParser } from "./modifiers.js";
5
6
 
6
7
  //#region src/primitives.d.ts
7
8
  /** @internal */
@@ -11,7 +12,7 @@ type OptionState<T> = ValueParserResult<T> | undefined;
11
12
  * produces a constant value of the type {@link T}.
12
13
  * @template T The type of the constant value produced by the parser.
13
14
  */
14
- declare function constant<const T>(value: T): Parser<"sync", T, T>;
15
+ declare function constant<const T>(value: T): FluentParser<"sync", T, T>;
15
16
  /**
16
17
  * Creates a parser that always fails without consuming any input.
17
18
  *
@@ -31,7 +32,7 @@ declare function constant<const T>(value: T): Parser<"sync", T, T>;
31
32
  * complete time.
32
33
  * @since 1.0.0
33
34
  */
34
- declare function fail<T>(): Parser<"sync", T, undefined>;
35
+ declare function fail<T>(): FluentParser<"sync", T, undefined>;
35
36
  /**
36
37
  * Options for the {@link option} parser.
37
38
  */
@@ -113,7 +114,7 @@ interface OptionErrorOptions {
113
114
  * @returns A {@link Parser} that can parse the specified options and their
114
115
  * values.
115
116
  */
116
- declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>]): Parser<M, T, ValueParserResult<T> | undefined>;
117
+ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>]): FluentParser<M, T, ValueParserResult<T> | undefined>;
117
118
  /**
118
119
  * Creates a parser for various styles of command-line options that take an
119
120
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
@@ -127,7 +128,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
127
128
  * @returns A {@link Parser} that can parse the specified options and their
128
129
  * values.
129
130
  */
130
- declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>, OptionOptions]): Parser<M, T, ValueParserResult<T> | undefined>;
131
+ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...readonly OptionName[], ValueParser<M, T>, OptionOptions]): FluentParser<M, T, ValueParserResult<T> | undefined>;
131
132
  /**
132
133
  * Creates a parser for various styles of command-line options that do not
133
134
  * take an argument value, such as `--option`, `-o`, or `/option`.
@@ -135,7 +136,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
135
136
  * @return A {@link Parser} that can parse the specified options as Boolean
136
137
  * flags, producing `true` if the option is present.
137
138
  */
138
- declare function option(...optionNames: readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", boolean, ValueParserResult<boolean> | undefined>;
139
+ declare function option(...optionNames: readonly [OptionName, ...readonly OptionName[]]): FluentParser<"sync", boolean, ValueParserResult<boolean> | undefined>;
139
140
  /**
140
141
  * Creates a parser for various styles of command-line options that take an
141
142
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
@@ -146,7 +147,7 @@ declare function option(...optionNames: readonly [OptionName, ...readonly Option
146
147
  * @returns A {@link Parser} that can parse the specified options and their
147
148
  * values.
148
149
  */
149
- declare function option(...args: readonly [OptionName, ...readonly OptionName[], OptionOptions]): Parser<"sync", boolean, ValueParserResult<boolean> | undefined>;
150
+ declare function option(...args: readonly [OptionName, ...readonly OptionName[], OptionOptions]): FluentParser<"sync", boolean, ValueParserResult<boolean> | undefined>;
150
151
  /**
151
152
  * Options for the {@link flag} parser.
152
153
  */
@@ -236,7 +237,7 @@ interface FlagErrorOptions {
236
237
  * });
237
238
  * ```
238
239
  */
239
- declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): Parser<"sync", true, ValueParserResult<true> | undefined>;
240
+ declare function flag(...args: readonly [OptionName, ...readonly OptionName[], FlagOptions] | readonly [OptionName, ...readonly OptionName[]]): FluentParser<"sync", true, ValueParserResult<true> | undefined>;
240
241
  /**
241
242
  * A non-empty list of option names, or a single option name.
242
243
  * @since 1.1.0
@@ -340,7 +341,7 @@ interface NegatableFlagState {
340
341
  * side, or shared by the positive and negative sides.
341
342
  * @since 1.1.0
342
343
  */
343
- declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): Parser<"sync", boolean, NegatableFlagState | undefined>;
344
+ declare function negatableFlag(names: NegatableFlagNames, options?: NegatableFlagOptions): FluentParser<"sync", boolean, NegatableFlagState | undefined>;
344
345
  /**
345
346
  * Options for the {@link argument} parser.
346
347
  */
@@ -399,7 +400,7 @@ interface ArgumentErrorOptions {
399
400
  * @returns A {@link Parser} that expects a single argument value and produces
400
401
  * the parsed value of type {@link T}.
401
402
  */
402
- declare function argument<M extends Mode, T>(valueParser: ValueParser<M, T>, options?: ArgumentOptions): Parser<M, T, ValueParserResult<T> | undefined>;
403
+ declare function argument<M extends Mode, T>(valueParser: ValueParser<M, T>, options?: ArgumentOptions): FluentParser<M, T, ValueParserResult<T> | undefined>;
403
404
  /**
404
405
  * Options for the {@link command} parser.
405
406
  * @since 0.5.0
@@ -507,7 +508,7 @@ type CommandState<TState> = undefined | ["matched", string] | ["parsing", TState
507
508
  * @throws {TypeError} If `name` is empty, whitespace-only, contains
508
509
  * embedded whitespace, or contains control characters.
509
510
  */
510
- declare function command<M extends Mode, T, TState>(name: string, parser: Parser<M, T, TState>, options?: CommandOptions): Parser<M, T, CommandState<TState>>;
511
+ declare function command<M extends Mode, T, TState>(name: string, parser: Parser<M, T, TState>, options?: CommandOptions): FluentParser<M, T, CommandState<TState>>;
511
512
  /**
512
513
  * Format options for how {@link passThrough} captures options.
513
514
  * @since 0.8.0
@@ -595,6 +596,6 @@ interface PassThroughOptions {
595
596
  *
596
597
  * @since 0.8.0
597
598
  */
598
- declare function passThrough(options?: PassThroughOptions): Parser<"sync", readonly string[], readonly string[]>;
599
+ declare function passThrough(options?: PassThroughOptions): FluentParser<"sync", readonly string[], readonly string[]>;
599
600
  //#endregion
600
601
  export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough };
@@ -9,9 +9,10 @@ import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedIni
9
9
  import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
10
10
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
11
11
  import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
12
+ import { extractDependencyMetadata } from "./dependency-metadata.js";
13
+ import { fluent } from "./modifiers.js";
12
14
  import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, expandCommandAliasSuggestions, findSimilar } from "./suggestion.js";
13
15
  import { extractLeadingCommandNames } from "./usage-internals.js";
14
- import { extractDependencyMetadata } from "./dependency-metadata.js";
15
16
  import { isValueParser } from "./valueparser.js";
16
17
 
17
18
  //#region src/primitives.ts
@@ -150,7 +151,7 @@ function constant(value) {
150
151
  enumerable: false,
151
152
  writable: false
152
153
  });
153
- return result;
154
+ return fluent(result);
154
155
  }
155
156
  /**
156
157
  * Creates a parser that always fails without consuming any input.
@@ -172,7 +173,7 @@ function constant(value) {
172
173
  * @since 1.0.0
173
174
  */
174
175
  function fail() {
175
- return {
176
+ return fluent({
176
177
  $valueType: [],
177
178
  $stateType: [],
178
179
  mode: "sync",
@@ -203,7 +204,7 @@ function fail() {
203
204
  getDocFragments(_state, _defaultValue) {
204
205
  return { fragments: [] };
205
206
  }
206
- };
207
+ });
207
208
  }
208
209
  /**
209
210
  * Internal helper to get suggestions from a value parser, using dependency values
@@ -741,7 +742,7 @@ function option(...args) {
741
742
  configurable: true,
742
743
  enumerable: false
743
744
  });
744
- return result;
745
+ return fluent(result);
745
746
  }
746
747
  /**
747
748
  * Creates a parser for command-line flags that must be explicitly provided.
@@ -944,7 +945,7 @@ function flag(...args) {
944
945
  enumerable: false,
945
946
  writable: false
946
947
  });
947
- return result;
948
+ return fluent(result);
948
949
  }
949
950
  function normalizeNegatableFlagNameList(names) {
950
951
  return typeof names === "string" ? [names] : names;
@@ -1162,7 +1163,7 @@ function negatableFlag(names, options = {}) {
1162
1163
  enumerable: false,
1163
1164
  writable: false
1164
1165
  });
1165
- return result;
1166
+ return fluent(result);
1166
1167
  }
1167
1168
  /**
1168
1169
  * Creates a parser that expects a single argument value.
@@ -1371,7 +1372,7 @@ function argument(valueParser, options = {}) {
1371
1372
  configurable: true,
1372
1373
  enumerable: false
1373
1374
  });
1374
- return result;
1375
+ return fluent(result);
1375
1376
  }
1376
1377
  function normalizeCommandState(state) {
1377
1378
  return normalizeInjectedAnnotationState(state);
@@ -1700,7 +1701,7 @@ function command(name, parser, options = {}) {
1700
1701
  configurable: true,
1701
1702
  enumerable: false
1702
1703
  });
1703
- return result;
1704
+ return fluent(result);
1704
1705
  }
1705
1706
  /**
1706
1707
  * Creates a parser that collects unrecognized options and passes them through.
@@ -1752,7 +1753,7 @@ function passThrough(options = {}) {
1752
1753
  const format = options.format ?? "equalsOnly";
1753
1754
  const optionPattern = /^-[a-z0-9-]|^--[a-z0-9-]+/i;
1754
1755
  const equalsOptionPattern = /^--[a-z0-9-]+=/i;
1755
- return {
1756
+ const result = {
1756
1757
  $valueType: [],
1757
1758
  $stateType: [],
1758
1759
  mode: "sync",
@@ -1884,6 +1885,7 @@ function passThrough(options = {}) {
1884
1885
  return `passThrough(${format})`;
1885
1886
  }
1886
1887
  };
1888
+ return fluent(result);
1887
1889
  }
1888
1890
 
1889
1891
  //#endregion
@@ -5844,6 +5844,218 @@ function findNonFiniteNumber(root) {
5844
5844
  }
5845
5845
  return void 0;
5846
5846
  }
5847
+ const CRON_MONTH_NAMES = new Map([
5848
+ ["JAN", 1],
5849
+ ["FEB", 2],
5850
+ ["MAR", 3],
5851
+ ["APR", 4],
5852
+ ["MAY", 5],
5853
+ ["JUN", 6],
5854
+ ["JUL", 7],
5855
+ ["AUG", 8],
5856
+ ["SEP", 9],
5857
+ ["OCT", 10],
5858
+ ["NOV", 11],
5859
+ ["DEC", 12]
5860
+ ]);
5861
+ const CRON_DAY_NAMES = new Map([
5862
+ ["SUN", 0],
5863
+ ["MON", 1],
5864
+ ["TUE", 2],
5865
+ ["WED", 3],
5866
+ ["THU", 4],
5867
+ ["FRI", 5],
5868
+ ["SAT", 6]
5869
+ ]);
5870
+ const CRON_FIELD_SPECS = {
5871
+ second: {
5872
+ kind: "second",
5873
+ min: 0,
5874
+ max: 59
5875
+ },
5876
+ minute: {
5877
+ kind: "minute",
5878
+ min: 0,
5879
+ max: 59
5880
+ },
5881
+ hour: {
5882
+ kind: "hour",
5883
+ min: 0,
5884
+ max: 23
5885
+ },
5886
+ dayOfMonth: {
5887
+ kind: "dayOfMonth",
5888
+ min: 1,
5889
+ max: 31
5890
+ },
5891
+ month: {
5892
+ kind: "month",
5893
+ min: 1,
5894
+ max: 12,
5895
+ names: CRON_MONTH_NAMES
5896
+ },
5897
+ dayOfWeek: {
5898
+ kind: "dayOfWeek",
5899
+ min: 0,
5900
+ max: 7,
5901
+ names: CRON_DAY_NAMES
5902
+ },
5903
+ year: {
5904
+ kind: "year",
5905
+ min: 1970,
5906
+ max: 2099
5907
+ }
5908
+ };
5909
+ function cron(options = {}) {
5910
+ const metavar$1 = options.metavar ?? "CRON";
5911
+ require_nonempty.ensureNonEmptyString(metavar$1);
5912
+ checkBooleanOption(options, "seconds");
5913
+ checkBooleanOption(options, "years");
5914
+ checkBooleanOption(options, "quartz");
5915
+ const seconds = options.seconds ?? false;
5916
+ const years = options.years ?? false;
5917
+ const quartz = options.quartz ?? false;
5918
+ const invalidCronError = options.errors?.invalidCron;
5919
+ const expectedFieldCount = 5 + (seconds ? 1 : 0) + (years ? 1 : 0);
5920
+ function makeError(input) {
5921
+ const error = invalidCronError instanceof Function ? invalidCronError(input) : invalidCronError ?? require_message.message`Expected a valid cron expression, but got ${input}.`;
5922
+ return {
5923
+ success: false,
5924
+ error
5925
+ };
5926
+ }
5927
+ function parseCron(input) {
5928
+ const fields = input.trim() === "" ? [] : input.trim().split(/\s+/u);
5929
+ if (fields.length !== expectedFieldCount) return makeError(input);
5930
+ let index = 0;
5931
+ const second = seconds ? fields[index++] : void 0;
5932
+ const minute = fields[index++];
5933
+ const hour = fields[index++];
5934
+ const dayOfMonth = fields[index++];
5935
+ const month = fields[index++];
5936
+ const dayOfWeek = fields[index++];
5937
+ const year = years ? fields[index++] : void 0;
5938
+ const fieldChecks = [
5939
+ [second, CRON_FIELD_SPECS.second],
5940
+ [minute, CRON_FIELD_SPECS.minute],
5941
+ [hour, CRON_FIELD_SPECS.hour],
5942
+ [dayOfMonth, CRON_FIELD_SPECS.dayOfMonth],
5943
+ [month, CRON_FIELD_SPECS.month],
5944
+ [dayOfWeek, CRON_FIELD_SPECS.dayOfWeek],
5945
+ [year, CRON_FIELD_SPECS.year]
5946
+ ];
5947
+ for (const [field, spec] of fieldChecks) if (field !== void 0 && !isValidCronField(field, spec, { quartz })) return makeError(input);
5948
+ if (quartz && dayOfMonth === "?" && dayOfWeek === "?") return makeError(input);
5949
+ return {
5950
+ success: true,
5951
+ value: {
5952
+ ...second !== void 0 ? { second } : {},
5953
+ minute,
5954
+ hour,
5955
+ dayOfMonth,
5956
+ month,
5957
+ dayOfWeek,
5958
+ ...year !== void 0 ? { year } : {}
5959
+ }
5960
+ };
5961
+ }
5962
+ return {
5963
+ mode: "sync",
5964
+ metavar: metavar$1,
5965
+ placeholder: {
5966
+ ...seconds ? { second: "0" } : {},
5967
+ minute: "0",
5968
+ hour: "0",
5969
+ dayOfMonth: "*",
5970
+ month: "*",
5971
+ dayOfWeek: "*",
5972
+ ...years ? { year: "1970" } : {}
5973
+ },
5974
+ parse: parseCron,
5975
+ format(value) {
5976
+ return [
5977
+ ...seconds ? [value.second ?? "0"] : [],
5978
+ value.minute,
5979
+ value.hour,
5980
+ value.dayOfMonth,
5981
+ value.month,
5982
+ value.dayOfWeek,
5983
+ ...years ? [value.year ?? "1970"] : []
5984
+ ].join(" ");
5985
+ },
5986
+ validate(value) {
5987
+ if (seconds && value.second == null || years && value.year == null) return makeError(this.format(value));
5988
+ if (!seconds && value.second != null || !years && value.year != null) return makeError(this.format(value));
5989
+ const result = parseCron(this.format(value));
5990
+ return result.success ? {
5991
+ success: true,
5992
+ value: result.value
5993
+ } : result;
5994
+ }
5995
+ };
5996
+ }
5997
+ function isValidCronField(field, spec, options) {
5998
+ if (field === "") return false;
5999
+ const parts = field.split(",");
6000
+ const standard = !parts.some((part) => part === "") && parts.every((part) => isValidCronFieldPart(part, spec));
6001
+ return standard || isQuartzCronField(field, spec, options.quartz);
6002
+ }
6003
+ function isQuartzCronField(field, spec, quartz) {
6004
+ if (!quartz) return false;
6005
+ const upper = field.toUpperCase();
6006
+ if (upper === "?") return spec.kind === "dayOfMonth" || spec.kind === "dayOfWeek";
6007
+ if (spec.kind === "dayOfMonth") {
6008
+ if (upper === "L" || upper === "LW") return true;
6009
+ const match = /^(?<day>\d{1,2})W$/u.exec(upper);
6010
+ return match != null && isCronValueInRange(match.groups.day, spec);
6011
+ }
6012
+ if (spec.kind === "dayOfWeek") {
6013
+ if (upper === "L") return true;
6014
+ const lastMatch = /^(?<day>[A-Z]{3}|\d)L$/u.exec(upper);
6015
+ if (lastMatch != null) return parseQuartzDayOfWeekSuffixValue(lastMatch.groups.day);
6016
+ const nthMatch = /^(?<day>[A-Z]{3}|\d)#(?<nth>[1-5])$/u.exec(upper);
6017
+ if (nthMatch != null) return parseQuartzDayOfWeekSuffixValue(nthMatch.groups.day);
6018
+ }
6019
+ return false;
6020
+ }
6021
+ function parseQuartzDayOfWeekSuffixValue(value) {
6022
+ if (/^[1-7]$/u.test(value)) return true;
6023
+ if (!/^[A-Z]{3}$/u.test(value)) return false;
6024
+ return CRON_DAY_NAMES.has(value);
6025
+ }
6026
+ function isValidCronFieldPart(part, spec) {
6027
+ const stepParts = part.split("/");
6028
+ if (stepParts.length > 2) return false;
6029
+ const [base, step] = stepParts;
6030
+ if (base === "") return false;
6031
+ if (step !== void 0 && !isPositiveCronStep(step)) return false;
6032
+ if (base === "*") return true;
6033
+ const rangeParts = base.split("-");
6034
+ if (rangeParts.length === 1) return parseCronValue(base, spec) !== void 0;
6035
+ if (rangeParts.length !== 2) return false;
6036
+ const [rawStart, rawEnd] = rangeParts;
6037
+ if (rawStart === "" || rawEnd === "") return false;
6038
+ const start = parseCronValue(rawStart, spec);
6039
+ const end = parseCronRangeEnd(rawStart, rawEnd, spec);
6040
+ return start !== void 0 && end !== void 0 && start <= end;
6041
+ }
6042
+ function isPositiveCronStep(step) {
6043
+ return /^\d+$/u.test(step) && Number.parseInt(step, 10) > 0;
6044
+ }
6045
+ function isCronValueInRange(value, spec) {
6046
+ return parseCronValue(value, spec) !== void 0;
6047
+ }
6048
+ function parseCronRangeEnd(start, end, spec) {
6049
+ if (spec.kind === "dayOfWeek" && start.toUpperCase() !== "SUN" && (end.toUpperCase() === "SUN" || end === "0")) return 7;
6050
+ return parseCronValue(end, spec);
6051
+ }
6052
+ function parseCronValue(value, spec) {
6053
+ const named = spec.names?.get(value.toUpperCase());
6054
+ if (named !== void 0) return named;
6055
+ if (!/^\d+$/u.test(value)) return void 0;
6056
+ const number = Number.parseInt(value, 10);
6057
+ return number >= spec.min && number <= spec.max ? number : void 0;
6058
+ }
5847
6059
  /**
5848
6060
  * Implementation of the {@link firstOf} combinator.
5849
6061
  */
@@ -6102,6 +6314,7 @@ exports.checkEnumOption = checkEnumOption;
6102
6314
  exports.choice = choice;
6103
6315
  exports.cidr = cidr;
6104
6316
  exports.color = color;
6317
+ exports.cron = cron;
6105
6318
  exports.domain = domain;
6106
6319
  exports.email = email;
6107
6320
  exports.ensureNonEmptyString = require_nonempty.ensureNonEmptyString;
@@ -2882,6 +2882,114 @@ declare function json(options: JsonOptions & {
2882
2882
  * @since 1.1.0
2883
2883
  */
2884
2884
  declare function json(options?: JsonOptions): ValueParser<"sync", Json>;
2885
+ /**
2886
+ * A validated cron schedule expression split into cron fields.
2887
+ *
2888
+ * The `second` field is present when {@link cron} is configured with
2889
+ * `seconds: true`, and the `year` field is present when it is configured
2890
+ * with `years: true`.
2891
+ *
2892
+ * @since 1.2.0
2893
+ */
2894
+ interface CronExpression {
2895
+ /** Seconds field, when enabled via `seconds: true`. */
2896
+ readonly second?: string;
2897
+ /** Minutes field. */
2898
+ readonly minute: string;
2899
+ /** Hours field. */
2900
+ readonly hour: string;
2901
+ /** Day-of-month field. */
2902
+ readonly dayOfMonth: string;
2903
+ /** Month field. */
2904
+ readonly month: string;
2905
+ /** Day-of-week field. */
2906
+ readonly dayOfWeek: string;
2907
+ /** Year field, when enabled via `years: true`. */
2908
+ readonly year?: string;
2909
+ }
2910
+ /**
2911
+ * Options for creating a {@link cron} value parser.
2912
+ *
2913
+ * @since 1.2.0
2914
+ */
2915
+ interface CronOptions {
2916
+ /**
2917
+ * The metavariable name for this parser.
2918
+ * @default `"CRON"`
2919
+ */
2920
+ readonly metavar?: NonEmptyString;
2921
+ /**
2922
+ * Whether to require a leading seconds field.
2923
+ * @default `false`
2924
+ */
2925
+ readonly seconds?: boolean;
2926
+ /**
2927
+ * Whether to require a trailing year field.
2928
+ * @default `false`
2929
+ */
2930
+ readonly years?: boolean;
2931
+ /**
2932
+ * Whether to allow common Quartz day-field extensions such as `?`, `L`,
2933
+ * `W`, and `#`.
2934
+ * @default `false`
2935
+ */
2936
+ readonly quartz?: boolean;
2937
+ /**
2938
+ * Custom error messages for cron parsing failures.
2939
+ *
2940
+ * @since 1.2.0
2941
+ */
2942
+ readonly errors?: {
2943
+ /**
2944
+ * Custom error message when the input is not a valid cron expression.
2945
+ * Can be a static message or a function that receives the raw input.
2946
+ */
2947
+ readonly invalidCron?: Message | ((input: string) => Message);
2948
+ };
2949
+ }
2950
+ /**
2951
+ * Cron expression result type for a specific {@link cron} option set.
2952
+ *
2953
+ * When `seconds: true` is configured, the `second` field is required in the
2954
+ * parser result. When `years: true` is configured, the `year` field is
2955
+ * required in the parser result.
2956
+ *
2957
+ * @since 1.2.0
2958
+ */
2959
+ type CronExpressionForOptions<O extends CronOptions> = Omit<CronExpression, "second" | "year"> & (O["seconds"] extends true ? {
2960
+ readonly second: string;
2961
+ } : {
2962
+ readonly second?: string;
2963
+ }) & (O["years"] extends true ? {
2964
+ readonly year: string;
2965
+ } : {
2966
+ readonly year?: string;
2967
+ });
2968
+ /**
2969
+ * Creates a {@link ValueParser} for cron schedule expressions.
2970
+ *
2971
+ * By default, the parser accepts standard five-field cron expressions:
2972
+ * minute, hour, day of month, month, and day of week. Enable
2973
+ * {@link CronOptions.seconds} to require a leading seconds field, and
2974
+ * {@link CronOptions.years} to require a trailing year field. Successful
2975
+ * parses return a {@link CronExpression} object whose fields preserve the
2976
+ * validated cron field expressions.
2977
+ *
2978
+ * The standard syntax supports `*`, numeric values, ranges (`1-5`), lists
2979
+ * (`1,2,3`), intervals (for example every five units or `1-10/2`), and
2980
+ * month/day names such as
2981
+ * `JAN` and `MON`. Enable {@link CronOptions.quartz} to allow common Quartz
2982
+ * day-field tokens: `?`, `L`, `LW`, `nW`, `nL`, and `n#k`.
2983
+ *
2984
+ * @param options Configuration options.
2985
+ * @returns A sync value parser producing {@link CronExpressionForOptions}
2986
+ * objects for the configured options.
2987
+ * @throws {TypeError} If `options.metavar` is an empty string.
2988
+ * @throws {TypeError} If `seconds`, `years`, or `quartz` is not a boolean.
2989
+ * @since 1.2.0
2990
+ */
2991
+ declare function cron(): ValueParser<"sync", CronExpression>;
2992
+ declare function cron<const O extends CronOptions>(options: O): ValueParser<"sync", CronExpressionForOptions<O>>;
2885
2993
  /**
2886
2994
  * Options for the {@link firstOf} combinator.
2887
2995
  * @since 1.1.0
@@ -3058,4 +3166,4 @@ declare function firstOf<const TParsers extends readonly [ValueParser<"sync", un
3058
3166
  */
3059
3167
  declare function firstOf<const TParsers extends readonly ValueParser<"sync", unknown>[]>(parsers: TParsers, options?: FirstOfOptions): ValueParser<"sync", ValueParserValue<TParsers[number]>>;
3060
3168
  //#endregion
3061
- export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, checkBooleanOption, checkEnumOption, choice, cidr, color, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, semVer, socketAddress, string, url, uuid };
3169
+ export { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CronExpression, CronExpressionForOptions, CronOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FirstOfOptions, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, KeyValueOptions, LocaleOptions, MacAddressOptions, type Mode, type ModeIterable, type ModeValue, type NonEmptyString, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, checkBooleanOption, checkEnumOption, choice, cidr, color, cron, domain, email, ensureNonEmptyString, fileSize, firstOf, float, hostname, integer, ip, ipv4, ipv6, isNonEmptyString, isValueParser, json, keyValue, locale, macAddress, port, portRange, semVer, socketAddress, string, url, uuid };