@naturalcycles/js-lib 14.54.0 → 14.57.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.
Files changed (39) hide show
  1. package/dist/error/app.error.js +7 -3
  2. package/dist/error/assert.d.ts +1 -1
  3. package/dist/error/assert.js +1 -16
  4. package/dist/error/http.error.js +0 -15
  5. package/dist/index.d.ts +3 -1
  6. package/dist/index.js +6 -1
  7. package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +2 -2
  8. package/dist/json-schema/jsonSchema.model.d.ts +3 -3
  9. package/dist/json-schema/jsonSchemaBuilder.d.ts +5 -5
  10. package/dist/lazy.d.ts +26 -0
  11. package/dist/lazy.js +55 -0
  12. package/dist/object/object.util.d.ts +23 -23
  13. package/dist/object/sortObject.d.ts +2 -1
  14. package/dist/promise/AggregatedError.js +1 -2
  15. package/dist/string/url.util.d.ts +15 -0
  16. package/dist/string/url.util.js +30 -0
  17. package/dist/types.d.ts +1 -1
  18. package/dist-esm/error/app.error.js +7 -3
  19. package/dist-esm/error/assert.js +1 -16
  20. package/dist-esm/error/http.error.js +0 -15
  21. package/dist-esm/index.js +3 -1
  22. package/dist-esm/lazy.js +50 -0
  23. package/dist-esm/promise/AggregatedError.js +1 -2
  24. package/dist-esm/string/url.util.js +26 -0
  25. package/package.json +2 -3
  26. package/src/error/app.error.ts +11 -3
  27. package/src/error/assert.ts +1 -17
  28. package/src/error/http.error.ts +0 -16
  29. package/src/index.ts +5 -0
  30. package/src/json-schema/from-data/generateJsonSchemaFromData.ts +3 -2
  31. package/src/json-schema/jsonSchema.model.ts +3 -5
  32. package/src/json-schema/jsonSchemaBuilder.ts +5 -6
  33. package/src/lazy.ts +62 -0
  34. package/src/object/object.util.ts +23 -31
  35. package/src/object/sortObject.ts +2 -2
  36. package/src/promise/AggregatedError.ts +1 -2
  37. package/src/string/url.util.ts +27 -0
  38. package/src/types.ts +1 -1
  39. package/CHANGELOG.md +0 -1328
@@ -0,0 +1,50 @@
1
+ /**
2
+ * const value = lazyValue(() => expensiveComputation())
3
+ *
4
+ * value() // calls expensiveComputation() once
5
+ * value() // returns cached result
6
+ * value() // returns cached result
7
+ *
8
+ * Based on: https://github.com/sindresorhus/lazy-value
9
+ */
10
+ export function _lazyValue(fn) {
11
+ let isCalled = false;
12
+ let result;
13
+ return (() => {
14
+ if (!isCalled) {
15
+ isCalled = true;
16
+ result = fn();
17
+ }
18
+ return result;
19
+ });
20
+ }
21
+ /**
22
+ * interface Obj {
23
+ * v: number
24
+ * }
25
+ *
26
+ * const obj = {} as Obj
27
+ *
28
+ * _defineLazyProperty(obj, 'v', () => expensiveComputation())
29
+ * obj.v // runs expensiveComputation() once
30
+ * obj.v // cached value
31
+ * obj.v // cached value
32
+ *
33
+ * Based on: https://github.com/sindresorhus/define-lazy-prop
34
+ */
35
+ export function _defineLazyProperty(obj, propertyName, fn) {
36
+ const define = (value) => Object.defineProperty(obj, propertyName, { value, enumerable: true, writable: true });
37
+ Object.defineProperty(obj, propertyName, {
38
+ configurable: true,
39
+ enumerable: true,
40
+ get() {
41
+ const result = fn();
42
+ define(result);
43
+ return result;
44
+ },
45
+ set(value) {
46
+ define(value);
47
+ },
48
+ });
49
+ return obj;
50
+ }
@@ -17,8 +17,6 @@ export class AggregatedError extends Error {
17
17
  super(message);
18
18
  this.errors = mappedErrors;
19
19
  this.results = results;
20
- this.constructor = AggregatedError;
21
- this.__proto__ = AggregatedError.prototype;
22
20
  Object.defineProperty(this, 'name', {
23
21
  value: this.constructor.name,
24
22
  configurable: true,
@@ -29,6 +27,7 @@ export class AggregatedError extends Error {
29
27
  else {
30
28
  Object.defineProperty(this, 'stack', {
31
29
  value: new Error().stack,
30
+ writable: true,
32
31
  configurable: true,
33
32
  });
34
33
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Parses `location.search` string (e.g `?a=1&b=2`) into a StringMap, e.g:
3
+ * `{ a: '1', b: '2' }`
4
+ *
5
+ * Pass `location.search` to it in the Frontend, or any other string on the Backend (where `location.search` is not available).
6
+ *
7
+ * Works both with and without leading `?` character.
8
+ *
9
+ * Yes, there's `URLSearchParams` existing in the Frontend (not in Node yet), but it's API is not
10
+ * as convenient. And the implementation here is super-small.
11
+ *
12
+ * Goal of this function is to produce exactly same output as URLSearchParams would.
13
+ */
14
+ export function _parseQueryString(search) {
15
+ const qs = {};
16
+ search
17
+ .substr(search[0] === '?' ? 1 : 0)
18
+ .split('&')
19
+ .forEach(p => {
20
+ const [k, v] = p.split('=');
21
+ if (!k)
22
+ return;
23
+ qs[decodeURIComponent(k)] = decodeURIComponent(v || '');
24
+ });
25
+ return qs;
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.54.0",
3
+ "version": "14.57.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -11,11 +11,10 @@
11
11
  "tslib": "^2.0.0"
12
12
  },
13
13
  "devDependencies": {
14
+ "@naturalcycles/bench-lib": "^1.5.0",
14
15
  "@naturalcycles/dev-lib": "^12.0.0",
15
16
  "@naturalcycles/nodejs-lib": "^12.33.4",
16
- "@types/benchmark": "^2.1.0",
17
17
  "@types/node": "^16.0.0",
18
- "benchmark": "^2.1.4",
19
18
  "jest": "^27.0.1",
20
19
  "patch-package": "^6.2.1",
21
20
  "prettier": "^2.1.2",
@@ -10,21 +10,29 @@ import { ErrorData } from './error.model'
10
10
  * Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
11
11
  */
12
12
  export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
13
- constructor(message: string, public data = {} as DATA_TYPE) {
13
+ data!: DATA_TYPE
14
+
15
+ constructor(message: string, data = {} as DATA_TYPE) {
14
16
  super(message)
15
17
 
16
- this.constructor = AppError
17
- ;(this as any).__proto__ = AppError.prototype
18
18
  Object.defineProperty(this, 'name', {
19
19
  value: this.constructor.name,
20
20
  configurable: true,
21
21
  })
22
22
 
23
+ Object.defineProperty(this, 'data', {
24
+ value: data,
25
+ writable: true,
26
+ configurable: true,
27
+ enumerable: false,
28
+ })
29
+
23
30
  if (Error.captureStackTrace) {
24
31
  Error.captureStackTrace(this, this.constructor)
25
32
  } else {
26
33
  Object.defineProperty(this, 'stack', {
27
34
  value: new Error().stack, // eslint-disable-line unicorn/error-message
35
+ writable: true,
28
36
  configurable: true,
29
37
  })
30
38
  }
@@ -123,23 +123,7 @@ export function _assertTypeOf<T>(v: any, expectedType: string, message?: string)
123
123
  }
124
124
 
125
125
  export class AssertionError extends AppError {
126
- constructor(message: string, data: ErrorData) {
126
+ constructor(message: string, data = {} as ErrorData) {
127
127
  super(message, data)
128
-
129
- this.constructor = AssertionError
130
- ;(this as any).__proto__ = AssertionError.prototype
131
- Object.defineProperty(this, 'name', {
132
- value: this.constructor.name,
133
- configurable: true, // otherwise throws with "TypeError: Cannot redefine property: name"
134
- })
135
-
136
- if (Error.captureStackTrace) {
137
- Error.captureStackTrace(this, this.constructor)
138
- } else {
139
- Object.defineProperty(this, 'stack', {
140
- value: new Error().stack, // eslint-disable-line unicorn/error-message
141
- configurable: true,
142
- })
143
- }
144
128
  }
145
129
  }
@@ -9,21 +9,5 @@ export class HttpError<
9
9
  > extends AppError<DATA_TYPE> {
10
10
  constructor(message: string, data: DATA_TYPE) {
11
11
  super(message, data)
12
-
13
- this.constructor = HttpError
14
- ;(this as any).__proto__ = HttpError.prototype
15
- Object.defineProperty(this, 'name', {
16
- value: this.constructor.name,
17
- configurable: true, // otherwise throws with "TypeError: Cannot redefine property: name"
18
- })
19
-
20
- if (Error.captureStackTrace) {
21
- Error.captureStackTrace(this, this.constructor)
22
- } else {
23
- Object.defineProperty(this, 'stack', {
24
- value: new Error().stack, // eslint-disable-line unicorn/error-message
25
- configurable: true,
26
- })
27
- }
28
12
  }
29
13
  }
package/src/index.ts CHANGED
@@ -21,6 +21,8 @@ import {
21
21
  _uniq,
22
22
  _uniqBy,
23
23
  } from './array/array.util'
24
+ import { _defineLazyProperty, _lazyValue } from './lazy'
25
+ import { _parseQueryString } from './string/url.util'
24
26
  import { _range } from './array/range'
25
27
  import {
26
28
  PromiseDecoratorCfg,
@@ -447,4 +449,7 @@ export {
447
449
  JsonSchemaAnyBuilder,
448
450
  JSON_SCHEMA_ORDER,
449
451
  generateJsonSchemaFromData,
452
+ _parseQueryString,
453
+ _defineLazyProperty,
454
+ _lazyValue,
450
455
  }
@@ -10,6 +10,7 @@ import {
10
10
  StringMap,
11
11
  _stringMapEntries,
12
12
  _uniq,
13
+ AnyObject,
13
14
  } from '../..'
14
15
 
15
16
  type PrimitiveType = 'undefined' | 'null' | 'boolean' | 'string' | 'number'
@@ -20,11 +21,11 @@ type Type = PrimitiveType | 'array' | 'object'
20
21
  *
21
22
  * `additionalProperties` is set to `true`, cause it's safer.
22
23
  */
23
- export function generateJsonSchemaFromData<T = unknown>(rows: any[]): JsonSchemaObject<T> {
24
+ export function generateJsonSchemaFromData<T = unknown>(rows: AnyObject[]): JsonSchemaObject<T> {
24
25
  return objectToJsonSchema(rows as any) as JsonSchemaObject<T>
25
26
  }
26
27
 
27
- function objectToJsonSchema(rows: Record<string, any>[]): JsonSchemaObject {
28
+ function objectToJsonSchema(rows: AnyObject[]): JsonSchemaObject {
28
29
  const typesByKey: StringMap<Set<Type>> = {}
29
30
 
30
31
  rows.forEach(r => {
@@ -1,4 +1,4 @@
1
- import { StringMap } from '../types'
1
+ import { AnyObject, StringMap } from '../types'
2
2
 
3
3
  // eslint-disable-next-line unused-imports/no-unused-vars
4
4
  export type JsonSchema<T = unknown> =
@@ -124,13 +124,11 @@ export interface JsonSchemaRef<T = unknown> extends JsonSchemaAny<T> {
124
124
  $ref: string
125
125
  }
126
126
 
127
- export interface JsonSchemaRootObject<T extends Record<any, any> = Record<any, unknown>>
128
- extends JsonSchemaObject<T> {
127
+ export interface JsonSchemaRootObject<T extends AnyObject = AnyObject> extends JsonSchemaObject<T> {
129
128
  $id: string
130
129
  }
131
130
 
132
- export interface JsonSchemaObject<T extends Record<any, any> = Record<any, unknown>>
133
- extends JsonSchemaAny<T> {
131
+ export interface JsonSchemaObject<T extends AnyObject = AnyObject> extends JsonSchemaAny<T> {
134
132
  type: 'object'
135
133
  // let's be strict and require all these
136
134
  properties: {
@@ -9,6 +9,7 @@ import {
9
9
  SavedDBEntity,
10
10
  _deepCopy,
11
11
  _sortObject,
12
+ AnyObject,
12
13
  } from '../index'
13
14
  import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst'
14
15
  import {
@@ -86,12 +87,12 @@ export const jsonSchema = {
86
87
  },
87
88
  // email: () => new JsonSchemaStringBuilder().email(),
88
89
  // complex types
89
- object<T extends Record<any, any>>(props: {
90
+ object<T extends AnyObject>(props: {
90
91
  [k in keyof T]: JsonSchemaAnyBuilder<T[k]>
91
92
  }) {
92
93
  return new JsonSchemaObjectBuilder<T>().addProperties(props)
93
94
  },
94
- rootObject<T extends Record<any, any>>(props: {
95
+ rootObject<T extends AnyObject>(props: {
95
96
  [k in keyof T]: JsonSchemaAnyBuilder<T[k]>
96
97
  }) {
97
98
  return new JsonSchemaObjectBuilder<T>().addProperties(props).$schemaDraft7()
@@ -309,7 +310,7 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder<string, JsonSc
309
310
  // contentEncoding?: string
310
311
  }
311
312
 
312
- export class JsonSchemaObjectBuilder<T extends Record<any, any>> extends JsonSchemaAnyBuilder<
313
+ export class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyBuilder<
313
314
  T,
314
315
  JsonSchemaObject<T>
315
316
  > {
@@ -378,9 +379,7 @@ export class JsonSchemaObjectBuilder<T extends Record<any, any>> extends JsonSch
378
379
  return this.baseDBEntity().addRequired(['id', 'created', 'updated']) as any
379
380
  }
380
381
 
381
- extend<T2 extends Record<any, any>>(
382
- s2: JsonSchemaObjectBuilder<T2>,
383
- ): JsonSchemaObjectBuilder<T & T2> {
382
+ extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2> {
384
383
  const builder = new JsonSchemaObjectBuilder<T & T2>()
385
384
  Object.assign(builder.schema, _deepCopy(this.schema))
386
385
  mergeJsonSchemaObjects(builder.schema, s2.schema)
package/src/lazy.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { AnyFunction, AnyObject } from './types'
2
+
3
+ /**
4
+ * const value = lazyValue(() => expensiveComputation())
5
+ *
6
+ * value() // calls expensiveComputation() once
7
+ * value() // returns cached result
8
+ * value() // returns cached result
9
+ *
10
+ * Based on: https://github.com/sindresorhus/lazy-value
11
+ */
12
+ export function _lazyValue<T extends AnyFunction>(fn: T): T {
13
+ let isCalled = false
14
+ let result: any
15
+
16
+ return (() => {
17
+ if (!isCalled) {
18
+ isCalled = true
19
+ result = fn()
20
+ }
21
+
22
+ return result
23
+ }) as any
24
+ }
25
+
26
+ /**
27
+ * interface Obj {
28
+ * v: number
29
+ * }
30
+ *
31
+ * const obj = {} as Obj
32
+ *
33
+ * _defineLazyProperty(obj, 'v', () => expensiveComputation())
34
+ * obj.v // runs expensiveComputation() once
35
+ * obj.v // cached value
36
+ * obj.v // cached value
37
+ *
38
+ * Based on: https://github.com/sindresorhus/define-lazy-prop
39
+ */
40
+ export function _defineLazyProperty<OBJ extends AnyObject>(
41
+ obj: OBJ,
42
+ propertyName: keyof OBJ,
43
+ fn: AnyFunction,
44
+ ): OBJ {
45
+ const define = (value: any) =>
46
+ Object.defineProperty(obj, propertyName, { value, enumerable: true, writable: true })
47
+
48
+ Object.defineProperty(obj, propertyName, {
49
+ configurable: true,
50
+ enumerable: true,
51
+ get() {
52
+ const result = fn()
53
+ define(result)
54
+ return result
55
+ },
56
+ set(value) {
57
+ define(value)
58
+ },
59
+ })
60
+
61
+ return obj
62
+ }
@@ -1,11 +1,11 @@
1
1
  import { PropertyPath } from '../lodash.types'
2
- import { ObjectMapper, ObjectPredicate, StringMap, ValueOf } from '../types'
2
+ import { AnyObject, ObjectMapper, ObjectPredicate, StringMap, ValueOf } from '../types'
3
3
 
4
4
  /**
5
5
  * Returns clone of `obj` with only `props` preserved.
6
6
  * Opposite of Omit.
7
7
  */
8
- export function _pick<T extends Record<string, any>, K extends keyof T>(
8
+ export function _pick<T extends AnyObject, K extends keyof T>(
9
9
  obj: T,
10
10
  props: readonly K[],
11
11
  mutate = false,
@@ -29,7 +29,7 @@ export function _pick<T extends Record<string, any>, K extends keyof T>(
29
29
  * Returns clone of `obj` with `props` omitted.
30
30
  * Opposite of Pick.
31
31
  */
32
- export function _omit<T extends Record<string, any>, K extends keyof T>(
32
+ export function _omit<T extends AnyObject, K extends keyof T>(
33
33
  obj: T,
34
34
  props: readonly K[],
35
35
  mutate = false,
@@ -51,7 +51,7 @@ export function _omit<T extends Record<string, any>, K extends keyof T>(
51
51
  * 'account.updated',
52
52
  * ])
53
53
  */
54
- export function _mask<T extends Record<string, any>>(obj: T, props: string[], mutate = false): T {
54
+ export function _mask<T extends AnyObject>(obj: T, props: string[], mutate = false): T {
55
55
  return props.reduce(
56
56
  (r, prop) => {
57
57
  _unset(r, prop)
@@ -64,14 +64,14 @@ export function _mask<T extends Record<string, any>>(obj: T, props: string[], mu
64
64
  /**
65
65
  * Removes "falsy" values from the object.
66
66
  */
67
- export function _filterFalsyValues<T extends Record<string, any>>(obj: T, mutate = false): T {
67
+ export function _filterFalsyValues<T extends AnyObject>(obj: T, mutate = false): T {
68
68
  return _filterObject(obj, (_k, v) => !!v, mutate)
69
69
  }
70
70
 
71
71
  /**
72
72
  * Removes values from the object that are `null` or `undefined`.
73
73
  */
74
- export function _filterNullishValues<T extends Record<string, any>>(obj: T, mutate = false): T {
74
+ export function _filterNullishValues<T extends AnyObject>(obj: T, mutate = false): T {
75
75
  return _filterObject(obj, (_k, v) => v !== undefined && v !== null, mutate)
76
76
  }
77
77
 
@@ -79,11 +79,11 @@ export function _filterNullishValues<T extends Record<string, any>>(obj: T, muta
79
79
  * Removes values from the object that are `undefined`.
80
80
  * Only `undefined` values are removed. `null` values are kept!
81
81
  */
82
- export function _filterUndefinedValues<T extends Record<string, any>>(obj: T, mutate = false): T {
82
+ export function _filterUndefinedValues<T extends AnyObject>(obj: T, mutate = false): T {
83
83
  return _filterObject(obj, (_k, v) => v !== undefined, mutate)
84
84
  }
85
85
 
86
- export function _filterEmptyArrays<T extends Record<string, any>>(obj: T, mutate = false): T {
86
+ export function _filterEmptyArrays<T extends AnyObject>(obj: T, mutate = false): T {
87
87
  return _filterObject(obj, (_k, v) => !Array.isArray(v) || v.length > 0, mutate)
88
88
  }
89
89
 
@@ -91,7 +91,7 @@ export function _filterEmptyArrays<T extends Record<string, any>>(obj: T, mutate
91
91
  * Returns clone of `obj` without properties that does not pass `predicate`.
92
92
  * Allows filtering by both key and value.
93
93
  */
94
- export function _filterObject<T extends Record<string, any>>(
94
+ export function _filterObject<T extends AnyObject>(
95
95
  obj: T,
96
96
  predicate: ObjectPredicate<T>,
97
97
  mutate = false,
@@ -118,7 +118,7 @@ export function _filterObject<T extends Record<string, any>>(
118
118
  * _.mapValues(users, 'age')
119
119
  * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
120
120
  */
121
- export function _mapValues<T extends Record<string, any>, OUT = T>(
121
+ export function _mapValues<T extends AnyObject, OUT = T>(
122
122
  obj: T,
123
123
  mapper: ObjectMapper<T, any>,
124
124
  mutate = false,
@@ -135,7 +135,7 @@ export function _mapValues<T extends Record<string, any>, OUT = T>(
135
135
  *
136
136
  * Does not support `mutate` flag.
137
137
  */
138
- export function _mapKeys<T extends Record<string, any>>(
138
+ export function _mapKeys<T extends AnyObject>(
139
139
  obj: T,
140
140
  mapper: ObjectMapper<T, string>,
141
141
  ): StringMap<T[keyof T]> {
@@ -162,7 +162,7 @@ export function _mapKeys<T extends Record<string, any>>(
162
162
  *
163
163
  * Non-string keys are passed via String(...)
164
164
  */
165
- export function _mapObject<IN extends Record<string, any>, OUT>(
165
+ export function _mapObject<IN extends AnyObject, OUT>(
166
166
  obj: IN,
167
167
  mapper: ObjectMapper<IN, [key: string, value: any]>,
168
168
  ): { [P in keyof IN]: OUT } {
@@ -175,17 +175,11 @@ export function _mapObject<IN extends Record<string, any>, OUT>(
175
175
  }, {} as { [P in keyof IN]: OUT })
176
176
  }
177
177
 
178
- export function _findKeyByValue<T extends Record<any, any>>(
179
- obj: T,
180
- v: ValueOf<T>,
181
- ): keyof T | undefined {
178
+ export function _findKeyByValue<T extends AnyObject>(obj: T, v: ValueOf<T>): keyof T | undefined {
182
179
  return Object.entries(obj).find(([_, value]) => value === v)?.[0] as keyof T
183
180
  }
184
181
 
185
- export function _objectNullValuesToUndefined<T extends Record<string, any>>(
186
- obj: T,
187
- mutate = false,
188
- ): T {
182
+ export function _objectNullValuesToUndefined<T extends AnyObject>(obj: T, mutate = false): T {
189
183
  return _mapValues(obj, (_k, v) => (v === null ? undefined : v), mutate)
190
184
  }
191
185
 
@@ -199,7 +193,7 @@ export function _deepCopy<T>(o: T): T {
199
193
  /**
200
194
  * Returns true if item is Object, not null and not Array.
201
195
  */
202
- export function _isObject(item: any): item is Record<string, any> {
196
+ export function _isObject(item: any): item is AnyObject {
203
197
  return (typeof item === 'object' && item !== null && !Array.isArray(item)) || false
204
198
  }
205
199
 
@@ -256,7 +250,7 @@ export function _undefinedIfEmpty<T>(obj: T | undefined): T | undefined {
256
250
  /**
257
251
  * Filters the object by removing all key-value pairs where Value is Empty (according to _isEmpty() specification).
258
252
  */
259
- export function _filterEmptyValues<T extends Record<string, any>>(obj: T, mutate = false): T {
253
+ export function _filterEmptyValues<T extends AnyObject>(obj: T, mutate = false): T {
260
254
  return _filterObject(obj, (_k, v) => !_isEmpty(v), mutate)
261
255
  }
262
256
 
@@ -289,7 +283,7 @@ export function _filterEmptyValues<T extends Record<string, any>>(obj: T, mutate
289
283
  *
290
284
  * Based on: https://gist.github.com/Salakar/1d7137de9cb8b704e48a
291
285
  */
292
- export function _merge<T extends Record<string, any>>(target: T, ...sources: any[]): T {
286
+ export function _merge<T extends AnyObject>(target: T, ...sources: any[]): T {
293
287
  sources.forEach(source => {
294
288
  if (_isObject(source)) {
295
289
  Object.keys(source).forEach(key => {
@@ -311,7 +305,7 @@ export function _merge<T extends Record<string, any>>(target: T, ...sources: any
311
305
  * Doesn't touch object KEYS.
312
306
  * Mutates.
313
307
  */
314
- export function _deepTrim<T extends Record<string, any> | string>(o: T): T {
308
+ export function _deepTrim<T extends AnyObject | string>(o: T): T {
315
309
  if (!o) return o
316
310
 
317
311
  if (typeof o === 'string') {
@@ -327,7 +321,7 @@ export function _deepTrim<T extends Record<string, any> | string>(o: T): T {
327
321
 
328
322
  // from: https://github.com/jonschlinkert/unset-value
329
323
  // mutates obj
330
- export function _unset<T extends Record<string, any>>(obj: T, prop: string): void {
324
+ export function _unset<T extends AnyObject>(obj: T, prop: string): void {
331
325
  if (!_isObject(obj)) {
332
326
  return
333
327
  }
@@ -350,9 +344,7 @@ export function _unset<T extends Record<string, any>>(obj: T, prop: string): voi
350
344
  delete obj[last!]
351
345
  }
352
346
 
353
- export function _invert<T extends Record<any, any>>(
354
- o: T,
355
- ): { [k in ValueOf<T>]: keyof T | undefined } {
347
+ export function _invert<T extends AnyObject>(o: T): { [k in ValueOf<T>]: keyof T | undefined } {
356
348
  const inv = {} as { [k in ValueOf<T>]: keyof T }
357
349
  Object.keys(o).forEach(k => {
358
350
  inv[o[k]] = k
@@ -375,7 +367,7 @@ export function _invertMap<K, V>(m: ReadonlyMap<K, V>): Map<V, K> {
375
367
  * @param def The value returned if the resolved value is undefined.
376
368
  * @return Returns the resolved value.
377
369
  */
378
- export function _get<T extends Record<string, any>>(obj = {} as T, path = '', def?: any): any {
370
+ export function _get<T extends AnyObject>(obj = {} as T, path = '', def?: any): any {
379
371
  const res = path
380
372
  .replace(/\[([^\]]+)]/g, '.$1')
381
373
  .split('.')
@@ -396,7 +388,7 @@ export function _get<T extends Record<string, any>>(obj = {} as T, path = '', de
396
388
  *
397
389
  * Based on: https://stackoverflow.com/a/54733755/4919972
398
390
  */
399
- export function _set<IN extends Record<string, any>, OUT = IN>(
391
+ export function _set<IN extends AnyObject, OUT = IN>(
400
392
  obj: IN,
401
393
  path: PropertyPath,
402
394
  value?: any,
@@ -455,7 +447,7 @@ export function _set<IN extends Record<string, any>, OUT = IN>(
455
447
  * _.has(other, 'a');
456
448
  * // => false
457
449
  */
458
- export function _has<T extends Record<string, any>>(obj: T, path?: string): boolean {
450
+ export function _has<T extends AnyObject>(obj: T, path?: string): boolean {
459
451
  const v = _get(obj, path)
460
452
  return v !== undefined && v !== null
461
453
  }
@@ -1,11 +1,11 @@
1
- import { _omit } from '../index'
1
+ import { _omit, AnyObject } from '../index'
2
2
 
3
3
  /**
4
4
  * Returns new object with keys sorder in the given order.
5
5
  * All keys that are not listed in `keyOrder` go last.
6
6
  * Does not mutate original object.
7
7
  */
8
- export function _sortObject<T extends Record<any, any>>(obj: T, keyOrder: (keyof T)[]): T {
8
+ export function _sortObject<T extends AnyObject>(obj: T, keyOrder: (keyof T)[]): T {
9
9
  const r = {} as T
10
10
 
11
11
  keyOrder.forEach(key => {
@@ -23,8 +23,6 @@ export class AggregatedError<RESULT = any> extends Error {
23
23
  this.errors = mappedErrors
24
24
  this.results = results
25
25
 
26
- this.constructor = AggregatedError
27
- ;(this as any).__proto__ = AggregatedError.prototype
28
26
  Object.defineProperty(this, 'name', {
29
27
  value: this.constructor.name,
30
28
  configurable: true,
@@ -35,6 +33,7 @@ export class AggregatedError<RESULT = any> extends Error {
35
33
  } else {
36
34
  Object.defineProperty(this, 'stack', {
37
35
  value: new Error().stack, // eslint-disable-line unicorn/error-message
36
+ writable: true,
38
37
  configurable: true,
39
38
  })
40
39
  }
@@ -0,0 +1,27 @@
1
+ import { StringMap } from '../types'
2
+
3
+ /**
4
+ * Parses `location.search` string (e.g `?a=1&b=2`) into a StringMap, e.g:
5
+ * `{ a: '1', b: '2' }`
6
+ *
7
+ * Pass `location.search` to it in the Frontend, or any other string on the Backend (where `location.search` is not available).
8
+ *
9
+ * Works both with and without leading `?` character.
10
+ *
11
+ * Yes, there's `URLSearchParams` existing in the Frontend (not in Node yet), but it's API is not
12
+ * as convenient. And the implementation here is super-small.
13
+ *
14
+ * Goal of this function is to produce exactly same output as URLSearchParams would.
15
+ */
16
+ export function _parseQueryString(search: string): StringMap {
17
+ const qs = {}
18
+ search
19
+ .substr(search[0] === '?' ? 1 : 0)
20
+ .split('&')
21
+ .forEach(p => {
22
+ const [k, v] = p.split('=')
23
+ if (!k) return
24
+ qs[decodeURIComponent(k)] = decodeURIComponent(v || '')
25
+ })
26
+ return qs
27
+ }
package/src/types.ts CHANGED
@@ -191,6 +191,6 @@ export function _stringMapEntries<T>(m: StringMap<T>): [k: string, v: T][] {
191
191
  *
192
192
  * @experimental
193
193
  */
194
- export function _objectKeys<T extends Record<string, any>>(obj: T): (keyof T)[] {
194
+ export function _objectKeys<T extends AnyObject>(obj: T): (keyof T)[] {
195
195
  return Object.keys(obj)
196
196
  }