@xylabs/object 5.0.80 → 5.0.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +654 -309
- package/package.json +8 -12
- package/src/AsObjectFactory.ts +0 -13
- package/src/AsTypeFactory.ts +0 -54
- package/src/EmptyObject.ts +0 -1
- package/src/IsObjectFactory.ts +0 -34
- package/src/JsonObject.ts +0 -37
- package/src/ObjectWrapper.ts +0 -13
- package/src/OmitStartsWith.ts +0 -35
- package/src/Optional.ts +0 -1
- package/src/Override.ts +0 -3
- package/src/PartialRecord.ts +0 -6
- package/src/PickStartsWith.ts +0 -15
- package/src/Simplify.ts +0 -1
- package/src/StringKeyObject.ts +0 -1
- package/src/Validator.ts +0 -13
- package/src/WithAdditional.ts +0 -4
- package/src/asObject.ts +0 -6
- package/src/deepMerge.ts +0 -105
- package/src/index-deprecated.ts +0 -2
- package/src/index-un-deprecated.ts +0 -22
- package/src/index.ts +0 -2
- package/src/isType.ts +0 -28
- package/src/omitBy.ts +0 -57
- package/src/pickBy.ts +0 -57
- package/src/removeFields.ts +0 -9
- package/src/toSafeJson.ts +0 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xylabs/object",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.82",
|
|
4
4
|
"description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
|
|
5
5
|
"homepage": "https://xyo.network",
|
|
6
6
|
"bugs": {
|
|
@@ -22,36 +22,32 @@
|
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
24
|
"types": "./dist/neutral/index.d.ts",
|
|
25
|
-
"source": "./src/index.ts",
|
|
26
25
|
"default": "./dist/neutral/index.mjs"
|
|
27
26
|
},
|
|
28
27
|
"./index-un-deprecated": {
|
|
29
28
|
"types": "./dist/neutral/index-un-deprecated.d.ts",
|
|
30
|
-
"source": "./src/index-un-deprecated.ts",
|
|
31
29
|
"default": "./dist/neutral/index-un-deprecated.mjs"
|
|
32
30
|
},
|
|
33
31
|
"./package.json": "./package.json"
|
|
34
32
|
},
|
|
35
33
|
"module": "./dist/neutral/index.mjs",
|
|
36
|
-
"source": "./src/index.ts",
|
|
37
34
|
"types": "./dist/neutral/index.d.ts",
|
|
38
35
|
"files": [
|
|
39
36
|
"dist",
|
|
40
|
-
"src",
|
|
41
37
|
"!**/*.bench.*",
|
|
42
38
|
"!**/*.spec.*",
|
|
43
39
|
"!**/*.test.*"
|
|
44
40
|
],
|
|
45
41
|
"dependencies": {
|
|
46
|
-
"@xylabs/assert": "~5.0.
|
|
47
|
-
"@xylabs/object-model": "~5.0.
|
|
48
|
-
"@xylabs/promise": "~5.0.
|
|
49
|
-
"@xylabs/typeof": "~5.0.
|
|
50
|
-
"@xylabs/zod": "~5.0.
|
|
42
|
+
"@xylabs/assert": "~5.0.82",
|
|
43
|
+
"@xylabs/object-model": "~5.0.82",
|
|
44
|
+
"@xylabs/promise": "~5.0.82",
|
|
45
|
+
"@xylabs/typeof": "~5.0.82",
|
|
46
|
+
"@xylabs/zod": "~5.0.82"
|
|
51
47
|
},
|
|
52
48
|
"devDependencies": {
|
|
53
|
-
"@xylabs/ts-scripts-yarn3": "~7.
|
|
54
|
-
"@xylabs/tsconfig": "~7.
|
|
49
|
+
"@xylabs/ts-scripts-yarn3": "~7.4.11",
|
|
50
|
+
"@xylabs/tsconfig": "~7.4.11",
|
|
55
51
|
"typescript": "~5.9.3",
|
|
56
52
|
"vitest": "~4.0.18",
|
|
57
53
|
"zod": "^4.3.6"
|
package/src/AsObjectFactory.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { TypeCheck } from '@xylabs/object-model'
|
|
2
|
-
import type { TypedObject } from '@xylabs/typeof'
|
|
3
|
-
|
|
4
|
-
import { AsTypeFactory } from './AsTypeFactory.ts'
|
|
5
|
-
|
|
6
|
-
export const AsObjectFactory = {
|
|
7
|
-
create: <T extends TypedObject>(typeCheck: TypeCheck<T>) => {
|
|
8
|
-
return AsTypeFactory.create<T>(typeCheck)
|
|
9
|
-
},
|
|
10
|
-
createOptional: <T extends TypedObject>(typeCheck: TypeCheck<T>) => {
|
|
11
|
-
return AsTypeFactory.createOptional<T>(typeCheck)
|
|
12
|
-
},
|
|
13
|
-
}
|
package/src/AsTypeFactory.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { assertDefinedEx } from '@xylabs/assert'
|
|
2
|
-
import type {
|
|
3
|
-
AsTypeFunction,
|
|
4
|
-
StringOrAlertFunction, TypeCheck, TypeCheckConfig,
|
|
5
|
-
TypeCheckRequiredConfig,
|
|
6
|
-
} from '@xylabs/object-model'
|
|
7
|
-
import type { AnyNonPromise } from '@xylabs/promise'
|
|
8
|
-
import { isPromise } from '@xylabs/promise'
|
|
9
|
-
import { isTruthy } from '@xylabs/typeof'
|
|
10
|
-
|
|
11
|
-
export const AsTypeFactory = {
|
|
12
|
-
create: <T extends AnyNonPromise>(typeCheck: TypeCheck<T>): AsTypeFunction<T> => {
|
|
13
|
-
const func = (
|
|
14
|
-
value: AnyNonPromise,
|
|
15
|
-
assertOrConfig?: StringOrAlertFunction<T> | TypeCheckConfig,
|
|
16
|
-
config?: TypeCheckConfig,
|
|
17
|
-
): T | undefined => {
|
|
18
|
-
// when used as a predicate, it seems that the index is passed as the second parameter (filter,map)
|
|
19
|
-
const isPredicate = typeof assertOrConfig === 'number'
|
|
20
|
-
const resolvedAssert = isPredicate
|
|
21
|
-
? undefined
|
|
22
|
-
: (typeof assertOrConfig === 'object' ? undefined : assertOrConfig) as (StringOrAlertFunction<T> | undefined)
|
|
23
|
-
const resolvedConfig = isPredicate ? undefined : typeof assertOrConfig === 'object' ? assertOrConfig : config
|
|
24
|
-
|
|
25
|
-
// only return undefined if not required
|
|
26
|
-
const required = isTruthy((resolvedConfig as (TypeCheckRequiredConfig | undefined))?.required)
|
|
27
|
-
if (!required && (value === undefined || value === null)) {
|
|
28
|
-
return undefined
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (isPromise(value)) {
|
|
32
|
-
throw new TypeError('un-awaited promises may not be sent to "as" functions')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const result = typeCheck(value, resolvedConfig) ? (value as T) : undefined
|
|
36
|
-
|
|
37
|
-
if (resolvedAssert !== undefined) {
|
|
38
|
-
return typeof resolvedAssert === 'function' ? assertDefinedEx<T>(result, resolvedAssert) : assertDefinedEx<T>(result, () => resolvedAssert)
|
|
39
|
-
}
|
|
40
|
-
return result
|
|
41
|
-
}
|
|
42
|
-
return func
|
|
43
|
-
},
|
|
44
|
-
createOptional: <T extends AnyNonPromise>(typeCheck: TypeCheck<T>) => {
|
|
45
|
-
const func = (value: AnyNonPromise): T | undefined => {
|
|
46
|
-
if (value === undefined || value === null) return undefined
|
|
47
|
-
if (isPromise(value)) {
|
|
48
|
-
throw new TypeError('un-awaited promises may not be sent to "as" functions')
|
|
49
|
-
}
|
|
50
|
-
return typeCheck(value) ? (value as T) : undefined
|
|
51
|
-
}
|
|
52
|
-
return func
|
|
53
|
-
},
|
|
54
|
-
}
|
package/src/EmptyObject.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type { EmptyObject } from '@xylabs/object-model'
|
package/src/IsObjectFactory.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { TypeCheck, TypeCheckConfig } from '@xylabs/object-model'
|
|
2
|
-
import {
|
|
3
|
-
isObject, isTruthy,
|
|
4
|
-
type ObjectTypeShape, type TypedObject,
|
|
5
|
-
} from '@xylabs/typeof'
|
|
6
|
-
import { isType } from '@xylabs/typeof'
|
|
7
|
-
|
|
8
|
-
export interface ObjectTypeConfig extends TypeCheckConfig {}
|
|
9
|
-
|
|
10
|
-
export class IsObjectFactory<T extends TypedObject> {
|
|
11
|
-
create(shape?: ObjectTypeShape, additionalChecks?: TypeCheck<TypedObject>[]): TypeCheck<T> {
|
|
12
|
-
return (obj: unknown, config?: TypeCheckConfig | number): obj is T => {
|
|
13
|
-
if (!isObject(obj)) {
|
|
14
|
-
return false
|
|
15
|
-
}
|
|
16
|
-
const log = (typeof config === 'object') ? config.log : undefined
|
|
17
|
-
return (
|
|
18
|
-
// do primary check
|
|
19
|
-
Object.entries(shape ?? {}).filter(([key, type]) => {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
const result = isType((obj as any)[key], type)
|
|
22
|
-
if (!result && isTruthy(log)) {
|
|
23
|
-
const logger = typeof log === 'object' ? log : console
|
|
24
|
-
logger.warn(`isType Failed: ${key}: ${type}`)
|
|
25
|
-
}
|
|
26
|
-
return !result
|
|
27
|
-
}).length === 0
|
|
28
|
-
// perform additional checks
|
|
29
|
-
// eslint-disable-next-line unicorn/no-array-reduce
|
|
30
|
-
&& (additionalChecks?.reduce((prev, check) => prev && check(obj, { log }), true) ?? true)
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/JsonObject.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
zodAsFactory, zodIsFactory, zodToFactory,
|
|
3
|
-
} from '@xylabs/zod'
|
|
4
|
-
import * as z from 'zod'
|
|
5
|
-
|
|
6
|
-
const JsonArrayZod = z.array(z.lazy(() => JsonValueZod))
|
|
7
|
-
|
|
8
|
-
// Define recursive JSON value schema
|
|
9
|
-
const JsonValueZod: z.ZodType<unknown> = z.lazy(() =>
|
|
10
|
-
z.union([
|
|
11
|
-
z.string(),
|
|
12
|
-
z.number(),
|
|
13
|
-
z.boolean(),
|
|
14
|
-
z.null(),
|
|
15
|
-
z.array(JsonValueZod),
|
|
16
|
-
z.record(z.string(), JsonValueZod), // object with string keys and JSON values
|
|
17
|
-
]))
|
|
18
|
-
|
|
19
|
-
// JSON object schema — top-level must be an object
|
|
20
|
-
export const JsonObjectZod = z.record(z.string(), JsonValueZod)
|
|
21
|
-
|
|
22
|
-
// TypeScript type for reference
|
|
23
|
-
export type JsonValue = z.infer<typeof JsonValueZod>
|
|
24
|
-
export type JsonObject = z.infer<typeof JsonObjectZod>
|
|
25
|
-
export type JsonArray = z.infer<typeof JsonArrayZod>
|
|
26
|
-
|
|
27
|
-
export const isJsonValue = zodIsFactory(JsonValueZod)
|
|
28
|
-
export const asJsonValue = zodAsFactory(JsonValueZod, 'asJsonValue')
|
|
29
|
-
export const toJsonValue = zodToFactory(JsonValueZod, 'toJsonValue')
|
|
30
|
-
|
|
31
|
-
export const isJsonArray = zodIsFactory(JsonArrayZod)
|
|
32
|
-
export const asJsonArray = zodAsFactory(JsonArrayZod, 'asJsonArray')
|
|
33
|
-
export const toJsonArray = zodToFactory(JsonArrayZod, 'toJsonArray')
|
|
34
|
-
|
|
35
|
-
export const isJsonObject = zodIsFactory(JsonObjectZod)
|
|
36
|
-
export const asJsonObject = zodAsFactory(JsonObjectZod, 'asJsonObject')
|
|
37
|
-
export const toJsonObject = zodToFactory(JsonObjectZod, 'toJsonObject')
|
package/src/ObjectWrapper.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { EmptyObject } from './EmptyObject.ts'
|
|
2
|
-
import type { StringKeyObject } from './StringKeyObject.ts'
|
|
3
|
-
|
|
4
|
-
export abstract class ObjectWrapper<T extends EmptyObject = EmptyObject> {
|
|
5
|
-
readonly obj: T
|
|
6
|
-
constructor(obj: T) {
|
|
7
|
-
this.obj = obj
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
protected get stringKeyObj() {
|
|
11
|
-
return this.obj as StringKeyObject
|
|
12
|
-
}
|
|
13
|
-
}
|
package/src/OmitStartsWith.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { JsonValue } from './JsonObject.ts'
|
|
2
|
-
|
|
3
|
-
export type OmitStartsWith<T, Prefix extends string> = {
|
|
4
|
-
[K in keyof T as K extends `${Prefix}${string}` ? never : K]: T[K];
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export type DeepOmitStartsWith<T, Prefix extends string> = T extends (infer U)[]
|
|
8
|
-
? DeepOmitStartsWith<U, Prefix>[] // Special handling for arrays
|
|
9
|
-
: T extends object
|
|
10
|
-
? {
|
|
11
|
-
[K in keyof T as K extends string
|
|
12
|
-
? K extends `${Prefix}${string}`
|
|
13
|
-
? never
|
|
14
|
-
: K
|
|
15
|
-
: K]: DeepOmitStartsWith<T[K], Prefix>;
|
|
16
|
-
}
|
|
17
|
-
: T
|
|
18
|
-
|
|
19
|
-
export type DeepRestrictToStringKeys<T> = {
|
|
20
|
-
[K in keyof T as K extends string ? K : never]: T[K] extends (infer U)[]
|
|
21
|
-
? DeepRestrictToStringKeys<U>[] // Handle arrays recursively
|
|
22
|
-
: T[K] extends object
|
|
23
|
-
? DeepRestrictToStringKeys<T[K]> // Handle objects recursively
|
|
24
|
-
: T[K]; // Leave other types untouched
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type DeepRestrictToJson<T> = {
|
|
28
|
-
[K in keyof T as K extends string ? K : never]: T[K] extends (infer U)[]
|
|
29
|
-
? DeepRestrictToJson<U>[] // Handle arrays recursively
|
|
30
|
-
: T[K] extends object
|
|
31
|
-
? DeepRestrictToJson<T[K]> // Handle objects recursively
|
|
32
|
-
: T[K] extends JsonValue
|
|
33
|
-
? T[K] // Leave JsonValue types untouched
|
|
34
|
-
: never; // Exclude other types
|
|
35
|
-
}
|
package/src/Optional.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type Optional<T extends object, F extends keyof T> = Omit<T, F> & Partial<Pick<T, F>>
|
package/src/Override.ts
DELETED
package/src/PartialRecord.ts
DELETED
package/src/PickStartsWith.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type PickStartsWith<T, Prefix extends string> = {
|
|
2
|
-
[K in keyof T as K extends `${Prefix}${string}` ? K : never]: T[K];
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export type DeepPickStartsWith<T, Prefix extends string> = T extends (infer U)[]
|
|
6
|
-
? DeepPickStartsWith<U, Prefix>[] // Special handling for arrays
|
|
7
|
-
: T extends object
|
|
8
|
-
? {
|
|
9
|
-
[K in keyof T as K extends string
|
|
10
|
-
? K extends `${Prefix}${string}`
|
|
11
|
-
? K
|
|
12
|
-
: never
|
|
13
|
-
: K]: DeepPickStartsWith<T[K], Prefix>;
|
|
14
|
-
}
|
|
15
|
-
: T
|
package/src/Simplify.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
package/src/StringKeyObject.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type StringKeyObject<T = unknown> = { [key: string]: T }
|
package/src/Validator.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { AnyObject } from '@xylabs/object-model'
|
|
2
|
-
import type { Promisable } from '@xylabs/promise'
|
|
3
|
-
|
|
4
|
-
import type { EmptyObject } from './EmptyObject.ts'
|
|
5
|
-
import { ObjectWrapper } from './ObjectWrapper.ts'
|
|
6
|
-
|
|
7
|
-
export interface Validator<T extends EmptyObject = AnyObject> {
|
|
8
|
-
validate(payload: T): Promisable<Error[]>
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export abstract class ValidatorBase<T extends EmptyObject = AnyObject> extends ObjectWrapper<Partial<T>> implements Validator<T> {
|
|
12
|
-
abstract validate(payload: T): Promisable<Error[]>
|
|
13
|
-
}
|
package/src/WithAdditional.ts
DELETED
package/src/asObject.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { AnyObject } from '@xylabs/object-model'
|
|
2
|
-
import { isObject } from '@xylabs/typeof'
|
|
3
|
-
|
|
4
|
-
import { AsObjectFactory } from './AsObjectFactory.ts'
|
|
5
|
-
|
|
6
|
-
export const asAnyObject = (() => AsObjectFactory.create<AnyObject>(<T extends AnyObject>(obj: unknown): obj is T => isObject(obj)))()
|
package/src/deepMerge.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import type { AnyObject } from '@xylabs/object-model'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Deeply merges two types into a new type.
|
|
5
|
-
*/
|
|
6
|
-
type DeepMerge<A, B> = {
|
|
7
|
-
[K in keyof A | keyof B]:
|
|
8
|
-
K extends keyof B
|
|
9
|
-
? K extends keyof A
|
|
10
|
-
? A[K] extends object
|
|
11
|
-
? B[K] extends object
|
|
12
|
-
? DeepMerge<A[K], B[K]>
|
|
13
|
-
: B[K]
|
|
14
|
-
: B[K]
|
|
15
|
-
: B[K]
|
|
16
|
-
: K extends keyof A
|
|
17
|
-
? A[K]
|
|
18
|
-
: never;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Merges multiple types into a new type.
|
|
23
|
-
*/
|
|
24
|
-
type MergeAll<T extends object[], R = {}>
|
|
25
|
-
= T extends [infer First extends object, ...infer Rest extends object[]]
|
|
26
|
-
? MergeAll<Rest, DeepMerge<R, First>>
|
|
27
|
-
: R
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Options for merging objects in the deep merge function.
|
|
31
|
-
*/
|
|
32
|
-
type MergeOptions = {
|
|
33
|
-
/**
|
|
34
|
-
* Strategy for merging arrays.
|
|
35
|
-
* - 'overwrite': Overwrites the array with the last object's value.
|
|
36
|
-
* - 'concat': Concatenates arrays from all objects.
|
|
37
|
-
* @default 'overwrite'
|
|
38
|
-
*/
|
|
39
|
-
arrayStrategy?: 'overwrite' | 'concat'
|
|
40
|
-
/**
|
|
41
|
-
* Mutate the first object in the list instead of creating a new one.
|
|
42
|
-
* @default false
|
|
43
|
-
*/
|
|
44
|
-
mutate?: boolean
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const isUnsafeKey = (key: string | symbol): boolean =>
|
|
48
|
-
key === '__proto__' || key === 'constructor' || key === 'prototype'
|
|
49
|
-
|
|
50
|
-
function merge<T extends AnyObject>(target: AnyObject, source?: AnyObject, options?: MergeOptions): T {
|
|
51
|
-
if (!source || typeof source !== 'object') return target as T
|
|
52
|
-
|
|
53
|
-
for (const key of Reflect.ownKeys(source)) {
|
|
54
|
-
const value = source[key]
|
|
55
|
-
if (isUnsafeKey(key)) {
|
|
56
|
-
continue
|
|
57
|
-
} else if (Array.isArray(value)) {
|
|
58
|
-
target[key]
|
|
59
|
-
// If the value is an array, handle it based on the configured array strategy
|
|
60
|
-
= options?.arrayStrategy === 'concat' && Array.isArray(target[key])
|
|
61
|
-
? [...target[key], ...value]
|
|
62
|
-
: value
|
|
63
|
-
} else if (value !== null && typeof value === 'object') {
|
|
64
|
-
// Recursively merge nested objects
|
|
65
|
-
if (!target[key] || typeof target[key] !== 'object') {
|
|
66
|
-
target[key] = {}
|
|
67
|
-
}
|
|
68
|
-
merge(target[key] as AnyObject, value as AnyObject, options)
|
|
69
|
-
} else {
|
|
70
|
-
// Overwrite with non-object values
|
|
71
|
-
target[key] = value
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return target as T
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Creates a deep merge function with the specified options.
|
|
80
|
-
* @param options Options for merging.
|
|
81
|
-
* @returns A deep merge function configured for the specified options.
|
|
82
|
-
*/
|
|
83
|
-
export function createDeepMerge(options: MergeOptions) {
|
|
84
|
-
return function deepMerge<T extends AnyObject[]>(...objects: T): MergeAll<T> {
|
|
85
|
-
const result = (options.mutate ? objects[0] ?? {} : {}) as MergeAll<T>
|
|
86
|
-
for (const obj of objects) {
|
|
87
|
-
merge(result, obj, options)
|
|
88
|
-
}
|
|
89
|
-
return result
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Deeply merges multiple objects into a new object.
|
|
95
|
-
* @param objects Multiple objects to merge deeply.
|
|
96
|
-
* The function merges properties from all objects into a new object.
|
|
97
|
-
* If a property exists in multiple objects, the last object's value will be used.
|
|
98
|
-
* If a property is an object, it will be merged recursively.
|
|
99
|
-
* If a property is an array, it will be overwritten by the last object's value.
|
|
100
|
-
* If a property is a primitive value, it will be overwritten by the last object's value.
|
|
101
|
-
* If a property is undefined in the source, it will be skipped.
|
|
102
|
-
* If a property is a symbol, it will be merged as well.
|
|
103
|
-
* @returns A new object with the merged properties.
|
|
104
|
-
*/
|
|
105
|
-
export const deepMerge = createDeepMerge({ arrayStrategy: 'overwrite', mutate: false })
|
package/src/index-deprecated.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export * from './asObject.ts'
|
|
2
|
-
export * from './AsObjectFactory.ts'
|
|
3
|
-
export * from './AsTypeFactory.ts'
|
|
4
|
-
export * from './deepMerge.ts'
|
|
5
|
-
export * from './IsObjectFactory.ts'
|
|
6
|
-
export * from './JsonObject.ts'
|
|
7
|
-
export * from './ObjectWrapper.ts'
|
|
8
|
-
export * from './omitBy.ts'
|
|
9
|
-
export * from './OmitStartsWith.ts'
|
|
10
|
-
export * from './Optional.ts'
|
|
11
|
-
export * from './Override.ts'
|
|
12
|
-
export * from './PartialRecord.ts'
|
|
13
|
-
export * from './pickBy.ts'
|
|
14
|
-
export * from './PickStartsWith.ts'
|
|
15
|
-
export * from './removeFields.ts'
|
|
16
|
-
export * from './Simplify.ts'
|
|
17
|
-
export * from './StringKeyObject.ts'
|
|
18
|
-
export * from './toSafeJson.ts'
|
|
19
|
-
export * from './Validator.ts'
|
|
20
|
-
export * from './WithAdditional.ts'
|
|
21
|
-
export * from '@xylabs/object-model'
|
|
22
|
-
export { isObject } from '@xylabs/typeof'
|
package/src/index.ts
DELETED
package/src/isType.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { FieldType } from '@xylabs/typeof'
|
|
2
|
-
|
|
3
|
-
/** @deprecated use from @xylabs/typeof instead */
|
|
4
|
-
export const isType = (value: unknown, expectedType: FieldType) => {
|
|
5
|
-
const typeofValue = typeof value
|
|
6
|
-
switch (expectedType) {
|
|
7
|
-
case 'array': {
|
|
8
|
-
return Array.isArray(value)
|
|
9
|
-
}
|
|
10
|
-
case 'null': {
|
|
11
|
-
return value === null
|
|
12
|
-
}
|
|
13
|
-
case 'undefined': {
|
|
14
|
-
return value === undefined
|
|
15
|
-
}
|
|
16
|
-
case 'object': {
|
|
17
|
-
// nulls resolve to objects, so exclude them
|
|
18
|
-
if (value === null) {
|
|
19
|
-
return false
|
|
20
|
-
}
|
|
21
|
-
// arrays resolve to objects, so exclude them
|
|
22
|
-
return typeofValue === 'object' && !Array.isArray(value)
|
|
23
|
-
}
|
|
24
|
-
default: {
|
|
25
|
-
return typeofValue === expectedType
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/omitBy.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { assertEx } from '@xylabs/assert'
|
|
2
|
-
|
|
3
|
-
import type { EmptyObject } from './EmptyObject.ts'
|
|
4
|
-
import type { JsonObject } from './JsonObject.ts'
|
|
5
|
-
import type { DeepOmitStartsWith } from './OmitStartsWith.ts'
|
|
6
|
-
|
|
7
|
-
export type OmitByPredicate<T extends EmptyObject = Record<string, unknown>> = (value: T[keyof T], key: keyof T) => boolean
|
|
8
|
-
|
|
9
|
-
const omitByArray = <T>(
|
|
10
|
-
obj: T[],
|
|
11
|
-
predicate: OmitByPredicate,
|
|
12
|
-
maxDepth: number,
|
|
13
|
-
): T[] => {
|
|
14
|
-
return obj.map((value) => {
|
|
15
|
-
return (value !== null && typeof value === 'object') ? omitBy(value, predicate, maxDepth) : value
|
|
16
|
-
}) as T[]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const omitByObject = <T extends EmptyObject>(
|
|
20
|
-
obj: T,
|
|
21
|
-
predicate: OmitByPredicate,
|
|
22
|
-
maxDepth: number,
|
|
23
|
-
): Partial<T> => {
|
|
24
|
-
const result: JsonObject = {}
|
|
25
|
-
|
|
26
|
-
for (const key in obj) {
|
|
27
|
-
if (Object.hasOwn(obj, key)) {
|
|
28
|
-
const value = obj[key]
|
|
29
|
-
if (!predicate(value, key)) {
|
|
30
|
-
result[key] = ((value !== null && typeof value === 'object') ? omitBy(value, predicate, maxDepth - 1) : value) as JsonObject
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return result as T
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const omitBy = <T extends EmptyObject>(
|
|
39
|
-
obj: T,
|
|
40
|
-
predicate: OmitByPredicate,
|
|
41
|
-
maxDepth = 1,
|
|
42
|
-
): Partial<T> => {
|
|
43
|
-
if (maxDepth <= 0) {
|
|
44
|
-
return obj
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return Array.isArray(obj) ? omitByArray(obj, predicate, maxDepth - 1) as T : omitByObject(obj, predicate, maxDepth - 1) as T
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const omitByPrefixPredicate = (prefix: string) => (_: unknown, key: string) => {
|
|
51
|
-
assertEx(typeof key === 'string', () => `Invalid key type [${key}, ${typeof key}]`)
|
|
52
|
-
return key.startsWith(prefix)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export const omitByPrefix = <T extends EmptyObject, P extends string>(payload: T, prefix: P, maxDepth = 100): DeepOmitStartsWith<T, P> => {
|
|
56
|
-
return omitBy(payload, omitByPrefixPredicate(prefix), maxDepth) as unknown as DeepOmitStartsWith<T, P>
|
|
57
|
-
}
|
package/src/pickBy.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { assertEx } from '@xylabs/assert'
|
|
2
|
-
|
|
3
|
-
import type { EmptyObject } from './EmptyObject.ts'
|
|
4
|
-
import type { JsonObject } from './JsonObject.ts'
|
|
5
|
-
import type { DeepPickStartsWith } from './PickStartsWith.ts'
|
|
6
|
-
|
|
7
|
-
export type PickByPredicate<T extends EmptyObject = Record<string, unknown>> = (value: T[keyof T], key: keyof T) => boolean
|
|
8
|
-
|
|
9
|
-
const pickByArray = <T>(
|
|
10
|
-
obj: T[],
|
|
11
|
-
predicate: PickByPredicate,
|
|
12
|
-
maxDepth: number,
|
|
13
|
-
): T[] => {
|
|
14
|
-
return obj.map((value) => {
|
|
15
|
-
return (value !== null && typeof value === 'object') ? pickBy(value, predicate, maxDepth) : value
|
|
16
|
-
}) as T[]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const pickByObject = <T extends EmptyObject>(
|
|
20
|
-
obj: T,
|
|
21
|
-
predicate: PickByPredicate,
|
|
22
|
-
maxDepth: number,
|
|
23
|
-
): Partial<T> => {
|
|
24
|
-
const result: JsonObject = {}
|
|
25
|
-
|
|
26
|
-
for (const key in obj) {
|
|
27
|
-
if (Object.hasOwn(obj, key)) {
|
|
28
|
-
const value = obj[key]
|
|
29
|
-
if (predicate(value, key)) {
|
|
30
|
-
result[key] = ((value !== null && typeof value === 'object') ? pickBy(value, predicate, maxDepth - 1) : value) as JsonObject
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return result as T
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const pickBy = <T extends EmptyObject>(
|
|
39
|
-
obj: T,
|
|
40
|
-
predicate: PickByPredicate,
|
|
41
|
-
maxDepth = 1,
|
|
42
|
-
): Partial<T> => {
|
|
43
|
-
if (maxDepth <= 0) {
|
|
44
|
-
return obj
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return Array.isArray(obj) ? pickByArray(obj, predicate, maxDepth - 1) as T : pickByObject(obj, predicate, maxDepth - 1) as T
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const pickByPrefixPredicate = (prefix: string) => (_: unknown, key: string) => {
|
|
51
|
-
assertEx(typeof key === 'string', () => `Invalid key type [${key}, ${typeof key}]`)
|
|
52
|
-
return key.startsWith(prefix)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export const pickByPrefix = <T extends EmptyObject, P extends string>(payload: T, prefix: P, maxDepth = 100): DeepPickStartsWith<T, P> => {
|
|
56
|
-
return pickBy(payload, pickByPrefixPredicate(prefix), maxDepth) as unknown as DeepPickStartsWith<T, P>
|
|
57
|
-
}
|
package/src/removeFields.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { EmptyObject } from './EmptyObject.ts'
|
|
2
|
-
|
|
3
|
-
export const removeFields = <T extends EmptyObject, K extends keyof T>(obj: T, fields: K[]): Omit<T, K> => {
|
|
4
|
-
const clone = { ...obj }
|
|
5
|
-
for (const field of fields) {
|
|
6
|
-
delete clone[field]
|
|
7
|
-
}
|
|
8
|
-
return clone
|
|
9
|
-
}
|
package/src/toSafeJson.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
JsonArray, JsonObject, JsonValue,
|
|
3
|
-
} from './JsonObject.ts'
|
|
4
|
-
|
|
5
|
-
export const toSafeJsonArray = (value: unknown[], cycleList?: unknown[], maxDepth = 3): JsonArray => {
|
|
6
|
-
return value.map(item => toSafeJsonValue(item, cycleList, maxDepth))
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const toSafeJsonObject = (value: object, cycleList?: unknown[], maxDepth = 3): JsonObject => {
|
|
10
|
-
const result: JsonObject = {}
|
|
11
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
12
|
-
result[key] = value === undefined ? '[Undefined]' : toSafeJsonValue(entry, cycleList, maxDepth)
|
|
13
|
-
}
|
|
14
|
-
return result
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const toSafeJsonValue = (value: unknown, cycleList?: unknown[], maxDepth = 3): JsonValue => {
|
|
18
|
-
if (maxDepth <= 0 && typeof value === 'object') {
|
|
19
|
-
return '[MaxDepth]'
|
|
20
|
-
}
|
|
21
|
-
if (cycleList?.includes(value)) {
|
|
22
|
-
return '[Circular]'
|
|
23
|
-
}
|
|
24
|
-
switch (typeof value) {
|
|
25
|
-
case 'string':
|
|
26
|
-
case 'boolean':
|
|
27
|
-
case 'number': {
|
|
28
|
-
return value
|
|
29
|
-
}
|
|
30
|
-
case 'object': {
|
|
31
|
-
if (value === null) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
const newCycleList = cycleList ?? []
|
|
35
|
-
newCycleList.push(value)
|
|
36
|
-
return Array.isArray(value) ? toSafeJsonArray(value, newCycleList, maxDepth - 1) : toSafeJsonObject(value, newCycleList, maxDepth - 1)
|
|
37
|
-
}
|
|
38
|
-
default: {
|
|
39
|
-
return `[${typeof value}]`
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const toSafeJsonString = (value: unknown, maxDepth = 3) => {
|
|
45
|
-
return JSON.stringify(toSafeJson(value, maxDepth), null, 2)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const toSafeJson = (value: unknown, maxDepth = 3): JsonValue => {
|
|
49
|
-
return toSafeJsonValue(value, undefined, maxDepth)
|
|
50
|
-
}
|