Skip to content

Commit

Permalink
add more examples
Browse files Browse the repository at this point in the history
  • Loading branch information
mistlog committed Aug 22, 2020
1 parent 32b4276 commit 6ee8937
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 8 deletions.
188 changes: 185 additions & 3 deletions src/ts-pattern.test.tsx
Expand Up @@ -95,9 +95,8 @@ describe("collection", () => {
});

test("match set patterns", () => {
const ContainsGabAndYo = (set: Set<string | number>) => Λ<[boolean, boolean]>(
"match"
)` ${set}
// prettier-ignore
const ContainsGabAndYo = (set: Set<string | number>) => Λ<[boolean, boolean]>("match")` ${set}
${new Set(["gab", "yo"])} -> ${[true, true]}
${new Set(["gab"])} -> ${[true, false]}
${new Set(["yo"])} -> ${[false, true]}
Expand All @@ -111,6 +110,189 @@ describe("collection", () => {
expect(ContainsGabAndYo(new Set([]))).toEqual([false, false]);
expect(ContainsGabAndYo(new Set([2]))).toEqual([false, false]);
});

test("match tuple patterns", () => {
const sum = (xs: number[]): number => Λ<number>("match")` ${xs}
${[]} -> ${0}
${[Number, Number]} -> ${([x, y]) => x + y}
${[Number, Number, Number]} -> ${([x, y, z]) => x + y + z}
${[Number, Number, Number, Number]} -> ${([x, y, z, w]) => x + y + z + w}
`;

expect(sum([2, 3, 2, 4])).toEqual(11);
});

test("match union of tuples", () => {
type Input = ["+", number, number] | ["*", number, number] | ["-", number] | ["++", number];

// prettier-ignore
const result1 = Λ<number>("match")` ${["-", 2]}
${["+", Number, Number]} -> ${value => {
const [, x, y] = value;
return x + y;
}}
${["*", Number, Number]} -> ${value => {
const [, x, y] = value;
return x * y;
}}
${["-", Number]} -> ${value => {
const [, x] = value;
return -x;
}}
`;

// prettier-ignore
const result2 = Λ<number>("match")` ${["-", 2] as Input}
${["+", __, __]} -> ${value => {
const [, x, y] = value;
return x + y;
}}
${["*", __, __]} -> ${value => {
const [, x, y] = value;
return x * y;
}}
${["-", __]} -> ${value => {
const [, x] = value;
return -x;
}}
`;

expect(result1).toEqual(-2);
expect(result2).toEqual(-2);
});

describe("match heterogenous tuple patterns", () => {
const tuples: { tuple: [string, number]; expected: string }[] = [
{ tuple: ["coucou", 20], expected: "number match" },
{ tuple: ["hello", 20], expected: "perfect match" },
{ tuple: ["hello", 21], expected: "string match" },
{ tuple: ["azeaze", 17], expected: "not matching" },
];

tuples.forEach(({ tuple, expected }) => {
it(`should work with ${tuple}`, () => {
expect(Λ("match")` ${tuple}
${["hello", 20]} -> ${"perfect match"}
${["hello", __]} -> ${"string match"}
${[__, 20]} -> ${"number match"}
${[String, Number]} -> ${"not matching"}
${[__, __]} -> ${"can't happen"}
${__} -> ${"can't happen"}
`).toEqual(expected);
});
});
});

test("match tuple of records", () => {
const init_state: State = {
status: "idle",
};

// prettier-ignore
const reducer = (state: State, event: Event) => Λ<State>("match")`${[state, event] as [State, Event]}
${[__, { type: "fetch" }]} -> ${{ status: "loading" }}
${[{ status: "loading" }, { type: "success" }]} -> ${x => ({ status: "success", data: x[1].data })}
${[{ status: "loading" }, { type: "error" }]} -> ${x => ({ status: "error", error: x[1].error })}
${[{ status: "loading" }, { type: "cancel" }]} -> ${init_state}
default: ${state}
`;

expect(reducer(init_state, { type: "fetch" })).toEqual({
status: "loading",
});

expect(reducer({ status: "loading" }, { type: "success", data: "yo" })).toEqual({
status: "success",
data: "yo",
});

expect(reducer({ status: "loading" }, { type: "cancel" })).toEqual({
status: "idle",
});
});
});

describe("unions", () => {
test("union 1", () => {
const value: Option<string> = {
kind: "some",
value: "hello",
};

const result = Λ("match")` ${value as Option<string>}
${{ kind: "some" }} -> ${o => o.value}
${{ kind: "none" }} -> ${"no value"}
`;

expect(result).toEqual("hello");
});

test("union 2", () => {
type Post = {
type: "post";
id: number;
content: { body: string };
};
type Video = { type: "video"; id: number; content: { src: string } };
type Image = { type: "image"; id: number; content: { src: number } };

type Input = Post | Video | Image;

const value: Input = {
type: "post",
id: 2,
content: { body: "yo" },
};

const result = Λ("match")` ${value as Input}
${{ type: "post", content: __ }} -> ${1}
${{ type: "post", id: 7 }} -> ${1}
${{ type: "video", content: { src: String } }} -> ${2}
${{ type: "image", content: { src: Number } }} -> ${3}
`;

expect(result).toEqual(1);
});

test("union 3", () => {
type Text = { type: "text"; content: string };
type Img = { type: "img"; src: string };
type Video = { type: "video"; src: string };
type Story = {
type: "story";
likes: number;
views: number;
author: string;
src: string;
};
type Data = Text | Img | Video | Story;

type Ok<T> = { type: "ok"; data: T };
type ResError<T> = { type: "error"; error: T };

type Result<TError, TOk> = Ok<TOk> | ResError<TError>;

const result: Result<Error, Data> = {
type: "ok",
data: { type: "img", src: "hello.com" },
};

// prettier-ignore
const ouput = Λ('match')` ${result as Result<Error, Data>}
${{ type: "ok", data: { type: "text" } }} -> ${res => `<p>${res.data.content}</p>`}
${{ type: "ok", data: { type: "img" } }} -> ${res => `<img src="${res.data.src}" />`}
${{ type: "ok", data: { type: "story", likes: 10 } }} -> ${res => `<div>story with ${res.data.likes} likes</div>`}
${{ type: "error" }} -> ${"<p>Oups! An error occured</p>"}
default: ${"<p>everything else</p>"}
`;

expect(ouput).toEqual('<img src="hello.com" />');
});
});

test("match condition", () => {
Expand Down
10 changes: 5 additions & 5 deletions test/refactor-draft-dsl-match.test.ts
Expand Up @@ -6,7 +6,7 @@ import { PatternMatch } from "../src/refactor-draft-dsl-match";
test("type param", () => {
const dsl = new PatternMatch();
const path = GetTemplateLiteralPath(`
Λ<number>("match")\`\${value as number} :
Λ<number>("match")\`\${value as number}
\${2} -> \${30}
\`
`);
Expand All @@ -18,7 +18,7 @@ test("type param", () => {
test("value only", () => {
const dsl = new PatternMatch();
const path = GetTemplateLiteralPath(`
Λ("match")\`\${value} :
Λ("match")\`\${value}
\${2} -> \${30}
\${'temp'} -> \${'temp'}
\${string_type} -> \${\`value is \${value}\`}
Expand All @@ -33,7 +33,7 @@ test("value only", () => {
test("return object", () => {
const dsl = new PatternMatch();
const path = GetTemplateLiteralPath(`
Λ("match")\`\${value} :
Λ("match")\`\${value}
\${2} -> \${ x =>({ type: 'image' })}
\${(value: any) => value === 3} -> \${"number: 3"}
\`
Expand All @@ -45,7 +45,7 @@ test("return object", () => {
test("use expression", () => {
const dsl = new PatternMatch();
const path = GetTemplateLiteralPath(`
Λ("match")\`\${input} :
Λ("match")\`\${input}
\${is3(input)} -> \${'temp'}
default : \${6}
\`;
Expand All @@ -58,7 +58,7 @@ test("use expression", () => {
test("use handler", () => {
const dsl = new PatternMatch();
const path = GetTemplateLiteralPath(`
Λ("match")\`\${['get', 2]} :
Λ("match")\`\${['get', 2]}
\${['get', as('value')]} -> \${(_: any, { value }: any) => value * 2}
\`;
`);
Expand Down

0 comments on commit 6ee8937

Please sign in to comment.