1 | {"version":3,"file":"canonicalStringify.js","sourceRoot":"","sources":["../../../src/utilities/common/canonicalStringify.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,UAAU,GAEX,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE;;;;;;;;;;;;;;;;KAgBK;AACL,MAAM,CAAC,IAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAC7C,SAAS,kBAAkB,CAAC,KAAU;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;AACrD,CAAC,EACD;IACE,KAAK;QACH,kEAAkE;QAClE,uEAAuE;QACvE,uDAAuD;QACvD,UAAU,GAAG,IAAI,sBAAsB,CACrC,UAAU,CAAC,kBAAkB,mDAAwC,CACtE,CAAC;IACJ,CAAC;CACF,CACF,CAAC;AAEF,IAAI,OAAO,EAAE,CAAC;IACZ,mBAAmB,CAAC,oBAAoB,EAAE,cAAM,OAAA,UAAU,CAAC,IAAI,EAAf,CAAe,CAAC,CAAC;AACnE,CAAC;AAED,8EAA8E;AAC9E,sCAAsC;AACtC,IAAI,UAA8D,CAAC;AACnE,kBAAkB,CAAC,KAAK,EAAE,CAAC;AAE3B,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AACxE,8EAA8E;AAC9E,qEAAqE;AACrE,yHAAyH;AACzH,SAAS,oBAAoB,CAAC,GAAW,EAAE,KAAU;IACnD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,IAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC3C,yEAAyE;QACzE,4EAA4E;QAC5E,yDAAyD;QACzD,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjD,IAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,uEAAuE;YACvE,sEAAsE;YACtE,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC9C,IAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,IAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBACvC,uEAAuE;gBACvE,uEAAuE;gBACvE,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;gBAC/C,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;gBACxC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YACxC,CAAC;YACD,IAAM,cAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1C,oEAAoE;YACpE,kCAAkC;YAClC,UAAU,CAAC,OAAO,CAAC,UAAC,GAAG;gBACrB,cAAY,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;YACH,OAAO,cAAY,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,sEAAsE;AACtE,8EAA8E;AAC9E,0CAA0C;AAC1C,SAAS,eAAe,CACtB,GAAW,EACX,CAAS,EACT,IAAuB;IAEvB,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;AACvC,CAAC","sourcesContent":["import {\n AutoCleanedStrongCache,\n cacheSizes,\n defaultCacheSizes,\n} from \"../../utilities/caching/index.js\";\nimport { registerGlobalCache } from \"../caching/getMemoryInternals.js\";\n\n/**\n * Like JSON.stringify, but with object keys always sorted in the same order.\n *\n * To achieve performant sorting, this function uses a Map from JSON-serialized\n * arrays of keys (in any order) to sorted arrays of the same keys, with a\n * single sorted array reference shared by all permutations of the keys.\n *\n * As a drawback, this function will add a little bit more memory for every\n * object encountered that has different (more, less, a different order of) keys\n * than in the past.\n *\n * In a typical application, this extra memory usage should not play a\n * significant role, as `canonicalStringify` will be called for only a limited\n * number of object shapes, and the cache will not grow beyond a certain point.\n * But in some edge cases, this could be a problem, so we provide\n * canonicalStringify.reset() as a way of clearing the cache.\n * */\nexport const canonicalStringify = Object.assign(\n function canonicalStringify(value: any): string {\n return JSON.stringify(value, stableObjectReplacer);\n },\n {\n reset() {\n // Clearing the sortingMap will reclaim all cached memory, without\n // affecting the logical results of canonicalStringify, but potentially\n // sacrificing performance until the cache is refilled.\n sortingMap = new AutoCleanedStrongCache<string, readonly string[]>(\n cacheSizes.canonicalStringify || defaultCacheSizes.canonicalStringify\n );\n },\n }\n);\n\nif (__DEV__) {\n registerGlobalCache(\"canonicalStringify\", () => sortingMap.size);\n}\n\n// Values are JSON-serialized arrays of object keys (in any order), and values\n// are sorted arrays of the same keys.\nlet sortingMap!: AutoCleanedStrongCache<string, readonly string[]>;\ncanonicalStringify.reset();\n\n// The JSON.stringify function takes an optional second argument called a\n// replacer function. This function is called for each key-value pair in the\n// object being stringified, and its return value is used instead of the\n// original value. If the replacer function returns a new value, that value is\n// stringified as JSON instead of the original value of the property.\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter\nfunction stableObjectReplacer(key: string, value: any) {\n if (value && typeof value === \"object\") {\n const proto = Object.getPrototypeOf(value);\n // We don't want to mess with objects that are not \"plain\" objects, which\n // means their prototype is either Object.prototype or null. This check also\n // prevents needlessly rearranging the indices of arrays.\n if (proto === Object.prototype || proto === null) {\n const keys = Object.keys(value);\n // If keys is already sorted, let JSON.stringify serialize the original\n // value instead of creating a new object with keys in the same order.\n if (keys.every(everyKeyInOrder)) return value;\n const unsortedKey = JSON.stringify(keys);\n let sortedKeys = sortingMap.get(unsortedKey);\n if (!sortedKeys) {\n keys.sort();\n const sortedKey = JSON.stringify(keys);\n // Checking for sortedKey in the sortingMap allows us to share the same\n // sorted array reference for all permutations of the same set of keys.\n sortedKeys = sortingMap.get(sortedKey) || keys;\n sortingMap.set(unsortedKey, sortedKeys);\n sortingMap.set(sortedKey, sortedKeys);\n }\n const sortedObject = Object.create(proto);\n // Reassigning the keys in sorted order will cause JSON.stringify to\n // serialize them in sorted order.\n sortedKeys.forEach((key) => {\n sortedObject[key] = value[key];\n });\n return sortedObject;\n }\n }\n return value;\n}\n\n// Since everything that happens in stableObjectReplacer benefits from being as\n// efficient as possible, we use a static function as the callback for\n// keys.every in order to test if the provided keys are already sorted without\n// allocating extra memory for a callback.\nfunction everyKeyInOrder(\n key: string,\n i: number,\n keys: readonly string[]\n): boolean {\n return i === 0 || keys[i - 1] <= key;\n}\n"]} |