@stacksjs/objects 0.75.451 → 0.75.452
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 +15 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/transform.d.ts +46 -17
- package/dist/transform.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -83,3 +83,18 @@ lengths throw without changing the original. A plain source record replaces a ne
|
|
|
83
83
|
Date, Map, Set or class target during `deepMerge`; those targets are not containers
|
|
84
84
|
for JSON fields. The package ships both its root and the narrow `objects/transform`
|
|
85
85
|
entry as JavaScript and declarations.
|
|
86
|
+
|
|
87
|
+
`omit` normalizes numeric exclusions. `objectMap` returns a partial record because
|
|
88
|
+
callbacks may remove entries. `setPath` preserves sparse slots and own enumerable
|
|
89
|
+
array siblings; its `SetPathResult` type follows known paths, with `unknown` for
|
|
90
|
+
dynamic paths and the replacement type for an empty path.
|
|
91
|
+
|
|
92
|
+
`deepMerge` tracks plain-record graphs per source overlay, preserving cycles and
|
|
93
|
+
sharing each source node's first destination. It updates the same target; arrays
|
|
94
|
+
and non-plain values remain atomic. Later sources use fresh graph tracking.
|
|
95
|
+
|
|
96
|
+
Path inference normalizes numeric/string aliases and distributes finite union
|
|
97
|
+
steps. Broad string/number/template steps and open index-signature object sources
|
|
98
|
+
return `unknown`; narrow before using them. Length changes drop fixed tuple index
|
|
99
|
+
guarantees, and generic array results include possible holes. Numeric-looking
|
|
100
|
+
named siblings such as `-1` and `1.5` retain their own value types.
|
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ import type { DeepMerge } from '@stacksjs/types';
|
|
|
26
26
|
* // { b: 2 }
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
export declare function objectMap<K extends string, V, NK extends PropertyKey = K, NV = V>(obj: Record<K, V>, fn: (key: K, value: V) => [NK, NV] | undefined): Record<NK, NV
|
|
29
|
+
export declare function objectMap<K extends string, V, NK extends PropertyKey = K, NV = V>(obj: Record<K, V>, fn: (key: K, value: V) => [NK, NV] | undefined): Partial<Record<NK, NV>>;
|
|
30
30
|
/**
|
|
31
31
|
* Type guard for any key, `k`.
|
|
32
32
|
* Marks `k` as a key of `T` if `k` is in `obj`.
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{notNullish}from"@stacksjs/utils";import{isObject}from"@stacksjs/validation";export*from"./transform";export function objectMap(obj,fn){return Object.fromEntries(Object.entries(obj).map(([k,v])=>fn(k,v)).filter(notNullish))}export function isKeyOf(obj,k){return k in obj}export function objectKeys(obj){return Object.keys(obj)}export function objectEntries(obj){return Object.entries(obj)}export function deepMerge(target,...sources){
|
|
1
|
+
import{notNullish}from"@stacksjs/utils";import{isObject}from"@stacksjs/validation";export*from"./transform";export function objectMap(obj,fn){return Object.fromEntries(Object.entries(obj).map(([k,v])=>fn(k,v)).filter(notNullish))}export function isKeyOf(obj,k){return k in obj}export function objectKeys(obj){return Object.keys(obj)}export function objectEntries(obj){return Object.entries(obj)}export function deepMerge(target,...sources){for(const source of sources)if(isMergeableObject(target)&&isMergeableObject(source))mergeGraph(target,source,new WeakMap);return target}function mergeGraph(into,from,seen){seen.set(from,into);for(const key of Object.keys(from)){if(key==="__proto__")continue;const value=from[key];let merged=value;if(isPlainObject(value)){const mapped=seen.get(value);if(mapped)merged=mapped;else{const existing=Object.hasOwn(into,key)?into[key]:void 0,child=isPlainObject(existing)?existing:{};mergeGraph(child,value,seen);merged=child}}if(Object.hasOwn(into,key))into[key]=merged;else Object.defineProperty(into,key,{value:merged,writable:!0,enumerable:!0,configurable:!0})}}function isMergeableObject(item){return isObject(item)&&!Array.isArray(item)}function isPlainObject(item){if(typeof item!=="object"||item===null)return!1;const proto=Object.getPrototypeOf(item);if(proto===null||proto===Object.prototype)return!0;if(Object.getPrototypeOf(proto)!==null)return!1;const constructor=Object.getOwnPropertyDescriptor(proto,"constructor")?.value;return typeof constructor==="function"&&Function.prototype.toString.call(constructor)===Function.prototype.toString.call(Object)}export function objectPick(obj,keys,omitUndefined=!1){return Object.fromEntries(keys.filter((key)=>(key in obj)&&(!omitUndefined||obj[key]!==void 0)).map((key)=>[key,obj[key]]))}export function clearUndefined(obj){Object.keys(obj).forEach((key)=>obj[key]===void 0&&delete obj[key]);return obj}export function hasOwnProperty(obj,v){return obj==null?!1:Object.prototype.hasOwnProperty.call(obj,v)}
|
package/dist/transform.d.ts
CHANGED
|
@@ -118,23 +118,7 @@ export declare function isEmptyObject(obj: object): boolean;
|
|
|
118
118
|
* ```
|
|
119
119
|
*/
|
|
120
120
|
export declare function getPath(source: unknown, path: readonly PathStep[], fallback?: unknown): unknown;
|
|
121
|
-
|
|
122
|
-
* A copy with the value at `path` replaced, creating missing steps on the way.
|
|
123
|
-
*
|
|
124
|
-
* Only the objects along the path are copied - siblings are shared with the
|
|
125
|
-
* original, which is what makes this cheap enough to use on every update. A
|
|
126
|
-
* numeric step creates an array where a step is missing, so
|
|
127
|
-
* `setPath({}, ['items', 0], x)` produces `{ items: [x] }` rather than
|
|
128
|
-
* `{ items: { 0: x } }`.
|
|
129
|
-
*
|
|
130
|
-
* @category Object
|
|
131
|
-
* @example
|
|
132
|
-
* ```ts
|
|
133
|
-
* setPath({ a: { b: 1 } }, ['a', 'b'], 2) // { a: { b: 2 } }
|
|
134
|
-
* setPath({}, ['a', 'b'], 1) // { a: { b: 1 } }
|
|
135
|
-
* ```
|
|
136
|
-
*/
|
|
137
|
-
export declare function setPath<O extends object>(source: O, path: readonly PathStep[], value: unknown): O;
|
|
121
|
+
export declare function setPath<O extends object, const Path extends readonly PathStep[], V>(source: O, path: Path, value: V): SetPathResult<O, Path, V>;
|
|
138
122
|
/**
|
|
139
123
|
* A copy with every value replaced by what `transform` returns.
|
|
140
124
|
*
|
|
@@ -151,3 +135,48 @@ export declare function setPath<O extends object>(source: O, path: readonly Path
|
|
|
151
135
|
export type MappedStringValues<O extends object, R> = { [K in keyof O as K extends string | number ? K : never]: R }
|
|
152
136
|
/** One step of a path: an object key or an array index. */
|
|
153
137
|
export type PathStep = string | number;
|
|
138
|
+
/**
|
|
139
|
+
* A copy with the value at `path` replaced, creating missing steps on the way.
|
|
140
|
+
*
|
|
141
|
+
* Only the objects along the path are copied - siblings are shared with the
|
|
142
|
+
* original, which is what makes this cheap enough to use on every update. A
|
|
143
|
+
* numeric step creates an array where a step is missing, so
|
|
144
|
+
* `setPath({}, ['items', 0], x)` produces `{ items: [x] }` rather than
|
|
145
|
+
* `{ items: { 0: x } }`.
|
|
146
|
+
*
|
|
147
|
+
* @category Object
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* setPath({ a: { b: 1 } }, ['a', 'b'], 2) // { a: { b: 2 } }
|
|
151
|
+
* setPath({}, ['a', 'b'], 1) // { a: { b: 1 } }
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
declare type KeyName<K> = K extends number ? `${K}` : K;
|
|
155
|
+
declare type MatchingKeys<S, K> = { [P in keyof S]-?: KeyName<P> extends KeyName<K> ? P : never }[keyof S];
|
|
156
|
+
declare type PathChild<S, K extends PropertyKey> = [MatchingKeys<S, K>] extends [never] ? undefined : S[MatchingKeys<S, K>];
|
|
157
|
+
declare type ArraySiblings<S extends readonly unknown[]> = Omit<S, keyof [...S]>;
|
|
158
|
+
declare type UpdatedArray<S extends readonly unknown[], K extends PathStep, Rest extends readonly PathStep[], V> = Array<S[number] | SetPathResult<PathChild<S, K>, Rest, V> | undefined>
|
|
159
|
+
& Omit<ArraySiblings<S>, MatchingKeys<ArraySiblings<S>, K>>
|
|
160
|
+
& { [P in K]: SetPathResult<PathChild<S, P>, Rest, V> }
|
|
161
|
+
declare type ArrayPathResult<S extends readonly unknown[], K extends PathStep, Rest extends readonly PathStep[], V> = K extends 'length' ? Array<S[number] | undefined> & Partial<ArraySiblings<S>>
|
|
162
|
+
: K extends number | `${number}`
|
|
163
|
+
? number extends S['length'] ? UpdatedArray<S, K, Rest, V>
|
|
164
|
+
: `${K}` extends keyof S
|
|
165
|
+
? { [I in keyof S]: I extends `${K}` ? SetPathResult<S[I], Rest, V> : S[I] }
|
|
166
|
+
: UpdatedArray<S, K, Rest, V>
|
|
167
|
+
: Omit<S, MatchingKeys<S, K>> & { [P in K]: SetPathResult<PathChild<S, P>, Rest, V> }
|
|
168
|
+
/** Known paths describe their updated shape; arbitrary or patterned steps return unknown. */
|
|
169
|
+
export type SetPathResult<S, Path extends readonly PathStep[], V> = number extends Path['length'] ? unknown
|
|
170
|
+
: Path extends readonly [] ? V
|
|
171
|
+
: Path extends readonly [infer K extends PathStep, ...infer Rest extends readonly PathStep[]]
|
|
172
|
+
? K extends unknown
|
|
173
|
+
// An empty object satisfies open index signatures, but not a required literal key.
|
|
174
|
+
? {} extends Record<K, never> ? unknown
|
|
175
|
+
: S extends readonly unknown[] ? ArrayPathResult<S, K, Rest, V>
|
|
176
|
+
: S extends object ? string extends keyof S ? unknown
|
|
177
|
+
: number extends keyof S ? unknown
|
|
178
|
+
: Omit<S, MatchingKeys<S, K>> & { [P in K]: SetPathResult<PathChild<S, P>, Rest, V> }
|
|
179
|
+
: K extends number ? ArrayPathResult<never[], K, Rest, V>
|
|
180
|
+
: { [P in K]: SetPathResult<undefined, Rest, V> }
|
|
181
|
+
: never
|
|
182
|
+
: unknown;
|
package/dist/transform.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function omit(obj,keys){const excluded=new Set(keys);return Object.fromEntries(Object.entries(obj).filter(([key])=>!excluded.has(key)))}export function pickBy(obj,predicate){return Object.fromEntries(Object.entries(obj).filter(([key,value])=>predicate(value,key)))}export function omitBy(obj,predicate){return pickBy(obj,(value,key)=>!predicate(value,key))}export function mapValues(obj,transform){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[key,transform(value,key)]))}export function mapKeys(obj,transform){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[transform(key,value),value]))}export function invert(obj){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[String(value),key]))}export function isEmptyObject(obj){for(const _key in obj)if(Object.hasOwn(obj,_key))return!1;return!0}export function getPath(source,path,fallback){let current=source;for(const step of path){if(current===null||current===void 0)return fallback;current=current[step]}return current===void 0?fallback:current}export function setPath(source,path,value){if(path.length===0)return value;const[step,...rest]=path,container=Array.isArray(source)?
|
|
1
|
+
export function omit(obj,keys){const excluded=new Set(keys.map((key)=>typeof key==="number"?String(key):key));return Object.fromEntries(Object.entries(obj).filter(([key])=>!excluded.has(key)))}export function pickBy(obj,predicate){return Object.fromEntries(Object.entries(obj).filter(([key,value])=>predicate(value,key)))}export function omitBy(obj,predicate){return pickBy(obj,(value,key)=>!predicate(value,key))}export function mapValues(obj,transform){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[key,transform(value,key)]))}export function mapKeys(obj,transform){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[transform(key,value),value]))}export function invert(obj){return Object.fromEntries(Object.entries(obj).map(([key,value])=>[String(value),key]))}export function isEmptyObject(obj){for(const _key in obj)if(Object.hasOwn(obj,_key))return!1;return!0}export function getPath(source,path,fallback){let current=source;for(const step of path){if(current===null||current===void 0)return fallback;current=current[step]}return current===void 0?fallback:current}export function setPath(source,path,value){if(path.length===0)return value;const[step,...rest]=path,container=Array.isArray(source)?copyArray(source):{...source};if(rest.length===0){defineKey(container,step,value);return container}const existing=Object.hasOwn(container,step)?container[step]:void 0,child=existing===null||typeof existing!=="object"?typeof rest[0]==="number"?[]:{}:existing;defineKey(container,step,setPath(child,rest,value));return container}function copyArray(source){const copy=Array(source.length);for(const key of Reflect.ownKeys(source)){if(!Object.prototype.propertyIsEnumerable.call(source,key))continue;defineKey(copy,key,source[key])}return copy}function defineKey(target,key,value){if(Array.isArray(target)&&key==="length"){Object.defineProperty(target,key,{value});return}Object.defineProperty(target,key,{value,writable:!0,enumerable:!0,configurable:!0})}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/objects",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.75.
|
|
4
|
+
"version": "0.75.452",
|
|
5
5
|
"description": "The Stacks objects.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -56,12 +56,12 @@
|
|
|
56
56
|
"prepublishOnly": "bun run build"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@stacksjs/utils": "0.75.
|
|
60
|
-
"@stacksjs/validation": "0.75.
|
|
59
|
+
"@stacksjs/utils": "0.75.452",
|
|
60
|
+
"@stacksjs/validation": "0.75.452"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@stacksjs/collections": "0.75.
|
|
64
|
-
"@stacksjs/types": "0.75.
|
|
63
|
+
"@stacksjs/collections": "0.75.452",
|
|
64
|
+
"@stacksjs/types": "0.75.452",
|
|
65
65
|
"better-dx": "^0.2.24"
|
|
66
66
|
},
|
|
67
67
|
"sideEffects": false
|