shelving 1.86.3 → 1.86.5

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.
@@ -16,7 +16,7 @@ export type FilterProps<T extends Data> = {
16
16
  [K in DataKey<T> as `${K}<` | `${K}<=` | `${K}>` | `${K}>=`]?: T[K];
17
17
  };
18
18
  /** List of filters in a flexible format. */
19
- export type FilterList<T extends Data> = Nullish<FilterProps<T> | FilterConstraint<T>> | Iterable<FilterList<T>>;
19
+ export type FilterList<T extends Data> = FilterProps<T> | FilterConstraint<T> | Iterable<Nullish<FilterProps<T> | FilterConstraint<T>>>;
20
20
  /**
21
21
  * Filter: filters a list of data.
22
22
  *
@@ -34,5 +34,5 @@ export declare class FilterConstraint<T extends Data = Data> implements Constrai
34
34
  transform(items: Iterable<T>): Iterable<T>;
35
35
  toString(): string;
36
36
  }
37
- /** Get the separate filters generated from a list of filters. */
38
- export declare function getFilters<T extends Data>(filters: FilterList<T>): Iterable<FilterConstraint<T>>;
37
+ /** Turn `FilterList` into a list of `FilterConstraint` instances. */
38
+ export declare function getFilters<T extends Data>(list: FilterList<T> | FilterList<T>[]): Iterable<FilterConstraint<T>>;
@@ -79,17 +79,18 @@ export class FilterConstraint {
79
79
  return `"${this.filterKey}":${JSON.stringify(this.value)}`;
80
80
  }
81
81
  }
82
- /** Get the separate filters generated from a list of filters. */
83
- export function* getFilters(filters) {
84
- if (filters instanceof FilterConstraint) {
85
- yield filters;
82
+ /** Turn `FilterList` into a list of `FilterConstraint` instances. */
83
+ export function* getFilters(list) {
84
+ if (list instanceof FilterConstraint) {
85
+ yield list;
86
86
  }
87
- else if (isIterable(filters)) {
88
- for (const filter of filters)
89
- yield* getFilters(filter);
87
+ else if (isIterable(list)) {
88
+ for (const filter of list)
89
+ if (filter)
90
+ yield* getFilters(filter);
90
91
  }
91
- else if (filters) {
92
- for (const [key, value] of Object.entries(filters))
92
+ else {
93
+ for (const [key, value] of Object.entries(list))
93
94
  yield new FilterConstraint(key, value);
94
95
  }
95
96
  }
@@ -8,14 +8,14 @@ import { Constraints } from "./Constraints.js";
8
8
  */
9
9
  export interface Filterable<T extends Data> extends Matchable<[T]> {
10
10
  /** Add a filter to this filterable. */
11
- filter(...filters: FilterList<Partial<T>>[]): this;
11
+ filter(...filters: FilterList<T>[]): this;
12
12
  /** Match an item against the filters specified for this object. */
13
13
  match(item: T): boolean;
14
14
  }
15
15
  /** A set of filters. */
16
- export declare class FilterConstraints<T extends Data = Data> extends Constraints<T, FilterConstraint<Partial<T>>> implements Filterable<T> {
17
- constructor(...filters: FilterList<Partial<T>>[]);
18
- filter(...filters: FilterList<Partial<T>>[]): this;
16
+ export declare class FilterConstraints<T extends Data = Data> extends Constraints<T, FilterConstraint<T>> implements Filterable<T> {
17
+ constructor(...filters: FilterList<T>[]);
18
+ filter(...filters: FilterList<T>[]): this;
19
19
  match(item: T): boolean;
20
20
  transform(items: Iterable<T>): Iterable<T>;
21
21
  toString(): string;
@@ -31,11 +31,11 @@ export declare class QueryConstraints<T extends Data = Data> extends Constraint<
31
31
  readonly filters: FilterConstraints<T>;
32
32
  readonly sorts: SortConstraints<T>;
33
33
  readonly limit: number | null;
34
- constructor(filters?: FilterList<Partial<T>> | FilterConstraints<T>, sorts?: SortList<Partial<T>> | SortConstraints<T>, limit?: number | null);
35
- filter(...filters: FilterList<Partial<T>>[]): this;
34
+ constructor(filters?: FilterList<T> | FilterConstraints<T>, sorts?: SortList<T> | SortConstraints<T>, limit?: number | null);
35
+ filter(...filters: FilterList<T>[]): this;
36
36
  get unfilter(): this;
37
37
  match(item: T): boolean;
38
- sort(...sorts: SortList<Partial<T>>[]): this;
38
+ sort(...sorts: SortList<T>[]): this;
39
39
  get unsort(): this;
40
40
  rank(left: T, right: T): number;
41
41
  after(item: T): this;
@@ -10,7 +10,7 @@ export type SortKeys<T extends Data> = SortKey<T> | ImmutableArray<SortKey<T>>;
10
10
  /** Possible operator references. */
11
11
  export type SortDirection = "ASC" | "DESC";
12
12
  /** List of sorts in a flexible format. */
13
- export type SortList<T extends Data> = Nullish<SortKeys<T> | SortConstraint<T> | Iterable<SortList<T>>>;
13
+ export type SortList<T extends Data> = SortKey<T> | SortConstraint<T> | Iterable<Nullish<SortKey<T> | SortConstraint<T>>>;
14
14
  /** Sort a list of values. */
15
15
  export declare class SortConstraint<T extends Data = Data> implements Constraint<T>, Rankable<T> {
16
16
  readonly key: string;
@@ -21,5 +21,5 @@ export declare class SortConstraint<T extends Data = Data> implements Constraint
21
21
  transform(items: Iterable<T>): Iterable<T>;
22
22
  toString(): string;
23
23
  }
24
- /** Get the separate sorts generated from a list of sorts. */
25
- export declare function getSorts<T extends Data>(sorts: SortList<T>): Iterable<SortConstraint<T>>;
24
+ /** Turn `SortList` into array of list of `SortConstraint` instances. */
25
+ export declare function getSorts<T extends Data>(list: SortList<T> | SortList<T>[]): Iterable<SortConstraint<T>>;
@@ -24,16 +24,17 @@ export class SortConstraint {
24
24
  return this.sortKey;
25
25
  }
26
26
  }
27
- /** Get the separate sorts generated from a list of sorts. */
28
- export function* getSorts(sorts) {
29
- if (typeof sorts === "string") {
30
- yield new SortConstraint(sorts);
31
- }
32
- else if (sorts instanceof SortConstraint) {
33
- yield sorts;
34
- }
35
- else if (sorts) {
36
- for (const sort of sorts)
37
- yield* getSorts(sort);
27
+ /** Turn `SortList` into array of list of `SortConstraint` instances. */
28
+ export function* getSorts(list) {
29
+ if (typeof list === "string") {
30
+ yield new SortConstraint(list);
31
+ }
32
+ else if (list instanceof SortConstraint) {
33
+ yield list;
34
+ }
35
+ else {
36
+ for (const sort of list)
37
+ if (sort)
38
+ yield* getSorts(sort);
38
39
  }
39
40
  }
@@ -8,12 +8,12 @@ import { SortConstraint, SortList } from "./SortConstraint.js";
8
8
  */
9
9
  export interface Sortable<T extends Data> extends Rankable<T> {
10
10
  /** Add one or more sorts to this sortable. */
11
- sort(...keys: SortList<Partial<T>>[]): this;
11
+ sort(...keys: SortList<T>[]): this;
12
12
  }
13
13
  /** A set of sorts. */
14
- export declare class SortConstraints<T extends Data = Data> extends Constraints<T, SortConstraint<Partial<T>>> implements Sortable<T> {
15
- constructor(...sorts: SortList<Partial<T>>[]);
16
- sort(...sorts: SortList<Partial<T>>[]): this;
14
+ export declare class SortConstraints<T extends Data = Data> extends Constraints<T, SortConstraint<T>> implements Sortable<T> {
15
+ constructor(...sorts: SortList<T>[]);
16
+ sort(...sorts: SortList<T>[]): this;
17
17
  rank(left: T, right: T): number;
18
18
  transform(items: Iterable<T>): Iterable<T>;
19
19
  toString(): string;
@@ -43,7 +43,7 @@ export declare class Collection<T extends Datas = Datas, K extends DataKey<T> =
43
43
  readonly db: Database<T>;
44
44
  readonly collection: K;
45
45
  constructor(db: Database<T>, collection: K);
46
- query(filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null): Query<T, K>;
46
+ query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K>;
47
47
  item(id: string): Item<T, K>;
48
48
  change(...changes: DeepIterable<Nullish<WriteChange<T, K>>>[]): ItemChanges<T, K>;
49
49
  get(id: string): ItemValue<T[K]>;
@@ -57,7 +57,7 @@ export declare class AsyncCollection<T extends Datas = Datas, K extends DataKey<
57
57
  readonly db: AsyncDatabase<T>;
58
58
  readonly collection: K;
59
59
  constructor(db: AsyncDatabase<T>, collection: K);
60
- query(filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null): AsyncQuery<T, K>;
60
+ query(filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): AsyncQuery<T, K>;
61
61
  item(id: string): AsyncItem<T, K>;
62
62
  change(...changes: DeepIterable<Nullish<WriteChange<T, K>>>[]): Promise<ItemChanges<T, K>>;
63
63
  get(id: string): Promise<ItemValue<T[K]>>;
package/db/Database.d.ts CHANGED
@@ -45,7 +45,7 @@ export declare class Database<T extends Datas = Datas> extends BaseDatabase<T> {
45
45
  readonly provider: Provider<T>;
46
46
  constructor(provider: Provider<T>);
47
47
  collection<K extends DataKey<T>>(collection: K): Collection<T, K>;
48
- query<K extends DataKey<T>>(collection: K, filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null): Query<T, K>;
48
+ query<K extends DataKey<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): Query<T, K>;
49
49
  item<K extends DataKey<T>>(collection: K, id: string): Item<T, K>;
50
50
  change(...changes: DeepIterable<Nullish<WriteChange<T>>>[]): ItemChanges<T>;
51
51
  get<K extends DataKey<T>>(collection: K, id: string): ItemValue<T[K]>;
@@ -59,7 +59,7 @@ export declare class AsyncDatabase<T extends Datas = Datas> extends BaseDatabase
59
59
  readonly provider: AsyncProvider<T>;
60
60
  constructor(provider: AsyncProvider<T>);
61
61
  collection<K extends DataKey<T>>(collection: K): AsyncCollection<T, K>;
62
- query<K extends DataKey<T>>(collection: K, filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null): AsyncQuery<T, K>;
62
+ query<K extends DataKey<T>>(collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null): AsyncQuery<T, K>;
63
63
  item<K extends DataKey<T>>(collection: K, id: string): AsyncItem<T, K>;
64
64
  change(...changes: DeepIterable<Nullish<WriteChange<T>>>[]): Promise<ItemChanges<T>>;
65
65
  get<K extends DataKey<T>>(collection: K, id: string): Promise<ItemValue<T[K]>>;
package/db/Query.d.ts CHANGED
@@ -73,7 +73,7 @@ declare abstract class BaseQuery<T extends Datas = Datas, K extends DataKey<T> =
73
73
  export declare class Query<T extends Datas = Datas, K extends DataKey<T> = DataKey<T>> extends BaseQuery<T, K> {
74
74
  readonly db: Database<T>;
75
75
  readonly collection: K;
76
- constructor(db: Database<T>, collection: K, filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null);
76
+ constructor(db: Database<T>, collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null);
77
77
  get value(): ItemArray<T[K]>;
78
78
  get count(): number;
79
79
  get exists(): boolean;
@@ -89,7 +89,7 @@ export declare class Query<T extends Datas = Datas, K extends DataKey<T> = DataK
89
89
  export declare class AsyncQuery<T extends Datas = Datas, K extends DataKey<T> = DataKey<T>> extends BaseQuery<T, K> {
90
90
  readonly db: AsyncDatabase<T>;
91
91
  readonly collection: K;
92
- constructor(db: AsyncDatabase<T>, collection: K, filters?: FilterList<Partial<ItemData<T[K]>>>, sorts?: SortList<Partial<ItemData<T[K]>>>, limit?: number | null);
92
+ constructor(db: AsyncDatabase<T>, collection: K, filters?: FilterList<ItemData<T[K]>>, sorts?: SortList<ItemData<T[K]>>, limit?: number | null);
93
93
  get value(): Promise<ItemArray<T[K]>>;
94
94
  get count(): Promise<number>;
95
95
  get exists(): Promise<boolean>;
package/db/Query.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getFirstItem, getLastItem, getOptionalFirstItem, getOptionalLastItem, isArrayMin, countArray } from "../util/array.js";
1
+ import { getFirstItem, getLastItem, getOptionalFirstItem, getOptionalLastItem, isArrayLength, countArray } from "../util/array.js";
2
2
  import { runSequence } from "../util/sequence.js";
3
3
  import { QueryConstraints } from "../constraint/QueryConstraints.js";
4
4
  /** Reference to a set of items in a sync or async provider. */
@@ -68,7 +68,7 @@ export class AsyncQuery extends BaseQuery {
68
68
  return this.value.then(countArray);
69
69
  }
70
70
  get exists() {
71
- return this.max(1).value.then(isArrayMin);
71
+ return this.max(1).value.then(isArrayLength);
72
72
  }
73
73
  get firstValue() {
74
74
  return this.max(1).value.then(getOptionalFirstItem);
@@ -41,7 +41,7 @@ export declare function getLineRegExp(content?: PossibleRegExp, end?: PossibleRe
41
41
  * - If we could use a negative lookbehind for the start of the word we wouldn't need to create a function that offsets the start.
42
42
  */
43
43
  export declare class WordRegExp extends RegExp {
44
- constructor(pattern: string);
44
+ constructor(pattern: string, flags?: string);
45
45
  exec(input: string): RegExpExecArray | null;
46
46
  test(input: string): boolean;
47
47
  }
package/markup/regexp.js CHANGED
@@ -26,8 +26,8 @@ export function getLineRegExp(content = LINE_REGEXP, end = LINE_END_REGEXP, star
26
26
  * - If we could use a negative lookbehind for the start of the word we wouldn't need to create a function that offsets the start.
27
27
  */
28
28
  export class WordRegExp extends RegExp {
29
- constructor(pattern) {
30
- super(`(?<lookbehind>^|[^\\p{L}\\p{N}])${pattern}(?![\\p{L}\\p{N}])`);
29
+ constructor(pattern, flags) {
30
+ super(`(?<lookbehind>^|[^\\p{L}\\p{N}])${pattern}(?![\\p{L}\\p{N}])`, flags);
31
31
  }
32
32
  exec(input) {
33
33
  var _a;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.86.3",
14
+ "version": "1.86.5",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
package/state/State.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Validatable } from "../util/validate.js";
1
2
  import { Dispatch, Handler, Stop } from "../util/function.js";
2
3
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
3
4
  /** Any `State` instance. */
@@ -12,7 +13,7 @@ export type AnyState = State<any>;
12
13
  * - To set the state to be loading, use the `State.NOVALUE` constant or a `Promise` value.
13
14
  * - To set the state to an explicit value, use that value or another `State` instance with a value.
14
15
  * */
15
- export declare class State<T> implements AsyncIterable<T> {
16
+ export declare class State<T> implements AsyncIterable<T>, Validatable<T> {
16
17
  /** The `NOVALUE` symbol indicates no value has been received by a `State` instance. */
17
18
  static readonly NOVALUE: unique symbol;
18
19
  /** Deferred sequence this state uses to issue values as they change. */
@@ -30,7 +31,7 @@ export declare class State<T> implements AsyncIterable<T> {
30
31
  /** Is there a current value, or is it still loading. */
31
32
  get loading(): boolean;
32
33
  /** Set the value of the state. */
33
- set(value: T): void;
34
+ set(next: T): void;
34
35
  /** Set the value of the state as values are pulled from a sequence. */
35
36
  through(sequence: AsyncIterable<T>): AsyncIterable<T>;
36
37
  /** Pull values from a source sequence until the returned stop function is called. */
@@ -38,6 +39,8 @@ export declare class State<T> implements AsyncIterable<T> {
38
39
  /** Push values to another state or callback to this state until the returned stop function is called. */
39
40
  to(target: Dispatch<[T]>, onError?: Handler): Stop;
40
41
  [Symbol.asyncIterator](): AsyncIterator<T>;
42
+ /** Validate data set on this state. */
43
+ validate(value: T): T;
41
44
  }
42
45
  /** Is an unknown value a `State` instance. */
43
46
  export declare const isState: <T extends AnyState>(v: unknown) => v is T;
package/state/State.js CHANGED
@@ -28,8 +28,12 @@ export class State {
28
28
  }
29
29
  /** State is initiated with an initial state. */
30
30
  constructor(initial = State.NOVALUE, next = new DeferredSequence()) {
31
- this._value = initial;
32
- this._time = initial !== State.NOVALUE ? Date.now() : null;
31
+ this._value = State.NOVALUE;
32
+ this._time = null;
33
+ if (initial !== State.NOVALUE) {
34
+ this._value = this.validate(initial);
35
+ this._time = Date.now();
36
+ }
33
37
  this.next = next;
34
38
  }
35
39
  /** Is there a current value, or is it still loading. */
@@ -37,7 +41,8 @@ export class State {
37
41
  return this._value === State.NOVALUE;
38
42
  }
39
43
  /** Set the value of the state. */
40
- set(value) {
44
+ set(next) {
45
+ const value = this.validate(next);
41
46
  if (value !== this._value) {
42
47
  this._value = value;
43
48
  this._time = Date.now();
@@ -67,6 +72,10 @@ export class State {
67
72
  yield this.value;
68
73
  yield* this.next;
69
74
  }
75
+ /** Validate data set on this state. */
76
+ validate(value) {
77
+ return value;
78
+ }
70
79
  }
71
80
  /** The `NOVALUE` symbol indicates no value has been received by a `State` instance. */
72
81
  State.NOVALUE = Symbol("shelving/State.NOVALUE");
package/util/array.d.ts CHANGED
@@ -60,20 +60,32 @@ export declare function limitArray<T>(items: Iterable<T>, limit: number): Immuta
60
60
  /** Count the items in an array. */
61
61
  export declare function countArray<T>(arr: ImmutableArray<T>): number;
62
62
  /** Does an array have the specified minimum length. */
63
- export declare function isArrayMin<T>(arr: ImmutableArray<T>, min?: 1): arr is [T, ...T[]];
64
- export declare function isArrayMin<T>(arr: ImmutableArray<T>, min: 2): arr is [T, T, ...T[]];
65
- export declare function isArrayMin<T>(arr: ImmutableArray<T>, min: 3): arr is [T, T, T, ...T[]];
66
- export declare function isArrayMin<T>(arr: ImmutableArray<T>, min: 4): arr is [T, T, T, T, ...T[]];
67
- export declare function isArrayMin<T>(arr: ImmutableArray<T>, min: number): boolean;
63
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 1, max: 1): arr is readonly [T];
64
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 2, max: 2): arr is readonly [T, T];
65
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 3, max: 3): arr is readonly [T, T, T];
66
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 4, max: 4): arr is readonly [T, T, T, T];
67
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min?: 1, max?: number): arr is readonly [T, ...T[]];
68
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 2, max?: number): arr is readonly [T, T, ...T[]];
69
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 3, max?: number): arr is readonly [T, T, T, ...T[]];
70
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min: 4, max?: number): arr is readonly [T, T, T, T, ...T[]];
71
+ export declare function isArrayLength<T>(arr: ImmutableArray<T>, min?: number, max?: number): boolean;
68
72
  /** Assert that a value has a specific length (or length is in a specific range). */
69
- export declare function assertArrayMin<T>(arr: ImmutableArray<T> | unknown, min?: 1): asserts arr is [T, ...T[]];
70
- export declare function assertArrayMin<T>(arr: ImmutableArray<T> | unknown, min: 2): asserts arr is [T, T, ...T[]];
71
- export declare function assertArrayMin<T>(arr: ImmutableArray<T> | unknown, min: 3): asserts arr is [T, T, T, ...T[]];
72
- export declare function assertArrayMin<T>(arr: ImmutableArray<T> | unknown, min: 4): asserts arr is [T, T, T, T, ...T[]];
73
- export declare function assertArrayMin<T>(arr: ImmutableArray<T> | unknown, min: number): asserts arr is ImmutableArray<T>;
73
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T>, min: 1, max: 1): asserts arr is readonly [T];
74
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T>, min: 2, max: 2): asserts arr is readonly [T, T];
75
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T>, min: 3, max: 3): asserts arr is readonly [T, T, T];
76
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T>, min: 4, max: 4): asserts arr is readonly [T, T, T, T];
77
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T> | unknown, min?: 1, max?: number): asserts arr is readonly [T, ...T[]];
78
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T> | unknown, min: 2, max?: number): asserts arr is readonly [T, T, ...T[]];
79
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T> | unknown, min: 3, max?: number): asserts arr is readonly [T, T, T, ...T[]];
80
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T> | unknown, min: 4, max?: number): asserts arr is readonly [T, T, T, T, ...T[]];
81
+ export declare function assertArrayLength<T>(arr: ImmutableArray<T> | unknown, min: number, max?: number): asserts arr is ImmutableArray<T>;
74
82
  /** Get an array if it has the specified minimum length. */
75
- export declare function getArrayMin<T>(arr: ImmutableArray<T>, min?: 1): [T, ...T[]];
76
- export declare function getArrayMin<T>(arr: ImmutableArray<T>, min: 2): [T, T, ...T[]];
77
- export declare function getArrayMin<T>(arr: ImmutableArray<T>, min: 3): [T, T, T, ...T[]];
78
- export declare function getArrayMin<T>(arr: ImmutableArray<T>, min: 4): [T, T, T, T, ...T[]];
79
- export declare function getArrayMin<T>(arr: ImmutableArray<T>, min: number): ImmutableArray<T>;
83
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 1, max: 1): readonly [T];
84
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 2, max: 2): readonly [T, T];
85
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 3, max: 3): readonly [T, T, T];
86
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 4, max: 4): readonly [T, T, T, T];
87
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min?: 1, max?: number): readonly [T, ...T[]];
88
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 2, max?: number): readonly [T, T, ...T[]];
89
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 3, max?: number): readonly [T, T, T, ...T[]];
90
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min: 4, max?: number): readonly [T, T, T, T, ...T[]];
91
+ export declare function getArrayLength<T>(arr: ImmutableArray<T>, min?: number, max?: number): ImmutableArray<T>;
package/util/array.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AssertionError } from "../error/AssertionError.js";
2
2
  import { RequiredError } from "../error/RequiredError.js";
3
3
  import { filterItems, omitItems, pickItems } from "./iterate.js";
4
+ import { formatRange } from "./number.js";
4
5
  /** Is an unknown value an array? */
5
6
  export const isArray = (v) => Array.isArray(v);
6
7
  /** Assert that a value is an array. */
@@ -137,14 +138,14 @@ export function limitArray(items, limit) {
137
138
  export function countArray(arr) {
138
139
  return arr.length;
139
140
  }
140
- export function isArrayMin(arr, min = 1) {
141
- return arr.length >= min;
141
+ export function isArrayLength(arr, min = 1, max = Infinity) {
142
+ return arr.length >= min && arr.length <= max;
142
143
  }
143
- export function assertArrayMin(arr, min = 1) {
144
- if (!isArray(arr) || !isArrayMin(arr, min))
145
- throw new AssertionError(`Must be array with minimum length ${min}`, arr);
144
+ export function assertArrayLength(arr, min = 1, max = Infinity) {
145
+ if (!isArray(arr) || !isArrayLength(arr, min, max))
146
+ throw new AssertionError(`Must be array with length ${formatRange(min, max)}`, arr);
146
147
  }
147
- export function getArrayMin(arr, min = 1) {
148
- assertArrayMin(arr, min);
148
+ export function getArrayLength(arr, min = 1, max = Infinity) {
149
+ assertArrayLength(arr, min, max);
149
150
  return arr;
150
151
  }
package/util/number.d.ts CHANGED
@@ -70,6 +70,8 @@ export declare function boundNumber(num: number, min: number, max: number): numb
70
70
  export declare function wrapNumber(num: number, min: number, max: number): number;
71
71
  /** Format a number (based on the user's browser language settings). */
72
72
  export declare function formatNumber(num: number, precision?: number | null): string;
73
+ /** Format a number range (based on the user's browser language settings). */
74
+ export declare function formatRange(min: number, max: number, precision?: number | null): string;
73
75
  /** Format a number with a short suffix, e.g. `1,000 kg` */
74
76
  export declare const formatQuantity: (num: number, abbr: string, precision?: number | null) => string;
75
77
  /** Format a number with a longer full-word suffix. */
package/util/number.js CHANGED
@@ -110,10 +110,16 @@ export function wrapNumber(num, min, max) {
110
110
  }
111
111
  /** Format a number (based on the user's browser language settings). */
112
112
  export function formatNumber(num, precision = null) {
113
+ if (Number.isNaN(num))
114
+ return "None";
113
115
  if (!Number.isFinite(num))
114
- return Number.isNaN(num) ? "None" : "Infinity";
116
+ return "";
115
117
  return new Intl.NumberFormat(undefined, { minimumFractionDigits: precision !== null && precision !== void 0 ? precision : undefined, maximumFractionDigits: precision !== null && precision !== void 0 ? precision : 20 }).format(num);
116
118
  }
119
+ /** Format a number range (based on the user's browser language settings). */
120
+ export function formatRange(min, max, precision = null) {
121
+ return `${formatNumber(min, precision)}–${formatNumber(max, precision)}`;
122
+ }
117
123
  /** Format a number with a short suffix, e.g. `1,000 kg` */
118
124
  export const formatQuantity = (num, abbr, precision) => `${formatNumber(num, precision)}${NNBSP}${abbr}`;
119
125
  /** Format a number with a longer full-word suffix. */
package/util/regexp.d.ts CHANGED
@@ -6,16 +6,6 @@ export declare const ALWAYS_REGEXP: RegExp;
6
6
  export declare const NEVER_REGEXP: RegExp;
7
7
  /** Things that can be convert to a regular expression. */
8
8
  export type PossibleRegExp = string | RegExp;
9
- /** Is an unknown value a `RegExp` instance? */
10
- export declare const isRegExp: <T extends RegExp>(v: unknown) => v is T;
11
- /** Assert that an unknown value is a `RegExp` instance. */
12
- export declare function assertRegExp<T extends RegExp>(v: T | unknown): asserts v is T;
13
- /** Convert a string to a regular expression that matches that string. */
14
- export declare const getRegExp: (pattern: PossibleRegExp, flags?: string) => RegExp;
15
- /** Convert a regular expression to its string source. */
16
- export declare const getRegExpSource: (regexp: PossibleRegExp) => string;
17
- /** Escape special characters in a string regular expression. */
18
- export declare const escapeRegExp: (pattern: string) => string;
19
9
  /** Set of named match groups from a regular expression. */
20
10
  export type NamedRegExpData = {
21
11
  [named: string]: string;
@@ -28,6 +18,19 @@ export interface NamedRegExpArray<T extends NamedRegExpData = NamedRegExpData> e
28
18
  export interface NamedRegExp<T extends NamedRegExpData = NamedRegExpData> extends RegExp {
29
19
  exec(input: string): NamedRegExpArray<T> | null;
30
20
  }
21
+ /** Is an unknown value a `RegExp` instance? */
22
+ export declare const isRegExp: <T extends RegExp>(v: unknown) => v is T;
23
+ /** Assert that an unknown value is a `RegExp` instance. */
24
+ export declare function assertRegExp<T extends RegExp>(v: T | unknown): asserts v is T;
25
+ /** Convert a string to a regular expression that matches that string. */
26
+ export declare function getRegExp<T extends string>(pattern: `(?<${T}>${string})`, flags?: string): NamedRegExp<{
27
+ [K in T]: string;
28
+ }>;
29
+ export declare function getRegExp(pattern: PossibleRegExp, flags?: string): RegExp;
30
+ /** Convert a regular expression to its string source. */
31
+ export declare const getRegExpSource: (regexp: PossibleRegExp) => string;
32
+ /** Escape special characters in a string regular expression. */
33
+ export declare const escapeRegExp: (pattern: string) => string;
31
34
  /** Create regular expression that matches any of a list of other expressions. */
32
35
  export declare function getAnyRegExp(patterns: Iterable<PossibleRegExp> & NotString, flags?: string): RegExp;
33
36
  /** Create regular expression that matches all of a list of other expressions. */
package/util/regexp.js CHANGED
@@ -11,8 +11,9 @@ export function assertRegExp(v) {
11
11
  if (!(v instanceof RegExp))
12
12
  throw new AssertionError("Must be regular expression", v);
13
13
  }
14
- /** Convert a string to a regular expression that matches that string. */
15
- export const getRegExp = (pattern, flags) => (typeof pattern === "string" ? new RegExp(pattern, flags) : pattern);
14
+ export function getRegExp(pattern, flags) {
15
+ return typeof pattern === "string" ? new RegExp(pattern, flags) : pattern;
16
+ }
16
17
  /** Convert a regular expression to its string source. */
17
18
  export const getRegExpSource = (regexp) => (typeof regexp === "string" ? regexp : regexp.source);
18
19
  /** Escape special characters in a string regular expression. */
package/util/string.d.ts CHANGED
@@ -27,6 +27,12 @@ export declare function assertString(value: unknown): asserts value is string;
27
27
  * - Everything else returns `"Unknown"`
28
28
  */
29
29
  export declare function getString(value: unknown): string;
30
+ /** Does a string have the specified minimum length. */
31
+ export declare const isStringLength: (str: string, min?: number, max?: number) => boolean;
32
+ /** Assert that a value has a specific length (or length is in a specific range). */
33
+ export declare function assertStringLength(str: string | unknown, min?: number, max?: number): asserts str is string;
34
+ /** Get a string if it has the specified minimum length. */
35
+ export declare function getStringLength(arr: string, min?: number, max?: number): string;
30
36
  /** Concatenate an iterable set of strings together. */
31
37
  export declare const joinStrings: (strs: Iterable<string> & NotString, joiner?: string) => string;
32
38
  /**
@@ -89,13 +95,17 @@ export declare function limitString(str: string, maxLength: number, append?: str
89
95
  * Divide a string into parts based on a separator.
90
96
  * - Like `String.prototype.split()` but with more useful arguments.
91
97
  * - Excess segments in `String.prototype.split()` is counterintuitive because further parts are thrown away.
92
- * - Excess segments in `splitString()` are concatenated onto the last segment (set `maxSegments` to `null` if you want infinite segments).
98
+ * - Excess segments in `splitString()` are concatenated onto the last segment (set `max` to `null` if you want infinite segments).
93
99
  *
94
- * @throws AssertionError if `minSegments` isn't met.
100
+ * @throws AssertionError if `min` isn't met.
95
101
  * @throws AssertionError if any of the segments are empty.
96
102
  */
97
- export declare function splitString(str: string, separator: string, minSegments: 1, maxSegments?: number): readonly [string, ...string[]];
98
- export declare function splitString(str: string, separator: string, minSegments: 2, maxSegments?: number): readonly [string, string, ...string[]];
99
- export declare function splitString(str: string, separator: string, minSegments: 3, maxSegments?: number): readonly [string, string, string, ...string[]];
100
- export declare function splitString(str: string, separator: string, minSegments: 4, maxSegments?: number): readonly [string, string, string, string, ...string[]];
101
- export declare function splitString(str: string, separator: string, minSegments?: number, maxSegments?: number | null): ImmutableArray<string>;
103
+ export declare function splitString(str: string, separator: string, min: 1, max: 1): readonly [string];
104
+ export declare function splitString(str: string, separator: string, min: 2, max: 2): readonly [string, string];
105
+ export declare function splitString(str: string, separator: string, min: 3, max: 3): readonly [string, string, string];
106
+ export declare function splitString(str: string, separator: string, min: 4, max: 4): readonly [string, string, string, string];
107
+ export declare function splitString(str: string, separator: string, min: 1, max?: number): readonly [string, ...string[]];
108
+ export declare function splitString(str: string, separator: string, min: 2, max?: number): readonly [string, string, ...string[]];
109
+ export declare function splitString(str: string, separator: string, min: 3, max?: number): readonly [string, string, string, ...string[]];
110
+ export declare function splitString(str: string, separator: string, min: 4, max?: number): readonly [string, string, string, string, ...string[]];
111
+ export declare function splitString(str: string, separator: string, min?: number, max?: number): ImmutableArray<string>;
package/util/string.js CHANGED
@@ -3,7 +3,7 @@ import { AssertionError } from "../error/AssertionError.js";
3
3
  import { formatDate, isDate } from "./date.js";
4
4
  import { formatObject, isObject } from "./object.js";
5
5
  import { getArray, isArray } from "./array.js";
6
- import { formatNumber, isBetween } from "./number.js";
6
+ import { formatNumber, formatRange, isBetween } from "./number.js";
7
7
  /** Is a value a string? */
8
8
  export const isString = (v) => typeof v === "string";
9
9
  /** Assert that a value is a string. */
@@ -45,6 +45,18 @@ export function getString(value) {
45
45
  return formatObject(value);
46
46
  return "Unknown";
47
47
  }
48
+ /** Does a string have the specified minimum length. */
49
+ export const isStringLength = (str, min = 1, max = Infinity) => str.length >= min && str.length <= max;
50
+ /** Assert that a value has a specific length (or length is in a specific range). */
51
+ export function assertStringLength(str, min = 1, max = Infinity) {
52
+ if (!isString(str) || !isStringLength(str, min, max))
53
+ throw new AssertionError(`Must be string with length ${formatRange(min, max)}`, str);
54
+ }
55
+ /** Get a string if it has the specified minimum length. */
56
+ export function getStringLength(arr, min = 1, max = Infinity) {
57
+ assertStringLength(arr, min, max);
58
+ return arr;
59
+ }
48
60
  /** Concatenate an iterable set of strings together. */
49
61
  export const joinStrings = (strs, joiner = "") => getArray(strs).join(joiner);
50
62
  /**
@@ -133,11 +145,11 @@ export function limitString(str, maxLength, append = "…") {
133
145
  const lastSpace = str.lastIndexOf(" ", maxLength);
134
146
  return `${str.slice(0, lastSpace > 0 ? lastSpace : maxLength).trimEnd()}${append}`;
135
147
  }
136
- export function splitString(str, separator, minSegments = 0, maxSegments = minSegments) {
148
+ export function splitString(str, separator, min = 1, max = Infinity) {
137
149
  const segments = str.split(separator);
138
- if (typeof maxSegments === "number" && segments.length > maxSegments)
139
- segments.splice(maxSegments - 1, segments.length, segments.slice(maxSegments - 1).join(separator));
140
- if (segments.length < minSegments || !segments.every(Boolean))
141
- throw new AssertionError(`Must be string with ${minSegments} non-empty segments separated by "${separator}"`, str);
150
+ if (segments.length > max)
151
+ segments.splice(max - 1, segments.length, segments.slice(max - 1).join(separator));
152
+ if (segments.length < min || !segments.every(Boolean))
153
+ throw new AssertionError(`Must be string with ${formatRange(min, max)} non-empty segments separated by "${separator}"`, str);
142
154
  return segments;
143
155
  }