serialize-function 1.0.15 → 1.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.
package/README.md CHANGED
@@ -4,10 +4,10 @@
4
4
  ![ci status](https://github.com/EvanK/npm-serialize-function/actions/workflows/ci.yaml/badge.svg)
5
5
  ](https://github.com/EvanK/npm-serialize-function/actions/workflows/ci.yaml)
6
6
  [
7
- ![node.js supported as of v20](https://img.shields.io/badge/Node.js-v20-yellow)
8
- ](https://nodejs.org/docs/latest-v20.x/api/)
7
+ ![Node.js supported and tested on v20 through v26](https://img.shields.io/badge/Node.js-v20%20--%20v26-seagreen?logo=nodedotjs "Node.js supported and tested on v20 through v26")
8
+ ](https://nodejs.org/en/about/previous-releases)
9
9
  [
10
- ![ECMAScript standard supported as of ES2023](https://img.shields.io/badge/ES-2023-green)
10
+ ![ECMAScript standard supported as of ES2023](https://img.shields.io/badge/ES-2023-dodgerblue "ECMAScript standard supported as of ES2023")
11
11
  ](https://compat-table.github.io/compat-table/es2016plus/)
12
12
 
13
13
  [
@@ -67,7 +67,7 @@ const tamperedFunc = await deserialize(hashedObj, { hash: true });
67
67
  // ChecksumError: Checksum failed
68
68
  ```
69
69
 
70
- > Under the hood, the browser-based implementation uses the [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) API, while the node implementation uses the built-in [crypto module](https://nodejs.org/docs/latest-v20.x/api/crypto.html).
70
+ > Under the hood, hashing uses the [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) API.
71
71
 
72
72
  ## Whitespace and comments
73
73
 
package/dist/main.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.deserialize=deserialize;exports.serialize=serialize;function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap,n=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var o,i,f={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return f;if(o=t?n:r){if(o.has(e))return o.get(e);o.set(e,f)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((i=(o=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(i.get||i.set)?o(f,t,i):f[t]=e[t]);return f})(e,t)}async function digest(input){const{createHash}=await Promise.resolve().then(()=>_interopRequireWildcard(require("node:crypto")));return createHash("sha256").update(input).digest("hex")}class JsonError extends Error{};class CryptoError extends Error{};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{hashed=await digest(json)}catch(cause){throw new CryptoError("Failed to generate hash digest",{cause})}return hashed}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]+))$/};class SerializeError extends Error{}class DeserializeError extends Error{}class ChecksumError extends Error{}class ConstructError extends Error{}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 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=stringified.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}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[1]?"Async":"";let params=type==="ArrowFunction"?match[2]??match[3]:match[2];params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match[4]??`return (${match[5]});`:match[3];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){return hasher(serialized).then(hashed=>{serialized.hash=hashed;return serialized}).catch(cause=>{throw new SerializeError("Failure hashing serialized function",{cause})})}return serialized}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;return hasher(test).then(checksum=>{if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}return deserialize(struct,{hash:false})}).catch(cause=>{if(cause instanceof ChecksumError||cause instanceof DeserializeError||cause instanceof ConstructError){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})}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.deserialize=deserialize;exports.serialize=serialize;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 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=stringified.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}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[1]?"Async":"";let params=type==="ArrowFunction"?match[2]??match[3]:match[2];params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match[4]??`return (${match[5]});`:match[3];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){return hasher(serialized).then(hashed=>{serialized.hash=hashed;return serialized}).catch(cause=>{throw new SerializeError("Failure hashing serialized function",{cause})})}return serialized}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;return hasher(test).then(checksum=>{if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}return deserialize(struct,{hash:false})}).catch(cause=>{if(cause instanceof ChecksumError||cause instanceof DeserializeError||cause instanceof ConstructError){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})}}
package/lib/main.js CHANGED
@@ -1 +1 @@
1
- async function digest(input){const hashBuffer=await window.crypto.subtle.digest("SHA-256",new TextEncoder().encode(input));return Array.from(new Uint8Array(hashBuffer)).map(item=>item.toString(16).padStart(2,"0")).join("")}class JsonError extends Error{};class CryptoError extends Error{};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{hashed=await digest(json)}catch(cause){throw new CryptoError("Failed to generate hash digest",{cause})}return hashed}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]+))$/};class SerializeError extends Error{}class DeserializeError extends Error{}class ChecksumError extends Error{}class ConstructError extends Error{}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 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=stringified.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}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[1]?"Async":"";let params=type==="ArrowFunction"?match[2]??match[3]:match[2];params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match[4]??`return (${match[5]});`:match[3];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){return hasher(serialized).then(hashed=>{serialized.hash=hashed;return serialized}).catch(cause=>{throw new SerializeError("Failure hashing serialized function",{cause})})}return serialized}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;return hasher(test).then(checksum=>{if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}return deserialize(struct,{hash:false})}).catch(cause=>{if(cause instanceof ChecksumError||cause instanceof DeserializeError||cause instanceof ConstructError){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})}}export{serialize,deserialize};
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 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=stringified.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}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[1]?"Async":"";let params=type==="ArrowFunction"?match[2]??match[3]:match[2];params=params.split(",").map(p=>opts.whitespace?p:p.trim()).filter(Boolean);let body=type==="ArrowFunction"?match[4]??`return (${match[5]});`:match[3];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){return hasher(serialized).then(hashed=>{serialized.hash=hashed;return serialized}).catch(cause=>{throw new SerializeError("Failure hashing serialized function",{cause})})}return serialized}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;return hasher(test).then(checksum=>{if(checksum!==struct.hash){throw new ChecksumError("Checksum failed",{cause:{a:checksum,b:struct.hash}})}return deserialize(struct,{hash:false})}).catch(cause=>{if(cause instanceof ChecksumError||cause instanceof DeserializeError||cause instanceof ConstructError){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})}}export{serialize,deserialize};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serialize-function",
3
- "version": "1.0.15",
3
+ "version": "1.1.0",
4
4
  "description": "Serializes javascript functions to a JSON-friendly format",
5
5
  "author": "Evan Kaufman <evan@evanskaufman.com>",
6
6
  "license": "MIT",
@@ -27,14 +27,13 @@
27
27
  },
28
28
  "browser": "./lib/main.js",
29
29
  "scripts": {
30
- "concat-browser": "cat src/001-digest-browser.mjs src/002-hasher.mjs src/003-main.mjs > build-main-browser.mjs",
31
- "concat-node": "cat src/001-digest-node.mjs src/002-hasher.mjs src/003-main.mjs > build-main-node.mjs",
32
- "transpile-browser": "babel build-main-browser.mjs --no-babelrc --out-file lib/main.js --config-file ./.babelrc.esm.json",
33
- "transpile-node": "babel build-main-node.mjs --no-babelrc --out-file dist/main.js --config-file ./.babelrc.cjs.json",
34
- "build-browser-dev": "npm run concat-browser && npm run transpile-browser",
35
- "build-node-dev": "npm run concat-node && npm run transpile-node && cp src/import.mjs dist/",
36
- "build-browser": "npm run concat-browser && npm run transpile-browser -- --minified --no-comments",
37
- "build-node": "npm run concat-node && npm run transpile-node -- --minified --no-comments && cp src/import.mjs dist/",
30
+ "clean": "rm -f ./build-*.*js ./tests/*.ignore.test.cjs ./0*.test.html ./screenshot.png && rm -rf ./lib ./dist",
31
+ "transpile-browser": "babel src/main.mjs --no-babelrc --out-file lib/main.js --config-file ./.babelrc.esm.json",
32
+ "transpile-node": "babel src/main.mjs --no-babelrc --out-file dist/main.js --config-file ./.babelrc.cjs.json",
33
+ "build-browser-dev": "npm run transpile-browser",
34
+ "build-node-dev": "npm run transpile-node && cp src/import.mjs dist/",
35
+ "build-browser": "npm run transpile-browser -- --minified --no-comments",
36
+ "build-node": "npm run transpile-node -- --minified --no-comments && cp src/import.mjs dist/",
38
37
  "dist-dev": "npm run build-browser-dev && npm run build-node-dev",
39
38
  "dist": "npm run build-browser && npm run build-node",
40
39
  "lint": "eslint .",
@@ -42,7 +41,7 @@
42
41
  "test-browser": "node ./tests/003-puppeteer.script.mjs",
43
42
  "prepare-test-node": "cat tests/001-general.test.template.cjs tests/general.spec.js > tests/001-general.ignore.test.cjs",
44
43
  "test-node": "mocha ./tests/**.test.*js",
45
- "test": "npm run prepare-test-browser && npm run test-browser && npm run prepare-test-node && npm run test-node"
44
+ "test": "npm run clean && npm run dist && npm run prepare-test-node && npm run test-node && npm run prepare-test-browser && npm run test-browser"
46
45
  },
47
46
  "devDependencies": {
48
47
  "@babel/cli": "^7.28.6",