@nadrif/thread 0.1.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.
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @file Serialize and deserialize values that contain functions.
3
+ *
4
+ * JavaScript's built-in `JSON.stringify` silently drops functions. The
5
+ * `Serializer` utility converts functions into a safe string
6
+ * representation (`{ __type: 'function', __value: '(x) => x + 1' }`) and
7
+ * revives them later via `new Function()`.
8
+ *
9
+ * This is primarily used internally by the thread module to pass function
10
+ * references across worker boundaries, but you can use it anywhere you
11
+ * need JSON-like serialization with function support.
12
+ *
13
+ * **Security note:** Deserialization uses `new Function()` to evaluate
14
+ * function strings. Only deserialize data you trust – never use this
15
+ * on user-supplied strings in production without sanitization.
16
+ *
17
+ * @example
18
+ * ```js
19
+ * import { Serializer } from './serializer.js';
20
+ *
21
+ * const data = {
22
+ * multiplier: 3,
23
+ * transform: (x) => x * 2,
24
+ * tags: ['a', 'b'],
25
+ * };
26
+ *
27
+ * const serialized = Serializer.serialize(data);
28
+ * // {
29
+ * // multiplier: 3,
30
+ * // transform: { __type: 'function', __value: '(x) => x * 2' },
31
+ * // tags: ['a', 'b'],
32
+ * // }
33
+ *
34
+ * const restored = Serializer.deserialize(serialized);
35
+ * console.log(restored.transform(5)); // 10
36
+ * ```
37
+ *
38
+ * @module serializer
39
+ */
40
+
41
+ /**
42
+ * Utility for serializing/deserializing values containing functions.
43
+ *
44
+ * All methods are stateless – the object is used as a namespace, not
45
+ * instantiated.
46
+ */
47
+ export const Serializer = {
48
+ /**
49
+ * Serialize a value, converting functions to a portable representation.
50
+ *
51
+ * **What gets converted:**
52
+ * - Functions → `{ __type: 'function', __value: fn.toString() }`
53
+ * - Arrays → each element is recursively serialized
54
+ * - Plain objects → each value is recursively serialized
55
+ * - Primitives, `null`, `undefined` → passed through unchanged
56
+ *
57
+ * **Limitations:**
58
+ * - Closures are **lost** – the deserialized function will not capture
59
+ * variables from its enclosing scope.
60
+ * - `Date`, `RegExp`, `Map`, `Set` etc. are treated as plain objects
61
+ * and their internal state may not survive the round-trip.
62
+ * - Circular references will cause a `TypeError` (not handled).
63
+ *
64
+ * @param {*} value - The value to serialize.
65
+ * @returns {*} A JSON-safe copy of the value with functions replaced
66
+ * by marker objects.
67
+ *
68
+ * @example
69
+ * ```js
70
+ * Serializer.serialize((a, b) => a + b);
71
+ * // { __type: 'function', __value: '(a, b) => a + b' }
72
+ * ```
73
+ *
74
+ * @example
75
+ * ```js
76
+ * Serializer.serialize([1, { fn: () => {} }, 'hello']);
77
+ * // [1, { fn: { __type: 'function', __value: '() => {}' } }, 'hello']
78
+ * ```
79
+ */
80
+ serialize(value) {
81
+ if (typeof value === 'function') {
82
+ return { __type: 'function', __value: value.toString() };
83
+ }
84
+ if (Array.isArray(value)) {
85
+ return value.map((v) => this.serialize(v));
86
+ }
87
+ if (value && typeof value === 'object') {
88
+ const obj = {};
89
+ for (const [k, v] of Object.entries(value)) {
90
+ obj[k] = this.serialize(v);
91
+ }
92
+ return obj;
93
+ }
94
+ return value;
95
+ },
96
+
97
+ /**
98
+ * Deserialize a value, reviving functions from their string form.
99
+ *
100
+ * Inverse of {@link Serializer.serialize}. The marker objects
101
+ * `{ __type: 'function', __value: '...' }` are converted back into
102
+ * callable functions via `new Function('return ' + value.__value)()`.
103
+ *
104
+ * **Warning:** This evaluates arbitrary code. Only call on data you
105
+ * serialized yourself or fully trust.
106
+ *
107
+ * @param {*} value - The serialized value.
108
+ * @returns {*} The original value with functions restored.
109
+ *
110
+ * @example
111
+ * ```js
112
+ * const serialized = {
113
+ * handler: { __type: 'function', __value: '(x) => x * 2' },
114
+ * name: 'doubler',
115
+ * };
116
+ *
117
+ * const restored = Serializer.deserialize(serialized);
118
+ * console.log(typeof restored.handler); // "function"
119
+ * console.log(restored.handler(21)); // 42
120
+ * ```
121
+ */
122
+ deserialize(value) {
123
+ if (value && typeof value === 'object' && value.__type === 'function') {
124
+ // eslint-disable-next-line no-new-func
125
+ return new Function('return ' + value.__value)();
126
+ }
127
+ if (Array.isArray(value)) {
128
+ return value.map((v) => this.deserialize(v));
129
+ }
130
+ if (value && typeof value === 'object') {
131
+ const obj = {};
132
+ for (const [k, v] of Object.entries(value)) {
133
+ obj[k] = this.deserialize(v);
134
+ }
135
+ return obj;
136
+ }
137
+ return value;
138
+ },
139
+ };