Skip to content

Instantly share code, notes, and snippets.

@ryyppy
Last active June 16, 2021 20:05
Show Gist options
  • Save ryyppy/179a90486365e2439cd4e68057e3e0bd to your computer and use it in GitHub Desktop.
Save ryyppy/179a90486365e2439cd4e68057e3e0bd to your computer and use it in GitHub Desktop.
deep-dive-reason-union-types
module Mark = {
[@unboxed]
type t =
| Any('a): t;
module Link = {
type attrs = {
href: string,
target: string,
};
type t = {attrs};
};
type case =
| Link(Link.t)
| Italic
| Bold
| Unknown(t);
let getType: t => string = [%raw
{|
function(value) {
if(typeof value === "object" && value.type != null) {
return value.type;
}
return "unknown";
}
|}
];
let classify = (v: t): case => {
switch (v->getType) {
| "italic" => Italic
| "bold" => Bold
| "link" => Link(v->Obj.magic)
| "unknown"
| _ => Unknown(v)
};
};
};
module Image = {
type attrs = {
alt: string,
src: string,
title: option(string),
};
type t = {attrs};
};
module Text = {
type t = {
text: string,
marks: option(array(Mark.t)),
};
};
[@unboxed]
type t =
| Any('a): t;
module Heading = {
type attrs = {level: int};
type h = {
attrs,
content: array(t),
};
};
type case =
| Doc(array(t))
| Text(Text.t)
| Paragraph(array(t))
| BulletList(array(t))
| OrderedList(array(t))
| ListItem(array(t))
| Unknown(t);
let getType: t => string = [%raw
{|
function(value) {
if(typeof value === "object" && value.type != null) {
return value.type;
}
return "unknown";
}
|}
];
let getContent: t => array(t) = [%raw
{|
function(value) {
if(typeof value === "object" && value.content != null) {
return value.content;
}
return [];
}
|}
];
let classify = (v: t): case =>
switch (v->getType) {
| "doc" => Doc(v->getContent)
| "bullet_list" => BulletList(v->getContent)
| "ordered_list" => OrderedList(v->getContent)
| "list_item" => ListItem(v->getContent)
| "text" => Text(v->Obj.magic)
| "paragraph" => Paragraph(v->getContent)
| "unknown"
| _ => Unknown(v)
};
// Final Example (should not be part of the actual module)
let v =
Any({
"type": "text",
"text": "Hello World",
"marks": [|
{"type": "bold"},
{"type": "italic"},
{
"type": "link",
"attrs": {
"href": "https://reasonml.org",
},
}->Obj.magic,
|],
});
let result =
switch (v->classify) {
| Text({marks: Some(marks)}) =>
open! Mark;
let r =
Belt.Array.map(marks, m =>
switch (m->classify) {
| Bold => "bold"
| Italic => "italic"
| Link({Link.attrs: {href}}) => "link-href: " ++ href
| Unknown(_) => ""
}
)
->Js.Array2.joinWith(", ");
"All Marks: " ++ r;
| Text({marks: None}) => "No marks found"
| _ => "No Text element"
};
module Mark: {
type t;
module Link: {
type attrs = {
href: string,
target: string,
};
type t = {attrs};
};
type case =
| Link(Link.t)
| Italic
| Bold
| Unknown(t);
let classify: t => case;
};
module Text: {
type t = {
text: string,
marks: option(array(Mark.t)),
};
};
type t;
type case =
| Doc(array(t))
| Text(Text.t)
| Paragraph(array(t))
| BulletList(array(t))
| OrderedList(array(t))
| ListItem(array(t))
| Unknown(t);
let classify: t => case;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment