Created
February 4, 2023 15:43
-
-
Save lxsmnsyc/a1da7be99cfd3b191dd19e4794d9db35 to your computer and use it in GitHub Desktop.
JS serializer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function serialize(source) { | |
const refs = []; | |
const assignments = []; | |
function checkRef(current) { | |
const index = refs.indexOf(current); | |
if (index === -1) { | |
refs.push(current) | |
return { first: true, index: refs.length - 1}; | |
} | |
return { first: false, index }; | |
} | |
function getRef(index) { | |
return `r[${index}]`; | |
} | |
function createAssignment(line) { | |
assignments.push(line + ','); | |
} | |
function traverse(current) { | |
if (current === true) { | |
return '!0'; | |
} | |
if (current === false) { | |
return '!1'; | |
} | |
if (typeof current === 'number' || current instanceof RegExp) { | |
return `${current}`; | |
} | |
if (current === undefined) { | |
return 'void 0'; | |
} | |
if (current === null) { | |
return 'null'; | |
} | |
if (typeof current === 'string') { | |
return JSON.stringify(current); | |
} | |
const { first, index } = checkRef(current); | |
const ref = getRef(index); | |
if (!first) { | |
return ref; | |
} | |
if (current instanceof Date) { | |
createAssignment(`${ref}=new Date("${current.toISOString()}")`); | |
return ref; | |
} | |
if (current instanceof Set) { | |
createAssignment(`${ref}=new Set()`); | |
for (const value of current.keys()) { | |
createAssignment(`${ref}.add(${traverse(value)})`); | |
} | |
return ref; | |
} | |
if (current instanceof Map) { | |
createAssignment(`${ref}=new Map()`); | |
for (const [key, value] of current.entries()) { | |
createAssignment(`${ref}.set(${traverse(key)},${traverse(value)})`); | |
} | |
return ref; | |
} | |
if (Array.isArray(current)) { | |
createAssignment(`${ref}=new Array(${current.length})`); | |
for (let i = 0, len = current.length; i < len; i += 1) { | |
if (i in current) { | |
createAssignment(`${ref}[${i}]=${traverse(current[i])}`); | |
} | |
} | |
return ref; | |
} | |
if (current && typeof current === 'object') { | |
createAssignment(`${ref}={}`); | |
for (const [key, value] of Object.entries(current)) { | |
const check = Number(key); | |
// Test if key is a valid number or JS identifier | |
// so that we don't have to serialize the key and wrap with brackets | |
if (check === check || /^([$A-Z_][0-9A-Z_$]*)$/i.test(key)) { | |
createAssignment(`${ref}.${key}=${traverse(value)}`); | |
} else { | |
createAssignment(`${ref}[${JSON.stringify(key)}]=${traverse(value)}`); | |
} | |
} | |
return ref; | |
} | |
} | |
const result = traverse(source); | |
const header = assignments.join(''); | |
return `(r=>(${header}${result}))([])`; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment