Skip to content

Commit f732f3f

Browse files
aspeddrofhammerschmidt
authored andcommitted
Automate playground compiler (#695)
* first tests * automate playground versions * fix typo * refactor * refactor * refactor * format * remove log * remove json binding * add revalidate route * parse rc * order experimental versions * last adjusts * cleanup * move Semver to CompilerManagerHook module
1 parent d3b9774 commit f732f3f

File tree

11 files changed

+369
-173
lines changed

11 files changed

+369
-173
lines changed

pages/api/revalidate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { handler as default } from "src/others/Revalidate.mjs";

pages/try.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import dynamic from "next/dynamic";
22

3-
const Try = dynamic(() => import("src/Try.mjs"), {
3+
export { getStaticProps } from "src/Try.mjs";
4+
import Try from "src/Try.mjs";
5+
6+
const Playground = dynamic(() => import("src/Playground.mjs"), {
47
ssr: false,
5-
//loading: () => <div> Loading... </div>
8+
loading: () => <span>Loading...</span>
69
});
710

8-
function Comp() {
9-
return <Try />;
11+
function Comp(props) {
12+
return (
13+
<Try>
14+
<Playground {...props} />
15+
</Try>
16+
);
1017
}
1118

1219
export default Comp;

src/Playground.res

Lines changed: 103 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -917,30 +917,88 @@ module Settings = {
917917
<div className=titleClass> {React.string("ReScript Version")} </div>
918918
<DropdownSelect
919919
name="compilerVersions"
920-
value=readyState.selected.id
920+
value={CompilerManagerHook.Semver.toString(readyState.selected.id)}
921921
onChange={evt => {
922922
ReactEvent.Form.preventDefault(evt)
923-
let id = (evt->ReactEvent.Form.target)["value"]
924-
onCompilerSelect(id)
923+
let id: string = (evt->ReactEvent.Form.target)["value"]
924+
switch id->CompilerManagerHook.Semver.parse {
925+
| Some(v) => onCompilerSelect(v)
926+
| None => ()
927+
}
925928
}}>
926-
{switch readyState.experimentalVersions {
927-
| [] => React.null
928-
| experimentalVersions =>
929+
{
930+
let (experimentalVersions, stableVersions) =
931+
readyState.versions->Js.Array2.reduce((acc, item) => {
932+
let (lhs, rhs) = acc
933+
if item.preRelease->Belt.Option.isSome {
934+
Js.Array2.push(lhs, item)
935+
} else {
936+
Js.Array2.push(rhs, item)
937+
}->ignore
938+
acc
939+
}, ([], []))
940+
929941
<>
930-
<option disabled=true className="py-4"> {React.string("---Experimental---")} </option>
931-
{Belt.Array.map(experimentalVersions, version =>
932-
<option className="py-4" key=version value=version>
933-
{React.string(version)}
934-
</option>
935-
)->React.array}
936-
<option disabled=true className="py-4">
937-
{React.string("---Official Releases---")}
938-
</option>
942+
{switch experimentalVersions {
943+
| [] => React.null
944+
| experimentalVersions =>
945+
let versionByOrder = experimentalVersions->Js.Array2.sortInPlaceWith((a, b) => {
946+
let cmp = ({
947+
CompilerManagerHook.Semver.major: major,
948+
minor,
949+
patch,
950+
preRelease,
951+
}) => {
952+
let preRelease = switch preRelease {
953+
| Some(preRelease) =>
954+
switch preRelease {
955+
| Dev(id) => 0 + id
956+
| Alpha(id) => 10 + id
957+
| Beta(id) => 20 + id
958+
| Rc(id) => 30 + id
959+
}
960+
| None => 0
961+
}
962+
let number =
963+
[major, minor, patch]
964+
->Js.Array2.map(v => v->Belt.Int.toString)
965+
->Js.Array2.joinWith("")
966+
->Belt.Int.fromString
967+
->Belt.Option.getWithDefault(0)
968+
969+
number + preRelease
970+
}
971+
cmp(b) - cmp(a)
972+
})
973+
<>
974+
<option disabled=true className="py-4">
975+
{React.string("---Experimental---")}
976+
</option>
977+
{versionByOrder
978+
->Belt.Array.map(version => {
979+
let version = CompilerManagerHook.Semver.toString(version)
980+
<option className="py-4" key=version value=version>
981+
{React.string(version)}
982+
</option>
983+
})
984+
->React.array}
985+
<option disabled=true className="py-4">
986+
{React.string("---Official Releases---")}
987+
</option>
988+
</>
989+
}}
990+
{switch stableVersions {
991+
| [] => React.null
992+
| stableVersions =>
993+
Belt.Array.map(stableVersions, version => {
994+
let version = CompilerManagerHook.Semver.toString(version)
995+
<option className="py-4" key=version value=version>
996+
{React.string(version)}
997+
</option>
998+
})->React.array
999+
}}
9391000
</>
940-
}}
941-
{Belt.Array.map(readyState.versions, version =>
942-
<option className="py-4" key=version value=version> {React.string(version)} </option>
943-
)->React.array}
1001+
}
9441002
</DropdownSelect>
9451003
</div>
9461004
<div className="mt-6">
@@ -1352,29 +1410,29 @@ module App = {
13521410

13531411
let initialReContent = `Js.log("Hello Reason 3.6!");`
13541412

1355-
/**
1356-
Takes a `versionStr` starting with a "v" and ending in major.minor.patch (e.g.
1357-
"v10.1.0") returns major, minor, patch as an integer tuple if it's actually in
1358-
a x.y.z format, otherwise will return `None`.
1359-
*/
1360-
let parseVersion = (versionStr: string): option<(int, int, int)> => {
1361-
switch versionStr->Js.String2.replace("v", "")->Js.String2.split(".") {
1362-
| [major, minor, patch] =>
1363-
switch (major->Belt.Int.fromString, minor->Belt.Int.fromString, patch->Belt.Int.fromString) {
1364-
| (Some(major), Some(minor), Some(patch)) => Some((major, minor, patch))
1365-
| _ => None
1366-
}
1367-
| _ => None
1368-
}
1369-
}
1370-
1371-
@react.component
1372-
let make = () => {
1413+
let default = (~props: Try.props) => {
13731414
let router = Next.Router.useRouter()
13741415

1416+
let versions =
1417+
props.versions
1418+
->Belt.Array.keepMap(v => v->CompilerManagerHook.Semver.parse)
1419+
->Js.Array2.sortInPlaceWith((a, b) => {
1420+
let cmp = ({CompilerManagerHook.Semver.major: major, minor, patch, _}) => {
1421+
[major, minor, patch]
1422+
->Js.Array2.map(v => v->Belt.Int.toString)
1423+
->Js.Array2.joinWith("")
1424+
->Belt.Int.fromString
1425+
->Belt.Option.getWithDefault(0)
1426+
}
1427+
cmp(b) - cmp(a)
1428+
})
1429+
1430+
let lastStableVersion =
1431+
versions->Js.Array2.find(version => version.preRelease->Belt.Option.isNone)
1432+
13751433
let initialVersion = switch Js.Dict.get(router.query, "version") {
1376-
| Some(version) => Some(version)
1377-
| None => CompilerManagerHook.CdnMeta.versions->Belt.Array.get(0)
1434+
| Some(version) => version->CompilerManagerHook.Semver.parse
1435+
| None => lastStableVersion
13781436
}
13791437

13801438
let initialLang = switch Js.Dict.get(router.query, "ext") {
@@ -1388,15 +1446,11 @@ let make = () => {
13881446
| (None, Res)
13891447
| (None, _) =>
13901448
switch initialVersion {
1391-
| Some(initialVersion) =>
1392-
switch parseVersion(initialVersion) {
1393-
| Some((major, minor, _)) =>
1394-
if major >= 10 && minor >= 1 {
1395-
InitialContent.since_10_1
1396-
} else {
1397-
InitialContent.original
1398-
}
1399-
| None => InitialContent.original
1449+
| Some({CompilerManagerHook.Semver.major: major, minor, _}) =>
1450+
if major >= 10 && minor >= 1 {
1451+
InitialContent.since_10_1
1452+
} else {
1453+
InitialContent.original
14001454
}
14011455
| None => InitialContent.original
14021456
}
@@ -1410,6 +1464,7 @@ let make = () => {
14101464
~initialVersion?,
14111465
~initialLang,
14121466
~onAction,
1467+
~versions,
14131468
(),
14141469
)
14151470

src/Playground.resi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
@react.component
2-
let make: unit => React.element
1+
let default: (~props: Try.props) => React.element

src/Try.res

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
@react.component
2-
let default = () => {
1+
let default = (props: {"children": React.element}) => {
32
let overlayState = React.useState(() => false)
43

4+
let playground = props["children"]
5+
56
<>
67
<Meta title="ReScript Playground" description="Try ReScript in the browser" />
78
<Next.Head>
@@ -10,8 +11,39 @@ let default = () => {
1011
<div className="text-16">
1112
<div className="text-gray-40 text-14">
1213
<Navigation fixed=false overlayState />
13-
<Playground />
14+
playground
1415
</div>
1516
</div>
1617
</>
1718
}
19+
20+
type props = {versions: array<string>}
21+
22+
let getStaticProps: Next.GetStaticProps.t<props, _> = async _ => {
23+
let versions = {
24+
let response = await Webapi.Fetch.fetch("https://cdn.rescript-lang.org/")
25+
let text = await Webapi.Fetch.Response.text(response)
26+
text
27+
->Js.String2.split("\n")
28+
->Belt.Array.keepMap(line => {
29+
switch line->Js.String2.startsWith("<a href") {
30+
| true =>
31+
// Adapted from https://semver.org/
32+
let semverRe = %re(
33+
"/v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?/"
34+
)
35+
switch Js.Re.exec_(semverRe, line) {
36+
| Some(result) =>
37+
switch Js.Re.captures(result)->Belt.Array.get(0) {
38+
| Some(str) => Js.Nullable.toOption(str)
39+
| None => None
40+
}
41+
| None => None
42+
}
43+
| false => None
44+
}
45+
})
46+
}
47+
48+
{"props": {versions: versions}}
49+
}

src/Try.resi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
let default: {"children": React.element} => React.element
2+
type props = {versions: array<string>}
3+
let getStaticProps: Next.GetStaticProps.t<props, 'a>

src/bindings/Webapi.res

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,12 @@ module Window = {
3636
@scope("window") @val external innerWidth: int = "innerWidth"
3737
@scope("window") @val external innerHeight: int = "innerHeight"
3838
}
39+
40+
module Fetch = {
41+
module Response = {
42+
type t
43+
@send external text: t => promise<string> = "text"
44+
}
45+
46+
@val external fetch: string => promise<Response.t> = "fetch"
47+
}

0 commit comments

Comments
 (0)