Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dependency on fast-json-stable-stringify #8222

Merged
merged 8 commits into from
May 18, 2021
Prev Previous commit
Next Next commit
Use ObjectCanon to speed up stable stringification.
This reimplementation of the stable `stringify` function used by
`getStoreKeyName` builds on the `ObjectCanon` introduced by my PR #7439,
which guarantees canonical objects keys are always in sorted order.
  • Loading branch information
benjamn committed May 14, 2021
commit 842eb5e2b820f5d0aec4746c229acaeb69306d1b
27 changes: 24 additions & 3 deletions src/cache/inmemory/object-canon.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { Trie } from "@wry/trie";
import { canUseWeakMap } from "../../utilities";
import { objToStr } from "./helpers";

function isObjectOrArray(value: any): boolean {
function isObjectOrArray(value: any): value is object {
return !!value && typeof value === "object";
}

@@ -109,7 +109,7 @@ export class ObjectCanon {
switch (objToStr.call(value)) {
case "[object Array]": {
if (this.known.has(value)) return value;
const array: any[] = value.map(this.admit, this);
const array: any[] = (value as any[]).map(this.admit, this);
// Arrays are looked up in the Trie using their recursively
// canonicalized elements, and the known version of the array is
// preserved as node.array.
@@ -134,7 +134,7 @@ export class ObjectCanon {
array.push(keys.json);
const firstValueIndex = array.length;
keys.sorted.forEach(key => {
array.push(this.admit(value[key]));
array.push(this.admit((value as any)[key]));
});
// Objects are looked up in the Trie by their prototype (which
// is *not* recursively canonicalized), followed by a JSON
@@ -193,3 +193,24 @@ type SortedKeysInfo = {
sorted: string[];
json: string;
};

const stringifyCanon = new ObjectCanon;
const stringifyCache = new WeakMap<object, string>();

// Since the keys of canonical objects are always created in lexicographically
// sorted order, we can use the ObjectCanon to implement a fast and stable
// version of JSON.stringify, which automatically sorts object keys.
benjamn marked this conversation as resolved.
Show resolved Hide resolved
export function canonicalStringify(value: any): string {
if (isObjectOrArray(value)) {
const canonical = stringifyCanon.admit(value);
let json = stringifyCache.get(canonical);
if (json === void 0) {
stringifyCache.set(
canonical,
json = JSON.stringify(canonical),
);
}
return json;
}
return JSON.stringify(value);
}
6 changes: 6 additions & 0 deletions src/cache/inmemory/policies.ts
Original file line number Diff line number Diff line change
@@ -48,6 +48,12 @@ import {
} from '../core/types/common';
import { WriteContext } from './writeToStore';

// Upgrade to a faster version of the default stable JSON.stringify function
// used by getStoreKeyName. This function is used when computing storeFieldName
// strings (when no keyArgs has been configured for a field).
import { canonicalStringify } from './object-canon';
getStoreKeyName.setStringify(canonicalStringify);

export type TypePolicies = {
[__typename: string]: TypePolicy;
}