@sequencemedia/dupe 0.0.2 → 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,16 +1,17 @@
1
1
  {
2
2
  "name": "@sequencemedia/dupe",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "keywords": [
5
5
  "dupe",
6
6
  "duplicate",
7
7
  "clone",
8
8
  "deep clone",
9
- "deep"
9
+ "deep",
10
+ "structured clone"
10
11
  ],
11
- "main": "./index.mjs",
12
+ "main": "./src/index.mjs",
12
13
  "type": "module",
13
- "types": "./index.d.mts",
14
+ "types": "./src/index.d.mts",
14
15
  "author": {
15
16
  "name": "Jonathan Perry for Sequence Media Limited",
16
17
  "email": "sequencemedia@sequencemedia.net",
@@ -42,7 +43,12 @@
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
  }
@@ -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/src/index.mjs ADDED
@@ -0,0 +1,147 @@
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
+ export function isArray (v) {
16
+ return Array.isArray(v)
17
+ }
18
+
19
+ /**
20
+ * @param {ValueType | ValueType[]} v
21
+ * @returns {boolean}
22
+ */
23
+ export 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
+ export function isFunction (v) {
32
+ return v instanceof Function
33
+ }
34
+ /**
35
+ * @param {ValueType | ValueType[]} v
36
+ * @returns {boolean}
37
+ */
38
+ function isPrimitive (v) {
39
+ return !(
40
+ isObject(v) ||
41
+ isArray(v) ||
42
+ isFunction(v)
43
+ )
44
+ }
45
+
46
+ /**
47
+ * @param {ArrayLiteralType} v
48
+ * @param {WeakMapType} weakMap
49
+ * @returns {ArrayLiteralType}
50
+ */
51
+ function getArray (v, weakMap) {
52
+ const a = []
53
+
54
+ weakMap.set(v, a)
55
+
56
+ return v.reduce(getReduceArray(weakMap), a)
57
+ }
58
+
59
+ /**
60
+ * @param {ObjectLiteralType} v
61
+ * @param {WeakMapType} weakMap
62
+ * @returns {ObjectLiteralType}
63
+ */
64
+ function getObject (v, weakMap) {
65
+ const o = {}
66
+
67
+ weakMap.set(v, o)
68
+
69
+ return Object.assign(o, Object.fromEntries(Object.entries(v).map(getMapEntries(weakMap))))
70
+ }
71
+
72
+ /**
73
+ * @param {WeakMapType} weakMap
74
+ * @returns {(a: ArrayLiteralType, v: ValueType | ValueType[]) => ArrayLiteralType}
75
+ */
76
+ function getReduceArray (weakMap) {
77
+ /**
78
+ * @param {ArrayLiteralType} a
79
+ * @param {ValueType | ValueType[]} v
80
+ * @returns {ArrayLiteralType}
81
+ */
82
+ return function reduceArray (a, v) {
83
+ if (isPrimitive(v) || isFunction(v)) {
84
+ a.push(v)
85
+ return a
86
+ }
87
+
88
+ if (weakMap.has(v)) {
89
+ a.push(weakMap.get(v))
90
+ return a
91
+ }
92
+
93
+ if (isArray(v)) {
94
+ a.push(getArray(v, weakMap))
95
+ return a
96
+ }
97
+
98
+ if (isObject(v)) {
99
+ a.push(getObject(v, weakMap))
100
+ return a
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @param {WeakMapType} weakMap
107
+ * @returns {(entry: [PropertyKey, ValueType | ValueType[]]) => [PropertyKey, ValueType | ValueType[]]}
108
+ */
109
+ function getMapEntries (weakMap) {
110
+ /**
111
+ * @param {[PropertyKey, ValueType | ValueType[]]} entry
112
+ * @returns {[PropertyKey, ValueType | ValueType[]]}
113
+ */
114
+ return function mapEntries ([k, v]) {
115
+ if (isPrimitive(v) || isFunction(v)) return [k, v]
116
+
117
+ if (weakMap.has(v)) {
118
+ return [k, weakMap.get(v)]
119
+ }
120
+
121
+ if (isArray(v)) {
122
+ return [k, getArray(v, weakMap)]
123
+ }
124
+
125
+ if (isObject(v)) {
126
+ return [k, getObject(v, weakMap)]
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Duplicate a value
133
+ *
134
+ * @param {ValueType | ValueType[]} v
135
+ * @returns {ValueType | ValueType[]}
136
+ */
137
+ export default function toDuplicate (v) {
138
+ if (isPrimitive(v) || isFunction(v)) return v
139
+
140
+ if (isArray(v)) {
141
+ return getArray(v, new WeakMap())
142
+ }
143
+
144
+ if (isObject(v)) {
145
+ return getObject(v, new WeakMap())
146
+ }
147
+ }
File without changes
@@ -32,6 +32,14 @@ function isFunction (v) {
32
32
  return v instanceof Function
33
33
  }
34
34
 
35
+ /**
36
+ * @param {ValueType | ValueType[]} v
37
+ * @returns {boolean}
38
+ */
39
+ function isBuffer (v) {
40
+ return Buffer.isBuffer(v)
41
+ }
42
+
35
43
  /**
36
44
  * @param {ValueType | ValueType[]} v
37
45
  * @returns {boolean}
@@ -45,14 +53,6 @@ function isPrimitive (v) {
45
53
  )
46
54
  }
47
55
 
48
- /**
49
- * @param {ValueType | ValueType[]} v
50
- * @returns {boolean}
51
- */
52
- function isBuffer (v) {
53
- return Buffer.isBuffer(v)
54
- }
55
-
56
56
  /**
57
57
  * function isArrayBuffer (v) {
58
58
  * return v instanceof ArrayBuffer