mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
@kbn/config-schema
: Add support for multi-unit duration (#187888)
This commit is contained in:
parent
5e0a52c4a2
commit
9a28fde4a3
3 changed files with 36 additions and 9 deletions
|
@ -461,8 +461,12 @@ const valueSchema = schema.duration({ defaultValue: '70ms' });
|
|||
```
|
||||
|
||||
__Notes:__
|
||||
* The string value for `schema.duration()` supports the following optional suffixes: `ms`, `s`, `m`, `h`, `d`, `w`, `M` and `Y`. The default suffix is `ms`.
|
||||
* The string value for `schema.duration()` supports the following optional suffixes: `ms`, `s`, `m`, `h`, `d`, `w`, `M` and `y`. The default suffix is `ms`.
|
||||
* The number value is treated as a number of milliseconds and hence should be a positive integer, e.g. `100` is equal to `'100ms'`.
|
||||
* Multi-unit duration strings are supported (`1m30s`).
|
||||
* Spaces are not allowed.
|
||||
* It allows any order in the units (`1m30s1d`).
|
||||
* It allows the same unit to be specified multiple times (`1m30s50m` is the same as `51m30s`).
|
||||
|
||||
#### `schema.conditional()`
|
||||
|
||||
|
|
|
@ -6,29 +6,36 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Duration, duration as momentDuration, DurationInputArg2, isDuration } from 'moment';
|
||||
import { Duration, duration as momentDuration, isDuration } from 'moment';
|
||||
export type { Duration };
|
||||
export { isDuration };
|
||||
|
||||
const timeFormatRegex = /^(0|[1-9][0-9]*)(ms|s|m|h|d|w|M|Y)$/;
|
||||
const timeFormatRegex = /^(0|[1-9][0-9]*)(ms|s|m|h|d|w|M|y|Y)(.*)$/;
|
||||
type TimeUnitString = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'y' | 'Y'; // Moment officially supports lowercased 'y', but keeping 'Y' for BWC
|
||||
|
||||
function stringToDuration(text: string) {
|
||||
function stringToDuration(text: string): Duration {
|
||||
const result = timeFormatRegex.exec(text);
|
||||
if (!result) {
|
||||
const number = Number(text);
|
||||
if (typeof number !== 'number' || isNaN(number)) {
|
||||
throw new Error(
|
||||
`Failed to parse value as time value. Value must be a duration in milliseconds, or follow the format ` +
|
||||
`<count>[ms|s|m|h|d|w|M|Y] (e.g. '70ms', '5s', '3d', '1Y'), where the duration is a safe positive integer.`
|
||||
`<count>[ms|s|m|h|d|w|M|y] (e.g. '70ms', '5s', '3d', '1y', '1m30s'), where the duration is a safe positive integer.`
|
||||
);
|
||||
}
|
||||
return numberToDuration(number);
|
||||
}
|
||||
|
||||
const count = parseInt(result[1], 10);
|
||||
const unit = result[2] as DurationInputArg2;
|
||||
const unit = result[2] as TimeUnitString;
|
||||
const rest = result[3];
|
||||
|
||||
return momentDuration(count, unit);
|
||||
const duration = momentDuration(count, unit as Exclude<TimeUnitString, 'Y'>); // Moment still supports capital 'Y', but officially (and type-wise), it doesn't.
|
||||
|
||||
if (rest) {
|
||||
return duration.add(stringToDuration(rest));
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
||||
function numberToDuration(numberMs: number) {
|
||||
|
|
|
@ -24,6 +24,22 @@ test('handles number', () => {
|
|||
expect(duration().validate(123000)).toEqual(momentDuration(123000));
|
||||
});
|
||||
|
||||
test('handles multi-unit', () => {
|
||||
expect(duration().validate('1m30s')).toEqual(momentDuration(90000));
|
||||
expect(duration().validate('1m30s70ms')).toEqual(momentDuration(90070));
|
||||
});
|
||||
|
||||
test.each([60000, '60000', '60000ms', '60s', '1m', '1m0s'])(
|
||||
'multiple ways of introducing 1 minute: %p',
|
||||
(d) => {
|
||||
expect(duration().validate(d)).toEqual(momentDuration(60000));
|
||||
}
|
||||
);
|
||||
|
||||
test('it supports years as Y and y', () => {
|
||||
expect(duration().validate('1y')).toEqual(duration().validate('1Y'));
|
||||
});
|
||||
|
||||
test('is required by default', () => {
|
||||
expect(() => duration().validate(undefined)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"expected value of type [moment.Duration] but got [undefined]"`
|
||||
|
@ -184,10 +200,10 @@ test('returns error when not valid string or non-safe positive integer', () => {
|
|||
);
|
||||
|
||||
expect(() => duration().validate('123foo')).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Failed to parse value as time value. Value must be a duration in milliseconds, or follow the format <count>[ms|s|m|h|d|w|M|Y] (e.g. '70ms', '5s', '3d', '1Y'), where the duration is a safe positive integer."`
|
||||
`"Failed to parse value as time value. Value must be a duration in milliseconds, or follow the format <count>[ms|s|m|h|d|w|M|y] (e.g. '70ms', '5s', '3d', '1y', '1m30s'), where the duration is a safe positive integer."`
|
||||
);
|
||||
|
||||
expect(() => duration().validate('123 456')).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Failed to parse value as time value. Value must be a duration in milliseconds, or follow the format <count>[ms|s|m|h|d|w|M|Y] (e.g. '70ms', '5s', '3d', '1Y'), where the duration is a safe positive integer."`
|
||||
`"Failed to parse value as time value. Value must be a duration in milliseconds, or follow the format <count>[ms|s|m|h|d|w|M|y] (e.g. '70ms', '5s', '3d', '1y', '1m30s'), where the duration is a safe positive integer."`
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue