shelving 1.47.3 → 1.49.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 CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.47.3",
14
+ "version": "1.49.1",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -63,19 +63,19 @@
63
63
  "@types/jest": "^27.4.0",
64
64
  "@types/react": "^17.0.38",
65
65
  "@types/react-dom": "^17.0.11",
66
- "@typescript-eslint/eslint-plugin": "^5.9.0",
67
- "@typescript-eslint/parser": "^5.9.0",
68
- "eslint": "^8.6.0",
66
+ "@typescript-eslint/eslint-plugin": "^5.9.1",
67
+ "@typescript-eslint/parser": "^5.9.1",
68
+ "eslint": "^8.7.0",
69
69
  "eslint-config-prettier": "^8.3.0",
70
70
  "eslint-plugin-import": "^2.25.4",
71
71
  "eslint-plugin-prettier": "^4.0.0",
72
- "firebase": "^9.6.2",
72
+ "firebase": "^9.6.3",
73
73
  "jest": "^27.4.7",
74
74
  "jest-ts-webcompat-resolver": "^1.0.0",
75
75
  "prettier": "^2.5.1",
76
76
  "react": "^17.0.2",
77
77
  "react-dom": "^17.0.2",
78
- "ts-jest": "^27.1.2",
78
+ "ts-jest": "^27.1.3",
79
79
  "typescript": "^4.5.4"
80
80
  },
81
81
  "peerDependencies": {
@@ -9,8 +9,8 @@ export declare class Filters<T extends Data> extends Rules<T, Filter<T>> impleme
9
9
  filter(props: FilterProps<T>): this;
10
10
  filter(key: "id" | "!id" | "id>" | "id>=" | "id<" | "id<=", value: string): this;
11
11
  filter(key: "id" | "!id", value: ImmutableArray<string>): this;
12
- filter<K extends Key<T>>(key: K | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
13
- filter<K extends Key<T>>(key: K | `!${K}`, value: ImmutableArray<string>): this;
12
+ filter<K extends Key<T>>(key: `${K}` | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
13
+ filter<K extends Key<T>>(key: `${K}` | `!${K}`, value: ImmutableArray<string>): this;
14
14
  filter<K extends Key<T>>(key: `${K}[]`, value: T[K] extends ImmutableArray ? ArrayType<T[K]> : never): this;
15
15
  match(entry: Entry<T>): boolean;
16
16
  transform(iterable: Entries<T>): Entries<T>;
package/query/Query.d.ts CHANGED
@@ -14,8 +14,8 @@ export declare class Query<T extends Data> extends Rule<T> implements Queryable<
14
14
  filter(props: FilterProps<T>): this;
15
15
  filter(key: "id" | "!id" | "id>" | "id>=" | "id<" | "id<=", value: string): this;
16
16
  filter(key: "id" | "!id", value: ImmutableArray<string>): this;
17
- filter<K extends Key<T>>(key: K | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
18
- filter<K extends Key<T>>(key: K | `!${K}`, value: ImmutableArray<T[K]>): this;
17
+ filter<K extends Key<T>>(key: `${K}` | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
18
+ filter<K extends Key<T>>(key: `${K}` | `!${K}`, value: ImmutableArray<T[K]>): this;
19
19
  filter<K extends Key<T>>(key: `${K}[]`, value: T[K] extends ImmutableArray ? ArrayType<T[K]> : never): this;
20
20
  get unfilter(): this;
21
21
  match(entry: Entry<T>): boolean;
package/query/types.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { Data, Key, Matchable, Entry, Rankable, ImmutableArray, ArrayType }
2
2
  /** Possible operator references. */
3
3
  export declare type FilterOperator = "IS" | "NOT" | "IN" | "OUT" | "CONTAINS" | "LT" | "LTE" | "GT" | "GTE";
4
4
  /** Format that allows filters to be specified as a string, e.g. `!name` means `name is not` and `age>` means `age is more than` and `tags[]` means `tags array contains` */
5
- export declare type FilterKey<T extends Data> = "id" | "!id" | "id>" | "id>=" | "id<" | "id<=" | Key<T> | `!${Key<T>}` | `${Key<T>}[]` | `${Key<T>}<` | `${Key<T>}<=` | `${Key<T>}>` | `${Key<T>}>=`;
5
+ export declare type FilterKey<T extends Data> = "id" | "!id" | "id>" | "id>=" | "id<" | "id<=" | Key<T> | `${Key<T>}` | `!${Key<T>}` | `${Key<T>}[]` | `${Key<T>}<` | `${Key<T>}<=` | `${Key<T>}>` | `${Key<T>}>=`;
6
6
  /** Format that allows multiple filters to be specified as a plain object. */
7
7
  export declare type FilterProps<T extends Data> = {
8
8
  "id"?: string | ImmutableArray<string>;
@@ -12,7 +12,7 @@ export declare type FilterProps<T extends Data> = {
12
12
  "id<"?: string;
13
13
  "id<="?: string;
14
14
  } & {
15
- [K in Key<T> as K | `!${K}`]?: T[K] | ImmutableArray<T[K]>;
15
+ [K in Key<T> as `${K}` | `!${K}`]?: T[K] | ImmutableArray<T[K]>;
16
16
  } & {
17
17
  [K in Key<T> as `${K}[]`]?: T[K] extends ImmutableArray ? ArrayType<T[K]> : never;
18
18
  } & {
@@ -27,14 +27,14 @@ export interface Filterable<T extends Data> extends Matchable<Entry<T>, void> {
27
27
  filter(props: FilterProps<T>): this;
28
28
  filter(key: "id" | "!id" | "id>" | "id>=" | "id<" | "id<=", value: string): this;
29
29
  filter(key: "id" | "!id", value: ImmutableArray<string>): this;
30
- filter<K extends Key<T>>(key: K | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
31
- filter<K extends Key<T>>(key: K | `!${K}`, value: ImmutableArray<string>): this;
30
+ filter<K extends Key<T>>(key: `${K}` | `!${K}` | `${K}>` | `${K}>=` | `${K}<` | `${K}<=`, value: T[K]): this;
31
+ filter<K extends Key<T>>(key: `${K}` | `!${K}`, value: ImmutableArray<string>): this;
32
32
  filter<K extends Key<T>>(key: `${K}[]`, value: T[K] extends ImmutableArray ? ArrayType<T[K]> : never): this;
33
33
  /** Match an entry against the filters specified for this object. */
34
34
  match(entry: Entry<T>): boolean;
35
35
  }
36
36
  /** Format that allows sorts to be set as a plain string, e.g. `name` sorts by name in ascending order and `!date` sorts by date in descending order. */
37
- export declare type SortKey<T extends Data> = "id" | "!id" | Key<T> | `!${Key<T>}`;
37
+ export declare type SortKey<T extends Data> = "id" | "!id" | Key<T> | `${Key<T>}` | `!${Key<T>}`;
38
38
  /** One or more sort keys. */
39
39
  export declare type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortKey<T>>;
40
40
  /** Possible operator references. */
package/util/date.d.ts CHANGED
@@ -1,17 +1,3 @@
1
- /** One second in millseconds. */
2
- export declare const SECOND = 1000;
3
- /** One minute in millseconds. */
4
- export declare const MINUTE: number;
5
- /** One hour in millseconds. */
6
- export declare const HOUR: number;
7
- /** One day in millseconds. */
8
- export declare const DAY: number;
9
- /** One week in millseconds. */
10
- export declare const WEEK: number;
11
- /** One month in millseconds. */
12
- export declare const MONTH: number;
13
- /** One year in millseconds. */
14
- export declare const YEAR: number;
15
1
  /** Is a value a date? */
16
2
  export declare const isDate: (v: unknown) => v is Date;
17
3
  /** Value that can possibly be converted to a `Date` instance. */
@@ -77,9 +63,9 @@ export declare const getWeeksUntil: (target: PossibleDate, current?: PossibleDat
77
63
  /** Count the number of weeks ago a date was. */
78
64
  export declare const getWeeksAgo: (target: PossibleDate, current?: PossibleDate | undefined) => number;
79
65
  /** Format a full description of a duration of time using the most reasonable units e.g. `5 years` or `1 week` or `4 minutes` or `12 milliseconds`. */
80
- export declare function formatFullDuration(ms: number): string;
66
+ export declare const formatFullDuration: (ms: number, maxPrecision?: number | undefined, minPrecision?: number | undefined) => string;
81
67
  /** Format a description of a duration of time using the most reasonable units e.g. `5y` or `4m` or `12ms`. */
82
- export declare function formatDuration(ms: number): string;
68
+ export declare const formatDuration: (ms: number, maxPrecision?: number | undefined, minPrecision?: number | undefined) => string;
83
69
  /**
84
70
  * Return full description of the gap between two dates, e.g. `in 10 days` or `2 hours ago`
85
71
  *
@@ -87,13 +73,6 @@ export declare function formatDuration(ms: number): string;
87
73
  * @param current Today's date (or a different date to measure from).
88
74
  */
89
75
  export declare function formatFullWhen(target: PossibleDate, current?: PossibleDate): string;
90
- /**
91
- * Return full description of when a date happened, e.g. `10 days` or `2 hours` or `-1 week`
92
- *
93
- * @param target The date when the thing will happen.
94
- * @param current Today's date (or a different date to measure from).
95
- */
96
- export declare const formatFullUntil: (target: PossibleDate, current?: PossibleDate | undefined) => string;
97
76
  /**
98
77
  * Return full description of when a date will happen, e.g. `10 days` or `2 hours` or `-1 week`
99
78
  *
@@ -128,3 +107,5 @@ export declare const formatDate: (date: PossibleDate) => string;
128
107
  export declare const isPast: (target: PossibleDate, current?: PossibleDate | undefined) => boolean;
129
108
  /** Is a date in the future? */
130
109
  export declare const isFuture: (target: PossibleDate, current?: PossibleDate | undefined) => boolean;
110
+ /** Is a date today (taking into account midnight). */
111
+ export declare const isToday: (target: PossibleDate, current?: PossibleDate | undefined) => boolean;
package/util/date.js CHANGED
@@ -1,19 +1,5 @@
1
1
  import { AssertionError } from "../error/index.js";
2
- import { formatFullQuantity, formatQuantity } from "./number.js";
3
- /** One second in millseconds. */
4
- export const SECOND = 1000;
5
- /** One minute in millseconds. */
6
- export const MINUTE = 60 * SECOND;
7
- /** One hour in millseconds. */
8
- export const HOUR = 60 * MINUTE;
9
- /** One day in millseconds. */
10
- export const DAY = 24 * HOUR;
11
- /** One week in millseconds. */
12
- export const WEEK = 7 * DAY;
13
- /** One month in millseconds. */
14
- export const MONTH = 30 * DAY;
15
- /** One year in millseconds. */
16
- export const YEAR = 365 * DAY;
2
+ import { DAY, HOUR, MINUTE, MONTH, SECOND, WEEK, YEAR, formatUnits, formatFullUnits } from "./units.js";
17
3
  /** Is a value a date? */
18
4
  export const isDate = (v) => v instanceof Date;
19
5
  /**
@@ -124,40 +110,26 @@ export const getDaysAgo = (target, current) => 0 - getDaysUntil(target, current)
124
110
  export const getWeeksUntil = (target, current) => Math.floor(getDaysUntil(target, current) / 7);
125
111
  /** Count the number of weeks ago a date was. */
126
112
  export const getWeeksAgo = (target, current) => 0 - getWeeksUntil(target, current);
127
- /** Format a full description of a duration of time using the most reasonable units e.g. `5 years` or `1 week` or `4 minutes` or `12 milliseconds`. */
128
- export function formatFullDuration(ms) {
113
+ function _formatDuration(formatter, ms, maxPrecision = 0, minPrecision) {
129
114
  const abs = Math.abs(ms);
130
115
  if (abs <= 99 * SECOND)
131
- return formatFullQuantity(ms, "second", "seconds", 0); // Up to 99 seconds, e.g. '22 seconds ago'
116
+ return formatter(ms, "second", maxPrecision, minPrecision); // Up to 99 seconds, e.g. '22 seconds ago'
132
117
  if (abs <= HOUR)
133
- return formatFullQuantity(ms / MINUTE, "minute", "minutes", 0); // Up to one hour — show minutes, e.g. '18 minutes ago'
118
+ return formatter(ms / MINUTE, "minute", maxPrecision, minPrecision); // Up to one hour — show minutes, e.g. '18 minutes ago'
134
119
  if (abs <= DAY)
135
- return formatFullQuantity(ms / HOUR, "hour", "hours", 0); // Up to one day — show hours, e.g. '23 hours ago'
120
+ return formatter(ms / HOUR, "hour", maxPrecision, minPrecision); // Up to one day — show hours, e.g. '23 hours ago'
136
121
  if (abs <= 2 * WEEK)
137
- return formatFullQuantity(ms / DAY, "day", "days", 0); // Up to 2 weeks — show days, e.g. '13 days ago'
122
+ return formatter(ms / DAY, "day", maxPrecision, minPrecision); // Up to 2 weeks — show days, e.g. '13 days ago'
138
123
  if (abs <= 10 * WEEK)
139
- return formatFullQuantity(ms / WEEK, "week", "weeks", 0); // Up to 2 months — show weeks, e.g. '6 weeks ago'
124
+ return formatter(ms / WEEK, "week", maxPrecision, minPrecision); // Up to 2 months — show weeks, e.g. '6 weeks ago'
140
125
  if (abs <= 18 * MONTH)
141
- return formatFullQuantity(ms / MONTH, "month", "months", 0); // Up to 18 months — show months, e.g. '6 months ago'
142
- return formatFullQuantity(ms / YEAR, "year", "years", 0); // Above 18 months — show years, e.g. '2 years ago'
126
+ return formatter(ms / MONTH, "month", maxPrecision, minPrecision); // Up to 18 months — show months, e.g. '6 months ago'
127
+ return formatter(ms / YEAR, "year", maxPrecision, minPrecision); // Above 18 months — show years, e.g. '2 years ago'
143
128
  }
129
+ /** Format a full description of a duration of time using the most reasonable units e.g. `5 years` or `1 week` or `4 minutes` or `12 milliseconds`. */
130
+ export const formatFullDuration = (ms, maxPrecision, minPrecision) => _formatDuration(formatFullUnits, ms, maxPrecision, minPrecision);
144
131
  /** Format a description of a duration of time using the most reasonable units e.g. `5y` or `4m` or `12ms`. */
145
- export function formatDuration(ms) {
146
- const abs = Math.abs(ms);
147
- if (abs <= 99 * SECOND)
148
- return formatQuantity(ms, "s", 0); // Up to 99 seconds, e.g. '22 seconds ago'
149
- if (abs <= HOUR)
150
- return formatQuantity(ms / MINUTE, "m", 0); // Up to one hour — show minutes, e.g. '18 minutes ago'
151
- if (abs <= DAY)
152
- return formatQuantity(ms / HOUR, "h", 0); // Up to one day — show hours, e.g. '23 hours ago'
153
- if (abs <= 2 * WEEK)
154
- return formatQuantity(ms / DAY, "d", 0); // Up to 2 weeks — show days, e.g. '13 days ago'
155
- if (abs <= 10 * WEEK)
156
- return formatQuantity(ms / WEEK, "w", 0); // Up to 2 months — show weeks, e.g. '6 weeks ago'
157
- if (abs <= 18 * MONTH)
158
- return formatQuantity(ms / MONTH, "m", 0); // Up to 18 months — show months, e.g. '6 months ago'
159
- return formatQuantity(ms / YEAR, "y", 0); // Above 18 months — show years, e.g. '2 years ago'
160
- }
132
+ export const formatDuration = (ms, maxPrecision, minPrecision) => _formatDuration(formatUnits, ms, maxPrecision, minPrecision);
161
133
  /**
162
134
  * Return full description of the gap between two dates, e.g. `in 10 days` or `2 hours ago`
163
135
  *
@@ -170,13 +142,6 @@ export function formatFullWhen(target, current) {
170
142
  const duration = formatFullDuration(abs);
171
143
  return abs < 10 * SECOND ? "just now" : ms > 0 ? `in ${duration}` : `${duration} ago`;
172
144
  }
173
- /**
174
- * Return full description of when a date happened, e.g. `10 days` or `2 hours` or `-1 week`
175
- *
176
- * @param target The date when the thing will happen.
177
- * @param current Today's date (or a different date to measure from).
178
- */
179
- export const formatFullUntil = (target, current) => formatFullDuration(getDuration(target, current));
180
145
  /**
181
146
  * Return full description of when a date will happen, e.g. `10 days` or `2 hours` or `-1 week`
182
147
  *
@@ -217,3 +182,5 @@ const _formatter = new Intl.DateTimeFormat(undefined, {});
217
182
  export const isPast = (target, current) => getDate(target) < getDate(current);
218
183
  /** Is a date in the future? */
219
184
  export const isFuture = (target, current) => getDate(target) > getDate(current);
185
+ /** Is a date today (taking into account midnight). */
186
+ export const isToday = (target, current) => getMidnight(target) === getMidnight(current);
@@ -10,9 +10,11 @@ export declare const PASSTHROUGH: <T>(value: T) => T;
10
10
  export declare const BLACKHOLE: (...args: Arguments) => void | undefined;
11
11
  /** Function that receives a dispatched value. */
12
12
  export declare type Dispatcher<T extends Arguments = []> = (...value: T) => void;
13
+ /** Function that receives a dispatched value. */
14
+ export declare type AsyncDispatcher<T extends Arguments = []> = (...value: T) => void | PromiseLike<void>;
13
15
  /** Safely dispatch a value to a dispatcher function. */
14
- export declare function dispatch<T extends Arguments>(dispatcher: Dispatcher<T>, ...value: T): void;
16
+ export declare function dispatch<T extends Arguments>(dispatcher: Dispatcher<T> | AsyncDispatcher<T>, ...value: T): void;
15
17
  /** Safely dispatch a value to a dispatcher method on an object. */
16
18
  export declare function dispatchMethod<T extends Arguments, M extends string | symbol>(obj: {
17
- [K in M]: Dispatcher<T>;
19
+ [K in M]: Dispatcher<T> | AsyncDispatcher<T>;
18
20
  }, key: M, ...value: T): void;
package/util/function.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { isAsync } from "./async.js";
1
2
  import { logError } from "./error.js";
2
3
  /** Is a value a function? */
3
4
  export const isFunction = (v) => typeof v === "function";
@@ -8,7 +9,9 @@ export const BLACKHOLE = () => undefined;
8
9
  /** Safely dispatch a value to a dispatcher function. */
9
10
  export function dispatch(dispatcher, ...value) {
10
11
  try {
11
- dispatcher(...value);
12
+ const result = dispatcher(...value);
13
+ if (isAsync(result))
14
+ result.then(BLACKHOLE, logError);
12
15
  }
13
16
  catch (thrown) {
14
17
  logError(thrown);
@@ -17,7 +20,9 @@ export function dispatch(dispatcher, ...value) {
17
20
  /** Safely dispatch a value to a dispatcher method on an object. */
18
21
  export function dispatchMethod(obj, key, ...value) {
19
22
  try {
20
- obj[key](...value);
23
+ const result = obj[key](...value);
24
+ if (isAsync(result))
25
+ result.then(BLACKHOLE, logError);
21
26
  }
22
27
  catch (thrown) {
23
28
  logError(thrown);
package/util/number.d.ts CHANGED
@@ -59,9 +59,9 @@ export declare const truncateNumber: (num: number, precision?: number) => number
59
59
  * @returns The number formatted as a string in the browser's current locale.
60
60
  */
61
61
  export declare const formatNumber: (num: number, maxPrecision?: number, minPrecision?: number) => string;
62
- /** Format a number with a short suffix (number and suffix are separated by a non-breaking narrow space). */
62
+ /** Format a number with a short suffix. */
63
63
  export declare const formatQuantity: (num: number, suffix: string, maxPrecision?: number | undefined, minPrecision?: number | undefined) => string;
64
- /** Format a number with a longer full-word suffix (number and suffix are separated by a non-breaking space). */
64
+ /** Format a number with a longer full-word suffix. */
65
65
  export declare function formatFullQuantity(num: number, singular: string, plural: string, maxPrecision?: number, minPrecision?: number): string;
66
66
  /**
67
67
  * Cram a large whole numbers into a space efficient format, e.g. `14.7M`
@@ -103,6 +103,13 @@ export declare const isBetween: (num: number, start: number, end: number) => boo
103
103
  * @param end The end of the range, e.g. `20`
104
104
  */
105
105
  export declare const getBetween: (num: number, start: number, end: number) => number;
106
+ /**
107
+ * Get a number as a percentage of another number.
108
+ *
109
+ * @param numerator Number representing the amount of progress.
110
+ * @param denumerator The number representing the whole amount.
111
+ */
112
+ export declare const getPercent: (numerator: number, denumerator: number) => number;
106
113
  /** Sum an iterable set of numbers and return the total. */
107
114
  export declare function sumNumbers(nums: Iterable<number>): number;
108
115
  /** Find the number that's closest to a target in an iterable set of numbers. */
package/util/number.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { AssertionError } from "../error/index.js";
2
- import { NBSP, NNBSP } from "./string.js";
3
2
  // Constants.
4
3
  export const TRILLION = 1000000000000;
5
4
  export const BILLION = 1000000000;
@@ -76,12 +75,12 @@ export const truncateNumber = (num, precision = 0) => Math.trunc(num * 10 ** pre
76
75
  * @returns The number formatted as a string in the browser's current locale.
77
76
  */
78
77
  export const formatNumber = (num, maxPrecision = 4, minPrecision = 0) => new Intl.NumberFormat(undefined, { maximumFractionDigits: maxPrecision, minimumFractionDigits: minPrecision }).format(num);
79
- /** Format a number with a short suffix (number and suffix are separated by a non-breaking narrow space). */
80
- export const formatQuantity = (num, suffix, maxPrecision, minPrecision) => `${formatNumber(num, maxPrecision, minPrecision)}${NNBSP}${suffix}`;
81
- /** Format a number with a longer full-word suffix (number and suffix are separated by a non-breaking space). */
78
+ /** Format a number with a short suffix. */
79
+ export const formatQuantity = (num, suffix, maxPrecision, minPrecision) => `${formatNumber(num, maxPrecision, minPrecision)}${suffix}`;
80
+ /** Format a number with a longer full-word suffix. */
82
81
  export function formatFullQuantity(num, singular, plural, maxPrecision, minPrecision) {
83
82
  const qty = formatNumber(num, maxPrecision, minPrecision);
84
- return `${qty}${NBSP}${qty === "1" ? singular : plural}`;
83
+ return `${qty} ${qty === "1" ? singular : plural}`;
85
84
  }
86
85
  /**
87
86
  * Cram a large whole numbers into a space efficient format, e.g. `14.7M`
@@ -138,6 +137,13 @@ export const isBetween = (num, start, end) => num >= start && num <= end;
138
137
  * @param end The end of the range, e.g. `20`
139
138
  */
140
139
  export const getBetween = (num, start, end) => Math.max(start, Math.min(end, num));
140
+ /**
141
+ * Get a number as a percentage of another number.
142
+ *
143
+ * @param numerator Number representing the amount of progress.
144
+ * @param denumerator The number representing the whole amount.
145
+ */
146
+ export const getPercent = (numerator, denumerator) => Math.max(0, Math.min(100, (100 / denumerator) * numerator));
141
147
  /** Sum an iterable set of numbers and return the total. */
142
148
  export function sumNumbers(nums) {
143
149
  let sum = 0;
package/util/units.d.ts CHANGED
@@ -1,9 +1,25 @@
1
+ /** One second in millseconds. */
2
+ export declare const SECOND = 1000;
3
+ /** One minute in millseconds. */
4
+ export declare const MINUTE: number;
5
+ /** One hour in millseconds. */
6
+ export declare const HOUR: number;
7
+ /** One day in millseconds. */
8
+ export declare const DAY: number;
9
+ /** One week in millseconds. */
10
+ export declare const WEEK: number;
11
+ /** One month in millseconds. */
12
+ export declare const MONTH: number;
13
+ /** One year in millseconds. */
14
+ export declare const YEAR: number;
1
15
  /** Valid information about a unit of measure. */
2
16
  export declare type UnitData = {
3
- /** Plural name for a unit, e.g. `feet` */
4
- readonly plural?: string;
5
17
  /** Type of a unit. */
6
18
  readonly type: UnitType;
19
+ /** Singular name for a unit, e.g. `foot` (only needed if different from reference). */
20
+ readonly singular?: string;
21
+ /** Plural name for a unit, e.g. `feet` */
22
+ readonly plural?: string;
7
23
  /** Short suffix for this unit, e.g. `km` */
8
24
  readonly suffix: string;
9
25
  /** All units must specify their 'base' unit, e.g. `meter` for for distance units and `liter` for volume units. */
@@ -14,7 +30,7 @@ export declare type UnitData = {
14
30
  /** Valid system of measurement reference. */
15
31
  export declare type UnitType = "percentage" | "angle" | "temperature" | "length" | "speed" | "pace" | "mass" | "time" | "volume";
16
32
  /** Valid unit of measurement reference (correspond to units allowed in `Intl.NumberFormat`, but not all). */
17
- export declare type UnitReference = "percent" | "degree" | "millimeter" | "centimeter" | "meter" | "kilometer" | "mile" | "yard" | "foot" | "inch" | "liter" | "milliliter" | "gallon" | "fluid-ounce" | "milligram" | "gram" | "kilogram" | "pound" | "stone" | "ounce" | "millisecond" | "second" | "minute" | "day" | "hour" | "week" | "month" | "year";
33
+ export declare type UnitReference = "percent" | "permille" | "permyriad" | "ppm" | "percentage-point" | "basis-point" | "degree" | "millimeter" | "centimeter" | "meter" | "kilometer" | "mile" | "yard" | "foot" | "inch" | "liter" | "milliliter" | "gallon" | "fluid-ounce" | "milligram" | "gram" | "kilogram" | "pound" | "stone" | "ounce" | "millisecond" | "second" | "minute" | "day" | "hour" | "week" | "month" | "year";
18
34
  /** List of units. */
19
35
  export declare const UNITS: {
20
36
  [K in UnitReference]: UnitData;
package/util/units.js CHANGED
@@ -1,37 +1,55 @@
1
1
  import { AssertionError } from "../error/index.js";
2
- import { DAY, HOUR, MINUTE, MONTH, SECOND, WEEK, YEAR } from "./date.js";
3
- import { formatFullQuantity, formatQuantity } from "./number.js";
2
+ import { formatFullQuantity, formatQuantity, MILLION } from "./number.js";
4
3
  import { NNBSP } from "./string.js";
4
+ /** One second in millseconds. */
5
+ export const SECOND = 1000;
6
+ /** One minute in millseconds. */
7
+ export const MINUTE = 60 * SECOND;
8
+ /** One hour in millseconds. */
9
+ export const HOUR = 60 * MINUTE;
10
+ /** One day in millseconds. */
11
+ export const DAY = 24 * HOUR;
12
+ /** One week in millseconds. */
13
+ export const WEEK = 7 * DAY;
14
+ /** One month in millseconds. */
15
+ export const MONTH = 30 * DAY;
16
+ /** One year in millseconds. */
17
+ export const YEAR = 365 * DAY;
5
18
  /** List of units. */
6
19
  export const UNITS = {
7
20
  "percent": { type: "percentage", base: 1, suffix: "%" },
8
- "degree": { type: "angle", base: 1, suffix: "deg" },
9
- "millimeter": { type: "length", base: 1, suffix: "mm" },
10
- "centimeter": { type: "length", base: 10, suffix: "cm" },
11
- "meter": { type: "length", base: 1000, centimeter: 100, millimeter: 1000, suffix: "m" },
12
- "kilometer": { type: "length", base: 1000000, centimeter: 100000, millimeter: 1000000, suffix: "km" },
13
- "inch": { type: "length", base: 25.4, suffix: "in" },
14
- "foot": { type: "length", base: 304.8, inch: 12, suffix: "ft", plural: "feet" },
15
- "yard": { type: "length", base: 914.4, inch: 36, foot: 3, suffix: "yd" },
16
- "mile": { type: "length", base: 1609344, yard: 1760, foot: 5280, inch: 63360, suffix: "mi" },
17
- "milliliter": { type: "volume", base: 1, suffix: "ml" },
18
- "liter": { type: "volume", base: 1000, suffix: "l" },
19
- "fluid-ounce": { type: "volume", base: 29.5735295625, gallon: 128, suffix: `fl${NNBSP}oz` },
20
- "gallon": { type: "volume", base: 3785.411784, suffix: "gal" },
21
- "milligram": { type: "mass", base: 1, suffix: "mg" },
22
- "gram": { type: "mass", base: 1000, suffix: "g" },
23
- "kilogram": { type: "mass", base: 1000000, suffix: "kg" },
24
- "ounce": { type: "mass", base: 28349.523125, pound: 0.0625, suffix: "oz" },
25
- "pound": { type: "mass", base: 453592.37, ounce: 16, suffix: "lb" },
26
- "stone": { type: "mass", base: 6350293.18, pound: 14, ounce: 224, suffix: "st", plural: "stone" },
27
- "millisecond": { type: "time", base: 1, suffix: "ms" },
28
- "second": { type: "time", base: SECOND, suffix: "s" },
29
- "minute": { type: "time", base: MINUTE, suffix: "m" },
30
- "hour": { type: "time", base: HOUR, suffix: "h" },
31
- "day": { type: "time", base: DAY, suffix: "d" },
32
- "week": { type: "time", base: WEEK, suffix: "w" },
33
- "month": { type: "time", base: MONTH, suffix: "m" },
34
- "year": { type: "time", base: YEAR, suffix: "y" },
21
+ "permille": { type: "percentage", base: 10, suffix: `${NNBSP}‰` },
22
+ "permyriad": { type: "percentage", base: 100, suffix: `${NNBSP}‱` },
23
+ "ppm": { type: "percentage", base: MILLION, suffix: `${NNBSP}ppm`, singular: "part per million", plural: "parts per million" },
24
+ "percentage-point": { type: "percentage", base: 1, suffix: `${NNBSP}pp`, singular: "percentage point", plural: "percentage points" },
25
+ "basis-point": { type: "percentage", base: 10000, suffix: `${NNBSP}bp`, singular: "basis point", plural: "basis points" },
26
+ "degree": { type: "angle", base: 1, suffix: `${NNBSP}deg` },
27
+ "millimeter": { type: "length", base: 1, suffix: `${NNBSP}mm` },
28
+ "centimeter": { type: "length", base: 10, suffix: `${NNBSP}cm` },
29
+ "meter": { type: "length", base: 1000, centimeter: 100, millimeter: 1000, suffix: `${NNBSP}m` },
30
+ "kilometer": { type: "length", base: 1000000, centimeter: 100000, millimeter: 1000000, suffix: `${NNBSP}km` },
31
+ "inch": { type: "length", base: 25.4, suffix: `${NNBSP}in` },
32
+ "foot": { type: "length", base: 304.8, inch: 12, suffix: `${NNBSP}ft`, plural: "feet" },
33
+ "yard": { type: "length", base: 914.4, inch: 36, foot: 3, suffix: `${NNBSP}yd` },
34
+ "mile": { type: "length", base: 1609344, yard: 1760, foot: 5280, inch: 63360, suffix: `${NNBSP}mi` },
35
+ "milliliter": { type: "volume", base: 1, suffix: `${NNBSP}ml` },
36
+ "liter": { type: "volume", base: 1000, suffix: `${NNBSP}l` },
37
+ "fluid-ounce": { type: "volume", base: 29.5735295625, gallon: 128, suffix: `${NNBSP}fl${NNBSP}oz`, singular: "fluid ounce", plural: "fluid ounces" },
38
+ "gallon": { type: "volume", base: 3785.411784, suffix: `${NNBSP}gal` },
39
+ "milligram": { type: "mass", base: 1, suffix: `${NNBSP}mg` },
40
+ "gram": { type: "mass", base: 1000, suffix: `${NNBSP}g` },
41
+ "kilogram": { type: "mass", base: 1000000, suffix: `${NNBSP}kg` },
42
+ "ounce": { type: "mass", base: 28349.523125, pound: 0.0625, suffix: `${NNBSP}oz` },
43
+ "pound": { type: "mass", base: 453592.37, ounce: 16, suffix: `${NNBSP}lb` },
44
+ "stone": { type: "mass", base: 6350293.18, pound: 14, ounce: 224, suffix: `${NNBSP}st`, plural: "stone" },
45
+ "millisecond": { type: "time", base: 1, suffix: `${NNBSP}ms` },
46
+ "second": { type: "time", base: SECOND, suffix: `${NNBSP}s` },
47
+ "minute": { type: "time", base: MINUTE, suffix: `${NNBSP}m` },
48
+ "hour": { type: "time", base: HOUR, suffix: `${NNBSP}h` },
49
+ "day": { type: "time", base: DAY, suffix: `${NNBSP}d` },
50
+ "week": { type: "time", base: WEEK, suffix: `${NNBSP}w` },
51
+ "month": { type: "time", base: MONTH, suffix: `${NNBSP}m` },
52
+ "year": { type: "time", base: YEAR, suffix: `${NNBSP}y` },
35
53
  };
36
54
  /** Convert between two units of the same type. */
37
55
  export function convertUnits(num, from, to) {
@@ -61,4 +79,4 @@ export const formatUnits = (num, unit, maxPrecision, minPrecision) => formatQuan
61
79
  * @param unit String reference for a unit of measure e.g. `kilometer`
62
80
  * @param maxPrecision Number of decimal places to round the number to e.g. `2`
63
81
  */
64
- export const formatFullUnits = (num, unit, maxPrecision, minPrecision) => formatFullQuantity(num, unit, UNITS[unit].plural || `${unit}s`, maxPrecision, minPrecision);
82
+ export const formatFullUnits = (num, unit, maxPrecision, minPrecision) => formatFullQuantity(num, UNITS[unit].singular || unit, UNITS[unit].plural || `${unit}s`, maxPrecision, minPrecision);