@sequencemedia/dupe 0.0.1 → 0.0.3

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 CHANGED
@@ -4,6 +4,38 @@ Produces a duplicate (or deep clone) of an object or array, preserving circular
4
4
 
5
5
  Primitives are returned as-is
6
6
 
7
- There is no special effort to identify `Buffer` or `ArrayBuffer` or typed arrays _etc_ in this version
7
+ ```javascript
8
+ import dupe from '@sequencemedia/dupe'
8
9
 
9
- For most values `structuredClone` is preferable, except where there are or may be functions involved
10
+ const a = [1, 2, 3]
11
+
12
+ a.push(a)
13
+
14
+ const o = { a: 4, b: 5, c: 6, func () { } }
15
+
16
+ o.o = o
17
+
18
+ a.push(o)
19
+
20
+ const array = dupe(a)
21
+ ```
22
+
23
+ These types as well as `Buffer` instances can be duplicated using `@sequencemedia/dupe/node`
24
+
25
+ ```javascript
26
+ import dupe from '@sequencemedia/dupe/node'
27
+
28
+ const a = [1, 2, 3, Buffer.from('x')]
29
+
30
+ a.push(a)
31
+
32
+ const o = { a: 4, b: 5, c: 6, func () { }, buff: Buffer.from('y') }
33
+
34
+ o.o = o
35
+
36
+ a.push(o)
37
+
38
+ const array = dupe(a)
39
+ ```
40
+
41
+ For most values (i.e., except functions) `structuredClone` is preferable
package/package.json CHANGED
@@ -1,48 +1,54 @@
1
1
  {
2
2
  "name": "@sequencemedia/dupe",
3
- "version": "0.0.1",
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
- },
3
+ "version": "0.0.3",
12
4
  "keywords": [
13
5
  "dupe",
14
6
  "duplicate",
15
7
  "clone",
16
8
  "deep clone",
17
- "deep"
9
+ "deep",
10
+ "structured clone"
18
11
  ],
12
+ "main": "./src/index.mjs",
13
+ "type": "module",
14
+ "types": "./src/index.d.mts",
15
+ "author": {
16
+ "name": "Jonathan Perry for Sequence Media Limited",
17
+ "email": "sequencemedia@sequencemedia.net",
18
+ "url": "https://sequencemedia.net"
19
+ },
19
20
  "license": "ISC",
20
21
  "scripts": {
21
22
  "lint": "eslint .",
22
23
  "lint:fix": "npm run lint -- --fix",
23
- "test": "cross-env NODE_ENV=test mocha test --recursive",
24
- "prepare": "husky"
24
+ "prepare": "husky",
25
+ "test": "cross-env NODE_ENV=test mocha test --recursive"
25
26
  },
26
27
  "dependencies": {
27
- "-": "^0.0.1",
28
- "chai": "^5.1.2",
29
- "D": "^1.0.0",
30
- "debug": "^4.4.0",
31
- "mocha": "^11.0.1"
28
+ "debug": "^4.4.0"
32
29
  },
33
30
  "devDependencies": {
31
+ "chai": "^5.1.2",
32
+ "mocha": "^11.0.1",
34
33
  "@babel/core": "^7.26.0",
35
34
  "@babel/preset-env": "^7.26.0",
36
35
  "@sequencemedia/eslint-config-standard": "^0.2.2",
37
36
  "@sequencemedia/eslint-config-typescript": "^0.1.2",
38
37
  "@types/debug": "^4.1.12",
38
+ "@types/mocha": "^10.0.10",
39
+ "@types/node": "^22.10.1",
39
40
  "core-js": "^3.39.0",
40
41
  "cross-env": "^7.0.3",
41
42
  "eslint": "^9.16.0",
42
43
  "globals": "^15.13.0",
43
44
  "husky": "^9.1.7"
44
45
  },
46
+ "imports": {
47
+ "#dupe": "./src/index.mjs",
48
+ "#dupe/node": "./src/node/index.mjs"
49
+ },
45
50
  "exports": {
46
- ".": "./index.mjs"
51
+ ".": "./src/index.mjs",
52
+ "./node": "./src/node/index.mjs"
47
53
  }
48
54
  }
@@ -12,7 +12,7 @@
12
12
  * @param {ValueType | ValueType[]} v
13
13
  * @returns {boolean}
14
14
  */
15
- function isArray (v) {
15
+ export function isArray (v) {
16
16
  return Array.isArray(v)
17
17
  }
18
18
 
@@ -20,7 +20,7 @@ function isArray (v) {
20
20
  * @param {ValueType | ValueType[]} v
21
21
  * @returns {boolean}
22
22
  */
23
- function isObject (v) {
23
+ export function isObject (v) {
24
24
  return (v || false) instanceof Object && !Array.isArray(v)
25
25
  }
26
26
 
@@ -28,16 +28,19 @@ function isObject (v) {
28
28
  * @param {ValueType | ValueType[]} v
29
29
  * @returns {boolean}
30
30
  */
31
- function isFunction (v) {
31
+ export function isFunction (v) {
32
32
  return v instanceof Function
33
33
  }
34
-
35
34
  /**
36
35
  * @param {ValueType | ValueType[]} v
37
36
  * @returns {boolean}
38
37
  */
39
38
  function isPrimitive (v) {
40
- return !isObject(v) && !isArray(v) && !isFunction(v)
39
+ return !(
40
+ isObject(v) ||
41
+ isArray(v) ||
42
+ isFunction(v)
43
+ )
41
44
  }
42
45
 
43
46
  /**
@@ -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 | Buffer | null | undefined
5
+
6
+ export default function dupe (v: ValueType | ValueType[]): ValueType | ValueType[]
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @typedef {unknown[] | never[]} ArrayLiteralType
3
+ *
4
+ * @typedef {Record<PropertyKey, unknown> | Record<PropertyKey, never>} ObjectLiteralType
5
+ *
6
+ * @typedef {string | number | ArrayLiteralType | ObjectLiteralType | Buffer | 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) && !Buffer.isBuffer(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 isBuffer (v) {
40
+ return Buffer.isBuffer(v)
41
+ }
42
+
43
+ /**
44
+ * @param {ValueType | ValueType[]} v
45
+ * @returns {boolean}
46
+ */
47
+ function isPrimitive (v) {
48
+ return !(
49
+ isObject(v) ||
50
+ isArray(v) ||
51
+ isFunction(v) ||
52
+ isBuffer(v)
53
+ )
54
+ }
55
+
56
+ /**
57
+ * function isArrayBuffer (v) {
58
+ * return v instanceof ArrayBuffer
59
+ * }
60
+ */
61
+
62
+ /**
63
+ * @param {ArrayLiteralType} v
64
+ * @param {WeakMapType} weakMap
65
+ * @returns {ArrayLiteralType}
66
+ */
67
+ function getArray (v, weakMap) {
68
+ const a = []
69
+
70
+ weakMap.set(v, a)
71
+
72
+ return v.reduce(getReduceArray(weakMap), a)
73
+ }
74
+
75
+ /**
76
+ * @param {ObjectLiteralType} v
77
+ * @param {WeakMapType} weakMap
78
+ * @returns {ObjectLiteralType}
79
+ */
80
+ function getObject (v, weakMap) {
81
+ const o = {}
82
+
83
+ weakMap.set(v, o)
84
+
85
+ return Object.assign(o, Object.fromEntries(Object.entries(v).map(getMapEntries(weakMap))))
86
+ }
87
+
88
+ /**
89
+ * @param {Buffer} v
90
+ * @param {WeakMapType} weakMap
91
+ * @returns {Buffer}
92
+ */
93
+ function getBuffer (v, weakMap) {
94
+ const b = Buffer.from(v)
95
+
96
+ weakMap.set(v, b)
97
+ return b
98
+ }
99
+
100
+ /**
101
+ * @param {WeakMapType} weakMap
102
+ * @returns {(a: ArrayLiteralType, v: ValueType | ValueType[]) => ArrayLiteralType}
103
+ */
104
+ function getReduceArray (weakMap) {
105
+ /**
106
+ * @param {ArrayLiteralType} a
107
+ * @param {ValueType | ValueType[]} v
108
+ * @returns {ArrayLiteralType}
109
+ */
110
+ return function reduceArray (a, v) {
111
+ if (isPrimitive(v) || isFunction(v)) {
112
+ a.push(v)
113
+ return a
114
+ }
115
+
116
+ if (weakMap.has(v)) {
117
+ a.push(weakMap.get(v))
118
+ return a
119
+ }
120
+
121
+ if (isArray(v)) {
122
+ a.push(getArray(v, weakMap))
123
+ return a
124
+ }
125
+
126
+ if (isObject(v)) {
127
+ a.push(getObject(v, weakMap))
128
+ return a
129
+ }
130
+
131
+ if (isBuffer(v)) {
132
+ a.push(getBuffer(v, weakMap))
133
+ return a
134
+ }
135
+ }
136
+ }
137
+
138
+ /**
139
+ * @param {WeakMapType} weakMap
140
+ * @returns {(entry: [PropertyKey, ValueType | ValueType[]]) => [PropertyKey, ValueType | ValueType[]]}
141
+ */
142
+ function getMapEntries (weakMap) {
143
+ /**
144
+ * @param {[PropertyKey, ValueType | ValueType[]]} entry
145
+ * @returns {[PropertyKey, ValueType | ValueType[]]}
146
+ */
147
+ return function mapEntries ([k, v]) {
148
+ if (isPrimitive(v) || isFunction(v)) return [k, v]
149
+
150
+ if (weakMap.has(v)) {
151
+ return [k, weakMap.get(v)]
152
+ }
153
+
154
+ if (isArray(v)) {
155
+ return [k, getArray(v, weakMap)]
156
+ }
157
+
158
+ if (isObject(v)) {
159
+ return [k, getObject(v, weakMap)]
160
+ }
161
+
162
+ if (isBuffer(v)) {
163
+ return [k, getBuffer(v, weakMap)]
164
+ }
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Duplicate a value
170
+ *
171
+ * @param {ValueType | ValueType[]} v
172
+ * @returns {ValueType | ValueType[]}
173
+ */
174
+ export default function toDuplicate (v) {
175
+ if (isPrimitive(v) || isFunction(v)) return v
176
+
177
+ if (isArray(v)) {
178
+ return getArray(v, new WeakMap())
179
+ }
180
+
181
+ if (isObject(v)) {
182
+ return getObject(v, new WeakMap())
183
+ }
184
+
185
+ if (isBuffer(v)) {
186
+ return getBuffer(v, new WeakMap())
187
+ }
188
+ }
File without changes