combo: add `raw` identity parser (#1827)

Summary:
If you want to parse an arbitrary JSON object, or if you want to parse a
complicated dynamic type that can’t easily be expressed in terms of the
other base parsers and combinators, use `C.raw`. This combinator accepts
any input and returns it as a `JsonObject`—not an `any`, so it’s still
safely typed, but the client (either an `fmap` transform or the consumer
of the eventual `parse`/`parseOrThrow`) will need to destructure it by
pattern matching on the `JsonObject` structure.

Test Plan:
Unit tests included (though full coverage technically doesn’t require
them).

wchargin-branch: combo-raw
This commit is contained in:
William Chargin 2020-05-31 22:24:17 -07:00 committed by GitHub
parent 500140d292
commit 0dae2346fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 0 deletions

View File

@ -95,6 +95,19 @@ export const null_: Parser<null> = new Parser((x) => {
return success(x);
});
// The identity operation: a parser that always succeeds, emitting a
// `JsonObject` (not `any`) with the input. Used when you need a parser
// that matches anything:
//
// // Accepts an arbitrary heterogeneous array and returns its length
// C.fmap(C.array(C.raw), (a) => a.length)
//
// // Accepts a config file with dynamic plugin-specific data
// C.object({version: string, pluginConfig: C.dict(C.raw)})
//
// To destructure the parsed value dynamically, pair with `fmap`.
export const raw: Parser<JsonObject> = new Parser(success);
// Lift a plain value into a parser that always returns that value,
// ignoring its input.
export function pure<T>(t: T): Parser<T> {

View File

@ -75,6 +75,29 @@ describe("src/util/combo", () => {
});
});
describe("raw", () => {
it("parses strings", () => {
expect(C.raw.parseOrThrow("hey")).toEqual("hey");
});
it("parses numbers", () => {
expect(C.raw.parseOrThrow(123)).toEqual(123);
});
it("parses booleans", () => {
expect(C.raw.parseOrThrow(true)).toEqual(true);
expect(C.raw.parseOrThrow(false)).toEqual(false);
});
it("parses null", () => {
expect(C.raw.parseOrThrow(null)).toEqual(null);
});
it("parses heterogeneous arrays", () => {
expect(C.raw.parseOrThrow([1, "two"])).toEqual([1, "two"]);
});
it("parses heterogeneous objects", () => {
const input = {one: 2, three: "five"};
expect(C.raw.parseOrThrow(input)).toEqual({one: 2, three: "five"});
});
});
describe("pure", () => {
it("does what it says on the tin", () => {
type Color = "RED" | "GREEN" | "BLUE";