@sequencemedia/dupe 0.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/README.md +9 -0
- package/index.d.mts +6 -0
- package/index.mjs +144 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `@sequencemedia/dupe`
|
|
2
|
+
|
|
3
|
+
Produces a duplicate (or deep clone) of an object or array, preserving circular references _in the duplicated values_, and preserving functions
|
|
4
|
+
|
|
5
|
+
Primitives are returned as-is
|
|
6
|
+
|
|
7
|
+
There is no special effort to identify `Buffer` or `ArrayBuffer` or typed arrays _etc_ in this version
|
|
8
|
+
|
|
9
|
+
For most values `structuredClone` is preferable, except where there are or may be functions involved
|
package/index.d.mts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type ArrayLiteralType = unknown[] | never[]
|
|
2
|
+
type ObjectLiteralType = Record<PropertyKey, unknown> | Record<PropertyKey, never>
|
|
3
|
+
|
|
4
|
+
type ValueType = string | number | ArrayLiteralType | ObjectLiteralType | null | undefined
|
|
5
|
+
|
|
6
|
+
export default function dupe (v: ValueType | ValueType[]): ValueType | ValueType[]
|
package/index.mjs
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {unknown[] | never[]} ArrayLiteralType
|
|
3
|
+
*
|
|
4
|
+
* @typedef {Record<PropertyKey, unknown> | Record<PropertyKey, never>} ObjectLiteralType
|
|
5
|
+
*
|
|
6
|
+
* @typedef {string | number | ArrayLiteralType | ObjectLiteralType | null | undefined} ValueType
|
|
7
|
+
*
|
|
8
|
+
* @typedef {WeakMap<WeakKey, ArrayLiteralType | ObjectLiteralType>} WeakMapType
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {ValueType | ValueType[]} v
|
|
13
|
+
* @returns {boolean}
|
|
14
|
+
*/
|
|
15
|
+
function isArray (v) {
|
|
16
|
+
return Array.isArray(v)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {ValueType | ValueType[]} v
|
|
21
|
+
* @returns {boolean}
|
|
22
|
+
*/
|
|
23
|
+
function isObject (v) {
|
|
24
|
+
return (v || false) instanceof Object && !Array.isArray(v)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {ValueType | ValueType[]} v
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function isFunction (v) {
|
|
32
|
+
return v instanceof Function
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {ValueType | ValueType[]} v
|
|
37
|
+
* @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
function isPrimitive (v) {
|
|
40
|
+
return !isObject(v) && !isArray(v) && !isFunction(v)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {ArrayLiteralType} v
|
|
45
|
+
* @param {WeakMapType} weakMap
|
|
46
|
+
* @returns {ArrayLiteralType}
|
|
47
|
+
*/
|
|
48
|
+
function getArray (v, weakMap) {
|
|
49
|
+
const a = []
|
|
50
|
+
|
|
51
|
+
weakMap.set(v, a)
|
|
52
|
+
|
|
53
|
+
return v.reduce(getReduceArray(weakMap), a)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {ObjectLiteralType} v
|
|
58
|
+
* @param {WeakMapType} weakMap
|
|
59
|
+
* @returns {ObjectLiteralType}
|
|
60
|
+
*/
|
|
61
|
+
function getObject (v, weakMap) {
|
|
62
|
+
const o = {}
|
|
63
|
+
|
|
64
|
+
weakMap.set(v, o)
|
|
65
|
+
|
|
66
|
+
return Object.assign(o, Object.fromEntries(Object.entries(v).map(getMapEntries(weakMap))))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {WeakMapType} weakMap
|
|
71
|
+
* @returns {(a: ArrayLiteralType, v: ValueType | ValueType[]) => ArrayLiteralType}
|
|
72
|
+
*/
|
|
73
|
+
function getReduceArray (weakMap) {
|
|
74
|
+
/**
|
|
75
|
+
* @param {ArrayLiteralType} a
|
|
76
|
+
* @param {ValueType | ValueType[]} v
|
|
77
|
+
* @returns {ArrayLiteralType}
|
|
78
|
+
*/
|
|
79
|
+
return function reduceArray (a, v) {
|
|
80
|
+
if (isPrimitive(v) || isFunction(v)) {
|
|
81
|
+
a.push(v)
|
|
82
|
+
return a
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (weakMap.has(v)) {
|
|
86
|
+
a.push(weakMap.get(v))
|
|
87
|
+
return a
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isArray(v)) {
|
|
91
|
+
a.push(getArray(v, weakMap))
|
|
92
|
+
return a
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isObject(v)) {
|
|
96
|
+
a.push(getObject(v, weakMap))
|
|
97
|
+
return a
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {WeakMapType} weakMap
|
|
104
|
+
* @returns {(entry: [PropertyKey, ValueType | ValueType[]]) => [PropertyKey, ValueType | ValueType[]]}
|
|
105
|
+
*/
|
|
106
|
+
function getMapEntries (weakMap) {
|
|
107
|
+
/**
|
|
108
|
+
* @param {[PropertyKey, ValueType | ValueType[]]} entry
|
|
109
|
+
* @returns {[PropertyKey, ValueType | ValueType[]]}
|
|
110
|
+
*/
|
|
111
|
+
return function mapEntries ([k, v]) {
|
|
112
|
+
if (isPrimitive(v) || isFunction(v)) return [k, v]
|
|
113
|
+
|
|
114
|
+
if (weakMap.has(v)) {
|
|
115
|
+
return [k, weakMap.get(v)]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (isArray(v)) {
|
|
119
|
+
return [k, getArray(v, weakMap)]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (isObject(v)) {
|
|
123
|
+
return [k, getObject(v, weakMap)]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Duplicate a value
|
|
130
|
+
*
|
|
131
|
+
* @param {ValueType | ValueType[]} v
|
|
132
|
+
* @returns {ValueType | ValueType[]}
|
|
133
|
+
*/
|
|
134
|
+
export default function toDuplicate (v) {
|
|
135
|
+
if (isPrimitive(v) || isFunction(v)) return v
|
|
136
|
+
|
|
137
|
+
if (isArray(v)) {
|
|
138
|
+
return getArray(v, new WeakMap())
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (isObject(v)) {
|
|
142
|
+
return getObject(v, new WeakMap())
|
|
143
|
+
}
|
|
144
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sequencemedia/dupe",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"main": "./index.mjs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./index.d.mts",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Jonathan Perry for Sequence Media Limited",
|
|
9
|
+
"email": "sequencemedia@sequencemedia.net",
|
|
10
|
+
"url": "https://sequencemedia.net"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"dupe",
|
|
14
|
+
"duplicate",
|
|
15
|
+
"clone",
|
|
16
|
+
"deep clone",
|
|
17
|
+
"deep"
|
|
18
|
+
],
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"scripts": {
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"lint:fix": "npm run lint -- --fix",
|
|
23
|
+
"test": "cross-env NODE_ENV=test mocha test --recursive"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"-": "^0.0.1",
|
|
27
|
+
"chai": "^5.1.2",
|
|
28
|
+
"D": "^1.0.0",
|
|
29
|
+
"debug": "^4.4.0",
|
|
30
|
+
"mocha": "^11.0.1"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@babel/core": "^7.26.0",
|
|
34
|
+
"@babel/preset-env": "^7.26.0",
|
|
35
|
+
"@sequencemedia/eslint-config-standard": "^0.2.0",
|
|
36
|
+
"@sequencemedia/eslint-config-typescript": "^0.1.0",
|
|
37
|
+
"@types/debug": "^4.1.12",
|
|
38
|
+
"core-js": "^3.39.0",
|
|
39
|
+
"cross-env": "^7.0.3",
|
|
40
|
+
"eslint": "^9.16.0",
|
|
41
|
+
"globals": "^15.13.0",
|
|
42
|
+
"husky": "^9.1.7"
|
|
43
|
+
},
|
|
44
|
+
"exports": {
|
|
45
|
+
".": "./index.mjs"
|
|
46
|
+
}
|
|
47
|
+
}
|