shelving 1.152.3 → 1.153.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/package.json +1 -1
- package/schema/DateSchema.d.ts +7 -2
- package/schema/DateSchema.js +13 -6
- package/schema/DateTimeSchema.d.ts +13 -0
- package/schema/DateTimeSchema.js +16 -0
- package/schema/StringSchema.d.ts +3 -3
- package/schema/TimeSchema.d.ts +7 -15
- package/schema/TimeSchema.js +14 -17
- package/schema/index.d.ts +1 -0
- package/schema/index.js +1 -0
- package/util/date.d.ts +8 -4
- package/util/date.js +20 -10
- package/util/format.d.ts +6 -5
- package/util/format.js +34 -12
- package/util/index.d.ts +0 -1
- package/util/index.js +0 -1
- package/util/time.d.ts +0 -48
- package/util/time.js +0 -115
package/package.json
CHANGED
package/schema/DateSchema.d.ts
CHANGED
|
@@ -2,19 +2,24 @@ import type { PossibleDate } from "../util/date.js";
|
|
|
2
2
|
import type { Nullish } from "../util/null.js";
|
|
3
3
|
import type { SchemaOptions } from "./Schema.js";
|
|
4
4
|
import { Schema } from "./Schema.js";
|
|
5
|
+
/** `type=""` prop for HTML `<input />` tags that are relevant for dates. */
|
|
6
|
+
export type DateInputType = "time" | "date" | "datetime-local";
|
|
5
7
|
/** Allowed options for `DateSchema` */
|
|
6
8
|
export interface DateSchemaOptions extends SchemaOptions {
|
|
7
9
|
readonly value?: PossibleDate | undefined;
|
|
8
10
|
readonly min?: Nullish<PossibleDate>;
|
|
9
11
|
readonly max?: Nullish<PossibleDate>;
|
|
12
|
+
readonly input?: DateInputType | undefined;
|
|
10
13
|
}
|
|
11
|
-
/** Define a valid date in YMD format, e.g. `2005-09-12` */
|
|
12
14
|
export declare class DateSchema extends Schema<string> {
|
|
13
15
|
readonly value: PossibleDate;
|
|
14
16
|
readonly min: Date | undefined;
|
|
15
17
|
readonly max: Date | undefined;
|
|
16
|
-
|
|
18
|
+
readonly input: DateInputType;
|
|
19
|
+
constructor({ min, max, value, input, ...options }: DateSchemaOptions);
|
|
17
20
|
validate(value?: unknown): string;
|
|
21
|
+
stringify(value: Date): string;
|
|
22
|
+
format(value: Date): string;
|
|
18
23
|
}
|
|
19
24
|
/** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
20
25
|
export declare const DATE: DateSchema;
|
package/schema/DateSchema.js
CHANGED
|
@@ -3,24 +3,31 @@ import { getDate, requireYMD } from "../util/date.js";
|
|
|
3
3
|
import { formatDate } from "../util/format.js";
|
|
4
4
|
import { NULLABLE } from "./NullableSchema.js";
|
|
5
5
|
import { Schema } from "./Schema.js";
|
|
6
|
-
/** Define a valid date in YMD format, e.g. `2005-09-12` */
|
|
7
6
|
export class DateSchema extends Schema {
|
|
8
7
|
min;
|
|
9
8
|
max;
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
input;
|
|
10
|
+
constructor({ min, max, value = "now", input = "datetime-local", ...options }) {
|
|
11
|
+
super({ title: "Date", value, ...options });
|
|
12
12
|
this.min = getDate(min);
|
|
13
13
|
this.max = getDate(max);
|
|
14
|
+
this.input = input;
|
|
14
15
|
}
|
|
15
16
|
validate(value = this.value) {
|
|
16
17
|
const date = getDate(value);
|
|
17
18
|
if (!date)
|
|
18
19
|
throw new ValueFeedback(value ? "Invalid date" : "Required", value);
|
|
19
20
|
if (this.min && date < this.min)
|
|
20
|
-
throw new ValueFeedback(`Minimum ${
|
|
21
|
+
throw new ValueFeedback(`Minimum ${this.format(this.min)}`, date);
|
|
21
22
|
if (this.max && date > this.max)
|
|
22
|
-
throw new ValueFeedback(`Maximum ${
|
|
23
|
-
return
|
|
23
|
+
throw new ValueFeedback(`Maximum ${this.format(this.max)}`, date);
|
|
24
|
+
return this.stringify(date);
|
|
25
|
+
}
|
|
26
|
+
stringify(value) {
|
|
27
|
+
return requireYMD(value);
|
|
28
|
+
}
|
|
29
|
+
format(value) {
|
|
30
|
+
return formatDate(value);
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
/** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DateSchema, type DateSchemaOptions } from "./DateSchema.js";
|
|
2
|
+
/** Allowed options for `DateSchema` */
|
|
3
|
+
export interface DateTimeSchemaOptions extends DateSchemaOptions {
|
|
4
|
+
}
|
|
5
|
+
/** Define a valid date in ISO 8601 format, e.g. `2005-09-12T18:15:00.000Z` */
|
|
6
|
+
export declare class DateTimeSchema extends DateSchema {
|
|
7
|
+
format(value: Date): string;
|
|
8
|
+
stringify(value: Date): string;
|
|
9
|
+
}
|
|
10
|
+
/** Valid datetime, e.g. `2005-09-12T08:00:00Z` (required because falsy values are invalid). */
|
|
11
|
+
export declare const DATETIME: DateTimeSchema;
|
|
12
|
+
/** Valid datetime, e.g. `2005-09-12T21:30:00Z`, or `null` */
|
|
13
|
+
export declare const NULLABLE_DATETIME: import("./NullableSchema.js").NullableSchema<string>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { formatDateTime } from "../util/format.js";
|
|
2
|
+
import { DateSchema } from "./DateSchema.js";
|
|
3
|
+
import { NULLABLE } from "./NullableSchema.js";
|
|
4
|
+
/** Define a valid date in ISO 8601 format, e.g. `2005-09-12T18:15:00.000Z` */
|
|
5
|
+
export class DateTimeSchema extends DateSchema {
|
|
6
|
+
format(value) {
|
|
7
|
+
return formatDateTime(value);
|
|
8
|
+
}
|
|
9
|
+
stringify(value) {
|
|
10
|
+
return value.toISOString();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Valid datetime, e.g. `2005-09-12T08:00:00Z` (required because falsy values are invalid). */
|
|
14
|
+
export const DATETIME = new DateTimeSchema({});
|
|
15
|
+
/** Valid datetime, e.g. `2005-09-12T21:30:00Z`, or `null` */
|
|
16
|
+
export const NULLABLE_DATETIME = NULLABLE(DATETIME);
|
package/schema/StringSchema.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SchemaOptions } from "./Schema.js";
|
|
2
2
|
import { Schema } from "./Schema.js";
|
|
3
3
|
/** `type=""` prop for HTML `<input />` tags that are relevant for strings. */
|
|
4
|
-
export type
|
|
4
|
+
export type StringInputType = "text" | "password" | "color" | "email" | "number" | "tel" | "search" | "url";
|
|
5
5
|
/** Options for `StringSchema` */
|
|
6
6
|
export interface StringSchemaOptions extends SchemaOptions {
|
|
7
7
|
readonly value?: string | undefined;
|
|
@@ -10,7 +10,7 @@ export interface StringSchemaOptions extends SchemaOptions {
|
|
|
10
10
|
readonly multiline?: boolean | undefined;
|
|
11
11
|
readonly match?: RegExp | undefined;
|
|
12
12
|
readonly case?: "upper" | "lower" | undefined;
|
|
13
|
-
readonly input?:
|
|
13
|
+
readonly input?: StringInputType | undefined;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Schema that defines a valid string.
|
|
@@ -29,7 +29,7 @@ export interface StringSchemaOptions extends SchemaOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
export declare class StringSchema extends Schema<string> {
|
|
31
31
|
readonly value: string;
|
|
32
|
-
readonly input:
|
|
32
|
+
readonly input: StringInputType;
|
|
33
33
|
readonly min: number;
|
|
34
34
|
readonly max: number;
|
|
35
35
|
readonly multiline: boolean;
|
package/schema/TimeSchema.d.ts
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
3
|
-
import { Time } from "../util/time.js";
|
|
4
|
-
import type { SchemaOptions } from "./Schema.js";
|
|
5
|
-
import { Schema } from "./Schema.js";
|
|
1
|
+
import { type PossibleDate } from "../util/date.js";
|
|
2
|
+
import { DateSchema, type DateSchemaOptions } from "./DateSchema.js";
|
|
6
3
|
/** Allowed options for `TimeSchama` */
|
|
7
|
-
export interface TimeSchemaOptions extends
|
|
8
|
-
|
|
9
|
-
readonly min?: Nullish<PossibleTime>;
|
|
10
|
-
readonly max?: Nullish<PossibleTime>;
|
|
11
|
-
readonly step?: number | undefined;
|
|
4
|
+
export interface TimeSchemaOptions extends DateSchemaOptions {
|
|
5
|
+
step?: number | undefined;
|
|
12
6
|
}
|
|
13
7
|
/** Define a valid time in 24h hh:mm:ss.fff format, e.g. `23:59` or `24:00 */
|
|
14
|
-
export declare class TimeSchema extends
|
|
15
|
-
readonly value:
|
|
16
|
-
readonly min: Time | undefined;
|
|
17
|
-
readonly max: Time | undefined;
|
|
8
|
+
export declare class TimeSchema extends DateSchema {
|
|
9
|
+
readonly value: PossibleDate;
|
|
18
10
|
/**
|
|
19
11
|
* Rounding step (in milliseconds, because that's the base unit for time), e.g. `60000` will round to the nearest second.
|
|
20
12
|
* - Note: `<input type="time">` elements expect `step=""` to be in _seconds_ so you need to multiply this by `1000`
|
|
21
13
|
*/
|
|
22
14
|
readonly step: number | undefined;
|
|
23
|
-
constructor({
|
|
15
|
+
constructor({ title, step, ...options }: TimeSchemaOptions);
|
|
24
16
|
validate(unsafeValue?: unknown): string;
|
|
25
17
|
}
|
|
26
18
|
/** Valid time, e.g. `2005-09-12` (required because falsy values are invalid). */
|
package/schema/TimeSchema.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
1
|
import { ValueFeedback } from "../feedback/Feedback.js";
|
|
2
|
+
import { getDate, requireTime } from "../util/date.js";
|
|
3
|
+
import { formatTime } from "../util/format.js";
|
|
2
4
|
import { roundStep } from "../util/number.js";
|
|
3
|
-
import {
|
|
5
|
+
import { DateSchema } from "./DateSchema.js";
|
|
4
6
|
import { NULLABLE } from "./NullableSchema.js";
|
|
5
|
-
import { Schema } from "./Schema.js";
|
|
6
7
|
/** Define a valid time in 24h hh:mm:ss.fff format, e.g. `23:59` or `24:00 */
|
|
7
|
-
export class TimeSchema extends
|
|
8
|
-
min;
|
|
9
|
-
max;
|
|
8
|
+
export class TimeSchema extends DateSchema {
|
|
10
9
|
/**
|
|
11
10
|
* Rounding step (in milliseconds, because that's the base unit for time), e.g. `60000` will round to the nearest second.
|
|
12
11
|
* - Note: `<input type="time">` elements expect `step=""` to be in _seconds_ so you need to multiply this by `1000`
|
|
13
12
|
*/
|
|
14
13
|
step;
|
|
15
|
-
constructor({
|
|
16
|
-
super({ title,
|
|
17
|
-
this.min = getTime(min);
|
|
18
|
-
this.max = getTime(max);
|
|
14
|
+
constructor({ title = "Time", step, ...options }) {
|
|
15
|
+
super({ title, ...options });
|
|
19
16
|
this.step = step;
|
|
20
17
|
}
|
|
21
18
|
validate(unsafeValue = this.value) {
|
|
22
|
-
const
|
|
23
|
-
if (!
|
|
19
|
+
const date = getDate(unsafeValue);
|
|
20
|
+
if (!date)
|
|
24
21
|
throw new ValueFeedback(unsafeValue ? "Invalid time" : "Required", unsafeValue);
|
|
25
|
-
const
|
|
26
|
-
if (this.max &&
|
|
27
|
-
throw new ValueFeedback(`Maximum ${this.max
|
|
28
|
-
if (this.min &&
|
|
29
|
-
throw new ValueFeedback(`Minimum ${this.min
|
|
30
|
-
return
|
|
22
|
+
const rounded = typeof this.step === "number" ? new Date(roundStep(date.getTime(), this.step)) : date;
|
|
23
|
+
if (this.max && rounded > this.max)
|
|
24
|
+
throw new ValueFeedback(`Maximum ${formatTime(this.max)}`, rounded);
|
|
25
|
+
if (this.min && rounded < this.min)
|
|
26
|
+
throw new ValueFeedback(`Minimum ${formatTime(this.min)}`, rounded);
|
|
27
|
+
return requireTime(rounded);
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
/** Valid time, e.g. `2005-09-12` (required because falsy values are invalid). */
|
package/schema/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./ChoiceSchema.js";
|
|
|
9
9
|
export * from "./ColorSchema.js";
|
|
10
10
|
export * from "./DataSchema.js";
|
|
11
11
|
export * from "./DateSchema.js";
|
|
12
|
+
export * from "./DateTimeSchema.js";
|
|
12
13
|
export * from "./DictionarySchema.js";
|
|
13
14
|
export * from "./EmailSchema.js";
|
|
14
15
|
export * from "./EntitySchema.js";
|
package/schema/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./ChoiceSchema.js";
|
|
|
11
11
|
export * from "./ColorSchema.js";
|
|
12
12
|
export * from "./DataSchema.js";
|
|
13
13
|
export * from "./DateSchema.js";
|
|
14
|
+
export * from "./DateTimeSchema.js";
|
|
14
15
|
export * from "./DictionarySchema.js";
|
|
15
16
|
export * from "./EmailSchema.js";
|
|
16
17
|
export * from "./EntitySchema.js";
|
package/util/date.d.ts
CHANGED
|
@@ -12,18 +12,18 @@ export declare function assertDate(value: unknown, caller?: AnyCaller): asserts
|
|
|
12
12
|
* Convert an unknown value to a valid `Date` instance, or return `undefined` if it couldn't be converted.
|
|
13
13
|
* - Note: `Date` instances can be invalid (e.g. `new Date("blah blah").getTime()` returns `NaN`). These are detected and will always return `null`
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* @param value Any value that we want to parse as a valid date (defaults to `undefined`).
|
|
16
16
|
* - `Date` instance returns unchanged (BUT if the date isn't valid, `undefined` is returned).
|
|
17
17
|
* - `null` or `undefined` or `""` empty string returns `undefined`
|
|
18
18
|
* - The string `"now"` returns the current date (e.g. `new Date()`).
|
|
19
19
|
* - The string `"today"` returns the current date at midnight (e.g. `getMidnight()`).
|
|
20
20
|
* - The string `"tomorrow"` returns tomorrow's date at midnight (e.g. `addDays(getMidnight(), 1)`).
|
|
21
21
|
* - The string `"yesterday"` returns yesterday's date at midnight (e.g. `addDays(getMidnight(), 1)`).
|
|
22
|
-
* -
|
|
22
|
+
* - Date strings (e.g. `"2003-09-12"` or `"2003 feb 20:09"`) return the corresponding date (using the user's current locale).
|
|
23
|
+
* - Time strings (e.g. `"18:32"` or `"23:59:59.999"`) return today's date at that time (using the user's current locale).
|
|
23
24
|
* - Numbers are return the corresponding date (using `new Date(number)`, i.e. milliseconds since 01/01/1970).
|
|
24
25
|
* - Anything else returns `undefined`
|
|
25
26
|
*
|
|
26
|
-
* @param value Any value that we want to parse as a valid date (defaults to `undefined`).
|
|
27
27
|
* @returns `Date` instance if the value could be converted to a valid date, and `null` if not.
|
|
28
28
|
*/
|
|
29
29
|
export declare function getDate(value: unknown): Date | undefined;
|
|
@@ -46,8 +46,12 @@ export declare function getTimestamp(value?: unknown): number | undefined;
|
|
|
46
46
|
export declare function requireTimestamp(value?: PossibleDate): number;
|
|
47
47
|
/** Convert an unknown value to a YMD date string like "2015-09-12", or `undefined` if it couldn't be converted. */
|
|
48
48
|
export declare function getYMD(value?: unknown): string | undefined;
|
|
49
|
-
/** Convert a `Date` instance to a YMD string like "2015-09-12", or throw `RequiredError` if it couldn't be converted. */
|
|
49
|
+
/** Convert a possible `Date` instance to a YMD string like "2015-09-12", or throw `RequiredError` if it couldn't be converted. */
|
|
50
50
|
export declare function requireYMD(value?: PossibleDate, caller?: AnyCaller): string;
|
|
51
|
+
/** Convert an unknown value to a HMS time string like "18:32:00", or `undefined` if it couldn't be converted. */
|
|
52
|
+
export declare function getTime(value?: unknown): string | undefined;
|
|
53
|
+
/** Convert a possible `Date` instance to an HMS string like "18:32:00", or throw `RequiredError` if it couldn't be converted. */
|
|
54
|
+
export declare function requireTime(value?: PossibleDate, caller?: AnyCaller): string;
|
|
51
55
|
/** List of day-of-week strings. */
|
|
52
56
|
export declare const DAYS: readonly ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
|
53
57
|
/** Type listing day-of-week strings. */
|
package/util/date.js
CHANGED
|
@@ -17,18 +17,18 @@ export function assertDate(value, caller = assertDate) {
|
|
|
17
17
|
* Convert an unknown value to a valid `Date` instance, or return `undefined` if it couldn't be converted.
|
|
18
18
|
* - Note: `Date` instances can be invalid (e.g. `new Date("blah blah").getTime()` returns `NaN`). These are detected and will always return `null`
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* @param value Any value that we want to parse as a valid date (defaults to `undefined`).
|
|
21
21
|
* - `Date` instance returns unchanged (BUT if the date isn't valid, `undefined` is returned).
|
|
22
22
|
* - `null` or `undefined` or `""` empty string returns `undefined`
|
|
23
23
|
* - The string `"now"` returns the current date (e.g. `new Date()`).
|
|
24
24
|
* - The string `"today"` returns the current date at midnight (e.g. `getMidnight()`).
|
|
25
25
|
* - The string `"tomorrow"` returns tomorrow's date at midnight (e.g. `addDays(getMidnight(), 1)`).
|
|
26
26
|
* - The string `"yesterday"` returns yesterday's date at midnight (e.g. `addDays(getMidnight(), 1)`).
|
|
27
|
-
* -
|
|
27
|
+
* - Date strings (e.g. `"2003-09-12"` or `"2003 feb 20:09"`) return the corresponding date (using the user's current locale).
|
|
28
|
+
* - Time strings (e.g. `"18:32"` or `"23:59:59.999"`) return today's date at that time (using the user's current locale).
|
|
28
29
|
* - Numbers are return the corresponding date (using `new Date(number)`, i.e. milliseconds since 01/01/1970).
|
|
29
30
|
* - Anything else returns `undefined`
|
|
30
31
|
*
|
|
31
|
-
* @param value Any value that we want to parse as a valid date (defaults to `undefined`).
|
|
32
32
|
* @returns `Date` instance if the value could be converted to a valid date, and `null` if not.
|
|
33
33
|
*/
|
|
34
34
|
export function getDate(value) {
|
|
@@ -46,6 +46,9 @@ export function getDate(value) {
|
|
|
46
46
|
const date = new Date(value);
|
|
47
47
|
if (Number.isFinite(date.getTime()))
|
|
48
48
|
return date;
|
|
49
|
+
const time = new Date(`${requireYMD()}T${value}`);
|
|
50
|
+
if (Number.isFinite(time.getTime()))
|
|
51
|
+
return time;
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
/** Get a date representing this exact moment. */
|
|
@@ -95,18 +98,25 @@ export function getYMD(value) {
|
|
|
95
98
|
if (date)
|
|
96
99
|
return _ymd(date);
|
|
97
100
|
}
|
|
98
|
-
/** Convert a `Date` instance to a YMD string like "2015-09-12", or throw `RequiredError` if it couldn't be converted. */
|
|
101
|
+
/** Convert a possible `Date` instance to a YMD string like "2015-09-12", or throw `RequiredError` if it couldn't be converted. */
|
|
99
102
|
export function requireYMD(value, caller = requireYMD) {
|
|
100
103
|
return _ymd(requireDate(value, caller));
|
|
101
104
|
}
|
|
102
105
|
function _ymd(date) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
return date.toISOString().slice(0, 10);
|
|
107
|
+
}
|
|
108
|
+
/** Convert an unknown value to a HMS time string like "18:32:00", or `undefined` if it couldn't be converted. */
|
|
109
|
+
export function getTime(value) {
|
|
110
|
+
const date = getDate(value);
|
|
111
|
+
if (date)
|
|
112
|
+
return _hms(date);
|
|
113
|
+
}
|
|
114
|
+
/** Convert a possible `Date` instance to an HMS string like "18:32:00", or throw `RequiredError` if it couldn't be converted. */
|
|
115
|
+
export function requireTime(value, caller = requireTime) {
|
|
116
|
+
return _hms(requireDate(value, caller));
|
|
107
117
|
}
|
|
108
|
-
function
|
|
109
|
-
return
|
|
118
|
+
function _hms(date) {
|
|
119
|
+
return date.toISOString().slice(11, 19);
|
|
110
120
|
}
|
|
111
121
|
/** List of day-of-week strings. */
|
|
112
122
|
export const DAYS = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
package/util/format.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type ImmutableArray } from "./array.js";
|
|
2
2
|
import { type PossibleDate } from "./date.js";
|
|
3
3
|
import { type ImmutableObject } from "./object.js";
|
|
4
|
-
import { type PossibleTime } from "./time.js";
|
|
5
4
|
import { type PossibleURL } from "./url.js";
|
|
6
5
|
/** Format a number range (based on the user's browser language settings). */
|
|
7
6
|
export declare function formatRange(min: number, max: number, options?: Intl.NumberFormatOptions): string;
|
|
@@ -30,9 +29,11 @@ export declare function formatObject(obj: ImmutableObject): string;
|
|
|
30
29
|
/** Format an unknown array as a string. */
|
|
31
30
|
export declare function formatArray(arr: ImmutableArray<unknown>, separator?: string): string;
|
|
32
31
|
/** Format a date in the browser locale. */
|
|
33
|
-
export declare function formatDate(date: PossibleDate): string;
|
|
34
|
-
/** Format a time
|
|
35
|
-
export declare function formatTime(time?:
|
|
32
|
+
export declare function formatDate(date: PossibleDate, options?: Intl.DateTimeFormatOptions): string;
|
|
33
|
+
/** Format a time in the browser locale (no seconds by default). */
|
|
34
|
+
export declare function formatTime(time?: PossibleDate, options?: Intl.DateTimeFormatOptions): string;
|
|
35
|
+
/** Format a datetime in the browser locale (no seconds by default). */
|
|
36
|
+
export declare function formatDateTime(date: PossibleDate, options?: Intl.DateTimeFormatOptions): string;
|
|
36
37
|
/** Format a URL as a user-friendly string, e.g. `http://shax.com/test?uid=129483` → `shax.com/test` */
|
|
37
38
|
export declare function formatURL(possible: PossibleURL, base?: PossibleURL): string;
|
|
38
39
|
/**
|
|
@@ -40,7 +41,7 @@ export declare function formatURL(possible: PossibleURL, base?: PossibleURL): st
|
|
|
40
41
|
* - Strings return the string.
|
|
41
42
|
* - Booleans return `"Yes"` or `"No"`
|
|
42
43
|
* - Numbers return formatted number with commas etc (e.g. `formatNumber()`).
|
|
43
|
-
* - Dates return formatted
|
|
44
|
+
* - Dates return formatted datetime (e.g. `formatDateTime()`).
|
|
44
45
|
* - Arrays return the array items converted to string (with `toTitle()`), and joined with a comma.
|
|
45
46
|
* - Objects return...
|
|
46
47
|
* 1. `object.name` if it exists, or
|
package/util/format.js
CHANGED
|
@@ -3,7 +3,6 @@ import { NNBSP } from "./constants.js";
|
|
|
3
3
|
import { isDate, requireDate } from "./date.js";
|
|
4
4
|
import { getPercent } from "./number.js";
|
|
5
5
|
import { isObject } from "./object.js";
|
|
6
|
-
import { requireTime } from "./time.js";
|
|
7
6
|
import { requireURL } from "./url.js";
|
|
8
7
|
/** Format a number range (based on the user's browser language settings). */
|
|
9
8
|
export function formatRange(min, max, options) {
|
|
@@ -24,8 +23,10 @@ export function formatNumber(num, options) {
|
|
|
24
23
|
}
|
|
25
24
|
/** Format a number with a longer full-word suffix. */
|
|
26
25
|
export function pluralizeQuantity(num, singular, plural, options) {
|
|
27
|
-
const
|
|
28
|
-
|
|
26
|
+
const qty = formatNumber(num, {
|
|
27
|
+
...options,
|
|
28
|
+
style: "decimal",
|
|
29
|
+
});
|
|
29
30
|
return `${qty}${NNBSP}${num === 1 ? singular : plural}`;
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
@@ -37,8 +38,12 @@ export function pluralizeQuantity(num, singular, plural, options) {
|
|
|
37
38
|
* @param denumerator The number representing the whole amount.
|
|
38
39
|
*/
|
|
39
40
|
export function formatPercent(numerator, denumerator, options) {
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
return formatNumber(getPercent(numerator, denumerator), {
|
|
42
|
+
maximumFractionDigits: 0,
|
|
43
|
+
roundingMode: "trunc",
|
|
44
|
+
...options,
|
|
45
|
+
style: "percent",
|
|
46
|
+
});
|
|
42
47
|
}
|
|
43
48
|
/**
|
|
44
49
|
* Format an unknown object as a string.
|
|
@@ -65,12 +70,29 @@ export function formatArray(arr, separator = ", ") {
|
|
|
65
70
|
return arr.map(formatValue).join(separator);
|
|
66
71
|
}
|
|
67
72
|
/** Format a date in the browser locale. */
|
|
68
|
-
export function formatDate(date) {
|
|
69
|
-
return requireDate(date, formatDate).toLocaleDateString();
|
|
73
|
+
export function formatDate(date, options) {
|
|
74
|
+
return requireDate(date, formatDate).toLocaleDateString(undefined, options);
|
|
70
75
|
}
|
|
71
|
-
/** Format a time
|
|
72
|
-
export function formatTime(time,
|
|
73
|
-
return
|
|
76
|
+
/** Format a time in the browser locale (no seconds by default). */
|
|
77
|
+
export function formatTime(time, options) {
|
|
78
|
+
return requireDate(time, formatTime).toLocaleTimeString(undefined, {
|
|
79
|
+
hour: "2-digit",
|
|
80
|
+
minute: "2-digit",
|
|
81
|
+
second: undefined, // No seconds by default.
|
|
82
|
+
...options,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Format a datetime in the browser locale (no seconds by default). */
|
|
86
|
+
export function formatDateTime(date, options) {
|
|
87
|
+
return requireDate(date, formatDateTime).toLocaleString(undefined, {
|
|
88
|
+
year: "numeric",
|
|
89
|
+
month: "numeric",
|
|
90
|
+
day: "numeric",
|
|
91
|
+
hour: "2-digit",
|
|
92
|
+
minute: "2-digit",
|
|
93
|
+
// No seconds by default.
|
|
94
|
+
...options,
|
|
95
|
+
});
|
|
74
96
|
}
|
|
75
97
|
/** Format a URL as a user-friendly string, e.g. `http://shax.com/test?uid=129483` → `shax.com/test` */
|
|
76
98
|
export function formatURL(possible, base) {
|
|
@@ -82,7 +104,7 @@ export function formatURL(possible, base) {
|
|
|
82
104
|
* - Strings return the string.
|
|
83
105
|
* - Booleans return `"Yes"` or `"No"`
|
|
84
106
|
* - Numbers return formatted number with commas etc (e.g. `formatNumber()`).
|
|
85
|
-
* - Dates return formatted
|
|
107
|
+
* - Dates return formatted datetime (e.g. `formatDateTime()`).
|
|
86
108
|
* - Arrays return the array items converted to string (with `toTitle()`), and joined with a comma.
|
|
87
109
|
* - Objects return...
|
|
88
110
|
* 1. `object.name` if it exists, or
|
|
@@ -104,7 +126,7 @@ export function formatValue(value) {
|
|
|
104
126
|
if (typeof value === "function")
|
|
105
127
|
return "Function";
|
|
106
128
|
if (isDate(value))
|
|
107
|
-
return
|
|
129
|
+
return formatDateTime(value);
|
|
108
130
|
if (isArray(value))
|
|
109
131
|
return formatArray(value);
|
|
110
132
|
if (isObject(value))
|
package/util/index.d.ts
CHANGED
package/util/index.js
CHANGED
package/util/time.d.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { AnyCaller } from "./function.js";
|
|
2
|
-
/** Class representing a time in the day in 24 hour format in the user's current locale. */
|
|
3
|
-
export declare class Time {
|
|
4
|
-
/** Make a new `Time` instance from a time string. */
|
|
5
|
-
static from(value: unknown): Time | undefined;
|
|
6
|
-
readonly time: number;
|
|
7
|
-
constructor(time: number);
|
|
8
|
-
/** Get the number of hours in this time. */
|
|
9
|
-
get h(): number;
|
|
10
|
-
/** Get the number of minutes in this time. */
|
|
11
|
-
get m(): number;
|
|
12
|
-
/** Get the number of seconds in this time. */
|
|
13
|
-
get s(): number;
|
|
14
|
-
/** Get the number of seconds in this time. */
|
|
15
|
-
get ms(): number;
|
|
16
|
-
/** Get the time as in `hh:mm` format (hours, minutes), e.g. `13.59` */
|
|
17
|
-
get short(): string;
|
|
18
|
-
/** Get the time in `hh:mm:ss` format (hours, minutes seconds), e.g. `13.16.19.123` */
|
|
19
|
-
get medium(): string;
|
|
20
|
-
/** Get this time in `hh:mm:ss.fff` format (ISO 8601 compatible, hours, minutes, seconds, milliseconds), e.g. `13:16:19.123` */
|
|
21
|
-
get long(): string;
|
|
22
|
-
/** Get a date corresponding to this time. */
|
|
23
|
-
get date(): Date;
|
|
24
|
-
/**
|
|
25
|
-
* Format this time using the browser locale settings with a specified amount of precision.
|
|
26
|
-
* @param precision Reveal additional parts of the time, e.g. `2` shows hours and minutes, `3` also shows seconds, and `4 | 5 | 6` show mlliseconds at increasing precision.
|
|
27
|
-
*/
|
|
28
|
-
format(precision?: 2 | 3 | 4 | 5 | 6): string;
|
|
29
|
-
valueOf(): number;
|
|
30
|
-
toString(): string;
|
|
31
|
-
}
|
|
32
|
-
/** Values that can be converted to times. */
|
|
33
|
-
export type PossibleTime = Time | Date | number | string;
|
|
34
|
-
/** Is an unknown value a `Time` instance. */
|
|
35
|
-
export declare function isTime(value: unknown): value is Time;
|
|
36
|
-
/**
|
|
37
|
-
* Convert a value to a `Time` instance, or return `undefined` if it couldn't be converted.
|
|
38
|
-
* - Works with possible dates, e.g. `now` or `Date` or `2022-09-12 18:32` or `19827263567`
|
|
39
|
-
* - Works with time strings, e.g. `18:32` or `23:59:59.999`
|
|
40
|
-
*
|
|
41
|
-
* @param value Any value that we want to parse as a valid time (defaults to `undefined`).
|
|
42
|
-
*/
|
|
43
|
-
export declare function getTime(value: unknown): Time | undefined;
|
|
44
|
-
/**
|
|
45
|
-
* Convert a possible date to a `Time` instance, or throw `ValueError` if it couldn't be converted (defaults to `"now"`).
|
|
46
|
-
* @param value Any value that we want to parse as a valid time (defaults to `"now"`).
|
|
47
|
-
*/
|
|
48
|
-
export declare function requireTime(value?: PossibleTime, caller?: AnyCaller): Time;
|
package/util/time.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { ValueError } from "../error/ValueError.js";
|
|
2
|
-
import { DAY, HOUR, MINUTE, SECOND } from "./constants.js";
|
|
3
|
-
import { getDate } from "./date.js";
|
|
4
|
-
import { wrapNumber } from "./number.js";
|
|
5
|
-
/** Class representing a time in the day in 24 hour format in the user's current locale. */
|
|
6
|
-
export class Time {
|
|
7
|
-
/** Make a new `Time` instance from a time string. */
|
|
8
|
-
static from(value) {
|
|
9
|
-
if (value === undefined || value === null || value === "")
|
|
10
|
-
return undefined;
|
|
11
|
-
if (isTime(value))
|
|
12
|
-
return value;
|
|
13
|
-
if (typeof value === "string") {
|
|
14
|
-
const matches = value.match(TIME_REGEXP);
|
|
15
|
-
if (matches) {
|
|
16
|
-
const [, h, m, s, ms] = matches;
|
|
17
|
-
return new Time(Number.parseInt(h, 10) * HOUR +
|
|
18
|
-
Number.parseInt(m, 10) * MINUTE +
|
|
19
|
-
(typeof s === "string" ? Number.parseInt(s, 10) * SECOND : 0) +
|
|
20
|
-
(typeof ms === "string" ? Number.parseInt(ms, 10) : 0));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
const date = getDate(value);
|
|
24
|
-
if (date)
|
|
25
|
-
return new Time(date.getHours() * HOUR + date.getMinutes() * MINUTE + date.getSeconds() * SECOND + date.getMilliseconds());
|
|
26
|
-
}
|
|
27
|
-
/* Total number of milliseconds in this time (always a number between `0` and `86400000` because higher/lower numbers wrap into the next/previous day). */
|
|
28
|
-
time;
|
|
29
|
-
constructor(time) {
|
|
30
|
-
this.time = wrapNumber(Math.round(time), 0, DAY);
|
|
31
|
-
}
|
|
32
|
-
/** Get the number of hours in this time. */
|
|
33
|
-
get h() {
|
|
34
|
-
return Math.trunc(this.time / HOUR);
|
|
35
|
-
}
|
|
36
|
-
/** Get the number of minutes in this time. */
|
|
37
|
-
get m() {
|
|
38
|
-
return Math.trunc((this.time % HOUR) / MINUTE);
|
|
39
|
-
}
|
|
40
|
-
/** Get the number of seconds in this time. */
|
|
41
|
-
get s() {
|
|
42
|
-
return Math.trunc((this.time % MINUTE) / SECOND);
|
|
43
|
-
}
|
|
44
|
-
/** Get the number of seconds in this time. */
|
|
45
|
-
get ms() {
|
|
46
|
-
return this.time % SECOND;
|
|
47
|
-
}
|
|
48
|
-
/** Get the time as in `hh:mm` format (hours, minutes), e.g. `13.59` */
|
|
49
|
-
get short() {
|
|
50
|
-
return `${_pad(this.h, 2)}:${_pad(this.m, 2)}`;
|
|
51
|
-
}
|
|
52
|
-
/** Get the time in `hh:mm:ss` format (hours, minutes seconds), e.g. `13.16.19.123` */
|
|
53
|
-
get medium() {
|
|
54
|
-
return `${_pad(this.h, 2)}:${_pad(this.m, 2)}:${_pad(this.s, 2)}`;
|
|
55
|
-
}
|
|
56
|
-
/** Get this time in `hh:mm:ss.fff` format (ISO 8601 compatible, hours, minutes, seconds, milliseconds), e.g. `13:16:19.123` */
|
|
57
|
-
get long() {
|
|
58
|
-
return `${_pad(this.h, 2)}:${_pad(this.m, 2)}:${_pad(this.s, 2)}.${_pad(this.ms, 3)}`;
|
|
59
|
-
}
|
|
60
|
-
/** Get a date corresponding to this time. */
|
|
61
|
-
get date() {
|
|
62
|
-
const date = new Date();
|
|
63
|
-
date.setHours(this.h, this.m, this.s, this.ms);
|
|
64
|
-
return date;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Format this time using the browser locale settings with a specified amount of precision.
|
|
68
|
-
* @param precision Reveal additional parts of the time, e.g. `2` shows hours and minutes, `3` also shows seconds, and `4 | 5 | 6` show mlliseconds at increasing precision.
|
|
69
|
-
*/
|
|
70
|
-
format(precision = 2) {
|
|
71
|
-
return this.date.toLocaleTimeString(undefined, {
|
|
72
|
-
hour: "2-digit",
|
|
73
|
-
minute: "2-digit",
|
|
74
|
-
second: precision >= 3 ? "2-digit" : undefined,
|
|
75
|
-
fractionalSecondDigits: precision >= 4 ? (precision - 3) : undefined,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
// Implement `valueOf()`
|
|
79
|
-
valueOf() {
|
|
80
|
-
return this.time;
|
|
81
|
-
}
|
|
82
|
-
// Implement `toString()`
|
|
83
|
-
toString() {
|
|
84
|
-
return this.long;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function _pad(num, size) {
|
|
88
|
-
return num.toString(10).padStart(size, "0000");
|
|
89
|
-
}
|
|
90
|
-
/** Regular expression that matches a time in ISO 8601 format. */
|
|
91
|
-
const TIME_REGEXP = /([0-9]+):([0-9]+)(?::([0-9]+)(?:.([0-9]+))?)?/;
|
|
92
|
-
/** Is an unknown value a `Time` instance. */
|
|
93
|
-
export function isTime(value) {
|
|
94
|
-
return value instanceof Time;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Convert a value to a `Time` instance, or return `undefined` if it couldn't be converted.
|
|
98
|
-
* - Works with possible dates, e.g. `now` or `Date` or `2022-09-12 18:32` or `19827263567`
|
|
99
|
-
* - Works with time strings, e.g. `18:32` or `23:59:59.999`
|
|
100
|
-
*
|
|
101
|
-
* @param value Any value that we want to parse as a valid time (defaults to `undefined`).
|
|
102
|
-
*/
|
|
103
|
-
export function getTime(value) {
|
|
104
|
-
return Time.from(value);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Convert a possible date to a `Time` instance, or throw `ValueError` if it couldn't be converted (defaults to `"now"`).
|
|
108
|
-
* @param value Any value that we want to parse as a valid time (defaults to `"now"`).
|
|
109
|
-
*/
|
|
110
|
-
export function requireTime(value = "now", caller = requireTime) {
|
|
111
|
-
const time = Time.from(value);
|
|
112
|
-
if (!time)
|
|
113
|
-
throw new ValueError("Invalid time", { received: value, caller });
|
|
114
|
-
return time;
|
|
115
|
-
}
|