Skip to content

Instantly share code, notes, and snippets.

@DarrenSem
Last active February 14, 2023 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DarrenSem/97a436f11dfb841f25837fd449f20756 to your computer and use it in GitHub Desktop.
Save DarrenSem/97a436f11dfb841f25837fd449f20756 to your computer and use it in GitHub Desktop.
stringify.js (handles virtually all types unlike the normal JSON.stringify -- intended for inspecting/displaying object values, NOT for serializing/exporting)
// stringify.js (handles virtually all types unlike the normal JSON.stringify -- intended for inspecting/displaying object values, NOT for serializing/exporting)
/*
this function's result is far more flexible, human-friendly, and USEFUL than JSON.stringify, because...
( Infinity ) => 'Infinity' and ( NaN ) => 'NaN' , instead of 'null'
( undefined ) => 'undefined' and ( Date ) => 'function Date() { [native code] }' , instead of undefined
( new TypeError("xyz") ) => 'TypeError: xyz' , instead of '{}'
( /z/img ) => '/z/gim' , instead of '{}' ( JSCRIPT => '/z/igm' )
( [ , ] ) => '[undefined]' , instead of '[null]'
( new Array(3) ) => '[undefined,undefined,undefined]' , instead of '[null,null,null]'
( new Map( [ ["3", 6.0], [9.0, "8.0"] ] ) ) => 'Map {3 => 6,9 => "8.0"}' , instead of '{}'
( new Set( [3, 6.0, "9", Symbol(3)] ) ) => 'Set {3,6,"9",Symbol(3)}' , instead of '{}'
( new Set( [ [3, 6] , [9, 12] ] ) ) => 'Set {[3,6],[9,12]}' , instead of '{}'
( new WeakSet( [Symbol(3)] ) ) => '[object WeakSet]' , instead of '{}'
( new Int8Array(3) ) => '[0,0,0]' , instead of '{"0":0,"1":0,"2":0}'
( new Int8Array( [ 3, 6, 9 ] ) ) => '[3,6,9]' , instead of '{"0":3,"1":6,"2":9}'
( Symbol(3) ) => 'Symbol(3)' , instead of undefined
( x=>Symbol( x ) ) => 'x=>Symbol( x )' , instead of undefined
( BigInt(3) ) => 3 , instead of TypeError: Do not know how to serialize a BigInt
*/
// with Set/Map "for of" logic, now 401 chars _=function(a){var b,c=String(a),d={}.toString.call(a).slice(8,-1),e=/Array$/.test(d),f="Object"===d,g=0;if(a&&"object"==typeof a){if(c=[],e)for(;g<a.length;)c.push(_(a[g++]));else{if(a.entries)for(g of a.entries(0))c.push(("Map"===d?g[0]+" => ":"")+_(g[1]));if(!c.length)for(g in a)c.push(g+":"+_(a[g]))}b=c.length||f,c=e?"["+c+"]":b?(f?"":d+" ")+"{"+c+"}":a+""}return"string"==typeof a?"\""+a+"\"":c}
// JSCRIPT or without Set/Map "for of" logic, just 310 chars _=function(a){var b,c=String(a),d={}.toString.call(a).slice(8,-1),e=/Array$/.test(d),f="Object"===d,g=0;if(a&&"object"==typeof a){if(c=[],e)for(;g<a.length;)c.push(_(a[g++]));else for(g in a)c.push(g+":"+_(a[g]));b=c.length||f,c=e?"["+c+"]":b?(f?"":d+" ")+"{"+c+"}":a+""}return"string"==typeof a?"\""+a+"\"":c}
var stringify = function(v) {
// "Returns a string representation of the object.
// For simple objects toString() will be used,
// for complex objects a JSON representation will be given." ( their version anyways: https://edabit.com/help/creating-challenges#javascript )
var elements = String(v); // minifier BREAKS THIS for v = Symbol; must be manually corrected back to c=String(a) because c=a+"" FAILS -- TypeError: Cannot convert a Symbol value to a string
var type = {}.toString.call(v).slice(8,-1);
var isArray = /Array$/.test(type);
var isPlainObject = type === "Object";
var isNonEmpty;
var key = 0;
if(v && "object" === typeof v) {
elements = [];
if(isArray) {
while(key < v.length) {
elements.push(
stringify( v[key ++] )
);
};
} else {
/// >> comment out this "for of" section for JScript... OR if you never call with ES6 "[object Map|Set]"
if(v.entries)for(key of v.entries(0)) {
elements.push(
( type !== "Map" ? "" : ( key[0] + " => " ) ) +
stringify( key[1] )
);
}; if(!elements.length)
for(key in v) {
elements.push(
key + ":" + stringify( v[key] )
);
};
};
isNonEmpty = elements.length || isPlainObject;
elements = isArray
? ( "[" + elements + "]" ) // no reason for this other than "space looks better": if(isNonEmpty)elements = elements.join(", ");
: isNonEmpty ? (
( isPlainObject ? "" : ( type + " " ) )
+ "{" + elements + "}"
) : String(v);
};
return (
typeof v === "string" ? ( '"' + v + '"' ) // stringify("A\"\'B") === stringify('A\"\'B') -- simpler than...
// typeof v === "string" ? /'/.test(v) ? ( '"' + v + '"' ) : ( "'" + v + "'" ) // ...this is probably overkill
: elements
);
};
// debugger; console.log(":" + stringify( new Set([3, 6.0, "9", Symbol(3)]) ) + ":" ); throw "STOP"; // :Set {3,6,"9",Symbol(3)}: , instead of :{}: via JSON.stringify
// debugger; console.log(":" + stringify( new Map( [ ["3", 6.0], [9.0, "8.0"] ] ) ) + ":" ); throw "STOP"; // :Map {3 => 6,9 => "8.0"}: , instead of :{}: via JSON.stringify
// debugger; console.log(":" + stringify( new WeakSet([Symbol(3), Symbol(6)]) ) + ":" ); throw "STOP"; // :[object WeakSet]: , instead of :{}: via JSON.stringify
/*@cc_on @if(@_jscript) console={log:function(){var b=arguments;b.length&&WScript.Echo([].join.call(b," "))}}; location={href:WScript.ScriptFullName}; @end@*/
// ^ JScript needs these additional 237 char, to add these 2 Objects that exist in web browsers...
// console={log:function(){var a=arguments;a.length&&WScript.Echo([].join.call(a," "))}};
// location={href:WScript.ScriptFullName};
var stringify_compared_to_JSON = function(func) {
return [
func( null ), // => 'null'
func( true ), // => 'true'
func( false ), // => 'false'
func( 0.0 ), // => '0'
func( "0.0" ), // => "'0.0'"
func( [] ), // => '[]'
func( {} ), // => '{}'
func( location ), // => .match(/^(Location )?{.*\bhref:\s*".+}$/) != null , .match(/^{ancestorOrigins: '\[object DOMStringList\]'/) != null
func( Infinity ), // => 'Infinity' , instead of 'null'
func( NaN ), // => 'NaN' , instead of 'null'
func( undefined ), // => 'undefined' , instead of undefined
func(), // => 'undefined' , instead of undefined
func( Date ), // => 'function Date() { [native code] }' , instead of undefined AKA .match(/^\s*function Date\(\) {\s+\[native code\]\s+}\s*$/) != null,
func( new TypeError("xyz") ), // => 'TypeError: xyz' , instead of '{}' AKA .match(/^({name: ")?TypeError.+ '?xyz('})?$/) != null
func( /z/img ), // => '/z/gim' , instead of '{}' ( JSCRIPT => '/z/igm' )
func( [ , ] ), // => '[undefined]' , instead of '[null]' ( JSCRIPT => '[undefined,undefined]' )
func( new Array(3) ) // => '[undefined,undefined,undefined]' , instead of '[null,null,null]'
/// >> comment out this section for JScript...
, func( new Map( [ ["3", 6.0], [9.0, "8.0"] ] ) ), // => 'Map {3 => 6,9 => "8.0"}' , instead of '{}'
func( new Set( [3, 6.0, "9", Symbol(3)] ) ), // => 'Set {3,6,"9",Symbol(3)}' , instead of '{}'
func( new Set( [ [3, 6] , [9, 12] ] ) ), // => 'Set {[3,6],[9,12]}' , instead of '{}'
func( new WeakSet( [Symbol(3)] ) ), // => '[object WeakSet]' , instead of '{}'
func( new Int8Array(3) ), // => '[0, 0, 0]' , instead of '{"0":0,"1":0,"2":0}'
func( new Int8Array( [ 3, 6, 9 ] ) ), // => '[3, 6, 9]' , instead of '{"0":3,"1":6,"2":9}'
func( Symbol(3) ), // => 'Symbol(3)' , instead of undefined
func( x=>Symbol( x ) ), // => 'x=>Symbol( x )' , instead of undefined
func === stringify ? func( BigInt(3) ) : "BigInt TypeError" // => '3' , instead of TypeError: Do not know how to serialize a BigInt
];
};
// null
// true
// false
// 0
// "0.0"
// []
// {}
// +THEN+ ... Location {ancestorOrigins:DOMStringList {length:0,contains:function contains() { [native code] },item:function item() { [native code] }},href:"file:///C:/data/simple.html",origin:"file://",protocol:"file:",host:"",hostname:"",port:"",pathname:"/C:/data/simple.html",search:"",hash:"",assign:function assign() { [native code] },reload:function reload() { [native code] },replace:function replace() { [native code] },toString:function toString() { [native code] }}
// Infinity
// NaN
// undefined
// undefined
// function Date() { [native code] }
// TypeError: xyz
// /z/gim
// [undefined]
// [undefined,undefined,undefined]
// Map {3 => 6,9 => 12}
// Set {3,6,9}
// Set {[3,6],[9,12]}
// [object WeakSet]
// [0,0,0]
// [3,6,9]
// Symbol(3)
// x=>Symbol( x )
// 3
// +VERSUS+ ... {"ancestorOrigins":{},"href":"file:///C:/data/simple.html","origin":"file://","protocol":"file:","host":"","hostname":"","port":"","pathname":"/C:/data/simple.html","search":"","hash":""}
// null
// null
// <undefined>
// <undefined>
// <undefined>
// {}
// {}
// [null]
// [null,null,null]
// {}
// {}
// [null]
// [null,null,null]
// {}
// {}
// {}
// {}
// {"0":0,"1":0,"2":0}
// {"0":3,"1":6,"2":9}
// <undefined>
// <undefined>
// BigInt TypeError
console.log(
stringify_compared_to_JSON(stringify),
Date.now && stringify_compared_to_JSON(JSON.stringify)
);
console.log([
stringify( null ) === 'null',
stringify( true ) === 'true',
stringify( false ) === 'false',
stringify( 0.0 ) === '0',
stringify( "0.0" ) === '"0.0"',
stringify( [] ) === '[]',
stringify( {} ) === '{}',
stringify( location ).match(/^(Location )?{.*\bhref:\s*".+}$/) != null,
stringify( Infinity ) === 'Infinity',
stringify( NaN ) === 'NaN',
stringify( undefined ) === 'undefined',
stringify() === 'undefined',
stringify( Date ).match(/^\s*function Date\(\) {\s+\[native code\]\s+}\s*$/) != null,
stringify( new TypeError("xyz") ).match(/^(Error )?({name:\s*")?TypeError.+"?xyz("})?$/) != null,
stringify( /z/img ) === ( Date.now ? '/z/gim' : '/z/igm' ),
stringify( [ , ] ).match(/^\[(undefined)((,)\1)?\]$/) != null, // === ( Date.now ? '[undefined]' : '[undefined,undefined]' ),
stringify( new Array(3) ).match(/^\[(undefined)(, ?)\1\2\1\]$/) != null
/// >> comment out this section for JScript...
, stringify( new Map( [ ["3", 6.0], [9.0, "8.0"] ] ) ).match(/^Map {3 => 6,9 => "8.0"}|\[object Map\]/) != null,
stringify( new Set( [3, 6.0, "9", Symbol(3)] ) ).match(/^(Set {3,6,"9",Symbol\(3\)}|\[object Set\])$/) != null,
stringify( new Set( [ [3, 6] , [9, 12] ] ) ).match(/^Set {\[3,6\],\[9,12\]}|\[object Set\]/) != null,
stringify( new WeakSet( [Symbol(3)] ) ) === '[object WeakSet]',
stringify( new Int8Array(3) ) === '[0,0,0]',
stringify( new Int8Array( [ 3, 6, 9 ] ) ) === '[3,6,9]',
stringify( Symbol(3) ) === 'Symbol(3)',
stringify( x=>Symbol( x ) ) === 'x=>Symbol( x )',
stringify( BigInt(3) ) === '3'
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment