@tstdl/base 0.90.85 → 0.90.89

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.
@@ -93,14 +93,8 @@ function getRequestBody(body) {
93
93
  if (isUndefined(body)) {
94
94
  return undefined;
95
95
  }
96
- if (isUint8Array(body)) {
97
- return { buffer: body };
98
- }
99
- if (isReadableStream(body)) {
100
- return { stream: body };
101
- }
102
- if (isBlob(body)) {
103
- return { blob: body };
96
+ if (isUint8Array(body) || isReadableStream(body) || isBlob(body)) {
97
+ return { binary: body };
104
98
  }
105
99
  if (isString(body)) {
106
100
  return { text: body };
@@ -1,56 +1,56 @@
1
1
  import type { ToJson } from '../interfaces.js';
2
- import type { Observable } from 'rxjs';
2
+ import { type Observable } from 'rxjs';
3
3
  export declare abstract class Collection<T, TThis extends Collection<T, TThis> = Collection<T, any>> implements Iterable<T>, ToJson {
4
4
  private readonly sizeSubject;
5
5
  private readonly changeSubject;
6
6
  private readonly clearSubject;
7
- /** emits collection on subscribe and change */
7
+ /** Emits collection on subscribe and change */
8
8
  readonly observe$: Observable<TThis>;
9
- /** emits size of collection */
9
+ /** Emits size of collection */
10
10
  readonly size$: Observable<number>;
11
- /** emits collection on change */
11
+ /** Emits collection on change */
12
12
  readonly change$: Observable<TThis>;
13
13
  readonly clear$: Observable<TThis>;
14
- /** emits when the collection is empty */
14
+ /** Emits when the collection is empty */
15
15
  readonly onEmpty$: Observable<void>;
16
- /** emits when the collection has items */
16
+ /** Emits when the collection has items */
17
17
  readonly onItems$: Observable<void>;
18
- /** emits whether the collection is empty */
18
+ /** Emits whether the collection is empty */
19
19
  readonly isEmpty$: Observable<boolean>;
20
- /** emits whether the collection has items */
20
+ /** Emits whether the collection has items */
21
21
  readonly hasItems$: Observable<boolean>;
22
- /** resolves when the collection is empty */
22
+ /** Resolves when the collection is empty */
23
23
  get $onEmpty(): Promise<void>;
24
- /** resolves when the collection has items */
24
+ /** Resolves when the collection has items */
25
25
  get $onItems(): Promise<void>;
26
- /** size of collection */
26
+ /** Size of collection */
27
27
  get size(): number;
28
- /** whether the collection is empty */
28
+ /** Whether the collection is empty */
29
29
  get isEmpty(): boolean;
30
- /** whether the collection has items */
30
+ /** Whether the collection has items */
31
31
  get hasItems(): boolean;
32
32
  constructor();
33
33
  [Symbol.iterator](): IterableIterator<T>;
34
34
  toArray(): T[];
35
35
  toJSON(): T[];
36
- /** remove all items */
36
+ /** Remove all items */
37
37
  clear(): void;
38
- /** sets collection size */
38
+ /** Sets collection size */
39
39
  protected setSize(size: number): void;
40
- /** increment collection size by amount (default 1) */
40
+ /** Increment collection size by amount (default 1) */
41
41
  protected incrementSize(amount?: number): void;
42
- /** decrement collection size by amount (default 1) */
42
+ /** Decrement collection size by amount (default 1) */
43
43
  protected decrementSize(amount?: number): void;
44
44
  protected emitChange(): void;
45
45
  abstract includes(item: T): boolean;
46
- /** add item to collection */
46
+ /** Add item to collection */
47
47
  abstract add(item: T): void;
48
- /** add many items to collection */
48
+ /** Add many items to collection */
49
49
  abstract addMany(items: Iterable<T>): void;
50
- /** clone collection */
50
+ /** Clone collection */
51
51
  abstract clone(): TThis;
52
- /** yields all items from the collection */
52
+ /** Yields all items from the collection */
53
53
  abstract items(): IterableIterator<T>;
54
- /** clear all data - size is set to 0 automatically */
54
+ /** Clear all data - size is set to 0 automatically */
55
55
  protected abstract _clear(): void;
56
56
  }
@@ -1,41 +1,41 @@
1
- import { BehaviorSubject, distinctUntilChanged, filter, firstValueFrom, map, startWith, Subject } from 'rxjs';
1
+ import { BehaviorSubject, Subject, distinctUntilChanged, filter, firstValueFrom, map, startWith } from 'rxjs';
2
2
  export class Collection {
3
3
  sizeSubject;
4
4
  changeSubject;
5
5
  clearSubject;
6
- /** emits collection on subscribe and change */
6
+ /** Emits collection on subscribe and change */
7
7
  observe$;
8
- /** emits size of collection */
8
+ /** Emits size of collection */
9
9
  size$;
10
- /** emits collection on change */
10
+ /** Emits collection on change */
11
11
  change$;
12
- /* emits collection on clear */
12
+ /* Emits collection on clear */
13
13
  clear$;
14
- /** emits when the collection is empty */
14
+ /** Emits when the collection is empty */
15
15
  onEmpty$;
16
- /** emits when the collection has items */
16
+ /** Emits when the collection has items */
17
17
  onItems$;
18
- /** emits whether the collection is empty */
18
+ /** Emits whether the collection is empty */
19
19
  isEmpty$;
20
- /** emits whether the collection has items */
20
+ /** Emits whether the collection has items */
21
21
  hasItems$;
22
- /** resolves when the collection is empty */
22
+ /** Resolves when the collection is empty */
23
23
  get $onEmpty() {
24
24
  return firstValueFrom(this.onEmpty$);
25
25
  }
26
- /** resolves when the collection has items */
26
+ /** Resolves when the collection has items */
27
27
  get $onItems() {
28
28
  return firstValueFrom(this.onItems$);
29
29
  }
30
- /** size of collection */
30
+ /** Size of collection */
31
31
  get size() {
32
32
  return this.sizeSubject.value;
33
33
  }
34
- /** whether the collection is empty */
34
+ /** Whether the collection is empty */
35
35
  get isEmpty() {
36
36
  return this.size == 0;
37
37
  }
38
- /** whether the collection has items */
38
+ /** Whether the collection has items */
39
39
  get hasItems() {
40
40
  return this.size > 0;
41
41
  }
@@ -61,24 +61,24 @@ export class Collection {
61
61
  toJSON() {
62
62
  return this.toArray();
63
63
  }
64
- /** remove all items */
64
+ /** Remove all items */
65
65
  clear() {
66
66
  this._clear();
67
67
  this.clearSubject.next(this);
68
68
  this.setSize(0);
69
69
  }
70
- /** sets collection size */
70
+ /** Sets collection size */
71
71
  setSize(size) {
72
72
  if (size != this.size) {
73
73
  this.sizeSubject.next(size);
74
74
  this.emitChange();
75
75
  }
76
76
  }
77
- /** increment collection size by amount (default 1) */
77
+ /** Increment collection size by amount (default 1) */
78
78
  incrementSize(amount = 1) {
79
79
  this.setSize(this.size + amount);
80
80
  }
81
- /** decrement collection size by amount (default 1) */
81
+ /** Decrement collection size by amount (default 1) */
82
82
  decrementSize(amount = 1) {
83
83
  this.setSize(this.size - amount);
84
84
  }
@@ -5,7 +5,7 @@ export declare class IterableWeakMap<K extends object, V> extends Collection<[K,
5
5
  private finalizationRegistry;
6
6
  readonly [Symbol.toStringTag] = "IterableWeakMap";
7
7
  /**
8
- * provides the real size. This is slow because it requires a cleanup iteration
8
+ * Provides the real size. This is slow because it requires a cleanup iteration
9
9
  */
10
10
  get realSize(): number;
11
11
  static get supported(): boolean;
@@ -17,7 +17,7 @@ export declare class IterableWeakMap<K extends object, V> extends Collection<[K,
17
17
  addMany(values: Iterable<readonly [K, V]>): void;
18
18
  set(key: K, value: V): this;
19
19
  delete(key: K): boolean;
20
- /** prune garbage collected entries */
20
+ /** Prune garbage collected entries */
21
21
  cleanup(): void;
22
22
  clone(): IterableWeakMap<K, V>;
23
23
  forEach(callback: (value: V, key: K, map: IterableWeakMap<K, V>) => void, thisArg?: any): void;
@@ -9,7 +9,7 @@ export class IterableWeakMap extends Collection {
9
9
  finalizationRegistry;
10
10
  [Symbol.toStringTag] = 'IterableWeakMap';
11
11
  /**
12
- * provides the real size. This is slow because it requires a cleanup iteration
12
+ * Provides the real size. This is slow because it requires a cleanup iteration
13
13
  */
14
14
  get realSize() {
15
15
  this.cleanup();
@@ -79,7 +79,7 @@ export class IterableWeakMap extends Collection {
79
79
  }
80
80
  return deleted;
81
81
  }
82
- /** prune garbage collected entries */
82
+ /** Prune garbage collected entries */
83
83
  cleanup() {
84
84
  drain(this);
85
85
  this.updateSize();
@@ -1,4 +1,4 @@
1
- import type { Flatten, StringMap } from '../types.js';
1
+ import type { Flatten, Record } from '../types.js';
2
2
  import type { Geometry } from '../types/geo-json.js';
3
3
  export type QueryOptions<T = any> = {
4
4
  sort?: Sort<T>[];
@@ -10,7 +10,7 @@ export type LogicalQueryTypes = keyof (LogicalAndQuery & LogicalOrQuery & Logica
10
10
  export declare const allLogicalQueryTypes: LogicalQueryTypes[];
11
11
  export type ComparisonQueryBody<T = any> = {
12
12
  [P in keyof T]?: ComparisonQueryOrValue<T[P]>;
13
- } & StringMap<ComparisonQueryOrValue>;
13
+ } & Record<ComparisonQueryOrValue>;
14
14
  export type ComparisonQueryOrValue<T = any> = ComparisonQuery<T> | T | Flatten<T>;
15
15
  export type ComparisonQuery<T = any> = Partial<ComparisonNotQuery<T> & ComparisonEqualsQuery<T> & ComparisonNotEqualsQuery<T> & ComparisonExistsQuery & ComparisonItemQuery<T> & ComparisonInQuery<T> & ComparisonNotInQuery<T> & ComparisonAllQuery<T> & ComparisonGreaterThanQuery<T> & ComparisonGreaterThanOrEqualsQuery<T> & ComparisonLessThanQuery<T> & ComparisonLessThanOrEqualsQuery<T> & ComparisonRegexQuery & ComparisonTextQuery & ComparisonGeoShapeQuery & ComparisonGeoDistanceQuery>;
16
16
  export type ComparisonQueryTypes = keyof ComparisonQuery;
@@ -100,11 +100,11 @@ export type ComparisonGeoDistanceQuery = {
100
100
  longitude: number;
101
101
  latitude: number;
102
102
  /**
103
- * maximum distance in meters
103
+ * Maximum distance in meters
104
104
  */
105
105
  maxDistance?: number;
106
106
  /**
107
- * minimum distance in meters
107
+ * Minimum distance in meters
108
108
  */
109
109
  minDistance?: number;
110
110
  };
@@ -1,9 +1,4 @@
1
- import { Signal } from '../../signals/api.js';
2
- import { Observable } from 'rxjs';
3
- export type ObserveIntersectionOptions = IntersectionObserverInit & {
4
- takeRecordsTrigger?: Observable<any>;
5
- observeTrigger?: Observable<Element>;
6
- unobserveTrigger?: Observable<Element>;
7
- };
8
- export declare function observeIntersection$(elements: Element | Element[], options?: ObserveIntersectionOptions): Observable<IntersectionObserverEntry[]>;
9
- export declare function observeIntersection(elements: Element | Element[], options?: ObserveIntersectionOptions): Signal<IntersectionObserverEntry[]>;
1
+ import { type Signal } from '../../signals/api.js';
2
+ import { type Observable } from 'rxjs';
3
+ export declare function observeIntersection$(element: Element, options?: IntersectionObserverInit): Observable<IntersectionObserverEntry>;
4
+ export declare function observeIntersection(elements: Element, options?: IntersectionObserverInit): Signal<IntersectionObserverEntry | undefined>;
@@ -1,31 +1,26 @@
1
+ import { IterableWeakMap } from '../../data-structures/iterable-weak-map.js';
1
2
  import { toSignal } from '../../signals/api.js';
2
- import { toArray } from '../../utils/array/array.js';
3
- import { isDefined } from '../../utils/type-guards.js';
4
- import { Observable } from 'rxjs';
5
- export function observeIntersection$(elements, options = {}) {
6
- const { takeRecordsTrigger, observeTrigger, unobserveTrigger, ...init } = options;
7
- return new Observable((subscriber) => {
8
- const observer = new IntersectionObserver((entries) => subscriber.next(entries), init);
9
- const subscriptions = [];
10
- for (const element of toArray(elements)) {
3
+ import { FactoryMap } from '../../utils/factory-map.js';
4
+ import { isDefined, isNumber } from '../../utils/type-guards.js';
5
+ import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
6
+ const observerMap = new FactoryMap((root) => new FactoryMap((rootMargin) => new FactoryMap((threshold) => {
7
+ const observer = new IntersectionObserver((entries) => subject.next(entries), { root, rootMargin, threshold });
8
+ const subject = new Subject;
9
+ return ({
10
+ observer,
11
+ subject,
12
+ elementObservables: new FactoryMap((element) => fromEventPattern((handler) => {
11
13
  observer.observe(element);
12
- }
13
- if (isDefined(takeRecordsTrigger)) {
14
- subscriptions.push(takeRecordsTrigger.subscribe({ next: () => subscriber.next(observer.takeRecords()) }));
15
- }
16
- if (isDefined(observeTrigger)) {
17
- subscriptions.push(observeTrigger.subscribe({ next: (element) => observer.observe(element) }));
18
- }
19
- if (isDefined(unobserveTrigger)) {
20
- subscriptions.push(unobserveTrigger.subscribe({ next: (element) => observer.unobserve(element) }));
21
- }
22
- subscriber.next(observer.takeRecords());
23
- return () => {
24
- observer.disconnect();
25
- subscriptions.forEach((subscription) => subscription.unsubscribe());
26
- };
14
+ return subject.pipe(map((entries) => entries.find((entry) => entry.target == element)), filter(isDefined)).subscribe((entry) => handler(entry));
15
+ }, (_, subscription) => {
16
+ observer.unobserve(element);
17
+ subscription.unsubscribe();
18
+ }).pipe(shareReplay({ bufferSize: 1, refCount: true })), new IterableWeakMap())
27
19
  });
20
+ }, undefined, (threshold) => isNumber(threshold) ? threshold : threshold?.join(','))));
21
+ export function observeIntersection$(element, options) {
22
+ return observerMap.get(options?.root).get(options?.rootMargin).get(options?.threshold).elementObservables.get(element);
28
23
  }
29
24
  export function observeIntersection(elements, options) {
30
- return toSignal(observeIntersection$(elements, options), { requireSync: true });
25
+ return toSignal(observeIntersection$(elements, options));
31
26
  }
@@ -1,8 +1,4 @@
1
- import { Signal } from '../../signals/api.js';
2
- import { Observable } from 'rxjs';
3
- export type ObserveResizeOptions = ResizeObserverOptions & {
4
- observeTrigger?: Observable<Element>;
5
- unobserveTrigger?: Observable<Element>;
6
- };
7
- export declare function observeResize$(elements: Element | (Element | [Element, ResizeObserverOptions])[], options?: ObserveResizeOptions): Observable<ResizeObserverEntry[]>;
8
- export declare function observeResize(elements: Element | (Element | [Element, ResizeObserverOptions])[], options?: ObserveResizeOptions): Signal<ResizeObserverEntry[]>;
1
+ import { type Signal } from '../../signals/api.js';
2
+ import { type Observable } from 'rxjs';
3
+ export declare function observeResize$(element: Element, options?: ResizeObserverOptions): Observable<ResizeObserverEntry>;
4
+ export declare function observeResize(elements: Element, options?: ResizeObserverOptions): Signal<ResizeObserverEntry | undefined>;
@@ -1,35 +1,29 @@
1
+ import { IterableWeakMap } from '../../data-structures/iterable-weak-map.js';
1
2
  import { toSignal } from '../../signals/api.js';
2
- import { toArray } from '../../utils/array/array.js';
3
- import { isArray, isDefined } from '../../utils/type-guards.js';
4
- import { Observable } from 'rxjs';
5
- export function observeResize$(elements, options = {}) {
6
- const { observeTrigger, unobserveTrigger, ...defaultOptions } = options;
7
- return new Observable((subscriber) => {
8
- const observer = new ResizeObserver((entries) => subscriber.next(entries));
9
- const subscriptions = [];
10
- for (const element of toArray(elements)) {
11
- observe(observer, element, defaultOptions);
12
- }
13
- if (isDefined(observeTrigger)) {
14
- subscriptions.push(observeTrigger.subscribe({ next: (element) => observe(observer, element, defaultOptions) }));
15
- }
16
- if (isDefined(unobserveTrigger)) {
17
- subscriptions.push(unobserveTrigger.subscribe({ next: (element) => observer.unobserve(element) }));
18
- }
19
- return () => {
20
- observer.disconnect();
21
- subscriptions.forEach((subscription) => subscription.unsubscribe());
22
- };
23
- });
3
+ import { FactoryMap } from '../../utils/factory-map.js';
4
+ import { isDefined } from '../../utils/type-guards.js';
5
+ import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
6
+ let observer;
7
+ let subject;
8
+ const elementObservablesMap = new FactoryMap(() => ({}), new IterableWeakMap());
9
+ export function observeResize$(element, options) {
10
+ const box = options?.box ?? 'undefined';
11
+ const elementObservables = elementObservablesMap.get(element);
12
+ if (isDefined(elementObservables) && isDefined(elementObservables[box])) {
13
+ return elementObservables[box];
14
+ }
15
+ subject ??= new Subject();
16
+ observer ??= new ResizeObserver((entries) => subject.next(entries));
17
+ const elementResize$ = fromEventPattern((handler) => {
18
+ observer.observe(element, options);
19
+ return subject.pipe(map((entries) => entries.find((entry) => entry.target == element)), filter(isDefined)).subscribe((entry) => handler(entry));
20
+ }, (_, subscription) => {
21
+ observer.unobserve(element);
22
+ subscription.unsubscribe();
23
+ }).pipe(shareReplay({ bufferSize: 1, refCount: true }));
24
+ elementObservables[box] = elementResize$;
25
+ return elementResize$;
24
26
  }
25
27
  export function observeResize(elements, options) {
26
- return toSignal(observeResize$(elements, options), { requireSync: true });
27
- }
28
- function observe(observer, element, defaultOptions) {
29
- if (isArray(element)) {
30
- observer.observe(element[0], element[1] ?? defaultOptions);
31
- }
32
- else {
33
- observer.observe(element, defaultOptions);
34
- }
28
+ return toSignal(observeResize$(elements, options));
35
29
  }
@@ -11,7 +11,7 @@ import { HttpError, HttpErrorReason } from '../../../http/http.error.js';
11
11
  import { Singleton, injectArgument, resolveArgumentType } from '../../../injector/index.js';
12
12
  import { Injector } from '../../../injector/injector.js';
13
13
  import { toArray } from '../../../utils/array/array.js';
14
- import { isDefined } from '../../../utils/type-guards.js';
14
+ import { isBlob, isDefined, isUint8Array } from '../../../utils/type-guards.js';
15
15
  import { HttpClientResponse } from '../http-client-response.js';
16
16
  import { HttpClientAdapter } from '../http-client.adapter.js';
17
17
  let defaultOptions = {};
@@ -26,14 +26,15 @@ let UndiciHttpClientAdapter = class UndiciHttpClientAdapter extends HttpClientAd
26
26
  else if (isDefined(httpClientRequest.body?.text)) {
27
27
  body = httpClientRequest.body.text;
28
28
  }
29
- else if (isDefined(httpClientRequest.body?.buffer)) {
30
- body = httpClientRequest.body.buffer;
31
- }
32
- else if (isDefined(httpClientRequest.body?.blob)) {
33
- body = Readable.from(httpClientRequest.body.blob.stream());
34
- }
35
- else if (isDefined(httpClientRequest.body?.stream)) {
36
- body = Readable.from(httpClientRequest.body.stream);
29
+ else if (isDefined(httpClientRequest.body?.binary)) {
30
+ if (isBlob(httpClientRequest.body.binary)) {
31
+ body = Readable.from(httpClientRequest.body.binary.stream());
32
+ }
33
+ else {
34
+ body = isUint8Array(httpClientRequest.body.binary)
35
+ ? httpClientRequest.body.binary
36
+ : Readable.from(httpClientRequest.body.binary);
37
+ }
37
38
  }
38
39
  else if (isDefined(httpClientRequest.body?.form)) {
39
40
  const params = new URLSearchParams();
@@ -44,6 +45,9 @@ let UndiciHttpClientAdapter = class UndiciHttpClientAdapter extends HttpClientAd
44
45
  }
45
46
  body = params.toString();
46
47
  }
48
+ else if (isDefined(httpClientRequest.body?.formData)) {
49
+ body = httpClientRequest.body.formData;
50
+ }
47
51
  try {
48
52
  const response = await request(httpClientRequest.url, {
49
53
  method: httpClientRequest.method,
@@ -1,5 +1,6 @@
1
1
  import { type CancellationSignal } from '../../cancellation/index.js';
2
2
  import { dispose, type Disposable } from '../../disposable/index.js';
3
+ import type { OneOrMany } from '../../schema/index.js';
3
4
  import type { Record, TypedOmit, UndefinableJson, UndefinableJsonObject } from '../../types.js';
4
5
  import { HttpForm, type HttpFormObject } from '../http-form.js';
5
6
  import { HttpHeaders, type HttpHeadersObject } from '../http-headers.js';
@@ -11,9 +12,8 @@ export type HttpRequestBody = {
11
12
  text?: string;
12
13
  json?: UndefinableJson;
13
14
  form?: HttpForm;
14
- buffer?: Uint8Array;
15
- blob?: Blob;
16
- stream?: ReadableStream<Uint8Array>;
15
+ formData?: FormData;
16
+ binary?: Uint8Array | Blob | ReadableStream<Uint8Array>;
17
17
  };
18
18
  export type HttpRequestAuthorization = {
19
19
  basic?: {
@@ -23,18 +23,17 @@ export type HttpRequestAuthorization = {
23
23
  bearer?: string;
24
24
  token?: string;
25
25
  };
26
+ export type HttpFormDataObjectValue = string | number | boolean | Uint8Array | Blob;
27
+ export type HttpFormDataObject = Record<string, OneOrMany<HttpFormDataObjectValue>>;
26
28
  export type HttpClientRequestOptions = Partial<TypedOmit<HttpClientRequest, 'url' | 'method' | 'abortSignal' | 'abort' | 'headers' | 'query' | 'body'>> & {
27
29
  urlParameter?: HttpUrlParametersObject | HttpUrlParameters;
28
30
  headers?: HttpHeadersObject | HttpHeaders;
29
31
  query?: HttpQueryObject | HttpQuery;
30
32
  credentials?: HttpRequestCredentials;
31
33
  authorization?: HttpRequestAuthorization;
32
- body?: {
33
- text?: string;
34
- json?: UndefinableJson;
34
+ body?: TypedOmit<HttpRequestBody, 'form' | 'formData'> & {
35
35
  form?: HttpFormObject | HttpForm;
36
- buffer?: Uint8Array;
37
- stream?: ReadableStream<Uint8Array>;
36
+ formData?: HttpFormDataObject | FormData;
38
37
  };
39
38
  abortSignal?: CancellationSignal;
40
39
  };
@@ -1,7 +1,8 @@
1
1
  import { CancellationToken } from '../../cancellation/index.js';
2
2
  import { dispose } from '../../disposable/index.js';
3
3
  import { clone } from '../../utils/clone.js';
4
- import { isDefined, isString, isUndefined } from '../../utils/type-guards.js';
4
+ import { objectEntries } from '../../utils/object/object.js';
5
+ import { isArray, isBlob, isDefined, isString, isUint8Array, isUndefined } from '../../utils/type-guards.js';
5
6
  import { HttpForm } from '../http-form.js';
6
7
  import { HttpHeaders } from '../http-headers.js';
7
8
  import { HttpQuery } from '../http-query.js';
@@ -149,5 +150,28 @@ function normalizeBody(body) {
149
150
  if (isDefined(normalizedBody.form)) {
150
151
  normalizedBody.form = new HttpForm(normalizedBody.form);
151
152
  }
153
+ if (isDefined(normalizedBody.formData) && !(normalizedBody.formData instanceof FormData)) {
154
+ const formData = new FormData();
155
+ for (const [key, value] of objectEntries(normalizedBody.formData)) {
156
+ if (isArray(value)) {
157
+ for (const item of value) {
158
+ formData.append(key, convertFormDataObjectValue(item));
159
+ }
160
+ }
161
+ else {
162
+ formData.set(key, convertFormDataObjectValue(value));
163
+ }
164
+ }
165
+ normalizedBody.formData = formData;
166
+ }
152
167
  return normalizedBody;
153
168
  }
169
+ function convertFormDataObjectValue(value) {
170
+ if (isString(value) || isBlob(value)) {
171
+ return value;
172
+ }
173
+ if (isUint8Array(value)) {
174
+ return new Blob([value]);
175
+ }
176
+ return String(value);
177
+ }
@@ -15,7 +15,7 @@ import { encodeUtf8 } from '../../utils/encoding.js';
15
15
  import { composeAsyncMiddleware } from '../../utils/middleware.js';
16
16
  import { objectEntries } from '../../utils/object/object.js';
17
17
  import { readableStreamFromPromise } from '../../utils/stream/readable-stream-from-promise.js';
18
- import { assertDefined, isArray, isDefined, isObject, isUndefined } from '../../utils/type-guards.js';
18
+ import { assertDefined, isArray, isBlob, isDefined, isObject, isUndefined } from '../../utils/type-guards.js';
19
19
  import { buildUrl } from '../../utils/url-builder.js';
20
20
  import { HttpHeaders } from '../http-headers.js';
21
21
  import { HttpError, HttpErrorReason } from '../http.error.js';
@@ -217,11 +217,13 @@ function getAddRequestHeadersMiddleware(defaultHeaders) {
217
217
  else if (isDefined(body.form)) {
218
218
  request.headers.contentType = 'application/x-www-form-urlencoded';
219
219
  }
220
- else if (isDefined(body.blob)) {
221
- request.headers.contentType = (body.blob.type.length > 0) ? body.blob.type : 'application/octet-stream';
220
+ else if (isDefined(body.formData)) {
221
+ // Form data content type header has to be set by implementation because of boundary value
222
222
  }
223
- else if (isDefined(body.stream) || isDefined(body.buffer)) {
224
- request.headers.contentType = 'application/octet-stream';
223
+ else if (isDefined(body.binary)) {
224
+ request.headers.contentType = ((isBlob(body.binary) && body.binary.type.length > 0))
225
+ ? body.binary.type
226
+ : 'application/octet-stream';
225
227
  }
226
228
  }
227
229
  if (isDefined(authorization) && isUndefined(request.headers.authorization)) {
@@ -1,4 +1,4 @@
1
- import type { Observable } from 'rxjs';
1
+ import { type Observable } from 'rxjs';
2
2
  export declare class ObservableFinalizationRegistry<T> extends FinalizationRegistry<T> {
3
3
  private readonly finalizeSubject;
4
4
  readonly finalize$: Observable<T>;
@@ -0,0 +1,16 @@
1
+ import type { Record, TypedOmit } from '../types.js';
2
+ export declare abstract class EntityMetadata {
3
+ revision: number;
4
+ revisionTimestamp: number;
5
+ createTimestamp: number;
6
+ deleteTimestamp: number | null;
7
+ attributes: Record;
8
+ }
9
+ export declare abstract class Entity {
10
+ id: string;
11
+ metadata: EntityMetadata;
12
+ }
13
+ export type NewEntity<T extends Entity> = TypedOmit<T, 'id' | 'metadata'> & {
14
+ id?: string;
15
+ metadata?: Partial<Pick<EntityMetadata, 'attributes'>>;
16
+ };
package/orm/entity.js ADDED
@@ -0,0 +1,49 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { NumberProperty, Property, any, record } from '../schema/index.js';
11
+ export class EntityMetadata {
12
+ revision;
13
+ revisionTimestamp;
14
+ createTimestamp;
15
+ deleteTimestamp;
16
+ attributes;
17
+ }
18
+ __decorate([
19
+ Property(),
20
+ __metadata("design:type", Number)
21
+ ], EntityMetadata.prototype, "revision", void 0);
22
+ __decorate([
23
+ Property(),
24
+ __metadata("design:type", Number)
25
+ ], EntityMetadata.prototype, "revisionTimestamp", void 0);
26
+ __decorate([
27
+ Property(),
28
+ __metadata("design:type", Number)
29
+ ], EntityMetadata.prototype, "createTimestamp", void 0);
30
+ __decorate([
31
+ NumberProperty({ nullable: true }),
32
+ __metadata("design:type", Object)
33
+ ], EntityMetadata.prototype, "deleteTimestamp", void 0);
34
+ __decorate([
35
+ Property({ schema: record(any(), any()) }),
36
+ __metadata("design:type", Object)
37
+ ], EntityMetadata.prototype, "attributes", void 0);
38
+ export class Entity {
39
+ id;
40
+ metadata;
41
+ }
42
+ __decorate([
43
+ Property(),
44
+ __metadata("design:type", String)
45
+ ], Entity.prototype, "id", void 0);
46
+ __decorate([
47
+ Property(EntityMetadata),
48
+ __metadata("design:type", EntityMetadata)
49
+ ], Entity.prototype, "metadata", void 0);
package/orm/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './entity.js';
2
+ export * from './query.js';
3
+ export * from './repository.js';
package/orm/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './entity.js';
2
+ export * from './query.js';
3
+ export * from './repository.js';
package/orm/query.d.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { Flatten, Record } from '../types.js';
2
+ import type { Geometry } from '../types/geo-json.js';
3
+ export type LogicalQuery<T = any> = LogicalAndQuery<T> | LogicalOrQuery<T> | LogicalNorQuery<T>;
4
+ export type LogicalQueryTypes = keyof (LogicalAndQuery & LogicalOrQuery & LogicalNorQuery);
5
+ export declare const allLogicalQueryTypes: LogicalQueryTypes[];
6
+ export type ComparisonQueryBody<T = any> = {
7
+ [P in keyof T]?: ComparisonQueryOrValue<T[P]>;
8
+ } & Record<ComparisonQueryOrValue>;
9
+ export type ComparisonQueryOrValue<T = any> = ComparisonQuery<T> | T | Flatten<T>;
10
+ export type ComparisonQuery<T = any> = Partial<ComparisonNotQuery<T> & ComparisonEqualsQuery<T> & ComparisonNotEqualsQuery<T> & ComparisonExistsQuery & ComparisonItemQuery<T> & ComparisonInQuery<T> & ComparisonNotInQuery<T> & ComparisonAllQuery<T> & ComparisonGreaterThanQuery<T> & ComparisonGreaterThanOrEqualsQuery<T> & ComparisonLessThanQuery<T> & ComparisonLessThanOrEqualsQuery<T> & ComparisonRegexQuery & ComparisonTextQuery & ComparisonGeoShapeQuery & ComparisonGeoDistanceQuery>;
11
+ export type ComparisonQueryTypes = keyof ComparisonQuery;
12
+ export declare const allComparisonQueryTypes: ComparisonQueryTypes[];
13
+ export type SpecialQuery<T = any> = Partial<TextSpanQuery<T>>;
14
+ export type SpecialQueryTypes = keyof SpecialQuery;
15
+ export declare const allSpecialQueryTypes: SpecialQueryTypes[];
16
+ export type Query<T = any> = LogicalQuery<T> | (ComparisonQueryBody<T> & SpecialQuery<T>);
17
+ export type QueryTypes = LogicalQueryTypes | ComparisonQueryTypes | SpecialQueryTypes;
18
+ export declare const allQueryTypes: ("$and" | "$or" | "$nor" | "$not" | "$eq" | "$neq" | "$exists" | "$item" | "$in" | "$nin" | "$all" | "$gt" | "$gte" | "$lt" | "$lte" | "$regex" | "$text" | "$geoShape" | "$geoDistance" | "$textSpan")[];
19
+ export type Order = 'asc' | 'desc';
20
+ export declare const allOrders: Order[];
21
+ export type Operator = 'and' | 'or';
22
+ export declare const allOperators: Operator[];
23
+ export type LogicalAndQuery<T = any> = {
24
+ $and: Query<T>[];
25
+ };
26
+ export type LogicalOrQuery<T = any> = {
27
+ $or: Query<T>[];
28
+ };
29
+ export type LogicalNorQuery<T = any> = {
30
+ $nor: Query<T>[];
31
+ };
32
+ export type ComparisonValue<T> = T | Flatten<T>;
33
+ export type ComparisonValueWithRegex<T> = T extends string ? ComparisonValue<T | RegExp> : T extends string[] ? ComparisonValue<(Flatten<T> | RegExp)[]> : (T | Flatten<T>);
34
+ export type ComparisonNotQuery<T = any> = {
35
+ $not: ComparisonQuery<T>;
36
+ };
37
+ export type ComparisonEqualsQuery<T = any> = {
38
+ $eq: ComparisonValueWithRegex<T>;
39
+ };
40
+ export type ComparisonNotEqualsQuery<T = any> = {
41
+ $neq: ComparisonValueWithRegex<T>;
42
+ };
43
+ export type ComparisonExistsQuery = {
44
+ $exists: ComparisonValue<boolean>;
45
+ };
46
+ export type ComparisonItemQuery<T = any> = {
47
+ $item: T extends (infer U)[] ? U extends Record<any, any> ? Query<U> : ComparisonQuery<U> : never;
48
+ };
49
+ export type ComparisonInQuery<T = any> = {
50
+ $in: ComparisonValueWithRegex<T>[];
51
+ };
52
+ export type ComparisonNotInQuery<T = any> = {
53
+ $nin: ComparisonValueWithRegex<T>[];
54
+ };
55
+ export type ComparisonAllQuery<T = any> = {
56
+ $all: ComparisonValueWithRegex<T>[];
57
+ };
58
+ export type ComparisonGreaterThanQuery<T = any> = {
59
+ $gt: ComparisonValue<T>;
60
+ };
61
+ export type ComparisonGreaterThanOrEqualsQuery<T = any> = {
62
+ $gte: ComparisonValue<T>;
63
+ };
64
+ export type ComparisonLessThanQuery<T = any> = {
65
+ $lt: ComparisonValue<T>;
66
+ };
67
+ export type ComparisonLessThanOrEqualsQuery<T = any> = {
68
+ $lte: ComparisonValue<T>;
69
+ };
70
+ export type ComparisonRegexQuery = {
71
+ $regex: string | RegExp | {
72
+ pattern: string;
73
+ flags: string;
74
+ };
75
+ };
76
+ export type ComparisonTextQuery = {
77
+ $text: string | {
78
+ text: string;
79
+ operator?: Operator;
80
+ };
81
+ };
82
+ export type GeoShapeRelation = 'intersects' | 'within' | 'disjoint' | 'contains';
83
+ export type ComparisonGeoShapeQuery = {
84
+ $geoShape: {
85
+ geometry: Geometry;
86
+ relation: GeoShapeRelation;
87
+ };
88
+ };
89
+ export type ComparisonGeoDistanceQuery = {
90
+ $geoDistance: {
91
+ longitude: number;
92
+ latitude: number;
93
+ /**
94
+ * Maximum distance in meters
95
+ */
96
+ maxDistance?: number;
97
+ /**
98
+ * Minimum distance in meters
99
+ */
100
+ minDistance?: number;
101
+ };
102
+ };
103
+ export type TextSpanQueryMode = 'best' | 'most' | 'cross';
104
+ export declare const allTextSpanQueryModes: TextSpanQueryMode[];
105
+ export type TextSpanQuery<T = any> = {
106
+ $textSpan: {
107
+ fields: (Extract<keyof T, string>)[];
108
+ text: string;
109
+ mode?: TextSpanQueryMode;
110
+ operator?: Operator;
111
+ };
112
+ };
package/orm/query.js ADDED
@@ -0,0 +1,7 @@
1
+ export const allLogicalQueryTypes = ['$and', '$or', '$nor'];
2
+ export const allComparisonQueryTypes = ['$all', '$not', '$eq', '$exists', '$gt', '$gte', '$in', '$item', '$lt', '$lte', '$neq', '$nin', '$regex', '$text', '$geoDistance', '$geoShape'];
3
+ export const allSpecialQueryTypes = ['$textSpan'];
4
+ export const allQueryTypes = [...allLogicalQueryTypes, ...allComparisonQueryTypes, ...allSpecialQueryTypes];
5
+ export const allOrders = ['asc', 'desc'];
6
+ export const allOperators = ['and', 'or'];
7
+ export const allTextSpanQueryModes = ['best', 'most', 'cross'];
@@ -0,0 +1,50 @@
1
+ import type { Paths, Type, TypedOmit } from '../types.js';
2
+ import type { Entity, EntityMetadata, NewEntity } from './entity.js';
3
+ import type { Query } from './query.js';
4
+ export declare const repositoryType: unique symbol;
5
+ export type OrderOptions<T extends Entity> = {
6
+ order?: {
7
+ [P in Paths<T>]?: 1 | -1 | 'asc' | 'desc';
8
+ };
9
+ };
10
+ export type LoadOptions<T extends Entity> = OrderOptions<T> & {
11
+ offset?: number;
12
+ };
13
+ export type LoadManyOptions<T extends Entity> = LoadOptions<T> & {
14
+ limit?: number;
15
+ };
16
+ export type EntityMetadataUpdate = {
17
+ metadata?: Partial<EntityMetadata>;
18
+ };
19
+ export type EntityUpdate<T extends Entity> = Partial<TypedOmit<T, 'metadata'>> & EntityMetadataUpdate;
20
+ export declare abstract class EntityRepository<T extends Entity = Entity> {
21
+ readonly type: Type<T>;
22
+ abstract load(id: string): Promise<T>;
23
+ abstract tryLoad(id: string): Promise<T | undefined>;
24
+ abstract loadByFilter(query: Query<T>, options?: LoadOptions<T>): Promise<T>;
25
+ abstract tryLoadByFilter(query: Query<T>, options?: LoadOptions<T>): Promise<T | undefined>;
26
+ abstract loadMany(ids: string[], options?: LoadManyOptions<T>): Promise<T[]>;
27
+ abstract loadManyCursor(ids: string[], options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
28
+ abstract loadManyByFilter(query: Query<T>, options?: LoadManyOptions<T>): Promise<T[]>;
29
+ abstract loadManyByFilterCursor(query: Query<T>, options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
30
+ abstract loadAll(options?: LoadManyOptions<T>): Promise<T[]>;
31
+ abstract loadAllCursor(options?: LoadManyOptions<T>): AsyncIterableIterator<T>;
32
+ abstract count(): Promise<number>;
33
+ abstract countByFilter(query: Query<T>): Promise<number>;
34
+ abstract has(id: string): Promise<boolean>;
35
+ abstract hasByFilter(query: Query<T>): Promise<boolean>;
36
+ abstract hasMany(ids: string[]): Promise<string[]>;
37
+ abstract hasAll(ids: string[]): Promise<boolean>;
38
+ abstract insert(entity: NewEntity<T>): Promise<T>;
39
+ abstract insertMany(entities: NewEntity<T>[]): Promise<T[]>;
40
+ abstract update(id: string, update: EntityUpdate<T>): Promise<void>;
41
+ abstract updateByFilter(query: Query<T>, update: EntityUpdate<T>): Promise<void>;
42
+ abstract updateMany(ids: string[], update: EntityUpdate<T>): Promise<void>;
43
+ abstract updateManyByFilter(filter: Query<T>, update: EntityUpdate<T>): Promise<void>;
44
+ abstract delete<U extends T>(entity: U): Promise<boolean>;
45
+ abstract deleteMany<U extends T>(entities: U[]): Promise<number>;
46
+ abstract deleteById(id: string): Promise<boolean>;
47
+ abstract deleteManyById(ids: string[]): Promise<number>;
48
+ abstract deleteByFilter<U extends T = T>(query: Query<U>): Promise<boolean>;
49
+ abstract deleteManyByFilter<U extends T = T>(query: Query<U>): Promise<number>;
50
+ }
@@ -0,0 +1,4 @@
1
+ export const repositoryType = Symbol('repositoryType');
2
+ export class EntityRepository {
3
+ type;
4
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.90.85",
3
+ "version": "0.90.89",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -115,7 +115,7 @@
115
115
  },
116
116
  "devDependencies": {
117
117
  "@mxssfd/typedoc-theme": "1.1",
118
- "@stylistic/eslint-plugin": "2.1",
118
+ "@stylistic/eslint-plugin": "2.2",
119
119
  "@types/chroma-js": "2.4",
120
120
  "@types/koa__router": "12.0",
121
121
  "@types/luxon": "3.4",
@@ -134,7 +134,7 @@
134
134
  "typescript": "5.4"
135
135
  },
136
136
  "peerDependencies": {
137
- "@elastic/elasticsearch": "^8.13",
137
+ "@elastic/elasticsearch": "^8.14",
138
138
  "@koa/router": "^12.0",
139
139
  "@tstdl/angular": "^0.90",
140
140
  "@zxcvbn-ts/core": "^3.0",
@@ -1,5 +1,5 @@
1
1
  import type { OneOrMany, Record, TypedOmit } from '../../types.js';
2
2
  import type { SchemaTestable } from '../schema.js';
3
- import type { ObjectSchema } from '../types/index.js';
3
+ import { type ObjectSchema } from '../types/index.js';
4
4
  export type RecordOptions<T extends Record = Record> = TypedOmit<ObjectSchema<T>, 'properties' | 'unknownProperties' | 'unknownPropertiesKey' | 'mask'>;
5
5
  export declare function record<K extends PropertyKey, T>(keySchema: OneOrMany<SchemaTestable<K>>, valueSchema: OneOrMany<SchemaTestable<T>>, options?: RecordOptions): ObjectSchema<Record<K, T>>;
@@ -1,4 +1,3 @@
1
- import { FactoryMap } from '../factory-map.js';
2
1
  import { isAsyncIterable } from './is-async-iterable.js';
3
2
  export async function groupToMapAsync(iterable, selector) {
4
3
  return isAsyncIterable(iterable)
@@ -6,20 +5,26 @@ export async function groupToMapAsync(iterable, selector) {
6
5
  : sync(iterable, selector);
7
6
  }
8
7
  async function async(iterable, selector) {
9
- const map = new FactoryMap(() => []);
8
+ const map = new Map();
10
9
  let index = 0;
11
10
  for await (const item of iterable) {
12
11
  const groupKey = await selector(item, index++);
12
+ if (!map.has(groupKey)) {
13
+ map.set(groupKey, []);
14
+ }
13
15
  map.get(groupKey).push(item);
14
16
  }
15
- return map.backingMap;
17
+ return map;
16
18
  }
17
19
  async function sync(iterable, selector) {
18
- const map = new FactoryMap(() => []);
20
+ const map = new Map();
19
21
  let index = 0;
20
22
  for (const item of iterable) {
21
23
  const groupKey = await selector(item, index++);
24
+ if (!map.has(groupKey)) {
25
+ map.set(groupKey, []);
26
+ }
22
27
  map.get(groupKey).push(item);
23
28
  }
24
- return map.backingMap;
29
+ return map;
25
30
  }
@@ -1,10 +1,12 @@
1
- import { FactoryMap } from '../../factory-map.js';
2
1
  import { parallelForEach } from './for-each.js';
3
2
  export async function parallelGroup(iterable, concurrency, selector) {
4
- const map = new FactoryMap(() => []);
3
+ const map = new Map();
5
4
  await parallelForEach(iterable, concurrency, async (item, index) => {
6
5
  const groupKey = await selector(item, index);
6
+ if (!map.has(groupKey)) {
7
+ map.set(groupKey, []);
8
+ }
7
9
  map.get(groupKey).push(item);
8
10
  });
9
- return map.backingMap;
11
+ return map;
10
12
  }
@@ -1,10 +1,16 @@
1
1
  export type Factory<Key, Value> = (key: Key) => Value;
2
- /** same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
3
- export declare class FactoryMap<K, V> implements Map<K, V> {
2
+ export type FactoryItemIdentityProvider<K, I> = (key: K) => I;
3
+ /** Same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
4
+ export declare class FactoryMap<K, V, I = K> implements Map<K, V> {
4
5
  private readonly factory;
5
6
  readonly [Symbol.toStringTag]: 'FactoryMap';
6
- readonly backingMap: Map<K, V>;
7
+ readonly backingMap: Map<I, {
8
+ key: K;
9
+ value: V;
10
+ }>;
11
+ readonly identityProvider: FactoryItemIdentityProvider<K, I>;
7
12
  get size(): number;
13
+ constructor(factory: Factory<K, V>, backingMap: Map<I, V> | undefined, identityProvider: FactoryItemIdentityProvider<K, I>);
8
14
  constructor(factory: Factory<K, V>, backingMap?: Map<K, V>);
9
15
  clear(): void;
10
16
  has(key: K): boolean;
@@ -12,7 +18,7 @@ export declare class FactoryMap<K, V> implements Map<K, V> {
12
18
  getWithoutBuild(key: K): V | undefined;
13
19
  set(key: K, value: V): this;
14
20
  delete(key: K): boolean;
15
- forEach(callback: (value: V, key: K, map: FactoryMap<K, V>) => void, thisArg?: any): void;
21
+ forEach(callback: (value: V, key: K, map: FactoryMap<K, V, I>) => void, thisArg?: any): void;
16
22
  [Symbol.iterator](): IterableIterator<[K, V]>;
17
23
  entries(): IterableIterator<[K, V]>;
18
24
  keys(): IterableIterator<K>;
@@ -1,55 +1,66 @@
1
- /** same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
1
+ /** Same as {@link Map}, except that it will build the value with the provided factory on {@link get} if it doesnt exist */
2
2
  export class FactoryMap {
3
3
  factory;
4
4
  [Symbol.toStringTag];
5
5
  backingMap;
6
+ identityProvider;
6
7
  get size() {
7
8
  return this.backingMap.size;
8
9
  }
9
- constructor(factory, backingMap) {
10
+ constructor(factory, backingMap, identityProvider) {
10
11
  this.factory = factory;
11
12
  this[Symbol.toStringTag] = 'FactoryMap';
12
13
  this.backingMap = backingMap ?? new Map();
14
+ this.identityProvider = identityProvider ?? ((key) => key);
13
15
  }
14
16
  clear() {
15
17
  this.backingMap.clear();
16
18
  }
17
19
  has(key) {
18
- return this.backingMap.has(key);
20
+ return this.backingMap.has(this.identityProvider(key));
19
21
  }
20
22
  get(key) {
21
- const has = this.backingMap.has(key);
23
+ const identity = this.identityProvider(key);
24
+ const has = this.backingMap.has(identity);
22
25
  if (has) {
23
- return this.backingMap.get(key);
26
+ return this.backingMap.get(identity).value;
24
27
  }
25
28
  const value = this.factory(key);
26
- this.backingMap.set(key, value);
29
+ this.backingMap.set(identity, { key, value });
27
30
  return value;
28
31
  }
29
32
  getWithoutBuild(key) {
30
- return this.backingMap.get(key);
33
+ return this.backingMap.get(this.identityProvider(key))?.value;
31
34
  }
32
35
  set(key, value) {
33
- this.backingMap.set(key, value);
36
+ this.backingMap.set(this.identityProvider(key), { key, value });
34
37
  return this;
35
38
  }
36
39
  delete(key) {
37
- return this.backingMap.delete(key);
40
+ return this.backingMap.delete(this.identityProvider(key));
38
41
  }
39
42
  forEach(callback, thisArg) {
40
43
  const boundCallback = callback.bind(thisArg);
41
- this.backingMap.forEach((value, key) => boundCallback(value, key, this));
44
+ this.backingMap.forEach(({ key, value }) => boundCallback(value, key, this));
42
45
  }
43
46
  *[Symbol.iterator]() {
44
- yield* this.backingMap[Symbol.iterator]();
47
+ for (const [, { key, value }] of this.backingMap) {
48
+ yield [key, value];
49
+ }
45
50
  }
46
51
  *entries() {
47
- yield* this.backingMap.entries();
52
+ for (const [, { key, value }] of this.backingMap.entries()) {
53
+ yield [key, value];
54
+ }
48
55
  }
49
56
  *keys() {
50
- yield* this.backingMap.keys();
57
+ for (const [, { key }] of this.backingMap.entries()) {
58
+ yield key;
59
+ }
51
60
  }
52
61
  *values() {
53
- yield* this.backingMap.values();
62
+ for (const [, { value }] of this.backingMap.entries()) {
63
+ yield value;
64
+ }
54
65
  }
55
66
  }
@@ -1,10 +1,12 @@
1
- import { FactoryMap } from '../factory-map.js';
2
1
  export function groupToMap(iterable, selector) {
3
- const map = new FactoryMap(() => []);
2
+ const map = new Map();
4
3
  let index = 0;
5
4
  for (const item of iterable) {
6
5
  const groupKey = selector(item, index++);
6
+ if (!map.has(groupKey)) {
7
+ map.set(groupKey, []);
8
+ }
7
9
  map.get(groupKey).push(item);
8
10
  }
9
- return map.backingMap;
11
+ return map;
10
12
  }