shelving 1.185.3 → 1.186.1
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/CurrencyAmountSchema.d.ts +33 -0
- package/schema/CurrencyAmountSchema.js +41 -0
- package/schema/CurrencyCodeSchema.d.ts +21 -0
- package/schema/CurrencyCodeSchema.js +35 -0
- package/schema/DateSchema.d.ts +5 -2
- package/schema/DateSchema.js +3 -4
- package/schema/DateTimeSchema.d.ts +1 -2
- package/schema/DateTimeSchema.js +2 -5
- package/schema/NumberSchema.d.ts +5 -1
- package/schema/NumberSchema.js +5 -3
- package/schema/PhoneSchema.d.ts +4 -1
- package/schema/PhoneSchema.js +6 -6
- package/schema/TimeSchema.d.ts +1 -2
- package/schema/TimeSchema.js +2 -5
- package/schema/index.d.ts +2 -0
- package/schema/index.js +2 -0
- package/util/currency.d.ts +28 -0
- package/util/currency.js +46 -0
- package/util/format.js +2 -1
- package/util/index.d.ts +1 -0
- package/util/index.js +1 -0
package/package.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type CurrencyCode } from "../util/currency.js";
|
|
2
|
+
import { NumberSchema, type NumberSchemaOptions } from "./NumberSchema.js";
|
|
3
|
+
/** Allowed options for `CurrencyAmountSchema`. */
|
|
4
|
+
export interface CurrencyAmountSchemaOptions extends NumberSchemaOptions {
|
|
5
|
+
readonly symbol?: string | undefined;
|
|
6
|
+
readonly currency: CurrencyCode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Schema representing a numeric amount in a specific currency.
|
|
10
|
+
*
|
|
11
|
+
* - The validation step is inferred from the currency's minor units.
|
|
12
|
+
* - The default formatter renders amounts using shelving's currency helpers.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const PRICE = new CurrencyAmountSchema({ currency: "GBP", min: 0 });
|
|
16
|
+
* PRICE.validate("12.345"); // 12.35
|
|
17
|
+
* PRICE.format(12.3); // "£12.30"
|
|
18
|
+
*/
|
|
19
|
+
export declare class CurrencyAmountSchema extends NumberSchema {
|
|
20
|
+
readonly currency: CurrencyCode;
|
|
21
|
+
readonly symbol: string;
|
|
22
|
+
constructor({ currency, one, title, symbol, step, format, ...options }: CurrencyAmountSchemaOptions);
|
|
23
|
+
}
|
|
24
|
+
/** Valid non-negative monetary amount in the a currency. */
|
|
25
|
+
export declare const CURRENCY_AMOUNT: (currency: CurrencyCode) => CurrencyAmountSchema;
|
|
26
|
+
export declare const USD_AMOUNT: CurrencyAmountSchema;
|
|
27
|
+
export declare const GBP_AMOUNT: CurrencyAmountSchema;
|
|
28
|
+
export declare const EUR_AMOUNT: CurrencyAmountSchema;
|
|
29
|
+
/** Valid optional monetary amount in the default currency, or `null`. */
|
|
30
|
+
export declare const NULLABLE_CURRENCY_AMOUNT: (currency: CurrencyCode) => import("./NullableSchema.js").NullableSchema<number>;
|
|
31
|
+
export declare const NULLABLE_USD_AMOUNT: import("./NullableSchema.js").NullableSchema<number>;
|
|
32
|
+
export declare const NULLABLE_GBP_AMOUNT: import("./NullableSchema.js").NullableSchema<number>;
|
|
33
|
+
export declare const NULLABLE_EUR_AMOUNT: import("./NullableSchema.js").NullableSchema<number>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getCurrencyStep, getCurrencySymbol, requireCurrencyCode } from "../util/currency.js";
|
|
2
|
+
import { formatCurrency } from "../util/format.js";
|
|
3
|
+
import { NULLABLE } from "./NullableSchema.js";
|
|
4
|
+
import { NumberSchema } from "./NumberSchema.js";
|
|
5
|
+
/**
|
|
6
|
+
* Schema representing a numeric amount in a specific currency.
|
|
7
|
+
*
|
|
8
|
+
* - The validation step is inferred from the currency's minor units.
|
|
9
|
+
* - The default formatter renders amounts using shelving's currency helpers.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const PRICE = new CurrencyAmountSchema({ currency: "GBP", min: 0 });
|
|
13
|
+
* PRICE.validate("12.345"); // 12.35
|
|
14
|
+
* PRICE.format(12.3); // "£12.30"
|
|
15
|
+
*/
|
|
16
|
+
export class CurrencyAmountSchema extends NumberSchema {
|
|
17
|
+
currency;
|
|
18
|
+
symbol;
|
|
19
|
+
constructor({ currency, one = "amount", title = "Amount", symbol, step, format = (value, options) => formatCurrency(value, currency, options), ...options }) {
|
|
20
|
+
const validCurrency = requireCurrencyCode(currency, CurrencyAmountSchema);
|
|
21
|
+
super({
|
|
22
|
+
one,
|
|
23
|
+
title,
|
|
24
|
+
step: step ?? getCurrencyStep(validCurrency, CurrencyAmountSchema),
|
|
25
|
+
format,
|
|
26
|
+
...options,
|
|
27
|
+
});
|
|
28
|
+
this.currency = validCurrency;
|
|
29
|
+
this.symbol = symbol ?? getCurrencySymbol(validCurrency, CurrencyAmountSchema);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Valid non-negative monetary amount in the a currency. */
|
|
33
|
+
export const CURRENCY_AMOUNT = (currency) => new CurrencyAmountSchema({ currency });
|
|
34
|
+
export const USD_AMOUNT = new CurrencyAmountSchema({ currency: "USD" });
|
|
35
|
+
export const GBP_AMOUNT = new CurrencyAmountSchema({ currency: "GBP" });
|
|
36
|
+
export const EUR_AMOUNT = new CurrencyAmountSchema({ currency: "EUR" });
|
|
37
|
+
/** Valid optional monetary amount in the default currency, or `null`. */
|
|
38
|
+
export const NULLABLE_CURRENCY_AMOUNT = (currency) => NULLABLE(CURRENCY_AMOUNT(currency));
|
|
39
|
+
export const NULLABLE_USD_AMOUNT = NULLABLE(USD_AMOUNT);
|
|
40
|
+
export const NULLABLE_GBP_AMOUNT = NULLABLE(GBP_AMOUNT);
|
|
41
|
+
export const NULLABLE_EUR_AMOUNT = NULLABLE(EUR_AMOUNT);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ImmutableArray } from "../util/array.js";
|
|
2
|
+
import { type CurrencyCode } from "../util/currency.js";
|
|
3
|
+
import type { StringSchemaOptions } from "./StringSchema.js";
|
|
4
|
+
import { StringSchema } from "./StringSchema.js";
|
|
5
|
+
/** Options for a `CurrencyCodeSchema` */
|
|
6
|
+
export interface CurrencyCodeSchemaOptions extends Omit<StringSchemaOptions, "input" | "min" | "max" | "match" | "multiline"> {
|
|
7
|
+
currencies?: ImmutableArray<CurrencyCode>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Type of `StringSchema` that defines a valid currency code.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CurrencyCodeSchema extends StringSchema {
|
|
13
|
+
readonly currencies: ImmutableArray<CurrencyCode>;
|
|
14
|
+
constructor({ one, title, currencies, ...options }: CurrencyCodeSchemaOptions);
|
|
15
|
+
sanitize(insaneString: string): string;
|
|
16
|
+
validate(value?: unknown): string;
|
|
17
|
+
}
|
|
18
|
+
/** Valid currency code, e.g. `GBP` */
|
|
19
|
+
export declare const CURRENCY_CODE: CurrencyCodeSchema;
|
|
20
|
+
/** Valid currency code, e.g. `GBP`, or `null` */
|
|
21
|
+
export declare const NULLABLE_CURRENCY_CODE: import("./NullableSchema.js").NullableSchema<string>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CURRENCY_CODES } from "../util/currency.js";
|
|
2
|
+
import { NULLABLE } from "./NullableSchema.js";
|
|
3
|
+
import { StringSchema } from "./StringSchema.js";
|
|
4
|
+
/**
|
|
5
|
+
* Type of `StringSchema` that defines a valid currency code.
|
|
6
|
+
*/
|
|
7
|
+
export class CurrencyCodeSchema extends StringSchema {
|
|
8
|
+
currencies;
|
|
9
|
+
constructor({ one = "currency", title = "Currency", currencies = CURRENCY_CODES, ...options }) {
|
|
10
|
+
super({
|
|
11
|
+
one,
|
|
12
|
+
title,
|
|
13
|
+
...options,
|
|
14
|
+
min: 3,
|
|
15
|
+
max: 3, // Valid currency code is 3 uppercase letters.
|
|
16
|
+
case: "upper",
|
|
17
|
+
match: /^[A-Z]{3}$/, // Valid currency code is 3 uppercase letters.
|
|
18
|
+
});
|
|
19
|
+
this.currencies = currencies;
|
|
20
|
+
}
|
|
21
|
+
sanitize(insaneString) {
|
|
22
|
+
// Strip characters that aren't A-Z (including whitespace).
|
|
23
|
+
return super.sanitize(insaneString).replace(/[^A-Z+]/g, "");
|
|
24
|
+
}
|
|
25
|
+
validate(value) {
|
|
26
|
+
const currency = super.validate(value);
|
|
27
|
+
if (!this.currencies.includes(currency))
|
|
28
|
+
throw "Unknown currency code";
|
|
29
|
+
return currency;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Valid currency code, e.g. `GBP` */
|
|
33
|
+
export const CURRENCY_CODE = new CurrencyCodeSchema({});
|
|
34
|
+
/** Valid currency code, e.g. `GBP`, or `null` */
|
|
35
|
+
export const NULLABLE_CURRENCY_CODE = NULLABLE(CURRENCY_CODE);
|
package/schema/DateSchema.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PossibleDate } from "../util/date.js";
|
|
2
|
+
import { formatDate } from "../util/format.js";
|
|
2
3
|
import type { Nullish } from "../util/null.js";
|
|
3
4
|
import type { SchemaOptions } from "./Schema.js";
|
|
4
5
|
import { Schema } from "./Schema.js";
|
|
@@ -10,6 +11,8 @@ export interface DateSchemaOptions extends SchemaOptions {
|
|
|
10
11
|
readonly min?: Nullish<PossibleDate>;
|
|
11
12
|
readonly max?: Nullish<PossibleDate>;
|
|
12
13
|
readonly input?: DateInputType | undefined;
|
|
14
|
+
/** Format the date for display in downstream UIs. */
|
|
15
|
+
readonly format?: typeof formatDate | undefined;
|
|
13
16
|
/**
|
|
14
17
|
* Rounding step (in milliseconds, because that's the base unit for time).
|
|
15
18
|
* - E.g. `1000 * 60` will round to the nearest minute.
|
|
@@ -23,10 +26,10 @@ export declare class DateSchema extends Schema<string> {
|
|
|
23
26
|
readonly max: Date | undefined;
|
|
24
27
|
readonly input: DateInputType;
|
|
25
28
|
readonly step: number | undefined;
|
|
26
|
-
|
|
29
|
+
format: typeof formatDate;
|
|
30
|
+
constructor({ one, min, max, value, input, step, format, ...options }: DateSchemaOptions);
|
|
27
31
|
validate(value?: unknown): string;
|
|
28
32
|
stringify(value: Date): string;
|
|
29
|
-
format(value: Date): string;
|
|
30
33
|
}
|
|
31
34
|
/** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
32
35
|
export declare const DATE: DateSchema;
|
package/schema/DateSchema.js
CHANGED
|
@@ -8,12 +8,14 @@ export class DateSchema extends Schema {
|
|
|
8
8
|
max;
|
|
9
9
|
input;
|
|
10
10
|
step;
|
|
11
|
-
|
|
11
|
+
format;
|
|
12
|
+
constructor({ one = "date", min, max, value, input = "date", step, format = formatDate, ...options }) {
|
|
12
13
|
super({ one, title: "Date", value, ...options });
|
|
13
14
|
this.min = getDate(min);
|
|
14
15
|
this.max = getDate(max);
|
|
15
16
|
this.input = input;
|
|
16
17
|
this.step = step;
|
|
18
|
+
this.format = format;
|
|
17
19
|
}
|
|
18
20
|
validate(value = this.value) {
|
|
19
21
|
const date = getDate(value);
|
|
@@ -29,9 +31,6 @@ export class DateSchema extends Schema {
|
|
|
29
31
|
stringify(value) {
|
|
30
32
|
return requireDateString(value);
|
|
31
33
|
}
|
|
32
|
-
format(value) {
|
|
33
|
-
return formatDate(value);
|
|
34
|
-
}
|
|
35
34
|
}
|
|
36
35
|
/** Valid date, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
37
36
|
export const DATE = new DateSchema({});
|
|
@@ -6,8 +6,7 @@ import { DateSchema, type DateSchemaOptions } from "./DateSchema.js";
|
|
|
6
6
|
* - If you wish to define an _abstract_ time without a timezone, e.g. a daily alarm, use `TimeSchema` instead.
|
|
7
7
|
*/
|
|
8
8
|
export declare class DateTimeSchema extends DateSchema {
|
|
9
|
-
constructor({ one, title, input, ...options }: DateSchemaOptions);
|
|
10
|
-
format(value: Date): string;
|
|
9
|
+
constructor({ one, title, input, format, ...options }: DateSchemaOptions);
|
|
11
10
|
stringify(value: Date): string;
|
|
12
11
|
}
|
|
13
12
|
/** Valid datetime, e.g. `2005-09-12T08:00:00Z` (required because falsy values are invalid). */
|
package/schema/DateTimeSchema.js
CHANGED
|
@@ -8,11 +8,8 @@ import { NULLABLE } from "./NullableSchema.js";
|
|
|
8
8
|
* - If you wish to define an _abstract_ time without a timezone, e.g. a daily alarm, use `TimeSchema` instead.
|
|
9
9
|
*/
|
|
10
10
|
export class DateTimeSchema extends DateSchema {
|
|
11
|
-
constructor({ one = "time", title = "Time", input = "datetime-local", ...options }) {
|
|
12
|
-
super({ one, title, input, ...options });
|
|
13
|
-
}
|
|
14
|
-
format(value) {
|
|
15
|
-
return formatDateTime(value);
|
|
11
|
+
constructor({ one = "time", title = "Time", input = "datetime-local", format = formatDateTime, ...options }) {
|
|
12
|
+
super({ one, title, input, format, ...options });
|
|
16
13
|
}
|
|
17
14
|
stringify(value) {
|
|
18
15
|
return value.toISOString();
|
package/schema/NumberSchema.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatNumber } from "../util/format.js";
|
|
1
2
|
import type { SchemaOptions } from "./Schema.js";
|
|
2
3
|
import { Schema } from "./Schema.js";
|
|
3
4
|
/** Allowed options for `NumberSchema` */
|
|
@@ -6,6 +7,8 @@ export interface NumberSchemaOptions extends SchemaOptions {
|
|
|
6
7
|
readonly min?: number | undefined;
|
|
7
8
|
readonly max?: number | undefined;
|
|
8
9
|
readonly step?: number | undefined;
|
|
10
|
+
/** Format the number for display in downstream UIs. */
|
|
11
|
+
readonly format?: typeof formatNumber | undefined;
|
|
9
12
|
}
|
|
10
13
|
/** Schema that defines a valid number. */
|
|
11
14
|
export declare class NumberSchema extends Schema<number> {
|
|
@@ -13,7 +16,8 @@ export declare class NumberSchema extends Schema<number> {
|
|
|
13
16
|
readonly min: number;
|
|
14
17
|
readonly max: number;
|
|
15
18
|
readonly step: number | undefined;
|
|
16
|
-
|
|
19
|
+
format: typeof formatNumber;
|
|
20
|
+
constructor({ one, title, min, max, step, format, value, ...options }: NumberSchemaOptions);
|
|
17
21
|
validate(value?: unknown): number;
|
|
18
22
|
}
|
|
19
23
|
/** Valid number, e.g. `2048.12345` or `0` zero and a default value of zero. */
|
package/schema/NumberSchema.js
CHANGED
|
@@ -7,11 +7,13 @@ export class NumberSchema extends Schema {
|
|
|
7
7
|
min;
|
|
8
8
|
max;
|
|
9
9
|
step;
|
|
10
|
-
|
|
10
|
+
format;
|
|
11
|
+
constructor({ one = "number", title = "Number", min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY, step, format = formatNumber, value, ...options }) {
|
|
11
12
|
super({ one, title, value, ...options });
|
|
12
13
|
this.min = min;
|
|
13
14
|
this.max = max;
|
|
14
15
|
this.step = step;
|
|
16
|
+
this.format = format;
|
|
15
17
|
}
|
|
16
18
|
validate(value = this.value) {
|
|
17
19
|
const number = getNumber(value);
|
|
@@ -19,9 +21,9 @@ export class NumberSchema extends Schema {
|
|
|
19
21
|
throw value ? `Must be ${this.one}` : "Required";
|
|
20
22
|
const stepped = typeof this.step === "number" ? roundStep(number, this.step) : number;
|
|
21
23
|
if (stepped < this.min)
|
|
22
|
-
throw !number ? "Required" : `Minimum ${
|
|
24
|
+
throw !number ? "Required" : `Minimum ${this.format(this.min)}`;
|
|
23
25
|
if (stepped > this.max)
|
|
24
|
-
throw `Maximum ${
|
|
26
|
+
throw `Maximum ${this.format(this.max)}`;
|
|
25
27
|
return stepped;
|
|
26
28
|
}
|
|
27
29
|
}
|
package/schema/PhoneSchema.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { StringSchemaOptions } from "./StringSchema.js";
|
|
2
2
|
import { StringSchema } from "./StringSchema.js";
|
|
3
|
+
/** Options for a `PhoneSchema` */
|
|
4
|
+
export interface PhoneSchemaOptions extends Omit<StringSchemaOptions, "input" | "min" | "max" | "match" | "multiline"> {
|
|
5
|
+
}
|
|
3
6
|
/**
|
|
4
7
|
* Type of `StringSchema` that defines a valid phone number.
|
|
5
8
|
* - Multiple string formats are automatically converted to E.164 format (starting with `+` plus).
|
|
6
9
|
* - Falsy values are converted to `""` empty string.
|
|
7
10
|
*/
|
|
8
11
|
export declare class PhoneSchema extends StringSchema {
|
|
9
|
-
constructor({ one, title, ...options }:
|
|
12
|
+
constructor({ one, title, ...options }: PhoneSchemaOptions);
|
|
10
13
|
sanitize(insaneString: string): string;
|
|
11
14
|
}
|
|
12
15
|
/** Valid phone number, e.g. `+441234567890` */
|
package/schema/PhoneSchema.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { NULLABLE } from "./NullableSchema.js";
|
|
2
2
|
import { StringSchema } from "./StringSchema.js";
|
|
3
|
-
// Valid phone number is max 16 digits made up of:
|
|
4
|
-
// - Country code (`+` plus character and 1-3 digits, e.g. `+44` or `+1`).
|
|
5
|
-
// - Subscriber number (5-12 digits — the Solomon Islands have five-digit phone numbers apparently).
|
|
6
|
-
const PHONE_REGEXP = /^\+[1-9][0-9]{0,2}[0-9]{5,12}$/;
|
|
7
3
|
/**
|
|
8
4
|
* Type of `StringSchema` that defines a valid phone number.
|
|
9
5
|
* - Multiple string formats are automatically converted to E.164 format (starting with `+` plus).
|
|
@@ -17,8 +13,12 @@ export class PhoneSchema extends StringSchema {
|
|
|
17
13
|
...options,
|
|
18
14
|
input: "tel",
|
|
19
15
|
min: 1,
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
// Valid phone number is 16 digits or fewer (15 numerals with a leading `+` plus).
|
|
17
|
+
max: 16,
|
|
18
|
+
// Valid phone number is max 16 digits made up of:
|
|
19
|
+
// - Country code (`+` plus character and 1-3 digits, e.g. `+44` or `+1`).
|
|
20
|
+
// - Subscriber number (5-12 digits — the Solomon Islands have five-digit phone numbers apparently).
|
|
21
|
+
match: /^\+[1-9][0-9]{0,2}[0-9]{5,12}$/,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
sanitize(insaneString) {
|
package/schema/TimeSchema.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { DateSchema, type DateSchemaOptions } from "./DateSchema.js";
|
|
2
2
|
/** Define a valid time in 24h hh:mm:ss.fff format, e.g. `23:59` or `24:00 */
|
|
3
3
|
export declare class TimeSchema extends DateSchema {
|
|
4
|
-
constructor({ one, title, input, ...options }: DateSchemaOptions);
|
|
4
|
+
constructor({ one, title, input, format, ...options }: DateSchemaOptions);
|
|
5
5
|
stringify(value: Date): string;
|
|
6
|
-
format(value: Date): string;
|
|
7
6
|
}
|
|
8
7
|
/** Valid time, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
9
8
|
export declare const TIME: TimeSchema;
|
package/schema/TimeSchema.js
CHANGED
|
@@ -4,15 +4,12 @@ import { DateSchema } from "./DateSchema.js";
|
|
|
4
4
|
import { NULLABLE } from "./NullableSchema.js";
|
|
5
5
|
/** Define a valid time in 24h hh:mm:ss.fff format, e.g. `23:59` or `24:00 */
|
|
6
6
|
export class TimeSchema extends DateSchema {
|
|
7
|
-
constructor({ one = "time", title = "Time", input = "time", ...options }) {
|
|
8
|
-
super({ one, title, input, ...options });
|
|
7
|
+
constructor({ one = "time", title = "Time", input = "time", format = formatTime, ...options }) {
|
|
8
|
+
super({ one, title, input, format, ...options });
|
|
9
9
|
}
|
|
10
10
|
stringify(value) {
|
|
11
11
|
return requireTimeString(value);
|
|
12
12
|
}
|
|
13
|
-
format(value) {
|
|
14
|
-
return formatTime(value);
|
|
15
|
-
}
|
|
16
13
|
}
|
|
17
14
|
/** Valid time, e.g. `2005-09-12` (required because falsy values are invalid). */
|
|
18
15
|
export const TIME = new TimeSchema({});
|
package/schema/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from "./BooleanSchema.js";
|
|
|
4
4
|
export * from "./ChoiceSchema.js";
|
|
5
5
|
export * from "./ColorSchema.js";
|
|
6
6
|
export * from "./CountrySchema.js";
|
|
7
|
+
export * from "./CurrencyAmountSchema.js";
|
|
8
|
+
export * from "./CurrencyCodeSchema.js";
|
|
7
9
|
export * from "./DataSchema.js";
|
|
8
10
|
export * from "./DateSchema.js";
|
|
9
11
|
export * from "./DateTimeSchema.js";
|
package/schema/index.js
CHANGED
|
@@ -4,6 +4,8 @@ export * from "./BooleanSchema.js";
|
|
|
4
4
|
export * from "./ChoiceSchema.js";
|
|
5
5
|
export * from "./ColorSchema.js";
|
|
6
6
|
export * from "./CountrySchema.js";
|
|
7
|
+
export * from "./CurrencyAmountSchema.js";
|
|
8
|
+
export * from "./CurrencyCodeSchema.js";
|
|
7
9
|
export * from "./DataSchema.js";
|
|
8
10
|
export * from "./DateSchema.js";
|
|
9
11
|
export * from "./DateTimeSchema.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ImmutableArray } from "./array.js";
|
|
2
|
+
import type { AnyCaller } from "./function.js";
|
|
3
|
+
/** ISO 4217 currency code, e.g. `GBP` or `USD`. */
|
|
4
|
+
export type CurrencyCode = string;
|
|
5
|
+
/** Array of all supported currency codes in this runtime. */
|
|
6
|
+
export declare const CURRENCY_CODES: ImmutableArray<CurrencyCode>;
|
|
7
|
+
/**
|
|
8
|
+
* Require that a value is a valid ISO 4217 currency code, and return it as a `Currency` type.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getCurrencyCode(value: string): CurrencyCode | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Require that a value is a valid ISO 4217 currency code, and return it as a `Currency` type.
|
|
13
|
+
*/
|
|
14
|
+
export declare function requireCurrencyCode(value: string, caller?: AnyCaller): CurrencyCode;
|
|
15
|
+
/**
|
|
16
|
+
* Get the display symbol used for a currency.
|
|
17
|
+
*
|
|
18
|
+
* @throws {RequiredError} If the currency code is malformed or unsupported.
|
|
19
|
+
*
|
|
20
|
+
* @example getCurrencySymbol("GBP"); // "£"
|
|
21
|
+
*/
|
|
22
|
+
export declare function getCurrencySymbol(currency: CurrencyCode, caller?: AnyCaller): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get the "step" value for a currency, i.e. the smallest fractional unit that is used for that currency.
|
|
25
|
+
* - E.g. `0.01` for USD, `0.001` for some cryptocurrencies, and `1` for JPY.
|
|
26
|
+
* @throws {RequiredError} If the currency code is malformed or unsupported.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getCurrencyStep(currency: CurrencyCode, caller?: AnyCaller): number;
|
package/util/currency.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { RequiredError } from "../error/RequiredError.js";
|
|
2
|
+
/** Array of all supported currency codes in this runtime. */
|
|
3
|
+
export const CURRENCY_CODES = Intl.supportedValuesOf("currency");
|
|
4
|
+
/**
|
|
5
|
+
* Require that a value is a valid ISO 4217 currency code, and return it as a `Currency` type.
|
|
6
|
+
*/
|
|
7
|
+
export function getCurrencyCode(value) {
|
|
8
|
+
const currency = value.toUpperCase().trim();
|
|
9
|
+
return CURRENCY_CODES.includes(currency) ? currency : undefined;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Require that a value is a valid ISO 4217 currency code, and return it as a `Currency` type.
|
|
13
|
+
*/
|
|
14
|
+
export function requireCurrencyCode(value, caller = requireCurrencyCode) {
|
|
15
|
+
const currency = getCurrencyCode(value);
|
|
16
|
+
if (!currency)
|
|
17
|
+
throw new RequiredError("Unknown currency code", { received: value, caller });
|
|
18
|
+
return currency;
|
|
19
|
+
}
|
|
20
|
+
function _formatter(currency, caller) {
|
|
21
|
+
return new Intl.NumberFormat(undefined, {
|
|
22
|
+
style: "currency",
|
|
23
|
+
currency: requireCurrencyCode(currency, caller),
|
|
24
|
+
currencyDisplay: "narrowSymbol",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const _isCurrencyNumberPart = ({ type }) => type === "currency";
|
|
28
|
+
/**
|
|
29
|
+
* Get the display symbol used for a currency.
|
|
30
|
+
*
|
|
31
|
+
* @throws {RequiredError} If the currency code is malformed or unsupported.
|
|
32
|
+
*
|
|
33
|
+
* @example getCurrencySymbol("GBP"); // "£"
|
|
34
|
+
*/
|
|
35
|
+
export function getCurrencySymbol(currency, caller = getCurrencySymbol) {
|
|
36
|
+
return _formatter(currency, caller).formatToParts(0).find(_isCurrencyNumberPart)?.value;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the "step" value for a currency, i.e. the smallest fractional unit that is used for that currency.
|
|
40
|
+
* - E.g. `0.01` for USD, `0.001` for some cryptocurrencies, and `1` for JPY.
|
|
41
|
+
* @throws {RequiredError} If the currency code is malformed or unsupported.
|
|
42
|
+
*/
|
|
43
|
+
export function getCurrencyStep(currency, caller = getCurrencyStep) {
|
|
44
|
+
const { minimumFractionDigits = 0 } = _formatter(currency, caller).resolvedOptions();
|
|
45
|
+
return 1 / 10 ** minimumFractionDigits;
|
|
46
|
+
}
|
package/util/format.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isArray } from "./array.js";
|
|
2
2
|
import { SECOND } from "./constants.js";
|
|
3
|
+
import { requireCurrencyCode } from "./currency.js";
|
|
3
4
|
import { isDate, requireDate } from "./date.js";
|
|
4
5
|
import { getBestTimeUnit, getMilliseconds } from "./duration.js";
|
|
5
6
|
import { getPercent } from "./number.js";
|
|
@@ -39,7 +40,7 @@ export function formatUnit(num, unit, options) {
|
|
|
39
40
|
export function formatCurrency(amount, currency, options) {
|
|
40
41
|
return Intl.NumberFormat(undefined, {
|
|
41
42
|
style: "currency",
|
|
42
|
-
currency,
|
|
43
|
+
currency: requireCurrencyCode(currency, formatCurrency),
|
|
43
44
|
...options,
|
|
44
45
|
}).format(amount);
|
|
45
46
|
}
|
package/util/index.d.ts
CHANGED
package/util/index.js
CHANGED