Skip to content

Commit 3e2c475

Browse files
Bindings
1 parent b316a4b commit 3e2c475

5 files changed

Lines changed: 406 additions & 391 deletions

File tree

packages/dev-playground/rescript.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"experimental-features": {
2020
"LetUnwrap": true
2121
},
22-
"compiler-flags": ["-open Xote"],
22+
"compiler-flags": ["-open Xote", "-open Bindings"],
2323
"warnings": {
2424
"error": "+8"
2525
}
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
type compilerApi
2+
type compilerInstance
3+
type rescriptCompiler
4+
type compilerConfig
5+
type compileResult
6+
type diagnostic
7+
8+
module Env = {
9+
@val
10+
external viteDefaultCompilerVersion: option<string> =
11+
"import.meta.env.VITE_DEFAULT_COMPILER_VERSION"
12+
@val external viteCompilerVersions: option<string> = "import.meta.env.VITE_COMPILER_VERSIONS"
13+
@val external viteBaseUrl: option<string> = "import.meta.env.BASE_URL"
14+
}
15+
16+
module DynamicProperty = {
17+
@get_index external get: ('value, string) => option<unknown> = ""
18+
}
19+
20+
module Api = {
21+
@val external global: option<compilerApi> = "globalThis.rescript_compiler"
22+
@send external makeCompiler: compilerApi => compilerInstance = "make"
23+
@get external apiVersion: compilerApi => option<string> = "api_version"
24+
}
25+
26+
module Instance = {
27+
@send external setModuleSystem: (compilerInstance, string) => unit = "setModuleSystem"
28+
@send external setWarnFlags: (compilerInstance, string) => unit = "setWarnFlags"
29+
@send external setFilename: (compilerInstance, string) => unit = "setFilename"
30+
@send external setJsxPreserveMode: (compilerInstance, bool) => unit = "setJsxPreserveMode"
31+
@send
32+
external setExperimentalFeatures: (compilerInstance, array<string>) => unit =
33+
"setExperimentalFeatures"
34+
@get external rescript: compilerInstance => rescriptCompiler = "rescript"
35+
@send external getConfig: compilerInstance => compilerConfig = "getConfig"
36+
@get external version: compilerInstance => option<string> = "version"
37+
}
38+
39+
module Rescript = {
40+
@get external version: rescriptCompiler => option<string> = "version"
41+
@send external compile: (rescriptCompiler, string) => compileResult = "compile"
42+
@send external compileWithDebug: (rescriptCompiler, string) => compileResult = "compileWithDebug"
43+
@send external format: (rescriptCompiler, string) => compileResult = "format"
44+
}
45+
46+
module Config = {
47+
@get external moduleSystem: compilerConfig => option<string> = "module_system"
48+
@get external warnFlags: compilerConfig => option<string> = "warn_flags"
49+
@get external jsxPreserveMode: compilerConfig => option<bool> = "jsx_preserve_mode"
50+
@get
51+
external experimentalFeatures: compilerConfig => option<array<string>> = "experimental_features"
52+
}
53+
54+
module Diagnostic = {
55+
@get external row: diagnostic => option<int> = "row"
56+
@get external column: diagnostic => option<int> = "column"
57+
@get external warnNumber: diagnostic => option<int> = "warnNumber"
58+
@get external isError: diagnostic => option<bool> = "isError"
59+
@get external shortMsg: diagnostic => option<string> = "shortMsg"
60+
@get external fullMsg: diagnostic => option<string> = "fullMsg"
61+
}
62+
63+
module CompileResult = {
64+
@get external type_: compileResult => option<string> = "type"
65+
@get external code: compileResult => option<string> = "code"
66+
@get external jsCode: compileResult => option<string> = "js_code"
67+
@get external parsetree: compileResult => option<string> = "parsetree"
68+
@get external typedtree: compileResult => option<string> = "typedtree"
69+
@get external lambda: compileResult => option<string> = "lambda"
70+
@get external lam: compileResult => option<string> = "lam"
71+
@get external errors: compileResult => option<array<diagnostic>> = "errors"
72+
@get external warnings: compileResult => option<array<diagnostic>> = "warnings"
73+
@get external msg: compileResult => option<string> = "msg"
74+
@get external shortMsg: compileResult => option<string> = "shortMsg"
75+
@get external fullMsg: compileResult => option<string> = "fullMsg"
76+
}
77+
78+
module Window = {
79+
@val external setTimeout: (unit => unit, int) => int = "setTimeout"
80+
@val external clearTimeout: int => unit = "clearTimeout"
81+
@val external requestAnimationFrame: (unit => unit) => unit = "window.requestAnimationFrame"
82+
}
83+
84+
module Url = {
85+
type t
86+
87+
@new external make: (string, string) => t = "URL"
88+
@get external href: t => string = "href"
89+
@get external pathname: t => string = "pathname"
90+
}
91+
92+
module Event = {
93+
@get external target: Dom.event => {..} = "target"
94+
@get external key: Dom.event => string = "key"
95+
@send external preventDefault: Dom.event => unit = "preventDefault"
96+
97+
let value = (event: Dom.event): string => (event->target)["value"]
98+
99+
let checked = (event: Dom.event): bool => (event->target)["checked"]
100+
101+
let selectionStart = (event: Dom.event): int => (event->target)["selectionStart"]
102+
103+
let scrollTop = (event: Dom.event): int => {
104+
let scrollTop: float = (event->target)["scrollTop"]
105+
scrollTop->Math.round->Float.toInt
106+
}
107+
108+
let scrollLeft = (event: Dom.event): int => {
109+
let scrollLeft: float = (event->target)["scrollLeft"]
110+
scrollLeft->Math.round->Float.toInt
111+
}
112+
}
113+
114+
module EventTarget = {
115+
let value = (target: {..}): string => target["value"]
116+
let setValue = (target: {..}, value: string) => target["value"] = value
117+
let selectionStart = (target: {..}): int => target["selectionStart"]
118+
let selectionEnd = (target: {..}): int => target["selectionEnd"]
119+
let setSelectionRange = (target: {..}, start, end_) => {
120+
let setSelectionRange: (int, int) => unit = target["setSelectionRange"]
121+
setSelectionRange(start, end_)
122+
}
123+
}
124+
125+
module Element = {
126+
@send external setAttribute: (Dom.element, string, string) => unit = "setAttribute"
127+
@send
128+
external addEventListener: (Dom.element, string, Dom.event => unit) => unit = "addEventListener"
129+
@send
130+
external removeEventListener: (Dom.element, string, Dom.event => unit) => unit =
131+
"removeEventListener"
132+
@send external appendChild: (Dom.element, Dom.element) => unit = "appendChild"
133+
@get @return(nullable)
134+
external getScrollHandler: Dom.element => option<Dom.event => unit> =
135+
"__devPlaygroundScrollHandler"
136+
@set
137+
external setScrollHandler: (Dom.element, Dom.event => unit) => unit =
138+
"__devPlaygroundScrollHandler"
139+
}
140+
141+
module ScriptElement = {
142+
@set external setSrc: (Dom.element, string) => unit = "src"
143+
@set external setAsync: (Dom.element, bool) => unit = "async"
144+
@set external setOnLoad: (Dom.element, unknown => unit) => unit = "onload"
145+
@set external setOnError: (Dom.element, unknown => unit) => unit = "onerror"
146+
}
147+
148+
module Document = {
149+
@val external current: {..} = "document"
150+
@get external head: {..} => Dom.element = "head"
151+
@send external createScriptElement: ({..}, @as("script") _) => Dom.element = "createElement"
152+
@send @return(nullable)
153+
external getElementById: ({..}, string) => option<Dom.element> = "getElementById"
154+
}
155+
156+
module UrlSearchParams = {
157+
type t
158+
159+
@new external make: string => t = "URLSearchParams"
160+
@send @return(nullable) external get: (t, string) => option<string> = "get"
161+
@send external set: (t, string, string) => unit = "set"
162+
@send external delete: (t, string) => unit = "delete"
163+
@send external toString: t => string = "toString"
164+
}
165+
166+
module Location = {
167+
@val external search: string = "window.location.search"
168+
@val external pathname: string = "window.location.pathname"
169+
@val external hash: string = "window.location.hash"
170+
@val external href: string = "window.location.href"
171+
@val external origin: string = "window.location.origin"
172+
}
173+
174+
module History = {
175+
@val @scope(("window", "history"))
176+
external replaceState: (@as(json`null`) _, @as("") _, string) => unit = "replaceState"
177+
}
178+
179+
module Performance = {
180+
@val @scope("performance") external now: unit => float = "now"
181+
}
182+
183+
module SharedCode = {
184+
let encode = async source => {
185+
ignore(source)
186+
let encoded: string = %raw(`
187+
(() => {
188+
const bytes = new TextEncoder().encode(source);
189+
let binary = "";
190+
const chunkSize = 0x8000;
191+
for (let index = 0; index < bytes.length; index += chunkSize) {
192+
const chunk = bytes.subarray(index, index + chunkSize);
193+
binary += String.fromCharCode(...chunk);
194+
}
195+
return "b:" + btoa(binary)
196+
.replace(/\+/g, "-")
197+
.replace(/\//g, "_")
198+
.replace(/=+$/g, "");
199+
})()
200+
`)
201+
encoded
202+
}
203+
204+
let decode = encoded => {
205+
ignore(encoded)
206+
let decoded: promise<string> = %raw(`
207+
(async () => {
208+
const base64UrlToBytes = value => {
209+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
210+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
211+
const binary = atob(padded);
212+
const bytes = new Uint8Array(binary.length);
213+
for (let index = 0; index < binary.length; index += 1) {
214+
bytes[index] = binary.charCodeAt(index);
215+
}
216+
return bytes;
217+
};
218+
219+
if (encoded.startsWith("z:")) {
220+
if (typeof DecompressionStream === "undefined") {
221+
throw new Error(
222+
"Compressed shared links require browser DecompressionStream support",
223+
);
224+
}
225+
226+
const compressedBytes = base64UrlToBytes(encoded.slice(2));
227+
const stream = new Blob([compressedBytes])
228+
.stream()
229+
.pipeThrough(new DecompressionStream("gzip"));
230+
return new TextDecoder().decode(
231+
new Uint8Array(await new Response(stream).arrayBuffer()),
232+
);
233+
}
234+
235+
if (encoded.startsWith("b:")) {
236+
return new TextDecoder().decode(base64UrlToBytes(encoded.slice(2)));
237+
}
238+
239+
return encoded;
240+
})()
241+
`)
242+
decoded
243+
}
244+
}
245+
246+
module Clipboard = {
247+
let writeText = value => {
248+
ignore(value)
249+
let promise: promise<unit> = %raw(`
250+
(async () => {
251+
if (navigator.clipboard?.writeText != null && window.isSecureContext) {
252+
await navigator.clipboard.writeText(value);
253+
return;
254+
}
255+
256+
const textarea = document.createElement("textarea");
257+
textarea.value = value;
258+
textarea.setAttribute("readonly", "");
259+
textarea.style.position = "fixed";
260+
textarea.style.top = "-9999px";
261+
textarea.style.left = "-9999px";
262+
document.body.appendChild(textarea);
263+
textarea.select();
264+
265+
try {
266+
if (!document.execCommand("copy")) {
267+
throw new Error("Copy command failed");
268+
}
269+
} finally {
270+
document.body.removeChild(textarea);
271+
}
272+
})()
273+
`)
274+
promise
275+
}
276+
}

0 commit comments

Comments
 (0)