tspo 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Sean Maxwell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # tspo ✈️
2
+
3
+ [![npm](https://img.shields.io/npm/v/tspo?label=npm&color=0ea5e9)](https://www.npmjs.com/package/tspo)
4
+ [![downloads](https://img.shields.io/npm/dm/tspo?label=downloads&color=38bdf8)](https://www.npmjs.com/package/tspo)
5
+ [![types](https://img.shields.io/npm/types/tspo?label=types&color=22c55e)](https://www.npmjs.com/package/tspo)
6
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/tspo?label=bundle&color=0f172a)](https://bundlephobia.com/package/tspo)
7
+ [![license](https://img.shields.io/npm/l/tspo?label=license&color=334155)](LICENSE)
8
+
9
+ Please refer to the official <a href="https://github.com/seanpmaxwell/tspo">github repo</a> for the most up-to-date documentation.
@@ -0,0 +1,6 @@
1
+ import {} from './isPlainObject.js';
2
+ import tspo from './tspo.js';
3
+ const typedTspo = tspo;
4
+ export {} from './utility-types.js';
5
+ export {} from './isPlainObject.js';
6
+ export default typedTspo;
@@ -0,0 +1,13 @@
1
+ const objectProto = Object.prototype;
2
+ function isPlainObject(arg) {
3
+ if (typeof arg !== 'object' || arg === null) {
4
+ return false;
5
+ }
6
+ const argProto = Object.getPrototypeOf(arg);
7
+ return ((argProto === null ||
8
+ argProto === objectProto ||
9
+ Object.getPrototypeOf(argProto) === null) &&
10
+ !(Symbol.toStringTag in arg) &&
11
+ !(Symbol.iterator in arg));
12
+ }
13
+ export default isPlainObject;
@@ -0,0 +1,133 @@
1
+ import isPlainObject, {} from './isPlainObject.js';
2
+ import compare from './utils/compare.js';
3
+ import copy from './utils/copy.js';
4
+ import iterate from './utils/iterate.js';
5
+ function omit(obj, keys) {
6
+ const retVal = {}, set = new Set(Array.isArray(keys) ? keys : [keys]);
7
+ for (const key in obj) {
8
+ if (!set.has(key)) {
9
+ retVal[key] = obj[key];
10
+ }
11
+ }
12
+ return retVal;
13
+ }
14
+ function pick(obj, keys) {
15
+ const retVal = {}, set = new Set(Array.isArray(keys) ? keys : [keys]);
16
+ for (const key in obj) {
17
+ if (set.has(key)) {
18
+ retVal[key] = obj[key];
19
+ }
20
+ }
21
+ return retVal;
22
+ }
23
+ function merge(a, b) {
24
+ return { ...a, ...b };
25
+ }
26
+ function fill(defaults, partial) {
27
+ return { ...defaults, ...(partial ?? {}) };
28
+ }
29
+ function append(obj, addOn) {
30
+ for (const key in addOn) {
31
+ obj[key] = addOn[key];
32
+ }
33
+ }
34
+ function appendOne(obj, entry) {
35
+ obj[entry[0]] = entry[1];
36
+ }
37
+ function remove(obj, keys) {
38
+ const keyArr = Array.isArray(keys) ? keys : [keys];
39
+ for (const key of keyArr) {
40
+ delete obj[key];
41
+ }
42
+ }
43
+ function index(obj, key) {
44
+ return obj[key];
45
+ }
46
+ function safeIndex(obj, key) {
47
+ if (key in obj) {
48
+ return obj[key];
49
+ }
50
+ else {
51
+ throw new Error('safeIndex was passed a key not present on the object. key: ' + key);
52
+ }
53
+ }
54
+ function reverseIndex(obj, value) {
55
+ const retVal = [];
56
+ for (const key in obj) {
57
+ if (obj[key] === value) {
58
+ retVal.push(key);
59
+ }
60
+ }
61
+ return retVal;
62
+ }
63
+ function safeReverseIndex(obj, value) {
64
+ const retVal = [];
65
+ for (const key in obj) {
66
+ if (obj[key] === value) {
67
+ retVal.push(key);
68
+ }
69
+ }
70
+ if (retVal.length !== 1) {
71
+ throw new Error('.safeReverseIndex found 0 or more than 1 keys for value: ' +
72
+ String(value));
73
+ }
74
+ return retVal[0];
75
+ }
76
+ function isKey(obj, arg) {
77
+ const keyArr = Array.isArray(arg) ? arg : [arg];
78
+ for (const key of keyArr) {
79
+ if (!(typeof arg === 'string' && arg in obj))
80
+ return false;
81
+ }
82
+ return true;
83
+ }
84
+ function isValue(obj, arg) {
85
+ const valArr = Array.isArray(arg) ? arg : [arg], valSet = new Set(Object.values(obj));
86
+ for (const val of valArr) {
87
+ if (!valSet.has(val))
88
+ return false;
89
+ }
90
+ return true;
91
+ }
92
+ function keys(obj) {
93
+ return Object.keys(obj);
94
+ }
95
+ function values(obj) {
96
+ return Object.values(obj);
97
+ }
98
+ function entries(obj) {
99
+ return Object.entries(obj);
100
+ }
101
+ function firstEntry(obj) {
102
+ return Object.entries(obj)[0];
103
+ }
104
+ function toDict(obj) {
105
+ if (!isPlainObject(obj)) {
106
+ throw new Error('value passed to ".toDict" not a plain-object');
107
+ }
108
+ return obj;
109
+ }
110
+ export default {
111
+ omit,
112
+ pick,
113
+ merge,
114
+ fill,
115
+ append,
116
+ appendOne,
117
+ index,
118
+ remove,
119
+ toDict,
120
+ safeIndex,
121
+ reverseIndex,
122
+ safeReverseIndex,
123
+ is: isPlainObject,
124
+ isKey,
125
+ isValue,
126
+ keys,
127
+ values,
128
+ entries,
129
+ firstEntry,
130
+ iterate,
131
+ copy,
132
+ compare,
133
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ const hop = Object.prototype.hasOwnProperty;
3
+ function compare(a, b) {
4
+ if (!isPlainObject(a) || !isPlainObject(b)) {
5
+ return false;
6
+ }
7
+ return comparePlainObjects(a, b);
8
+ }
9
+ function comparePlainObjects(a, b) {
10
+ const aKeys = Object.keys(a), bKeys = Object.keys(b);
11
+ if (aKeys.length !== bKeys.length)
12
+ return false;
13
+ for (const key of aKeys) {
14
+ if (!hop.call(b, key))
15
+ return false;
16
+ if (!compareValue(a[key], b[key]))
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ function compareValue(a, b) {
22
+ if (Object.is(a, b))
23
+ return true;
24
+ if (a instanceof Date || b instanceof Date) {
25
+ return (a instanceof Date && b instanceof Date && a.getTime() === b.getTime());
26
+ }
27
+ const aIsArray = Array.isArray(a), bIsArray = Array.isArray(b);
28
+ if (aIsArray || bIsArray) {
29
+ return aIsArray && bIsArray && compareArrays(a, b);
30
+ }
31
+ const aIsPlainObject = isPlainObject(a), bIsPlainObject = isPlainObject(b);
32
+ if (aIsPlainObject || bIsPlainObject) {
33
+ return aIsPlainObject && bIsPlainObject && comparePlainObjects(a, b);
34
+ }
35
+ if (typeof a === 'object' &&
36
+ a !== null &&
37
+ typeof b === 'object' &&
38
+ b !== null) {
39
+ return a === b;
40
+ }
41
+ return false;
42
+ }
43
+ function compareArrays(a, b) {
44
+ if (a.length !== b.length)
45
+ return false;
46
+ for (let i = 0; i < a.length; i++) {
47
+ if (!compareValue(a[i], b[i]))
48
+ return false;
49
+ }
50
+ return true;
51
+ }
52
+ export default compare;
@@ -0,0 +1,75 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ import {} from '../utility-types.js';
3
+ const hop = Object.prototype.hasOwnProperty;
4
+ function copy(value, options) {
5
+ if (!isPlainObject(value)) {
6
+ throw new TypeError('copy only accepts a plain-object as the root value');
7
+ }
8
+ const resetDates = options?.resetDates === true;
9
+ return clonePlainObject(value, Object.getPrototypeOf(value), resetDates);
10
+ }
11
+ function clonePlainObject(source, proto, resetDates) {
12
+ const out = proto === null ? Object.create(null) : {};
13
+ for (const key in source) {
14
+ if (!hop.call(source, key))
15
+ continue;
16
+ out[key] = cloneValue(source[key], resetDates);
17
+ }
18
+ return out;
19
+ }
20
+ function cloneValue(value, resetDates) {
21
+ if (isPlainObject(value)) {
22
+ return clonePlainObject(value, Object.getPrototypeOf(value), resetDates);
23
+ }
24
+ if (Array.isArray(value)) {
25
+ return cloneArray(value, resetDates);
26
+ }
27
+ if (value instanceof Date) {
28
+ if (resetDates) {
29
+ return new Date();
30
+ }
31
+ return new Date(value.getTime());
32
+ }
33
+ if (typeof value === 'object' && value !== null) {
34
+ return cloneNonPlainShallow(value);
35
+ }
36
+ return value;
37
+ }
38
+ function cloneArray(source, resetDates) {
39
+ const len = source.length;
40
+ const out = new Array(len);
41
+ for (let i = 0; i < len; i++) {
42
+ out[i] = cloneValue(source[i], resetDates);
43
+ }
44
+ return out;
45
+ }
46
+ function cloneNonPlainShallow(value) {
47
+ if (value instanceof RegExp) {
48
+ const re = new RegExp(value.source, value.flags);
49
+ re.lastIndex = value.lastIndex;
50
+ return re;
51
+ }
52
+ if (value instanceof Map)
53
+ return new Map(value);
54
+ if (value instanceof Set)
55
+ return new Set(value);
56
+ if (ArrayBuffer.isView(value)) {
57
+ const anyVal = value;
58
+ if (typeof anyVal.slice === 'function')
59
+ return anyVal.slice();
60
+ if (value instanceof DataView) {
61
+ return new DataView(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
62
+ }
63
+ return new anyVal.constructor(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
64
+ }
65
+ if (value instanceof ArrayBuffer)
66
+ return value.slice(0);
67
+ const proto = Object.getPrototypeOf(value);
68
+ const out = Object.create(proto);
69
+ for (const key in value) {
70
+ if (hop.call(value, key))
71
+ out[key] = value[key];
72
+ }
73
+ return out;
74
+ }
75
+ export default copy;
@@ -0,0 +1,30 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ function iterate(root, cb) {
3
+ if (!isPlainObject(root))
4
+ return;
5
+ iterateHelper(root, [], cb);
6
+ }
7
+ function iterateHelper(node, path, cb) {
8
+ if (Array.isArray(node)) {
9
+ let i = 0;
10
+ for (const [key, value] of node.entries()) {
11
+ if (isPlainObject(value) || Array.isArray(value)) {
12
+ iterateHelper(value, [...path, key, i], cb);
13
+ }
14
+ else {
15
+ cb({ parent: node, key, value, path });
16
+ }
17
+ i++;
18
+ }
19
+ return;
20
+ }
21
+ for (const [key, value] of Object.entries(node)) {
22
+ if (isPlainObject(value) || Array.isArray(value)) {
23
+ iterateHelper(value, [...path, key], cb);
24
+ }
25
+ else {
26
+ cb({ parent: node, key, value, path });
27
+ }
28
+ }
29
+ }
30
+ export default iterate;
@@ -0,0 +1,6 @@
1
+ import {} from './isPlainObject.js';
2
+ import tspo from './tspo.js';
3
+ const typedTspo = tspo;
4
+ export {} from './utility-types.js';
5
+ export {} from './isPlainObject.js';
6
+ export default typedTspo;
@@ -0,0 +1,13 @@
1
+ const objectProto = Object.prototype;
2
+ function isPlainObject(arg) {
3
+ if (typeof arg !== 'object' || arg === null) {
4
+ return false;
5
+ }
6
+ const argProto = Object.getPrototypeOf(arg);
7
+ return ((argProto === null ||
8
+ argProto === objectProto ||
9
+ Object.getPrototypeOf(argProto) === null) &&
10
+ !(Symbol.toStringTag in arg) &&
11
+ !(Symbol.iterator in arg));
12
+ }
13
+ export default isPlainObject;
@@ -0,0 +1,133 @@
1
+ import isPlainObject, {} from './isPlainObject.js';
2
+ import compare from './utils/compare.js';
3
+ import copy from './utils/copy.js';
4
+ import iterate from './utils/iterate.js';
5
+ function omit(obj, keys) {
6
+ const retVal = {}, set = new Set(Array.isArray(keys) ? keys : [keys]);
7
+ for (const key in obj) {
8
+ if (!set.has(key)) {
9
+ retVal[key] = obj[key];
10
+ }
11
+ }
12
+ return retVal;
13
+ }
14
+ function pick(obj, keys) {
15
+ const retVal = {}, set = new Set(Array.isArray(keys) ? keys : [keys]);
16
+ for (const key in obj) {
17
+ if (set.has(key)) {
18
+ retVal[key] = obj[key];
19
+ }
20
+ }
21
+ return retVal;
22
+ }
23
+ function merge(a, b) {
24
+ return { ...a, ...b };
25
+ }
26
+ function fill(defaults, partial) {
27
+ return { ...defaults, ...(partial ?? {}) };
28
+ }
29
+ function append(obj, addOn) {
30
+ for (const key in addOn) {
31
+ obj[key] = addOn[key];
32
+ }
33
+ }
34
+ function appendOne(obj, entry) {
35
+ obj[entry[0]] = entry[1];
36
+ }
37
+ function remove(obj, keys) {
38
+ const keyArr = Array.isArray(keys) ? keys : [keys];
39
+ for (const key of keyArr) {
40
+ delete obj[key];
41
+ }
42
+ }
43
+ function index(obj, key) {
44
+ return obj[key];
45
+ }
46
+ function safeIndex(obj, key) {
47
+ if (key in obj) {
48
+ return obj[key];
49
+ }
50
+ else {
51
+ throw new Error('safeIndex was passed a key not present on the object. key: ' + key);
52
+ }
53
+ }
54
+ function reverseIndex(obj, value) {
55
+ const retVal = [];
56
+ for (const key in obj) {
57
+ if (obj[key] === value) {
58
+ retVal.push(key);
59
+ }
60
+ }
61
+ return retVal;
62
+ }
63
+ function safeReverseIndex(obj, value) {
64
+ const retVal = [];
65
+ for (const key in obj) {
66
+ if (obj[key] === value) {
67
+ retVal.push(key);
68
+ }
69
+ }
70
+ if (retVal.length !== 1) {
71
+ throw new Error('.safeReverseIndex found 0 or more than 1 keys for value: ' +
72
+ String(value));
73
+ }
74
+ return retVal[0];
75
+ }
76
+ function isKey(obj, arg) {
77
+ const keyArr = Array.isArray(arg) ? arg : [arg];
78
+ for (const key of keyArr) {
79
+ if (!(typeof arg === 'string' && arg in obj))
80
+ return false;
81
+ }
82
+ return true;
83
+ }
84
+ function isValue(obj, arg) {
85
+ const valArr = Array.isArray(arg) ? arg : [arg], valSet = new Set(Object.values(obj));
86
+ for (const val of valArr) {
87
+ if (!valSet.has(val))
88
+ return false;
89
+ }
90
+ return true;
91
+ }
92
+ function keys(obj) {
93
+ return Object.keys(obj);
94
+ }
95
+ function values(obj) {
96
+ return Object.values(obj);
97
+ }
98
+ function entries(obj) {
99
+ return Object.entries(obj);
100
+ }
101
+ function firstEntry(obj) {
102
+ return Object.entries(obj)[0];
103
+ }
104
+ function toDict(obj) {
105
+ if (!isPlainObject(obj)) {
106
+ throw new Error('value passed to ".toDict" not a plain-object');
107
+ }
108
+ return obj;
109
+ }
110
+ export default {
111
+ omit,
112
+ pick,
113
+ merge,
114
+ fill,
115
+ append,
116
+ appendOne,
117
+ index,
118
+ remove,
119
+ toDict,
120
+ safeIndex,
121
+ reverseIndex,
122
+ safeReverseIndex,
123
+ is: isPlainObject,
124
+ isKey,
125
+ isValue,
126
+ keys,
127
+ values,
128
+ entries,
129
+ firstEntry,
130
+ iterate,
131
+ copy,
132
+ compare,
133
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ const hop = Object.prototype.hasOwnProperty;
3
+ function compare(a, b) {
4
+ if (!isPlainObject(a) || !isPlainObject(b)) {
5
+ return false;
6
+ }
7
+ return comparePlainObjects(a, b);
8
+ }
9
+ function comparePlainObjects(a, b) {
10
+ const aKeys = Object.keys(a), bKeys = Object.keys(b);
11
+ if (aKeys.length !== bKeys.length)
12
+ return false;
13
+ for (const key of aKeys) {
14
+ if (!hop.call(b, key))
15
+ return false;
16
+ if (!compareValue(a[key], b[key]))
17
+ return false;
18
+ }
19
+ return true;
20
+ }
21
+ function compareValue(a, b) {
22
+ if (Object.is(a, b))
23
+ return true;
24
+ if (a instanceof Date || b instanceof Date) {
25
+ return (a instanceof Date && b instanceof Date && a.getTime() === b.getTime());
26
+ }
27
+ const aIsArray = Array.isArray(a), bIsArray = Array.isArray(b);
28
+ if (aIsArray || bIsArray) {
29
+ return aIsArray && bIsArray && compareArrays(a, b);
30
+ }
31
+ const aIsPlainObject = isPlainObject(a), bIsPlainObject = isPlainObject(b);
32
+ if (aIsPlainObject || bIsPlainObject) {
33
+ return aIsPlainObject && bIsPlainObject && comparePlainObjects(a, b);
34
+ }
35
+ if (typeof a === 'object' &&
36
+ a !== null &&
37
+ typeof b === 'object' &&
38
+ b !== null) {
39
+ return a === b;
40
+ }
41
+ return false;
42
+ }
43
+ function compareArrays(a, b) {
44
+ if (a.length !== b.length)
45
+ return false;
46
+ for (let i = 0; i < a.length; i++) {
47
+ if (!compareValue(a[i], b[i]))
48
+ return false;
49
+ }
50
+ return true;
51
+ }
52
+ export default compare;
@@ -0,0 +1,75 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ import {} from '../utility-types.js';
3
+ const hop = Object.prototype.hasOwnProperty;
4
+ function copy(value, options) {
5
+ if (!isPlainObject(value)) {
6
+ throw new TypeError('copy only accepts a plain-object as the root value');
7
+ }
8
+ const resetDates = options?.resetDates === true;
9
+ return clonePlainObject(value, Object.getPrototypeOf(value), resetDates);
10
+ }
11
+ function clonePlainObject(source, proto, resetDates) {
12
+ const out = proto === null ? Object.create(null) : {};
13
+ for (const key in source) {
14
+ if (!hop.call(source, key))
15
+ continue;
16
+ out[key] = cloneValue(source[key], resetDates);
17
+ }
18
+ return out;
19
+ }
20
+ function cloneValue(value, resetDates) {
21
+ if (isPlainObject(value)) {
22
+ return clonePlainObject(value, Object.getPrototypeOf(value), resetDates);
23
+ }
24
+ if (Array.isArray(value)) {
25
+ return cloneArray(value, resetDates);
26
+ }
27
+ if (value instanceof Date) {
28
+ if (resetDates) {
29
+ return new Date();
30
+ }
31
+ return new Date(value.getTime());
32
+ }
33
+ if (typeof value === 'object' && value !== null) {
34
+ return cloneNonPlainShallow(value);
35
+ }
36
+ return value;
37
+ }
38
+ function cloneArray(source, resetDates) {
39
+ const len = source.length;
40
+ const out = new Array(len);
41
+ for (let i = 0; i < len; i++) {
42
+ out[i] = cloneValue(source[i], resetDates);
43
+ }
44
+ return out;
45
+ }
46
+ function cloneNonPlainShallow(value) {
47
+ if (value instanceof RegExp) {
48
+ const re = new RegExp(value.source, value.flags);
49
+ re.lastIndex = value.lastIndex;
50
+ return re;
51
+ }
52
+ if (value instanceof Map)
53
+ return new Map(value);
54
+ if (value instanceof Set)
55
+ return new Set(value);
56
+ if (ArrayBuffer.isView(value)) {
57
+ const anyVal = value;
58
+ if (typeof anyVal.slice === 'function')
59
+ return anyVal.slice();
60
+ if (value instanceof DataView) {
61
+ return new DataView(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
62
+ }
63
+ return new anyVal.constructor(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
64
+ }
65
+ if (value instanceof ArrayBuffer)
66
+ return value.slice(0);
67
+ const proto = Object.getPrototypeOf(value);
68
+ const out = Object.create(proto);
69
+ for (const key in value) {
70
+ if (hop.call(value, key))
71
+ out[key] = value[key];
72
+ }
73
+ return out;
74
+ }
75
+ export default copy;
@@ -0,0 +1,30 @@
1
+ import isPlainObject, {} from '../isPlainObject.js';
2
+ function iterate(root, cb) {
3
+ if (!isPlainObject(root))
4
+ return;
5
+ iterateHelper(root, [], cb);
6
+ }
7
+ function iterateHelper(node, path, cb) {
8
+ if (Array.isArray(node)) {
9
+ let i = 0;
10
+ for (const [key, value] of node.entries()) {
11
+ if (isPlainObject(value) || Array.isArray(value)) {
12
+ iterateHelper(value, [...path, key, i], cb);
13
+ }
14
+ else {
15
+ cb({ parent: node, key, value, path });
16
+ }
17
+ i++;
18
+ }
19
+ return;
20
+ }
21
+ for (const [key, value] of Object.entries(node)) {
22
+ if (isPlainObject(value) || Array.isArray(value)) {
23
+ iterateHelper(value, [...path, key], cb);
24
+ }
25
+ else {
26
+ cb({ parent: node, key, value, path });
27
+ }
28
+ }
29
+ }
30
+ export default iterate;
@@ -0,0 +1,28 @@
1
+ import { type Dict, type PlainObject } from './isPlainObject.js';
2
+ import tspo from './tspo.js';
3
+ import type { KeysParam, KeyUnion, SetToNever } from './utility-types.js';
4
+ /******************************************************************************
5
+ Types
6
+ ******************************************************************************/
7
+ type CollapseType<T> = {
8
+ [K in keyof T]: T[K];
9
+ } & {};
10
+ type Append = <T extends PlainObject, U extends PlainObject>(obj: T, addOn: U) => asserts obj is CollapseType<T & U>;
11
+ type AppendOne = <T extends PlainObject, K extends string, V>(obj: T, entry: [K, V]) => asserts obj is CollapseType<T & Record<K, V>>;
12
+ type Remove = <T extends PlainObject, K extends KeysParam<T>>(obj: T, keys: K) => asserts obj is CollapseType<SetToNever<T, KeyUnion<T, K>>>;
13
+ type ToDict = (obj: unknown) => Dict;
14
+ /******************************************************************************
15
+ Constants
16
+ ******************************************************************************/
17
+ declare const typedTspo: Readonly<typeof tspo> & {
18
+ readonly append: Append;
19
+ readonly appendOne: AppendOne;
20
+ readonly remove: Remove;
21
+ readonly toDict: ToDict;
22
+ };
23
+ /******************************************************************************
24
+ Export
25
+ ******************************************************************************/
26
+ export { type OmitNever } from './utility-types.js';
27
+ export { type Dict } from './isPlainObject.js';
28
+ export default typedTspo;
@@ -0,0 +1,19 @@
1
+ /******************************************************************************
2
+ Constants
3
+ ******************************************************************************/
4
+ /******************************************************************************
5
+ Types
6
+ ******************************************************************************/
7
+ export type Dict = Record<string, unknown>;
8
+ export type PlainObject = NonNullable<object>;
9
+ /******************************************************************************
10
+ Functions
11
+ ******************************************************************************/
12
+ /**
13
+ * Check if a 'unknown' is a 'PlainObject.
14
+ */
15
+ declare function isPlainObject(arg: unknown): arg is PlainObject;
16
+ /******************************************************************************
17
+ Export
18
+ ******************************************************************************/
19
+ export default isPlainObject;
@@ -0,0 +1,116 @@
1
+ import isPlainObject, { type Dict, type PlainObject } from './isPlainObject.js';
2
+ import type { DeepWiden, EntriesTuple, KeysParam, KeyTuple, KeyUnion, Mutable, OmitKeys, PickKeys, SetToNever, ValueTuple } from './utility-types.js';
3
+ import compare from './utils/compare.js';
4
+ import copy from './utils/copy.js';
5
+ import iterate from './utils/iterate.js';
6
+ /******************************************************************************
7
+ Types
8
+ ******************************************************************************/
9
+ type CollapseType<T> = {
10
+ -readonly [K in keyof T]: T[K];
11
+ } & {};
12
+ /******************************************************************************
13
+ Functions
14
+ ******************************************************************************/
15
+ /**
16
+ * Return a new object by excluding certains keys from an object.
17
+ */
18
+ declare function omit<T extends PlainObject, K extends KeysParam<T>>(obj: T, keys: K): CollapseType<OmitKeys<T, K>>;
19
+ /**
20
+ * Return a new object by selecting a specific set of keys on an object.
21
+ */
22
+ declare function pick<T extends PlainObject, K extends KeysParam<T>>(obj: T, keys: K): CollapseType<PickKeys<T, K>>;
23
+ /**
24
+ * Merge two object together and return a new type.
25
+ */
26
+ declare function merge<T extends PlainObject, U extends PlainObject>(a: T, b: U): CollapseType<Mutable<Omit<T, keyof U> & U>>;
27
+ /**
28
+ * Fill the missing entries in a partial, will the values from a 'defaults'
29
+ * object.
30
+ */
31
+ declare function fill<const T extends object>(defaults: T, partial?: Partial<DeepWiden<T>>): CollapseType<Mutable<DeepWiden<T>>>;
32
+ /**
33
+ * Append one object to another, modifying the reference to the original
34
+ * object.
35
+ */
36
+ declare function append<T extends PlainObject, U extends PlainObject>(obj: T, addOn: U): asserts obj is CollapseType<T & U>;
37
+ /**
38
+ * Append a single entry to an object.
39
+ */
40
+ declare function appendOne<T extends PlainObject, K extends string, V>(obj: T, entry: [K, V]): asserts obj is CollapseType<T & Record<K, V>>;
41
+ /**
42
+ * Remove keys from an object and set the type to 'never'.
43
+ */
44
+ declare function remove<T extends PlainObject, K extends KeysParam<T>>(obj: T, keys: K): asserts obj is CollapseType<SetToNever<T, KeyUnion<T, K>>>;
45
+ /**
46
+ * Get a value on an object and return 'undefined' if not found.
47
+ */
48
+ declare function index<T extends object>(obj: T, key: string | number): T[keyof T] | undefined;
49
+ /**
50
+ * Get a value on an object and return 'undefined' if not found.
51
+ */
52
+ declare function safeIndex<T extends object>(obj: T, key: string | number): T[keyof T];
53
+ /**
54
+ * Get a list of keys for which the value matches.
55
+ */
56
+ declare function reverseIndex<T extends object>(obj: T, value: unknown): (keyof T)[];
57
+ /**
58
+ * Get a key for a value only if you know the value is unique.
59
+ */
60
+ declare function safeReverseIndex<T extends object>(obj: T, value: unknown): keyof T;
61
+ /**
62
+ * Validator function to check
63
+ */
64
+ declare function isKey<T extends object>(obj: T, arg: PropertyKey): arg is keyof T;
65
+ /**
66
+ * Validator function to check
67
+ */
68
+ declare function isValue<T extends object>(obj: T, arg: unknown): arg is T[keyof T];
69
+ /**
70
+ * Get a type-safe array of the object keys.
71
+ */
72
+ declare function keys<T extends object>(obj: T): KeyTuple<T>;
73
+ /**
74
+ * Get a type-safe array of the object values
75
+ */
76
+ declare function values<T extends object>(obj: T): ValueTuple<T>;
77
+ /**
78
+ * Get a type-safe array of the object entries
79
+ */
80
+ declare function entries<T extends object>(obj: T): EntriesTuple<T>;
81
+ /**
82
+ * Get a type-safe array of the object e
83
+ */
84
+ declare function firstEntry<T extends object, K extends keyof T>(obj: T): [K, T[K]];
85
+ /**
86
+ * Check if something is a plain
87
+ */
88
+ declare function toDict(obj: unknown): Dict;
89
+ /******************************************************************************
90
+ Export
91
+ ******************************************************************************/
92
+ declare const _default: {
93
+ readonly omit: typeof omit;
94
+ readonly pick: typeof pick;
95
+ readonly merge: typeof merge;
96
+ readonly fill: typeof fill;
97
+ readonly append: typeof append;
98
+ readonly appendOne: typeof appendOne;
99
+ readonly index: typeof index;
100
+ readonly remove: typeof remove;
101
+ readonly toDict: typeof toDict;
102
+ readonly safeIndex: typeof safeIndex;
103
+ readonly reverseIndex: typeof reverseIndex;
104
+ readonly safeReverseIndex: typeof safeReverseIndex;
105
+ readonly is: typeof isPlainObject;
106
+ readonly isKey: typeof isKey;
107
+ readonly isValue: typeof isValue;
108
+ readonly keys: typeof keys;
109
+ readonly values: typeof values;
110
+ readonly entries: typeof entries;
111
+ readonly firstEntry: typeof firstEntry;
112
+ readonly iterate: typeof iterate;
113
+ readonly copy: typeof copy;
114
+ readonly compare: typeof compare;
115
+ };
116
+ export default _default;
@@ -0,0 +1,29 @@
1
+ export type KeysParam<T extends object> = keyof T | (keyof T)[];
2
+ export type KeyUnion<T extends object, K extends KeysParam<T>> = K extends (keyof T)[] ? K[number] : K;
3
+ export type OmitKeys<T extends object, K extends KeysParam<T>> = Omit<T, KeyUnion<T, K>>;
4
+ export type PickKeys<T extends object, K extends KeysParam<T>> = Pick<T, KeyUnion<T, K>>;
5
+ export type Mutable<T> = {
6
+ -readonly [K in keyof T]: T[K];
7
+ };
8
+ export type SetToNever<T, K extends PropertyKey> = T & {
9
+ [P in K]: never;
10
+ };
11
+ type NonNeverKeys<T extends object> = {
12
+ [K in keyof T]-?: [T[K]] extends [never] ? never : K;
13
+ }[keyof T];
14
+ export type OmitNever<T extends object> = Pick<T, NonNeverKeys<T>>;
15
+ type UnionToTuple<U, R extends any[] = []> = [U] extends [never] ? R : UnionToTuple<Exclude<U, LastOf<U>>, [LastOf<U>, ...R]>;
16
+ type LastOf<U> = UnionToIntersection<U extends any ? () => U : never> extends () => infer L ? L : never;
17
+ type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
18
+ type Entries<T extends object> = {
19
+ [K in keyof T]-?: [K, T[K]];
20
+ }[keyof T];
21
+ export type EntriesTuple<T extends object> = UnionToTuple<Entries<T>>;
22
+ export type KeyTuple<T extends object> = UnionToTuple<keyof T>;
23
+ export type ValueTuple<T extends object> = UnionToTuple<T[keyof T]>;
24
+ type Primitive = string | number | boolean | bigint | symbol | null | undefined;
25
+ type WidenPrimitive<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends bigint ? bigint : T extends symbol ? symbol : T;
26
+ export type DeepWiden<T> = T extends Primitive ? WidenPrimitive<T> : T extends (...args: any[]) => any ? T : T extends readonly (infer U)[] ? DeepWiden<U>[] : T extends object ? {
27
+ [K in keyof T]: DeepWiden<T[K]>;
28
+ } : T;
29
+ export {};
@@ -0,0 +1,18 @@
1
+ import { type PlainObject } from '../isPlainObject.js';
2
+ /******************************************************************************
3
+ Functions
4
+ ******************************************************************************/
5
+ /**
6
+ * Recursively compares two plain objects.
7
+ *
8
+ * Traversal rules:
9
+ * - recurse into plain objects
10
+ * - recurse into arrays
11
+ * - compare Date by epoch (`getTime()`)
12
+ * - compare any other object values by reference
13
+ */
14
+ declare function compare(a: PlainObject, b: PlainObject): boolean;
15
+ /******************************************************************************
16
+ Export
17
+ ******************************************************************************/
18
+ export default compare;
@@ -0,0 +1,16 @@
1
+ import { type PlainObject } from '../isPlainObject.js';
2
+ import { type Mutable } from '../utility-types.js';
3
+ type CopyOptions = {
4
+ resetDates?: boolean;
5
+ };
6
+ /**
7
+ * Deep clones ONLY plain-objects (incl. null-prototype).
8
+ *
9
+ * - Root value must be a plain-object.
10
+ * - Recursion descends only into plain-objects and arrays.
11
+ * - Nested Date values are copied by epoch.
12
+ * - `resetDates` resets all nested Date values to current time.
13
+ * - Other nested non-plain objects are shallow-cloned.
14
+ */
15
+ declare function copy<T extends PlainObject>(value: T, options?: CopyOptions): Mutable<T>;
16
+ export default copy;
@@ -0,0 +1,28 @@
1
+ import { type PlainObject } from '../isPlainObject.js';
2
+ /******************************************************************************
3
+ Types
4
+ ******************************************************************************/
5
+ type Path = readonly (string | number)[];
6
+ type IterateParent = PlainObject | unknown[];
7
+ type IterateKey = string | number;
8
+ type IterateCb = (args: {
9
+ parent: IterateParent;
10
+ key: IterateKey;
11
+ value: unknown;
12
+ path: Path;
13
+ }) => void;
14
+ /******************************************************************************
15
+ Functions
16
+ ******************************************************************************/
17
+ /**
18
+ * Recursively walks plain-objects and arrays, and calls a callback for
19
+ * every key whose value is neither a plain-object nor an array.
20
+ *
21
+ * - Descends into a value if it is a plain-object or array.
22
+ * - Fires callback for every non-descended value.
23
+ */
24
+ declare function iterate(root: unknown, cb: IterateCb): void;
25
+ /******************************************************************************
26
+ Export
27
+ ******************************************************************************/
28
+ export default iterate;
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "tspo",
3
+ "version": "1.0.0",
4
+ "description": "A collection of utilities for handling both runtime and compile-time behavior for plain-objects.",
5
+ "keywords": [
6
+ "typescript",
7
+ "javascript",
8
+ "tspo",
9
+ "plain-object",
10
+ "object-utils",
11
+ "utility-library",
12
+ "type-safe",
13
+ "type-guard",
14
+ "object-manipulation",
15
+ "object-merge",
16
+ "object-omit",
17
+ "object-pick",
18
+ "object-iterate",
19
+ "indexing",
20
+ "deep-copy",
21
+ "deep-compare",
22
+ "runtime-validation",
23
+ "zero-dependency"
24
+ ],
25
+ "homepage": "https://github.com/seanpmaxwell/tspo#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/seanpmaxwell/tspo/issues"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/seanpmaxwell/tspo.git"
32
+ },
33
+ "license": "MIT",
34
+ "author": "seanpmaxwell",
35
+ "type": "module",
36
+ "main": "./dist/cjs/index.js",
37
+ "module": "./dist/esm/index.js",
38
+ "browser": "./dist/esm/index.js",
39
+ "types": "./dist/types/index.d.ts",
40
+ "files": [
41
+ "dist"
42
+ ],
43
+ "scripts": {
44
+ "build": "rm -rf ./dist && tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json && tsc -p tsconfig.types.json",
45
+ "clean-install": "rm -rf ./node_modules && rm -r package-lock.json && npm i",
46
+ "lint": "eslint .",
47
+ "format": "eslint --fix .",
48
+ "pre-publish": "mv README.md README-git && mv README-npm README.md",
49
+ "post-publish": "mv README.md README-npm && mv README-git README.md",
50
+ "test": "NODE_ENV=test vitest"
51
+ },
52
+ "devDependencies": {
53
+ "@eslint/js": "^9.26.0",
54
+ "@stylistic/eslint-plugin": "^5.6.1",
55
+ "@trivago/prettier-plugin-sort-imports": "^6.0.1",
56
+ "@types/node": "^22.8.1",
57
+ "dts-bundle-generator": "^9.5.1",
58
+ "eslint": "^9.26.0",
59
+ "eslint-config-prettier": "^10.1.8",
60
+ "jiti": "^2.6.1",
61
+ "prettier": "^3.7.4",
62
+ "typescript": "~5.9.3",
63
+ "typescript-eslint": "^8.50.0",
64
+ "vitest": "^4.0.15"
65
+ }
66
+ }