Change API to sort+serialize

This commit is contained in:
Simon Warta 2020-09-30 10:13:42 +02:00
parent 8e337ad6b1
commit d69f6041b8
3 changed files with 42 additions and 42 deletions

View File

@ -1,55 +1,50 @@
import { sortJson } from "./encoding";
import { sortedJsonStringify } from "./encoding";
describe("encoding", () => {
describe("sortJson", () => {
describe("sortedJsonStringify", () => {
it("leaves non-objects unchanged", () => {
expect(sortJson(true)).toEqual(true);
expect(sortJson(false)).toEqual(false);
expect(sortJson("aabbccdd")).toEqual("aabbccdd");
expect(sortJson(75)).toEqual(75);
expect(sortJson(null)).toEqual(null);
expect(sortJson([5, 6, 7, 1])).toEqual([5, 6, 7, 1]);
expect(sortJson([5, ["a", "b"], true, null, 1])).toEqual([5, ["a", "b"], true, null, 1]);
expect(sortedJsonStringify(true)).toEqual(`true`);
expect(sortedJsonStringify(false)).toEqual(`false`);
expect(sortedJsonStringify("aabbccdd")).toEqual(`"aabbccdd"`);
expect(sortedJsonStringify(75)).toEqual(`75`);
expect(sortedJsonStringify(null)).toEqual(`null`);
expect(sortedJsonStringify([5, 6, 7, 1])).toEqual(`[5,6,7,1]`);
expect(sortedJsonStringify([5, ["a", "b"], true, null, 1])).toEqual(`[5,["a","b"],true,null,1]`);
});
it("sorts objects by key", () => {
// already sorted
expect(sortJson({})).toEqual({});
expect(sortJson({ a: 3 })).toEqual({ a: 3 });
expect(sortJson({ a: 3, b: 2, c: 1 })).toEqual({ a: 3, b: 2, c: 1 });
expect(sortedJsonStringify({})).toEqual(`{}`);
expect(sortedJsonStringify({ a: 3 })).toEqual(`{"a":3}`);
expect(sortedJsonStringify({ a: 3, b: 2, c: 1 })).toEqual(`{"a":3,"b":2,"c":1}`);
// not yet sorted
expect(sortJson({ b: 2, a: 3, c: 1 })).toEqual({ a: 3, b: 2, c: 1 });
expect(sortJson({ aaa: true, aa: true, a: true })).toEqual({ a: true, aa: true, aaa: true });
expect(sortedJsonStringify({ b: 2, a: 3, c: 1 })).toEqual(`{"a":3,"b":2,"c":1}`);
expect(sortedJsonStringify({ aaa: true, aa: true, a: true })).toEqual(
`{"a":true,"aa":true,"aaa":true}`,
);
});
it("sorts nested objects", () => {
// already sorted
expect(sortJson({ x: { y: { z: null } } })).toEqual({ x: { y: { z: null } } });
expect(sortedJsonStringify({ x: { y: { z: null } } })).toEqual(`{"x":{"y":{"z":null}}}`);
// not yet sorted
expect(sortJson({ b: { z: true, x: true, y: true }, a: true, c: true })).toEqual({
a: true,
b: { x: true, y: true, z: true },
c: true,
});
expect(sortedJsonStringify({ b: { z: true, x: true, y: true }, a: true, c: true })).toEqual(
`{"a":true,"b":{"x":true,"y":true,"z":true},"c":true}`,
);
});
it("sorts objects in arrays", () => {
// already sorted
expect(sortJson([1, 2, { x: { y: { z: null } } }, 4])).toEqual([1, 2, { x: { y: { z: null } } }, 4]);
expect(sortedJsonStringify([1, 2, { x: { y: { z: null } } }, 4])).toEqual(
`[1,2,{"x":{"y":{"z":null}}},4]`,
);
// not yet sorted
expect(sortJson([1, 2, { b: { z: true, x: true, y: true }, a: true, c: true }, 4])).toEqual([
1,
2,
{
a: true,
b: { x: true, y: true, z: true },
c: true,
},
4,
]);
expect(sortedJsonStringify([1, 2, { b: { z: true, x: true, y: true }, a: true, c: true }, 4])).toEqual(
`[1,2,{"a":true,"b":{"x":true,"y":true,"z":true},"c":true},4]`,
);
});
});
});

View File

@ -5,25 +5,30 @@ import { Uint53 } from "@cosmjs/math";
import { Msg } from "./msgs";
import { StdFee } from "./types";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function sortJson(json: any): any {
if (typeof json !== "object" || json === null) {
return json;
function sortedObject(obj: any): any {
if (typeof obj !== "object" || obj === null) {
return obj;
}
if (Array.isArray(json)) {
return json.map(sortJson);
if (Array.isArray(obj)) {
return obj.map(sortedObject);
}
const sortedKeys = Object.keys(json).sort();
const sortedKeys = Object.keys(obj).sort();
const result = sortedKeys.reduce(
(accumulator, key) => ({
...accumulator,
[key]: sortJson(json[key]),
[key]: sortedObject(obj[key]),
}),
{},
);
return result;
}
/** Returns a JSON string with objects sorted by key */
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function sortedJsonStringify(obj: any): string {
return JSON.stringify(sortedObject(obj));
}
/**
* The document to be signed
*
@ -57,6 +62,5 @@ export function makeSignDoc(
}
export function serializeSignDoc(signDoc: StdSignDoc): Uint8Array {
const sortedSignDoc = sortJson(signDoc);
return toUtf8(JSON.stringify(sortedSignDoc));
return toUtf8(sortedJsonStringify(signDoc));
}

View File

@ -1,6 +1,7 @@
import { Msg } from "./msgs";
import { StdFee } from "./types";
export declare function sortJson(json: any): any;
/** Returns a JSON string with objects sorted by key */
export declare function sortedJsonStringify(obj: any): string;
/**
* The document to be signed
*