serialize-function 1.2.5 → 2.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 +90 -7
- package/dist/import.mjs +3 -4
- package/dist/main.js +1 -1
- package/lib/main.js +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|

|
|
15
15
|
](https://www.npmjs.com/package/serialize-function)
|
|
16
16
|
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
- [Quickstart](#quickstart)
|
|
20
|
+
- [Deep serialization](#deep-serialization)
|
|
21
|
+
- [Hashing](#hashing)
|
|
22
|
+
- [Whitespace and comments](#whitespace-and-comments)
|
|
23
|
+
- [Function type support](#function-type-support)
|
|
24
|
+
- [Changelog](#changelog)
|
|
25
|
+
|
|
17
26
|
|
|
18
27
|
## Quickstart
|
|
19
28
|
|
|
@@ -30,7 +39,7 @@ Serializes javascript functions to a JSON-encodable object suitable for storage
|
|
|
30
39
|
```js
|
|
31
40
|
function doTheThing(a,b,c,d,e) { return a + b * c / d % e; }
|
|
32
41
|
|
|
33
|
-
const obj = serialize(doTheThing);
|
|
42
|
+
const obj = await serialize(doTheThing);
|
|
34
43
|
console.log(obj);
|
|
35
44
|
// {
|
|
36
45
|
// params: [ 'a', 'b', 'c', 'd', 'e' ],
|
|
@@ -42,17 +51,70 @@ console.log(obj);
|
|
|
42
51
|
Deserializes back into an invokable function:
|
|
43
52
|
|
|
44
53
|
```js
|
|
45
|
-
const func = deserialize(obj);
|
|
54
|
+
const func = await deserialize(obj);
|
|
46
55
|
console.log( func(1, 2, 3, 4, 5) );
|
|
47
56
|
// 2.5
|
|
48
57
|
```
|
|
49
58
|
|
|
59
|
+
|
|
60
|
+
## Deep serialization
|
|
61
|
+
|
|
62
|
+
You may want to deeply serialize _any_ functions nested at arbitrary levels of your data structures. The provided convenience functions will traverse and selectively clone any containing objects, while serializing any functions found:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const { deepSerialize, deepDeserialize } = require('serialize-function');
|
|
66
|
+
|
|
67
|
+
const original = {
|
|
68
|
+
foo: () => 'something',
|
|
69
|
+
bar: [
|
|
70
|
+
function* (seed = 0) { let n = seed; while(true) { n = n * 2; yield n; } }
|
|
71
|
+
],
|
|
72
|
+
baz: new Date('2026-01-01')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const clone = await deepSerialize(original);
|
|
76
|
+
// {
|
|
77
|
+
// foo: {
|
|
78
|
+
// params: [],
|
|
79
|
+
// body: "return ('something');",
|
|
80
|
+
// type: 'ArrowFunction'
|
|
81
|
+
// },
|
|
82
|
+
// bar: [
|
|
83
|
+
// {
|
|
84
|
+
// params: [ 'seed = 0' ],
|
|
85
|
+
// body: 'let n = seed; while(true) { n = n * 2; yield n; }',
|
|
86
|
+
// type: 'Generator'
|
|
87
|
+
// }
|
|
88
|
+
// ],
|
|
89
|
+
// baz: 2026-01-01T00:00:00.000Z
|
|
90
|
+
// }
|
|
91
|
+
|
|
92
|
+
// original container and functions remain unmodified
|
|
93
|
+
original.foo(); // 'something'
|
|
94
|
+
const gen1 = original.bar[0](3.14);
|
|
95
|
+
gen1.next().value; // 6.28
|
|
96
|
+
gen1.next().value; // 12.56
|
|
97
|
+
|
|
98
|
+
const restored = await deepDeserialize(clone);
|
|
99
|
+
// {
|
|
100
|
+
// foo: [Function: anonymous],
|
|
101
|
+
// bar: [ [GeneratorFunction: anonymous] ],
|
|
102
|
+
// baz: 2026-01-01T00:00:00.000Z
|
|
103
|
+
// }
|
|
104
|
+
|
|
105
|
+
// deserialized functions remain invokable
|
|
106
|
+
restored.foo(); // 'something'
|
|
107
|
+
const gen2 = restored.bar[0](901364);
|
|
108
|
+
gen2.next().value; // 1802728
|
|
109
|
+
gen2.next().value; // 3605456
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
|
|
50
113
|
## Hashing
|
|
51
114
|
|
|
52
115
|
Optionally supports SHA256 checksum hashing to prevent MITM tampering:
|
|
53
116
|
|
|
54
117
|
```js
|
|
55
|
-
// note: use of hashing returns a promise
|
|
56
118
|
const hashedObj = await serialize(doTheThing, { hash: true });
|
|
57
119
|
console.log(hashedObj);
|
|
58
120
|
// {
|
|
@@ -69,6 +131,7 @@ const tamperedFunc = await deserialize(hashedObj, { hash: true });
|
|
|
69
131
|
|
|
70
132
|
> Under the hood, hashing uses the [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) API.
|
|
71
133
|
|
|
134
|
+
|
|
72
135
|
## Whitespace and comments
|
|
73
136
|
|
|
74
137
|
Line breaks within the function body are preserved and normalized, but all other padding whitespace is removed from the function by default, along with any comments.
|
|
@@ -97,7 +160,7 @@ function thingNumberTwo(
|
|
|
97
160
|
return remainder;
|
|
98
161
|
}
|
|
99
162
|
|
|
100
|
-
const commentedObj = serialize(thingNumberTwo, { whitespace: true, comments: true });
|
|
163
|
+
const commentedObj = await serialize(thingNumberTwo, { whitespace: true, comments: true });
|
|
101
164
|
console.log(commentedObj);
|
|
102
165
|
// {
|
|
103
166
|
// params: [ '\n /* marco */\n a', ' b', '\tc', '\n d', 'e/* polo */\n' ],
|
|
@@ -120,12 +183,13 @@ console.log(commentedObj);
|
|
|
120
183
|
// }
|
|
121
184
|
```
|
|
122
185
|
|
|
186
|
+
|
|
123
187
|
## Function type support
|
|
124
188
|
|
|
125
189
|
Arrow functions, generators, and all async variants are supported (contingent on _browser support_ where relevant):
|
|
126
190
|
|
|
127
191
|
```js
|
|
128
|
-
serialize(
|
|
192
|
+
await serialize(
|
|
129
193
|
(i,j,k) => ({ i, j, k })
|
|
130
194
|
);
|
|
131
195
|
// {
|
|
@@ -134,7 +198,7 @@ serialize(
|
|
|
134
198
|
// type: 'ArrowFunction'
|
|
135
199
|
// }
|
|
136
200
|
|
|
137
|
-
serialize(
|
|
201
|
+
await serialize(
|
|
138
202
|
function* (x,y,z) {
|
|
139
203
|
yield x;
|
|
140
204
|
yield y;
|
|
@@ -147,7 +211,7 @@ serialize(
|
|
|
147
211
|
// type: 'Generator'
|
|
148
212
|
// }
|
|
149
213
|
|
|
150
|
-
serialize(
|
|
214
|
+
await serialize(
|
|
151
215
|
async (ms) => new Promise(
|
|
152
216
|
resolve => setTimeout(resolve, ms)
|
|
153
217
|
)
|
|
@@ -158,3 +222,22 @@ serialize(
|
|
|
158
222
|
// type: 'AsyncArrowFunction'
|
|
159
223
|
// }
|
|
160
224
|
```
|
|
225
|
+
|
|
226
|
+
> [!NOTE]
|
|
227
|
+
> As there is no global `Class` object constructor, there is no way to safely deserialize [ES6 classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
|
|
228
|
+
>
|
|
229
|
+
> As such, ES6 classes are _not_ currently supported for serialization.
|
|
230
|
+
>
|
|
231
|
+
> Alternatively, you can rewrite your classes as functions, or transpile them with tools like [Babel](https://babeljs.io/docs/babel-plugin-transform-classes/).
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
## Changelog
|
|
235
|
+
|
|
236
|
+
Any potentially breaking changes will be documented here.
|
|
237
|
+
|
|
238
|
+
- 1.1.0 - Standardized both node and web builds on SubtleCrypto API
|
|
239
|
+
- 1.2.0 - Refactored comment stripping, to address potential regex DOS
|
|
240
|
+
- 2.0.0
|
|
241
|
+
- Made all exported functions fully async
|
|
242
|
+
- Implemented named captures for format patterns
|
|
243
|
+
- Implemented deep de/serialization
|
package/dist/import.mjs
CHANGED
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.deserialize=deserialize;exports.serialize=serialize;class JsonError extends Error{}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SerializeError=exports.JsonError=exports.DeserializeError=exports.CryptoError=exports.ConstructError=exports.ChecksumError=void 0;exports.deepDeserialize=deepDeserialize;exports.deepSerialize=deepSerialize;exports.deserialize=deserialize;exports.serialize=serialize;class JsonError extends Error{}exports.JsonError=JsonError;;class CryptoError extends Error{}exports.CryptoError=CryptoError;;class SerializeError extends Error{}exports.SerializeError=SerializeError;;class DeserializeError extends Error{}exports.DeserializeError=DeserializeError;;class ChecksumError extends Error{}exports.ChecksumError=ChecksumError;;class ConstructError extends Error{}exports.ConstructError=ConstructError;;const AsyncFunction=async function(){}.constructor;const Generator=function*(){}.constructor;const AsyncGenerator=async function*(){}.constructor;const formatPatterns={"Generator":/^(?<isAsync>async\s+)?function\*\s*[^()]*\((?<params>[^)]*)\)\s*{(?<body>[\s\S]*)}$/,"Function":/^(?<isAsync>async\s+)?function\s*[^()]*\((?<params>[^)]*)\)\s*{(?<body>[\s\S]*)}$/,"ArrowFunction":/^(?<isAsync>async\s+)?(?:\((?<params>[^)]*)\)|(?<singleParam>[^=\s(]+))\s*=>\s*(?:{(?<bracedBody>[\s\S]*)}|(?<bodyExpr>[\s\S]+))$/};async function hasher(obj){let json,hashed;try{json=JSON.stringify(obj)}catch(cause){throw new JsonError("Failed to stringify serialized function structure",{cause})}try{const hashBuffer=await(globalThis?.crypto?.subtle??window?.crypto?.subtle).digest("SHA-256",new TextEncoder().encode(json));hashed=Array.from(new Uint8Array(hashBuffer)).map(item=>item.toString(16).padStart(2,"0")).join("")}catch(cause){throw new CryptoError("Failed to generate hash digest",{cause})}return hashed}function getConstructor(type){switch(type){case"Function":case"ArrowFunction":return Function;case"AsyncFunction":case"AsyncArrowFunction":return AsyncFunction;case"Generator":return Generator;case"AsyncGenerator":return AsyncGenerator;default:throw new ConstructError(`Unexpected type ${type}`)}}function removeComments(input){let[...output]=`__${input}__`;const mode={singleQuote:false,doubleQuote:false,regex:false,blockComment:false,lineComment:false};for(let i=0,l=output.length;i<l;i++){if(mode.regex){if(output[i]==="/"&&output[i-1]!=="\\")mode.regex=false;continue}if(mode.singleQuote){if(output[i]==="'"&&output[i-1]!=="\\")mode.singleQuote=false;continue}if(mode.doubleQuote){if(output[i]==="\""&&output[i-1]!=="\\")mode.doubleQuote=false;continue}if(mode.blockComment){if(output[i]==="*"&&output[i+1]==="/"){output[i+1]="";mode.blockComment=false}output[i]="";continue}if(mode.lineComment){if(output[i+1]==="\n"||output[i+1]==="\r")mode.lineComment=false;output[i]="";continue}mode.doubleQuote=output[i]==="\"";mode.singleQuote=output[i]==="'";if(output[i]==="/"){if(output[i+1]==="*"){output[i]="";mode.blockComment=true;continue}if(output[i+1]==="/"){output[i]="";mode.lineComment=true;continue}mode.regex=true}}return output.join("").slice(2,-2)}async function serialize(func,opts){const def={hash:false,comments:false,whitespace:false};opts=typeof opts==="object"&&null!==opts?Object.assign({},def,opts):Object.assign({},def);const typed=typeof func;if(typed!=="function"){throw new SerializeError("Invalid argument type, must be a function",{cause:{"typeof":typed}})}let stringified=func.toString();if(!opts.comments){stringified=removeComments(stringified)}if(!opts.whitespace){stringified=stringified.split(/[\r\n]+/).map(line=>line.trim()).filter(line=>line!=="").join("\n")}let match,serialized;for(const[type,pattern]of Object.entries(formatPatterns)){try{match=stringified.match(pattern);if(match){let async=match.groups.isAsync?"Async":"";let params=type==="ArrowFunction"?match.groups.params??match.groups.singleParam:match.groups.params;params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match.groups.bracedBody??`return (${match.groups.bodyExpr});`:match.groups.body;if(!opts.whitespace)body=body.trim();serialized={params,body,type:`${async}${type}`};break}}catch(cause){throw new SerializeError(`Unexpected error serializing ${type}`,{cause})}}if(!serialized){throw new SerializeError("Unsupported function format",{cause:stringified})}if(opts.hash){try{const hashed=await hasher(serialized);serialized.hash=hashed}catch(cause){throw new SerializeError("Failure hashing serialized function",{cause})}}return serialized}async function deserialize(struct,opts={hash:false}){if(opts?.hash){if(struct?.hash===undefined){throw new DeserializeError("Deserialized function missing hash")}const test=Object.assign({},struct);delete test.hash;try{const checksum=await hasher(test);if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}}catch(cause){if(cause instanceof ChecksumError)throw cause;throw new DeserializeError("Failure generating checksum",{cause})}}try{const constructor=getConstructor(struct.type);return new constructor(...struct.params,struct.body)}catch(cause){if(cause instanceof ConstructError)throw cause;throw new DeserializeError("Failure deserializing",{cause})}}async function traverse(input,tester,converter){if(tester(input)){return await converter(input)}if(input===null||typeof input!=="object"){return input}const nonTraversables=[String,Boolean,Number,Date,RegExp];for(const constructor of nonTraversables){if(input instanceof constructor){return new constructor(input.valueOf())}}if(input instanceof Array){const cloned=[];for(let i=0;i<input.length;i++){if(tester(input[i]))cloned[i]=await converter(input[i]);else cloned[i]=await traverse(input[i],tester,converter)}return cloned}if(input instanceof Set){const cloned=new Set;for(const value of input){if(tester(value))cloned.add(await converter(value));else cloned.add(await traverse(value,tester,converter))}return cloned}if(input instanceof Map){const cloned=new Map;for(const[key,value]of input){if(tester(value))cloned.set(key,await converter(value));else cloned.set(key,await traverse(value,tester,converter))}return cloned}if(input instanceof Object){const cloned=Object.create(Object.getPrototypeOf(input));for(const key in input){if(Object.hasOwn(input,key)){if(tester(input[key]))cloned[key]=await converter(input[key]);else cloned[key]=await traverse(input[key],tester,converter)}}return cloned}return input}async function deepSerialize(value,options){try{return await traverse(value,input=>typeof input==="function",input=>serialize(input,options))}catch(cause){throw new SerializeError("Failure traversing and serializing",{cause})}}async function deepDeserialize(value,options){try{return await traverse(value,input=>typeof input==="object"&&Object.hasOwn(input,"params")&&Object.hasOwn(input,"body")&&Object.hasOwn(input,"type"),input=>deserialize(input,Object.assign({hash:Object.hasOwn(input,"hash")},options)))}catch(cause){throw new DeserializeError("Failure traversing and deserializing",{cause})}}
|
package/lib/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class JsonError extends Error{};class CryptoError extends Error{};class SerializeError extends Error{}class DeserializeError extends Error{}class ChecksumError extends Error{}class ConstructError extends Error{}const AsyncFunction=async function(){}.constructor;const Generator=function*(){}.constructor;const AsyncGenerator=async function*(){}.constructor;const formatPatterns={"Generator":/^(async\s+)?function\*\s*[^()]*\(([^)]*)\)\s*{([\s\S]*)}$/,"Function":/^(async\s+)?function\s*[^()]*\(([^)]*)\)\s*{([\s\S]*)}$/,"ArrowFunction":/^(async\s+)?(?:\(([^)]*)\)|([^=\s(]+))\s*=>\s*(?:{([\s\S]*)}|([\s\S]+))$/};async function hasher(obj){let json,hashed;try{json=JSON.stringify(obj)}catch(cause){throw new JsonError("Failed to stringify serialized function structure",{cause})}try{const hashBuffer=await(globalThis?.crypto?.subtle??window?.crypto?.subtle).digest("SHA-256",new TextEncoder().encode(json));hashed=Array.from(new Uint8Array(hashBuffer)).map(item=>item.toString(16).padStart(2,"0")).join("")}catch(cause){throw new CryptoError("Failed to generate hash digest",{cause})}return hashed}function getConstructor(type){switch(type){case"Function":case"ArrowFunction":return Function;case"AsyncFunction":case"AsyncArrowFunction":return AsyncFunction;case"Generator":return Generator;case"AsyncGenerator":return AsyncGenerator;default:throw new ConstructError(`Unexpected type ${type}`)}}function removeComments(input){let[...output]=`__${input}__`;const mode={singleQuote:false,doubleQuote:false,regex:false,blockComment:false,lineComment:false
|
|
1
|
+
class JsonError extends Error{};class CryptoError extends Error{};class SerializeError extends Error{};class DeserializeError extends Error{};class ChecksumError extends Error{};class ConstructError extends Error{};const AsyncFunction=async function(){}.constructor;const Generator=function*(){}.constructor;const AsyncGenerator=async function*(){}.constructor;const formatPatterns={"Generator":/^(?<isAsync>async\s+)?function\*\s*[^()]*\((?<params>[^)]*)\)\s*{(?<body>[\s\S]*)}$/,"Function":/^(?<isAsync>async\s+)?function\s*[^()]*\((?<params>[^)]*)\)\s*{(?<body>[\s\S]*)}$/,"ArrowFunction":/^(?<isAsync>async\s+)?(?:\((?<params>[^)]*)\)|(?<singleParam>[^=\s(]+))\s*=>\s*(?:{(?<bracedBody>[\s\S]*)}|(?<bodyExpr>[\s\S]+))$/};async function hasher(obj){let json,hashed;try{json=JSON.stringify(obj)}catch(cause){throw new JsonError("Failed to stringify serialized function structure",{cause})}try{const hashBuffer=await(globalThis?.crypto?.subtle??window?.crypto?.subtle).digest("SHA-256",new TextEncoder().encode(json));hashed=Array.from(new Uint8Array(hashBuffer)).map(item=>item.toString(16).padStart(2,"0")).join("")}catch(cause){throw new CryptoError("Failed to generate hash digest",{cause})}return hashed}function getConstructor(type){switch(type){case"Function":case"ArrowFunction":return Function;case"AsyncFunction":case"AsyncArrowFunction":return AsyncFunction;case"Generator":return Generator;case"AsyncGenerator":return AsyncGenerator;default:throw new ConstructError(`Unexpected type ${type}`)}}function removeComments(input){let[...output]=`__${input}__`;const mode={singleQuote:false,doubleQuote:false,regex:false,blockComment:false,lineComment:false};for(let i=0,l=output.length;i<l;i++){if(mode.regex){if(output[i]==="/"&&output[i-1]!=="\\")mode.regex=false;continue}if(mode.singleQuote){if(output[i]==="'"&&output[i-1]!=="\\")mode.singleQuote=false;continue}if(mode.doubleQuote){if(output[i]==="\""&&output[i-1]!=="\\")mode.doubleQuote=false;continue}if(mode.blockComment){if(output[i]==="*"&&output[i+1]==="/"){output[i+1]="";mode.blockComment=false}output[i]="";continue}if(mode.lineComment){if(output[i+1]==="\n"||output[i+1]==="\r")mode.lineComment=false;output[i]="";continue}mode.doubleQuote=output[i]==="\"";mode.singleQuote=output[i]==="'";if(output[i]==="/"){if(output[i+1]==="*"){output[i]="";mode.blockComment=true;continue}if(output[i+1]==="/"){output[i]="";mode.lineComment=true;continue}mode.regex=true}}return output.join("").slice(2,-2)}async function serialize(func,opts){const def={hash:false,comments:false,whitespace:false};opts=typeof opts==="object"&&null!==opts?Object.assign({},def,opts):Object.assign({},def);const typed=typeof func;if(typed!=="function"){throw new SerializeError("Invalid argument type, must be a function",{cause:{"typeof":typed}})}let stringified=func.toString();if(!opts.comments){stringified=removeComments(stringified)}if(!opts.whitespace){stringified=stringified.split(/[\r\n]+/).map(line=>line.trim()).filter(line=>line!=="").join("\n")}let match,serialized;for(const[type,pattern]of Object.entries(formatPatterns)){try{match=stringified.match(pattern);if(match){let async=match.groups.isAsync?"Async":"";let params=type==="ArrowFunction"?match.groups.params??match.groups.singleParam:match.groups.params;params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match.groups.bracedBody??`return (${match.groups.bodyExpr});`:match.groups.body;if(!opts.whitespace)body=body.trim();serialized={params,body,type:`${async}${type}`};break}}catch(cause){throw new SerializeError(`Unexpected error serializing ${type}`,{cause})}}if(!serialized){throw new SerializeError("Unsupported function format",{cause:stringified})}if(opts.hash){try{const hashed=await hasher(serialized);serialized.hash=hashed}catch(cause){throw new SerializeError("Failure hashing serialized function",{cause})}}return serialized}async function deserialize(struct){let opts=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{hash:false};if(opts?.hash){if(struct?.hash===undefined){throw new DeserializeError("Deserialized function missing hash")}const test=Object.assign({},struct);delete test.hash;try{const checksum=await hasher(test);if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}}catch(cause){if(cause instanceof ChecksumError)throw cause;throw new DeserializeError("Failure generating checksum",{cause})}}try{const constructor=getConstructor(struct.type);return new constructor(...struct.params,struct.body)}catch(cause){if(cause instanceof ConstructError)throw cause;throw new DeserializeError("Failure deserializing",{cause})}}async function traverse(input,tester,converter){if(tester(input)){return await converter(input)}if(input===null||typeof input!=="object"){return input}const nonTraversables=[String,Boolean,Number,Date,RegExp];for(const constructor of nonTraversables){if(input instanceof constructor){return new constructor(input.valueOf())}}if(input instanceof Array){const cloned=[];for(let i=0;i<input.length;i++){if(tester(input[i]))cloned[i]=await converter(input[i]);else cloned[i]=await traverse(input[i],tester,converter)}return cloned}if(input instanceof Set){const cloned=new Set;for(const value of input){if(tester(value))cloned.add(await converter(value));else cloned.add(await traverse(value,tester,converter))}return cloned}if(input instanceof Map){const cloned=new Map;for(const[key,value]of input){if(tester(value))cloned.set(key,await converter(value));else cloned.set(key,await traverse(value,tester,converter))}return cloned}if(input instanceof Object){const cloned=Object.create(Object.getPrototypeOf(input));for(const key in input){if(Object.hasOwn(input,key)){if(tester(input[key]))cloned[key]=await converter(input[key]);else cloned[key]=await traverse(input[key],tester,converter)}}return cloned}return input}async function deepSerialize(value,options){try{return await traverse(value,input=>typeof input==="function",input=>serialize(input,options))}catch(cause){throw new SerializeError("Failure traversing and serializing",{cause})}}async function deepDeserialize(value,options){try{return await traverse(value,input=>typeof input==="object"&&Object.hasOwn(input,"params")&&Object.hasOwn(input,"body")&&Object.hasOwn(input,"type"),input=>deserialize(input,Object.assign({hash:Object.hasOwn(input,"hash")},options)))}catch(cause){throw new DeserializeError("Failure traversing and deserializing",{cause})}}export{serialize,deserialize,deepSerialize,deepDeserialize,JsonError,CryptoError,SerializeError,DeserializeError,ChecksumError,ConstructError};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serialize-function",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Serializes javascript functions to a JSON-friendly format",
|
|
5
5
|
"author": "Evan Kaufman <evan@evanskaufman.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"build-node": "npm run transpile-node -- --minified --no-comments && cp src/import.mjs dist/",
|
|
37
37
|
"dist-dev": "npm run build-browser-dev && npm run build-node-dev",
|
|
38
38
|
"dist": "npm run build-browser && npm run build-node",
|
|
39
|
+
"docs-html": "jsdoc -c ./jsdoc.json ./src/main.mjs",
|
|
39
40
|
"lint": "eslint .",
|
|
40
41
|
"prepare-test-browser": "sed '/TEST_SPEC_END/e cat tests/general.spec.js' tests/003-browser.test.html > ./003-browser.test.html",
|
|
41
42
|
"test-browser": "node ./tests/003-puppeteer.script.mjs",
|
|
@@ -52,10 +53,12 @@
|
|
|
52
53
|
"@fastify/static": "^9.0.0",
|
|
53
54
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
54
55
|
"chai": "^6.2.2",
|
|
56
|
+
"classy-template": "^1.5.4",
|
|
55
57
|
"eslint": "^10.0.3",
|
|
56
58
|
"eslint-plugin-mocha": "^11.2.0",
|
|
57
59
|
"fastify": "^5.8.2",
|
|
58
60
|
"globals": "^17.4.0",
|
|
61
|
+
"jsdoc": "^4.0.5",
|
|
59
62
|
"mocha": "^11.7.5",
|
|
60
63
|
"proxyquire": "^2.1.3",
|
|
61
64
|
"puppeteer": "^24.38.0",
|