diff --git a/src/jsifier.mjs b/src/jsifier.mjs index ff277b3bdc066..816e073a6b7f9 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -33,6 +33,7 @@ import { compileTimeContext, printErr, readFile, + runInMacroContext, warn, warnOnce, warningOccured, @@ -79,6 +80,19 @@ function stringifyWithFunctions(obj) { if (Array.isArray(obj)) { return '[' + obj.map(stringifyWithFunctions).join(',') + ']'; } + + // preserve the type of the object if it is one of [Map, Set, WeakMap, WeakSet]. + const builtinContainers = runInMacroContext('[Map, Set, WeakMap, WeakSet]', { + filename: '', + }); + for (const container of builtinContainers) { + if (obj instanceof container) { + const className = container.name; + assert(!obj.size, `cannot stringify ${className} with data`); + return `new ${className}`; + } + } + var rtn = '{\n'; for (const [key, value] of Object.entries(obj)) { var str = stringifyWithFunctions(value); diff --git a/test/test_other.py b/test/test_other.py index c2cbc74872959..0a1d4876af2fb 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -4974,6 +4974,34 @@ def test_jslib_has_library(self): ''') self.do_runf(test_file('hello_world.c'), emcc_args=['-L', '-lfoo.js']) + def test_jslib_new_objects_basic(self): + create_file('lib.js', ''' + addToLibrary({ + $obj: { + a: new Map(), + b: new Set(), + c: new WeakMap(), + d: new WeakSet() + } + }); + ''') + self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=obj,_main']) + self.assertContained("a:new Map,", read_file('a.out.js')) + self.assertContained("b:new Set,", read_file('a.out.js')) + self.assertContained("c:new WeakMap,", read_file('a.out.js')) + self.assertContained("d:new WeakSet,", read_file('a.out.js')) + + def test_jslib_new_objects_non_empty(self): + create_file('lib.js', ''' + addToLibrary({ + $obj: { + bad: new Map([[1,2],[3,4]]) + } + }); + ''') + err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=obj,_main']) + self.assertContained('cannot stringify Map with data', err) + def test_EMCC_BUILD_DIR(self): # EMCC_BUILD_DIR was necessary in the past since we used to force the cwd to be src/ for # technical reasons.