@naturalcycles/js-lib 15.34.0 → 15.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ import type { AbortablePredicate, FalsyValue, Mapper, Predicate, SortDirection,
5
5
  *
6
6
  * @param array The array to process.
7
7
  * @param size The length of each chunk.
8
- * @return Returns the new array containing chunks.
8
+ * @returns Returns the new array containing chunks.
9
9
  *
10
10
  * https://lodash.com/docs#chunk
11
11
  *
@@ -6,7 +6,7 @@ import { END } from '../types.js';
6
6
  *
7
7
  * @param array The array to process.
8
8
  * @param size The length of each chunk.
9
- * @return Returns the new array containing chunks.
9
+ * @returns Returns the new array containing chunks.
10
10
  *
11
11
  * https://lodash.com/docs#chunk
12
12
  *
@@ -79,8 +79,7 @@ export function _pushUniqBy(a, mapper, ...items) {
79
79
  */
80
80
  export function _uniqBy(arr, mapper) {
81
81
  const map = new Map();
82
- for (let i = 0; i < arr.length; i++) {
83
- const item = arr[i];
82
+ for (const item of arr) {
84
83
  const key = item === undefined || item === null ? item : mapper(item);
85
84
  if (!map.has(key))
86
85
  map.set(key, item);
@@ -109,8 +108,7 @@ export function _uniqBy(arr, mapper) {
109
108
  */
110
109
  export function _by(items, mapper) {
111
110
  const map = {};
112
- for (let i = 0; i < items.length; i++) {
113
- const v = items[i];
111
+ for (const v of items) {
114
112
  const k = mapper(v);
115
113
  if (k !== undefined) {
116
114
  map[k] = v;
@@ -123,8 +121,7 @@ export function _by(items, mapper) {
123
121
  */
124
122
  export function _mapBy(items, mapper) {
125
123
  const map = new Map();
126
- for (let i = 0; i < items.length; i++) {
127
- const item = items[i];
124
+ for (const item of items) {
128
125
  const key = mapper(item);
129
126
  if (key !== undefined) {
130
127
  map.set(key, item);
@@ -145,8 +142,7 @@ export function _mapBy(items, mapper) {
145
142
  */
146
143
  export function _groupBy(items, mapper) {
147
144
  const map = {};
148
- for (let i = 0; i < items.length; i++) {
149
- const item = items[i];
145
+ for (const item of items) {
150
146
  const key = mapper(item);
151
147
  if (key !== undefined) {
152
148
  ;
@@ -444,8 +440,7 @@ export function _maxByOrUndefined(array, mapper) {
444
440
  return;
445
441
  let maxItem;
446
442
  let max;
447
- for (let i = 0; i < array.length; i++) {
448
- const item = array[i];
443
+ for (const item of array) {
449
444
  const v = mapper(item);
450
445
  if (v !== undefined && (max === undefined || v > max)) {
451
446
  maxItem = item;
@@ -459,8 +454,7 @@ export function _minByOrUndefined(array, mapper) {
459
454
  return;
460
455
  let minItem;
461
456
  let min;
462
- for (let i = 0; i < array.length; i++) {
463
- const item = array[i];
457
+ for (const item of array) {
464
458
  const v = mapper(item);
465
459
  if (v !== undefined && (min === undefined || v < min)) {
466
460
  minItem = item;
@@ -25,12 +25,12 @@ export interface AsyncMemoInstance {
25
25
  getCache: (instance: AnyAsyncFunction) => AsyncMemoCache | undefined;
26
26
  }
27
27
  /**
28
- * Like @_Memo, but allowing async MemoCache implementation.
28
+ * Like `@_Memo`, but allowing async MemoCache implementation.
29
29
  *
30
- * Implementation is more complex than @_Memo, because it needs to handle "in-flight" Promises
30
+ * Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
31
31
  * while waiting for cache to resolve, to prevent "async swarm" issue.
32
32
  *
33
- * @experimental consider normal @_Memo for most of the cases, it's stable and predictable
33
+ * @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
34
34
  */
35
35
  export declare const _AsyncMemo: <FN>(opt: AsyncMemoOptions<FN>) => MethodDecorator<FN>;
36
36
  /**
@@ -3,12 +3,12 @@ import { _objectAssign, MISS } from '../types.js';
3
3
  import { _getTargetMethodSignature } from './decorator.util.js';
4
4
  import { jsonMemoSerializer } from './memo.util.js';
5
5
  /**
6
- * Like @_Memo, but allowing async MemoCache implementation.
6
+ * Like `@_Memo`, but allowing async MemoCache implementation.
7
7
  *
8
- * Implementation is more complex than @_Memo, because it needs to handle "in-flight" Promises
8
+ * Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
9
9
  * while waiting for cache to resolve, to prevent "async swarm" issue.
10
10
  *
11
- * @experimental consider normal @_Memo for most of the cases, it's stable and predictable
11
+ * @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
12
12
  */
13
13
  // eslint-disable-next-line @typescript-eslint/naming-convention
14
14
  export const _AsyncMemo = (opt) => (target, key, descriptor) => {
@@ -70,7 +70,7 @@ export function _LogMethod(opt = {}) {
70
70
  return descriptor;
71
71
  };
72
72
  }
73
- // eslint-disable-next-line max-params
73
+ // oxlint-disable-next-line max-params
74
74
  function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
75
75
  const millis = Date.now() - started;
76
76
  const t = ['<<', callSignature, 'took', _ms(millis)];
@@ -83,7 +83,7 @@ export interface AppErrorOptions {
83
83
  * data - optional "any" payload.
84
84
  * data.userFriendly - if present, will be displayed to the User as is.
85
85
  *
86
- * Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
86
+ * Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
87
87
  */
88
88
  export declare class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
89
89
  data: DATA_TYPE;
@@ -221,7 +221,7 @@ export function _errorDataAppend(err, data) {
221
221
  * data - optional "any" payload.
222
222
  * data.userFriendly - if present, will be displayed to the User as is.
223
223
  *
224
- * Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
224
+ * Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
225
225
  */
226
226
  export class AppError extends Error {
227
227
  data;
@@ -1,4 +1,4 @@
1
- import type { AnyObject, BaseDBEntity, IsoDate, UnixTimestamp } from '../types.js';
1
+ import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js';
2
2
  import type { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './jsonSchema.model.js';
3
3
  export interface JsonSchemaBuilder<T = unknown> {
4
4
  build: () => JsonSchema<T>;
@@ -20,8 +20,17 @@ export declare const j: {
20
20
  unixTimestamp(): JsonSchemaNumberBuilder<UnixTimestamp>;
21
21
  unixTimestamp2000(): JsonSchemaNumberBuilder<UnixTimestamp>;
22
22
  string<T extends string = string>(): JsonSchemaStringBuilder<T>;
23
+ /**
24
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
25
+ */
23
26
  isoDate(): JsonSchemaStringBuilder<IsoDate>;
27
+ /**
28
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
29
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
30
+ */
31
+ isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
24
32
  object: typeof object;
33
+ dbEntity<T extends AnyObject>(props: T): JsonSchemaObjectBuilder<BaseDBEntity & { [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<infer U, any> ? U : never; }>;
25
34
  rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T>;
26
35
  array<T extends JsonSchemaAnyBuilder<any>>(itemSchema: T): JsonSchemaArrayBuilder<T["infer"]>;
27
36
  tuple<T extends any[] = unknown[]>(items: JsonSchemaAnyBuilder[]): JsonSchemaTupleBuilder<T>;
@@ -87,13 +96,13 @@ export declare class JsonSchemaNumberBuilder<T extends number = number> extends
87
96
  }
88
97
  export declare class JsonSchemaStringBuilder<T extends string = string> extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>> {
89
98
  constructor();
99
+ regex(pattern: RegExp): this;
90
100
  pattern(pattern: string): this;
91
101
  min(minLength: number): this;
92
102
  max(maxLength: number): this;
93
103
  length(minLength: number, maxLength: number): this;
94
104
  format(format: string): this;
95
105
  email: () => this;
96
- isoDate: () => this;
97
106
  url: () => this;
98
107
  ipv4: () => this;
99
108
  ipv6: () => this;
@@ -108,6 +117,15 @@ export declare class JsonSchemaStringBuilder<T extends string = string> extends
108
117
  toLowerCase: (toLowerCase?: boolean) => this;
109
118
  toUpperCase: (toUpperCase?: boolean) => this;
110
119
  branded<B extends string>(): JsonSchemaStringBuilder<B>;
120
+ /**
121
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
122
+ */
123
+ isoDate(): JsonSchemaStringBuilder<IsoDate>;
124
+ /**
125
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
126
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
127
+ */
128
+ isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
111
129
  private transformModify;
112
130
  }
113
131
  export declare class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>> {
@@ -56,12 +56,31 @@ export const j = {
56
56
  string() {
57
57
  return new JsonSchemaStringBuilder();
58
58
  },
59
+ /**
60
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
61
+ */
59
62
  isoDate() {
60
63
  return new JsonSchemaStringBuilder().isoDate();
61
64
  },
65
+ /**
66
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
67
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
68
+ */
69
+ isoDateTime() {
70
+ return new JsonSchemaStringBuilder().isoDateTime();
71
+ },
62
72
  // email: () => new JsonSchemaStringBuilder().email(),
63
73
  // complex types
64
74
  object,
75
+ dbEntity(props) {
76
+ return j
77
+ .object({
78
+ id: j.string(),
79
+ created: j.unixTimestamp2000(),
80
+ updated: j.unixTimestamp2000(),
81
+ })
82
+ .extend(j.object(props));
83
+ },
65
84
  rootObject(props) {
66
85
  return new JsonSchemaObjectBuilder().addProperties(props).$schemaDraft7();
67
86
  },
@@ -222,6 +241,9 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
222
241
  type: 'string',
223
242
  });
224
243
  }
244
+ regex(pattern) {
245
+ return this.pattern(pattern.source);
246
+ }
225
247
  pattern(pattern) {
226
248
  Object.assign(this.schema, { pattern });
227
249
  return this;
@@ -243,7 +265,6 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
243
265
  return this;
244
266
  }
245
267
  email = () => this.format('email');
246
- isoDate = () => this.format('date').description('IsoDate'); // todo: make it custom isoDate instead
247
268
  url = () => this.format('url');
248
269
  ipv4 = () => this.format('ipv4');
249
270
  ipv6 = () => this.format('ipv6');
@@ -260,6 +281,19 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
260
281
  branded() {
261
282
  return this;
262
283
  }
284
+ /**
285
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
286
+ */
287
+ isoDate() {
288
+ return this.format('IsoDate').branded().description('IsoDate');
289
+ }
290
+ /**
291
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
292
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
293
+ */
294
+ isoDateTime() {
295
+ return this.format('IsoDateTime').branded().description('IsoDateTime');
296
+ }
263
297
  transformModify(t, add) {
264
298
  if (add) {
265
299
  this.schema.transform = _uniq([...(this.schema.transform || []), t]);
@@ -126,7 +126,6 @@ export declare function _filterEmptyValues<T extends AnyObject>(obj: T, opt?: Mu
126
126
  *
127
127
  * **Note:** This method mutates `object`.
128
128
  *
129
- * @category Object
130
129
  * @param target The destination object.
131
130
  * @param sources The source objects.
132
131
  * @returns Returns `object`.
@@ -177,7 +176,7 @@ type PropertyPath = Many<PropertyKey>;
177
176
  * @param obj The object to modify.
178
177
  * @param path The path of the property to set.
179
178
  * @param value The value to set.
180
- * @return Returns object.
179
+ * @returns Returns object.
181
180
  *
182
181
  * Based on: https://stackoverflow.com/a/54733755/4919972
183
182
  */
@@ -185,7 +184,6 @@ export declare function _set<T extends AnyObject>(obj: T, path: PropertyPath, va
185
184
  /**
186
185
  * Checks if `path` is a direct property of `object` (not null, not undefined).
187
186
  *
188
- * @category Object
189
187
  * @param obj The object to query.
190
188
  * @param path The path to check.
191
189
  * @returns Returns `true` if `path` exists, else `false`.
@@ -236,7 +236,6 @@ export function _filterEmptyValues(obj, opt = {}) {
236
236
  *
237
237
  * **Note:** This method mutates `object`.
238
238
  *
239
- * @category Object
240
239
  * @param target The destination object.
241
240
  * @param sources The source objects.
242
241
  * @returns Returns `object`.
@@ -340,7 +339,7 @@ export function _get(obj = {}, path = '') {
340
339
  return (path
341
340
  .replaceAll(/\[([^\]]+)]/g, '.$1')
342
341
  .split('.')
343
- // eslint-disable-next-line unicorn/no-array-reduce
342
+ // oxlint-disable-next-line unicorn/no-array-reduce
344
343
  .reduce((o, p) => o?.[p], obj));
345
344
  }
346
345
  /**
@@ -350,7 +349,7 @@ export function _get(obj = {}, path = '') {
350
349
  * @param obj The object to modify.
351
350
  * @param path The path of the property to set.
352
351
  * @param value The value to set.
353
- * @return Returns object.
352
+ * @returns Returns object.
354
353
  *
355
354
  * Based on: https://stackoverflow.com/a/54733755/4919972
356
355
  */
@@ -365,7 +364,7 @@ export function _set(obj, path, value) {
365
364
  else if (!path.length) {
366
365
  return obj;
367
366
  }
368
- // eslint-disable-next-line unicorn/no-array-reduce
367
+ // oxlint-disable-next-line unicorn/no-array-reduce
369
368
  ;
370
369
  path.slice(0, -1).reduce((a, c, i) =>
371
370
  // biome-ignore lint/style/useConsistentBuiltinInstantiation: ok
@@ -384,7 +383,6 @@ export function _set(obj, path, value) {
384
383
  /**
385
384
  * Checks if `path` is a direct property of `object` (not null, not undefined).
386
385
  *
387
- * @category Object
388
386
  * @param obj The object to query.
389
387
  * @param path The path to check.
390
388
  * @returns Returns `true` if `path` exists, else `false`.
@@ -85,7 +85,7 @@ export async function pMap(iterable, mapper, opt = {}) {
85
85
  }
86
86
  ret[i] = value;
87
87
  resolvingCount--;
88
- next();
88
+ next(); // oxlint-disable-line no-callback-in-promise
89
89
  }, (err) => {
90
90
  if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
91
91
  isSettled = true;
@@ -100,7 +100,7 @@ export async function pMap(iterable, mapper, opt = {}) {
100
100
  logger?.error(err);
101
101
  }
102
102
  resolvingCount--;
103
- next();
103
+ next(); // oxlint-disable-line no-callback-in-promise
104
104
  }
105
105
  });
106
106
  };
@@ -13,7 +13,8 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
13
13
  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces);
14
14
  }
15
15
  }
16
- /* eslint-disable @typescript-eslint/no-unused-expressions, no-bitwise, no-implicit-coercion */
16
+ /* eslint-disable no-bitwise, no-implicit-coercion */
17
+ // oxlint-disable no-unused-expressions
17
18
  function serializer(replacer, cycleReplacer) {
18
19
  const stack = [];
19
20
  const keys = [];
@@ -16,7 +16,7 @@ export declare function _lowerFirst(s: string): Uncapitalize<string>;
16
16
  /**
17
17
  * Like String.split(), but with limit, returning the tail together with last element.
18
18
  *
19
- * @return Returns the new array of string segments.
19
+ * @returns Returns the new array of string segments.
20
20
  */
21
21
  export declare function _split(str: string, separator: string, limit: number): string[];
22
22
  export declare function _removeWhitespace(s: string): string;
@@ -26,7 +26,7 @@ export function _lowerFirst(s) {
26
26
  /**
27
27
  * Like String.split(), but with limit, returning the tail together with last element.
28
28
  *
29
- * @return Returns the new array of string segments.
29
+ * @returns Returns the new array of string segments.
30
30
  */
31
31
  export function _split(str, separator, limit) {
32
32
  const parts = str.split(separator);
@@ -37,8 +37,6 @@ type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ?
37
37
  type FooWithoutA = Except<Foo, 'a' | 'c'>;
38
38
  //=> {b: string};
39
39
  ```
40
-
41
- @category Utilities
42
40
  */
43
41
  export type Except<ObjectType, KeysType extends keyof ObjectType> = {
44
42
  [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
@@ -82,8 +80,6 @@ export type OmitIndexSignature<ObjectType> = {
82
80
 
83
81
  const ab: Merge<Foo, Bar> = {a: 1, b: 2};
84
82
  ```
85
-
86
- @category Utilities
87
83
  */
88
84
  export type Merge<Destination, Source> = {
89
85
  [Key in keyof OmitIndexSignature<Destination & Source>]: Key extends keyof Source ? Source[Key] : Key extends keyof Destination ? Destination[Key] : never;
@@ -109,7 +105,6 @@ export type Merge<Destination, Source> = {
109
105
  type StringKeysAndUndefined = ConditionalKeys<Example, string | undefined>;
110
106
  //=> 'a' | 'c'
111
107
  ```
112
- @category Utilities
113
108
  */
114
109
  export type ConditionalKeys<Base, Condition> = NonNullable<{
115
110
  [Key in keyof Base]: Base[Key] extends Condition ? Key : never;
@@ -141,7 +136,6 @@ export type ConditionalKeys<Base, Condition> = NonNullable<{
141
136
  type NonStringKeysOnly = ConditionalExcept<Example, string>;
142
137
  //=> {b: string | number; c: () => void; d: {}}
143
138
  ```
144
- @category Utilities
145
139
  */
146
140
  export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Base, Condition>>;
147
141
  /**
@@ -171,7 +165,6 @@ export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Ba
171
165
  type StringKeysOnly = ConditionalPick<Example, string>;
172
166
  //=> {a: string}
173
167
  ```
174
- @category Utilities
175
168
  */
176
169
  export type ConditionalPick<Base, Condition> = Pick<Base, ConditionalKeys<Base, Condition>>;
177
170
  /**
package/dist/types.d.ts CHANGED
@@ -310,7 +310,7 @@ export type FalsyValue = false | '' | 0 | null | undefined;
310
310
  * err.data = {} // can be done, because it was casted
311
311
  * }
312
312
  */
313
- export declare function _typeCast<T>(v: any): asserts v is T;
313
+ export declare function _typeCast<T>(_v: any): asserts _v is T;
314
314
  /**
315
315
  * Type-safe Object.assign that checks that part is indeed a Partial<T>
316
316
  */
@@ -371,8 +371,6 @@ export type Class<T = any> = new (...args: any[]) => T;
371
371
  data.foo.push('bar');
372
372
  //=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
373
373
  ```
374
-
375
- @category Utilities
376
374
  */
377
375
  export type ReadonlyDeep<T> = T extends Primitive | ((...args: any[]) => unknown) ? T : T extends ReadonlyMap<infer KeyType, infer ValueType> ? ReadonlyMapDeep<KeyType, ValueType> : T extends ReadonlySet<infer ItemType> ? ReadonlySetDeep<ItemType> : T extends object ? ReadonlyObjectDeep<T> : unknown;
378
376
  /**
package/dist/types.js CHANGED
@@ -59,7 +59,7 @@ export const _objectEntries = Object.entries;
59
59
  * err.data = {} // can be done, because it was casted
60
60
  * }
61
61
  */
62
- export function _typeCast(v) { }
62
+ export function _typeCast(_v) { }
63
63
  /**
64
64
  * Type-safe Object.assign that checks that part is indeed a Partial<T>
65
65
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
3
  "type": "module",
4
- "version": "15.34.0",
4
+ "version": "15.35.0",
5
5
  "dependencies": {
6
6
  "tslib": "^2",
7
7
  "undici": "^7",
@@ -15,7 +15,7 @@ import { END } from '../types.js'
15
15
  *
16
16
  * @param array The array to process.
17
17
  * @param size The length of each chunk.
18
- * @return Returns the new array containing chunks.
18
+ * @returns Returns the new array containing chunks.
19
19
  *
20
20
  * https://lodash.com/docs#chunk
21
21
  *
@@ -91,8 +91,7 @@ export function _pushUniqBy<T>(a: T[], mapper: Mapper<T, any>, ...items: T[]): T
91
91
  */
92
92
  export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
93
93
  const map = new Map<any, T>()
94
- for (let i = 0; i < arr.length; i++) {
95
- const item = arr[i]!
94
+ for (const item of arr) {
96
95
  const key = item === undefined || item === null ? item : mapper(item)
97
96
  if (!map.has(key)) map.set(key, item)
98
97
  }
@@ -121,8 +120,7 @@ export function _uniqBy<T>(arr: readonly T[], mapper: Mapper<T, any>): T[] {
121
120
  */
122
121
  export function _by<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T> {
123
122
  const map: StringMap<T> = {}
124
- for (let i = 0; i < items.length; i++) {
125
- const v = items[i]!
123
+ for (const v of items) {
126
124
  const k = mapper(v)
127
125
  if (k !== undefined) {
128
126
  map[k] = v
@@ -140,8 +138,7 @@ export function _mapBy<ITEM, KEY>(
140
138
  mapper: Mapper<ITEM, KEY>,
141
139
  ): Map<KEY, ITEM> {
142
140
  const map = new Map<KEY, ITEM>()
143
- for (let i = 0; i < items.length; i++) {
144
- const item = items[i]!
141
+ for (const item of items) {
145
142
  const key = mapper(item)
146
143
  if (key !== undefined) {
147
144
  map.set(key, item)
@@ -164,8 +161,7 @@ export function _mapBy<ITEM, KEY>(
164
161
  export function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): StringMap<T[]> {
165
162
  const map: StringMap<T[]> = {}
166
163
 
167
- for (let i = 0; i < items.length; i++) {
168
- const item = items[i]!
164
+ for (const item of items) {
169
165
  const key = mapper(item)
170
166
  if (key !== undefined) {
171
167
  ;(map[key] ||= []).push(item)
@@ -531,8 +527,7 @@ export function _maxByOrUndefined<T>(
531
527
  let maxItem: T | undefined
532
528
  let max: number | string | undefined
533
529
 
534
- for (let i = 0; i < array.length; i++) {
535
- const item = array[i]!
530
+ for (const item of array) {
536
531
  const v = mapper(item)
537
532
  if (v !== undefined && (max === undefined || v > max)) {
538
533
  maxItem = item
@@ -551,8 +546,7 @@ export function _minByOrUndefined<T>(
551
546
  let minItem: T | undefined
552
547
  let min: number | string | undefined
553
548
 
554
- for (let i = 0; i < array.length; i++) {
555
- const item = array[i]!
549
+ for (const item of array) {
556
550
  const v = mapper(item)
557
551
  if (v !== undefined && (min === undefined || v < min)) {
558
552
  minItem = item
@@ -1,6 +1,8 @@
1
1
  import { isServerSide } from '../env.js'
2
2
  import { loadScript } from './script.util.js'
3
3
 
4
+ // oxlint-disable no-var
5
+
4
6
  declare global {
5
7
  var dataLayer: any[]
6
8
  var gtag: (...args: any[]) => void
@@ -36,12 +36,12 @@ export interface AsyncMemoInstance {
36
36
  }
37
37
 
38
38
  /**
39
- * Like @_Memo, but allowing async MemoCache implementation.
39
+ * Like `@_Memo`, but allowing async MemoCache implementation.
40
40
  *
41
- * Implementation is more complex than @_Memo, because it needs to handle "in-flight" Promises
41
+ * Implementation is more complex than `@_Memo`, because it needs to handle "in-flight" Promises
42
42
  * while waiting for cache to resolve, to prevent "async swarm" issue.
43
43
  *
44
- * @experimental consider normal @_Memo for most of the cases, it's stable and predictable
44
+ * @experimental consider normal `@_Memo` for most of the cases, it's stable and predictable
45
45
  */
46
46
  // eslint-disable-next-line @typescript-eslint/naming-convention
47
47
  export const _AsyncMemo =
@@ -138,7 +138,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
138
138
  }
139
139
  }
140
140
 
141
- // eslint-disable-next-line max-params
141
+ // oxlint-disable-next-line max-params
142
142
  function logFinished(
143
143
  logger: CommonLogger,
144
144
  callSignature: string,
@@ -304,7 +304,7 @@ export interface AppErrorOptions {
304
304
  * data - optional "any" payload.
305
305
  * data.userFriendly - if present, will be displayed to the User as is.
306
306
  *
307
- * Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
307
+ * Based on: `https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801`
308
308
  */
309
309
  export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
310
310
  data!: DATA_TYPE
@@ -1,7 +1,7 @@
1
1
  import { _uniq } from '../array/array.util.js'
2
2
  import { _deepCopy } from '../object/object.util.js'
3
3
  import { _sortObject } from '../object/sortObject.js'
4
- import type { AnyObject, BaseDBEntity, IsoDate, UnixTimestamp } from '../types.js'
4
+ import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js'
5
5
  import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js'
6
6
  import type {
7
7
  JsonSchema,
@@ -77,16 +77,40 @@ export const j = {
77
77
  unixTimestamp2000() {
78
78
  return new JsonSchemaNumberBuilder<UnixTimestamp>().unixTimestamp2000()
79
79
  },
80
+
80
81
  // string types
81
82
  string<T extends string = string>() {
82
83
  return new JsonSchemaStringBuilder<T>()
83
84
  },
85
+
86
+ /**
87
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
88
+ */
84
89
  isoDate() {
85
90
  return new JsonSchemaStringBuilder<IsoDate>().isoDate()
86
91
  },
92
+
93
+ /**
94
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
95
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
96
+ */
97
+ isoDateTime() {
98
+ return new JsonSchemaStringBuilder<IsoDateTime>().isoDateTime()
99
+ },
100
+
87
101
  // email: () => new JsonSchemaStringBuilder().email(),
88
102
  // complex types
89
103
  object,
104
+ dbEntity<T extends AnyObject>(props: T) {
105
+ return j
106
+ .object<BaseDBEntity>({
107
+ id: j.string(),
108
+ created: j.unixTimestamp2000(),
109
+ updated: j.unixTimestamp2000(),
110
+ })
111
+ .extend(j.object(props))
112
+ },
113
+
90
114
  rootObject<T extends AnyObject>(props: {
91
115
  [K in keyof T]: JsonSchemaAnyBuilder<T[K]>
92
116
  }) {
@@ -292,6 +316,10 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
292
316
  })
293
317
  }
294
318
 
319
+ regex(pattern: RegExp): this {
320
+ return this.pattern(pattern.source)
321
+ }
322
+
295
323
  pattern(pattern: string): this {
296
324
  Object.assign(this.schema, { pattern })
297
325
  return this
@@ -318,7 +346,6 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
318
346
  }
319
347
 
320
348
  email = (): this => this.format('email')
321
- isoDate = (): this => this.format('date').description('IsoDate') // todo: make it custom isoDate instead
322
349
  url = (): this => this.format('url')
323
350
  ipv4 = (): this => this.format('ipv4')
324
351
  ipv6 = (): this => this.format('ipv6')
@@ -338,6 +365,21 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
338
365
  return this as unknown as JsonSchemaStringBuilder<B>
339
366
  }
340
367
 
368
+ /**
369
+ * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
370
+ */
371
+ isoDate(): JsonSchemaStringBuilder<IsoDate> {
372
+ return this.format('IsoDate').branded<IsoDate>().description('IsoDate')
373
+ }
374
+
375
+ /**
376
+ * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
377
+ * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
378
+ */
379
+ isoDateTime(): JsonSchemaStringBuilder<IsoDateTime> {
380
+ return this.format('IsoDateTime').branded<IsoDateTime>().description('IsoDateTime')
381
+ }
382
+
341
383
  private transformModify(t: 'trim' | 'toLowerCase' | 'toUpperCase', add: boolean): this {
342
384
  if (add) {
343
385
  this.schema.transform = _uniq([...(this.schema.transform || []), t])
@@ -292,7 +292,6 @@ export function _filterEmptyValues<T extends AnyObject>(obj: T, opt: MutateOptio
292
292
  *
293
293
  * **Note:** This method mutates `object`.
294
294
  *
295
- * @category Object
296
295
  * @param target The destination object.
297
296
  * @param sources The source objects.
298
297
  * @returns Returns `object`.
@@ -402,7 +401,7 @@ export function _get<T extends AnyObject>(obj = {} as T, path = ''): unknown {
402
401
  path
403
402
  .replaceAll(/\[([^\]]+)]/g, '.$1')
404
403
  .split('.')
405
- // eslint-disable-next-line unicorn/no-array-reduce
404
+ // oxlint-disable-next-line unicorn/no-array-reduce
406
405
  .reduce((o, p) => o?.[p], obj)
407
406
  )
408
407
  }
@@ -417,7 +416,7 @@ type PropertyPath = Many<PropertyKey>
417
416
  * @param obj The object to modify.
418
417
  * @param path The path of the property to set.
419
418
  * @param value The value to set.
420
- * @return Returns object.
419
+ * @returns Returns object.
421
420
  *
422
421
  * Based on: https://stackoverflow.com/a/54733755/4919972
423
422
  */
@@ -432,7 +431,7 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
432
431
  return obj as any
433
432
  }
434
433
 
435
- // eslint-disable-next-line unicorn/no-array-reduce
434
+ // oxlint-disable-next-line unicorn/no-array-reduce
436
435
  ;(path as any[]).slice(0, -1).reduce(
437
436
  (
438
437
  a,
@@ -458,7 +457,6 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
458
457
  /**
459
458
  * Checks if `path` is a direct property of `object` (not null, not undefined).
460
459
  *
461
- * @category Object
462
460
  * @param obj The object to query.
463
461
  * @param path The path to check.
464
462
  * @returns Returns `true` if `path` exists, else `false`.
@@ -126,7 +126,7 @@ export async function pMap<IN, OUT>(
126
126
 
127
127
  ret[i] = value
128
128
  resolvingCount--
129
- next()
129
+ next() // oxlint-disable-line no-callback-in-promise
130
130
  },
131
131
  (err: Error) => {
132
132
  if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
@@ -140,7 +140,7 @@ export async function pMap<IN, OUT>(
140
140
  logger?.error(err)
141
141
  }
142
142
  resolvingCount--
143
- next()
143
+ next() // oxlint-disable-line no-callback-in-promise
144
144
  }
145
145
  },
146
146
  )
@@ -20,8 +20,8 @@ export function _safeJsonStringify(
20
20
  }
21
21
  }
22
22
 
23
- /* eslint-disable @typescript-eslint/no-unused-expressions, no-bitwise, no-implicit-coercion */
24
-
23
+ /* eslint-disable no-bitwise, no-implicit-coercion */
24
+ // oxlint-disable no-unused-expressions
25
25
  function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
26
26
  const stack: any[] = []
27
27
  const keys: string[] = []
@@ -31,7 +31,7 @@ export function _lowerFirst(s: string): Uncapitalize<string> {
31
31
  /**
32
32
  * Like String.split(), but with limit, returning the tail together with last element.
33
33
  *
34
- * @return Returns the new array of string segments.
34
+ * @returns Returns the new array of string segments.
35
35
  */
36
36
  export function _split(str: string, separator: string, limit: number): string[] {
37
37
  const parts = str.split(separator)
package/src/typeFest.ts CHANGED
@@ -42,8 +42,6 @@ type Filter<KeyType, ExcludeType> =
42
42
  type FooWithoutA = Except<Foo, 'a' | 'c'>;
43
43
  //=> {b: string};
44
44
  ```
45
-
46
- @category Utilities
47
45
  */
48
46
  export type Except<ObjectType, KeysType extends keyof ObjectType> = {
49
47
  [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType]
@@ -94,8 +92,6 @@ export type OmitIndexSignature<ObjectType> = {
94
92
 
95
93
  const ab: Merge<Foo, Bar> = {a: 1, b: 2};
96
94
  ```
97
-
98
- @category Utilities
99
95
  */
100
96
  export type Merge<Destination, Source> = {
101
97
  [Key in keyof OmitIndexSignature<Destination & Source>]: Key extends keyof Source
@@ -126,7 +122,6 @@ export type Merge<Destination, Source> = {
126
122
  type StringKeysAndUndefined = ConditionalKeys<Example, string | undefined>;
127
123
  //=> 'a' | 'c'
128
124
  ```
129
- @category Utilities
130
125
  */
131
126
  export type ConditionalKeys<Base, Condition> = NonNullable<
132
127
  // Wrap in `NonNullable` to strip away the `undefined` type from the produced union.
@@ -169,7 +164,6 @@ export type ConditionalKeys<Base, Condition> = NonNullable<
169
164
  type NonStringKeysOnly = ConditionalExcept<Example, string>;
170
165
  //=> {b: string | number; c: () => void; d: {}}
171
166
  ```
172
- @category Utilities
173
167
  */
174
168
  export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Base, Condition>>
175
169
 
@@ -200,7 +194,6 @@ export type ConditionalExcept<Base, Condition> = Except<Base, ConditionalKeys<Ba
200
194
  type StringKeysOnly = ConditionalPick<Example, string>;
201
195
  //=> {a: string}
202
196
  ```
203
- @category Utilities
204
197
  */
205
198
  export type ConditionalPick<Base, Condition> = Pick<Base, ConditionalKeys<Base, Condition>>
206
199
 
package/src/types.ts CHANGED
@@ -396,7 +396,7 @@ export type FalsyValue = false | '' | 0 | null | undefined
396
396
  * err.data = {} // can be done, because it was casted
397
397
  * }
398
398
  */
399
- export function _typeCast<T>(v: any): asserts v is T {}
399
+ export function _typeCast<T>(_v: any): asserts _v is T {}
400
400
 
401
401
  /**
402
402
  * Type-safe Object.assign that checks that part is indeed a Partial<T>
@@ -469,8 +469,6 @@ export type Class<T = any> = new (...args: any[]) => T
469
469
  data.foo.push('bar');
470
470
  //=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
471
471
  ```
472
-
473
- @category Utilities
474
472
  */
475
473
  /* eslint-disable @typescript-eslint/no-restricted-types */
476
474
  export type ReadonlyDeep<T> = T extends Primitive | ((...args: any[]) => unknown)