From a315853fcb17c8c334abcc204af94d2a77c8109a Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Mon, 29 May 2023 13:14:59 -0300 Subject: [PATCH 01/15] first tests --- pages/try.js | 6 ++++-- src/Try.res | 17 +++++++++++++++-- src/Try.resi | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/Try.resi diff --git a/pages/try.js b/pages/try.js index 93d83541a..f58e8801a 100644 --- a/pages/try.js +++ b/pages/try.js @@ -1,12 +1,14 @@ import dynamic from "next/dynamic"; +export { getStaticProps } from "src/Try.mjs"; + const Try = dynamic(() => import("src/Try.mjs"), { ssr: false, //loading: () =>
Loading...
}); -function Comp() { - return ; +function Comp(props) { + return ; } export default Comp; diff --git a/src/Try.res b/src/Try.res index 8152a69d2..dd5dd810f 100644 --- a/src/Try.res +++ b/src/Try.res @@ -1,7 +1,12 @@ -@react.component -let default = () => { +type props = { + versions: string +} + +let default = (props: props) => { let overlayState = React.useState(() => false) + Js.log(props) + <> @@ -15,3 +20,11 @@ let default = () => { } + +let getStaticProps: Next.GetStaticProps.t<_, _> = async _ctx => { + // let (archived, nonArchived) = BlogApi.getAllPosts()->Belt.Array.partition(data => data.archived) + + let a = {"props": {"versions": "name"}} + Js.log(a) + a +} diff --git a/src/Try.resi b/src/Try.resi new file mode 100644 index 000000000..753ad3940 --- /dev/null +++ b/src/Try.resi @@ -0,0 +1,3 @@ +type props = {versions: string} +let default: props => React.element +let getStaticProps: Next.GetStaticProps.t<{"versions": string}, 'a> From c92c5b1bc40d1dd42b847034ba96acd6eb992499 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 13:56:53 -0300 Subject: [PATCH 02/15] automate playground versions --- pages/try.js | 11 ++- src/Playground.res | 105 ++++++++++++++-------- src/Playground.resi | 3 +- src/Try.res | 40 ++++++--- src/Try.resi | 6 +- src/bindings/Webapi.res | 10 +++ src/common/CompilerManagerHook.res | 131 +++++++++++----------------- src/common/CompilerManagerHook.resi | 9 +- src/common/Util.res | 71 +++++++++++++++ src/common/Util.resi | 8 ++ 10 files changed, 247 insertions(+), 147 deletions(-) diff --git a/pages/try.js b/pages/try.js index f58e8801a..fb0d51113 100644 --- a/pages/try.js +++ b/pages/try.js @@ -1,14 +1,17 @@ import dynamic from "next/dynamic"; export { getStaticProps } from "src/Try.mjs"; +import Try from "src/Try.mjs"; -const Try = dynamic(() => import("src/Try.mjs"), { +const Playground = dynamic(() => import("src/Playground.mjs"), { ssr: false, - //loading: () =>
Loading...
-}); + loading: () => Loading..., +}) function Comp(props) { - return ; + return + + ; } export default Comp; diff --git a/src/Playground.res b/src/Playground.res index 70462f11b..129ea098e 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -921,24 +921,49 @@ module Settings = { let id = (evt->ReactEvent.Form.target)["value"] onCompilerSelect(id) }}> - {switch readyState.experimentalVersions { - | [] => React.null - | experimentalVersions => + { + let (experimentalVersions, stableVersions) = + readyState.versions->Js.Array2.reduce((acc, item) => { + let (lhs, rhs) = acc + if item.preRelease->Belt.Option.isSome { + Js.Array2.push(lhs, item) + } else { + Js.Array2.push(rhs, item) + }->ignore + acc + }, ([], [])) + <> - - {Belt.Array.map(experimentalVersions, version => - - )->React.array} - + {switch experimentalVersions { + | [] => React.null + | experimentalVersions => + <> + + {Belt.Array.map(experimentalVersions, version => { + let version = Util.Semver.toString(version) + + })->React.array} + + + }} + {switch stableVersions { + | [] => React.null + | stableVersions => + Belt.Array.map(stableVersions, version => { + let version = Util.Semver.toString(version) + + })->React.array + }} - }} - {Belt.Array.map(readyState.versions, version => - - )->React.array} + }
@@ -1350,29 +1375,34 @@ module App = { let initialReContent = j`Js.log("Hello Reason 3.6!");` -/** -Takes a `versionStr` starting with a "v" and ending in major.minor.patch (e.g. -"v10.1.0") returns major, minor, patch as an integer tuple if it's actually in -a x.y.z format, otherwise will return `None`. -*/ -let parseVersion = (versionStr: string): option<(int, int, int)> => { - switch versionStr->Js.String2.replace("v", "")->Js.String2.split(".") { - | [major, minor, patch] => - switch (major->Belt.Int.fromString, minor->Belt.Int.fromString, patch->Belt.Int.fromString) { - | (Some(major), Some(minor), Some(patch)) => Some((major, minor, patch)) - | _ => None - } - | _ => None - } -} - -@react.component -let make = () => { +let default = (~props: Try.props) => { let router = Next.Router.useRouter() + let versions = + props.versions + ->Js.Array2.map(Util.Semver.parse) + ->Belt.Array.keepMap(x => x) + ->Js.Array2.sortInPlaceWith((a, b) => { + let cmp = ({Util.Semver.major: major, minor, patch, _}) => { + [major, minor, patch] + ->Js.Array2.map(v => v->Belt.Int.toString) + ->Js.Array2.joinWith("") + ->Belt.Int.fromString + ->Belt.Option.getWithDefault(0) + } + cmp(b) - cmp(a) + }) + + let lastStableVersion = + versions->Js.Array2.find(version => version.preRelease->Belt.Option.isNone) + let initialVersion = switch Js.Dict.get(router.query, "version") { | Some(version) => Some(version) - | None => CompilerManagerHook.CdnMeta.versions->Belt.Array.get(0) + | None => + switch lastStableVersion { + | Some(version) => Util.Semver.toString(version)->Some + | None => None + } } let initialLang = switch Js.Dict.get(router.query, "ext") { @@ -1387,8 +1417,8 @@ let make = () => { | (None, _) => switch initialVersion { | Some(initialVersion) => - switch parseVersion(initialVersion) { - | Some((major, minor, _)) => + switch Util.Semver.parse(initialVersion) { + | Some({Util.Semver.major: major, minor, _}) => if major >= 10 && minor >= 1 { InitialContent.since_10_1 } else { @@ -1408,6 +1438,7 @@ let make = () => { ~initialVersion?, ~initialLang, ~onAction, + ~versions, (), ) diff --git a/src/Playground.resi b/src/Playground.resi index 1ca44ce26..72031edb8 100644 --- a/src/Playground.resi +++ b/src/Playground.resi @@ -1,2 +1 @@ -@react.component -let make: unit => React.element +let default: (~props: Try.props) => React.element diff --git a/src/Try.res b/src/Try.res index dd5dd810f..c89accaf6 100644 --- a/src/Try.res +++ b/src/Try.res @@ -1,11 +1,7 @@ -type props = { - versions: string -} - -let default = (props: props) => { +let default = (props: {"children": React.element}) => { let overlayState = React.useState(() => false) - Js.log(props) + let playground = props["children"] <> @@ -15,16 +11,36 @@ let default = (props: props) => {
- + playground
} -let getStaticProps: Next.GetStaticProps.t<_, _> = async _ctx => { - // let (archived, nonArchived) = BlogApi.getAllPosts()->Belt.Array.partition(data => data.archived) +type props = {versions: array} + +let getStaticProps: Next.GetStaticProps.t = async _ => { + let versions = { + let response = await Webapi.Fetch.fetch("https://cdn.rescript-lang.org/") + let text = await Webapi.Fetch.Response.text(response) + text + ->Js.String2.split("\n") + ->Js.Array2.filter(line => line->Js.String2.startsWith("Belt.Array.keepMap(line => { + // Adapted from https://semver.org/ + let semverRe = %re("/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-]+)*))?/ +") + let result = Js.Re.exec_(semverRe, line) + switch result { + | Some(r) => + switch Js.Re.captures(r)->Belt.Array.get(0) { + | Some(str) => Js.Nullable.toOption(str) + | None => None + } + | None => None + } + }) + } - let a = {"props": {"versions": "name"}} - Js.log(a) - a + {"props": {versions: versions}} } diff --git a/src/Try.resi b/src/Try.resi index 753ad3940..2611af9cf 100644 --- a/src/Try.resi +++ b/src/Try.resi @@ -1,3 +1,3 @@ -type props = {versions: string} -let default: props => React.element -let getStaticProps: Next.GetStaticProps.t<{"versions": string}, 'a> +let default: {"children": React.element} => React.element +type props = {versions: array} +let getStaticProps: Next.GetStaticProps.t diff --git a/src/bindings/Webapi.res b/src/bindings/Webapi.res index 92fa03094..9aaf7ef9c 100644 --- a/src/bindings/Webapi.res +++ b/src/bindings/Webapi.res @@ -36,3 +36,13 @@ module Window = { @scope("window") @val external innerWidth: int = "innerWidth" @scope("window") @val external innerHeight: int = "innerHeight" } + +module Fetch = { + module Response = { + type t + @send external json: t => promise = "json" + @send external text: t => promise = "text" + } + + @val external fetch: string => promise = "fetch" +} diff --git a/src/common/CompilerManagerHook.res b/src/common/CompilerManagerHook.res index 534f8cfed..8d9919547 100644 --- a/src/common/CompilerManagerHook.res +++ b/src/common/CompilerManagerHook.res @@ -35,22 +35,6 @@ module LoadScript = { } module CdnMeta = { - // Make sure versions exist on https://cdn.rescript-lang.org - // [0] = latest - let versions = [ - "v10.1.2", - "v10.0.1", - "v10.0.0", - "v9.1.2", - "v9.0.2", - "v9.0.1", - "v9.0.0", - "v8.4.2", - "v8.3.0-dev.2", - ] - - let experimentalVersions = ["v11.0.0-alpha.5"] - let getCompilerUrl = (version: string): string => j`https://cdn.rescript-lang.org/$version/compiler.js` @@ -159,8 +143,7 @@ type selected = { } type ready = { - versions: array, - experimentalVersions: array, + versions: array, selected: selected, targetLang: Lang.t, errors: array, // For major errors like bundle loading @@ -196,6 +179,7 @@ let useCompilerManager = ( ~initialVersion: option=?, ~initialLang: Lang.t=Res, ~onAction: option unit>=?, + ~versions: array, (), ) => { let (state, setState) = React.useState(_ => Init) @@ -334,74 +318,58 @@ let useCompilerManager = ( let updateState = async () => { switch state { | Init => - switch CdnMeta.versions { + switch versions { | [] => dispatchError(SetupError("No compiler versions found")) | versions => - let latest = versions[0] - - // If the provided initialVersion is not available, fall back - // to "latest" - let initVersion = switch initialVersion { + switch initialVersion { | Some(version) => - let allVersions = Belt.Array.concat(CdnMeta.versions, CdnMeta.experimentalVersions) - if ( - allVersions->Js.Array2.some(v => { - version == v - }) - ) { - version - } else { - latest - } - | None => latest - } + // Latest version is already running on @rescript/react + let libraries = getLibrariesForVersion(~version) + + switch await attachCompilerAndLibraries(~version, ~libraries, ()) { + | Ok() => + let instance = Compiler.make() + let apiVersion = apiVersion->Version.fromString + + // Note: The compiler bundle currently defaults to + // commonjs when initiating the compiler, but our playground + // should default to ES6. So we override the config + // and use the `setConfig` function to sync up the + // internal compiler state with our playground state. + let config = { + ...instance->Compiler.getConfig, + module_system: "es6", + } + instance->Compiler.setConfig(config) + + let selected = { + id: version, + apiVersion, + compilerVersion: instance->Compiler.version, + ocamlVersion: instance->Compiler.ocamlVersion, + config, + libraries, + instance, + } - // Latest version is already running on @rescript/react - let libraries = getLibrariesForVersion(~version=initVersion) - - switch await attachCompilerAndLibraries(~version=initVersion, ~libraries, ()) { - | Ok() => - let instance = Compiler.make() - let apiVersion = apiVersion->Version.fromString - - // Note: The compiler bundle currently defaults to - // commonjs when initiating the compiler, but our playground - // should default to ES6. So we override the config - // and use the `setConfig` function to sync up the - // internal compiler state with our playground state. - let config = { - ...instance->Compiler.getConfig, - module_system: "es6", + let targetLang = + Version.availableLanguages(apiVersion) + ->Js.Array2.find(l => l === initialLang) + ->Belt.Option.getWithDefault(Version.defaultTargetLang) + + setState(_ => Ready({ + selected, + targetLang, + versions, + errors: [], + result: FinalResult.Nothing, + })) + | Error(errs) => + let msg = Js.Array2.joinWith(errs, "; ") + + dispatchError(CompilerLoadingError(msg)) } - instance->Compiler.setConfig(config) - - let selected = { - id: initVersion, - apiVersion, - compilerVersion: instance->Compiler.version, - ocamlVersion: instance->Compiler.ocamlVersion, - config, - libraries, - instance, - } - - let targetLang = - Version.availableLanguages(apiVersion) - ->Js.Array2.find(l => l === initialLang) - ->Belt.Option.getWithDefault(Version.defaultTargetLang) - - setState(_ => Ready({ - selected, - targetLang, - versions, - experimentalVersions: CdnMeta.experimentalVersions, - errors: [], - result: FinalResult.Nothing, - })) - | Error(errs) => - let msg = Js.Array2.joinWith(errs, "; ") - - dispatchError(CompilerLoadingError(msg)) + | None => dispatchError(CompilerLoadingError("Cant not found the initial version")) } } | SwitchingCompiler(ready, version) => @@ -435,7 +403,6 @@ let useCompilerManager = ( selected, targetLang: Version.defaultTargetLang, versions: ready.versions, - experimentalVersions: ready.experimentalVersions, errors: [], result: FinalResult.Nothing, })) diff --git a/src/common/CompilerManagerHook.resi b/src/common/CompilerManagerHook.resi index ca82af5f1..039a207fb 100644 --- a/src/common/CompilerManagerHook.resi +++ b/src/common/CompilerManagerHook.resi @@ -8,11 +8,6 @@ module FinalResult: { | Nothing } -module CdnMeta: { - /** All available versions on the CDN */ - let versions: array -} - type selected = { id: string, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) apiVersion: Version.t, // The playground API version in use @@ -24,8 +19,7 @@ type selected = { } type ready = { - versions: array, - experimentalVersions: array, + versions: array, selected: selected, targetLang: Lang.t, errors: array, // For major errors like bundle loading @@ -50,5 +44,6 @@ let useCompilerManager: ( ~initialVersion: string=?, ~initialLang: Lang.t=?, ~onAction: action => unit=?, + ~versions: array, unit, ) => (state, action => unit) diff --git a/src/common/Util.res b/src/common/Util.res index b0c19da69..7cef5f1fd 100644 --- a/src/common/Util.res +++ b/src/common/Util.res @@ -84,3 +84,74 @@ module Date = { dateTimeFormat("en-US", {"month": "short", "day": "numeric", "year": "numeric"})->format(date) } } + +/** +Takes a `version` string starting with a "v" and ending in major.minor.patch or +major.minor.patch-prereleader.identider (e.g. "v10.1.0" or "v10.1.0-alpha.2") +*/ +module Semver = { + type preRelease = Alpha(int) | Beta(int) | Dev(int) + + type t = {major: int, minor: int, patch: int, preRelease: option} + + let parse = (versionStr: string) => { + let parsePreRelease = str => { + switch str->Js.String2.split("-") { + | [_, identifier] => + switch identifier->Js.String2.split(".") { + | [name, number] => + switch Belt.Int.fromString(number) { + | None => None + | Some(buildIdentifier) => + switch name { + | "dev" => buildIdentifier->Dev->Some + | "beta" => buildIdentifier->Beta->Some + | "alpha" => buildIdentifier->Alpha->Some + | _ => None + } + } + | _ => None + } + | _ => None + } + } + + // Some version contain a suffix. Example: v11.0.0-alpha.5, v11.0.0-beta.1 + let isPrerelease = versionStr->Js.String2.search(%re("/-/")) != -1 + + // Get the first part i.e vX.Y.Z + let versionNumber = + versionStr->Js.String2.split("-")->Belt.Array.get(0)->Belt.Option.getWithDefault(versionStr) + + switch versionNumber->Js.String2.replace("v", "")->Js.String2.split(".") { + | [major, minor, patch] => + switch (major->Belt.Int.fromString, minor->Belt.Int.fromString, patch->Belt.Int.fromString) { + | (Some(major), Some(minor), Some(patch)) => + let preReleaseIdentifier = if isPrerelease { + parsePreRelease(versionStr) + } else { + None + } + Some({major, minor, patch, preRelease: preReleaseIdentifier}) + | _ => None + } + | _ => None + } + } + + let toString = ({major, minor, patch, preRelease}) => { + let mainVersion = `v${major->Belt.Int.toString}.${minor->Belt.Int.toString}.${patch->Belt.Int.toString}` + + switch preRelease { + | None => mainVersion + | Some(identifier) => + let identifier = switch identifier { + | Dev(number) => `dev.${number->Belt.Int.toString}` + | Alpha(number) => `alpha.${number->Belt.Int.toString}` + | Beta(number) => `beta.${number->Belt.Int.toString}` + } + + `${mainVersion}-${identifier}` + } + } +} diff --git a/src/common/Util.resi b/src/common/Util.resi index b1d2d4647..e2545b869 100644 --- a/src/common/Util.resi +++ b/src/common/Util.resi @@ -18,3 +18,11 @@ module Date: { module Json: { let prettyStringify: Js.Json.t => string } + +module Semver: { + type preRelease = Alpha(int) | Beta(int) | Dev(int) + type t = {major: int, minor: int, patch: int, preRelease: option} + + let parse: string => option + let toString: t => string +} From 0977b88bfe8ff9722122dee9daa4f054b000045c Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 14:52:03 -0300 Subject: [PATCH 03/15] fix typo --- src/common/Util.res | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Util.res b/src/common/Util.res index 7cef5f1fd..4e5bd9edf 100644 --- a/src/common/Util.res +++ b/src/common/Util.res @@ -87,7 +87,7 @@ module Date = { /** Takes a `version` string starting with a "v" and ending in major.minor.patch or -major.minor.patch-prereleader.identider (e.g. "v10.1.0" or "v10.1.0-alpha.2") +major.minor.patch-prerelease.identifier (e.g. "v10.1.0" or "v10.1.0-alpha.2") */ module Semver = { type preRelease = Alpha(int) | Beta(int) | Dev(int) From 47ae9d8dbb91ff38ee075f8592cc527d12981829 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 16:38:25 -0300 Subject: [PATCH 04/15] refactor --- src/Playground.res | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Playground.res b/src/Playground.res index 129ea098e..fda96ade3 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -1380,8 +1380,7 @@ let default = (~props: Try.props) => { let versions = props.versions - ->Js.Array2.map(Util.Semver.parse) - ->Belt.Array.keepMap(x => x) + ->Belt.Array.keepMap(v => v->Util.Semver.parse) ->Js.Array2.sortInPlaceWith((a, b) => { let cmp = ({Util.Semver.major: major, minor, patch, _}) => { [major, minor, patch] From 9458067c3dc797ee6758c671202e3ba095990292 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 17:26:55 -0300 Subject: [PATCH 05/15] refactor --- src/Playground.res | 31 ++++++--------- src/common/CompilerManagerHook.res | 62 +++++++++++++---------------- src/common/CompilerManagerHook.resi | 8 ++-- 3 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/Playground.res b/src/Playground.res index fda96ade3..a58782b42 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -915,11 +915,14 @@ module Settings = {
{React.string("ReScript Version")}
{ ReactEvent.Form.preventDefault(evt) - let id = (evt->ReactEvent.Form.target)["value"] - onCompilerSelect(id) + let id: string = (evt->ReactEvent.Form.target)["value"] + switch id->Util.Semver.parse { + | Some(v) => onCompilerSelect(v) + | None => () + } }}> { let (experimentalVersions, stableVersions) = @@ -1396,12 +1399,8 @@ let default = (~props: Try.props) => { versions->Js.Array2.find(version => version.preRelease->Belt.Option.isNone) let initialVersion = switch Js.Dict.get(router.query, "version") { - | Some(version) => Some(version) - | None => - switch lastStableVersion { - | Some(version) => Util.Semver.toString(version)->Some - | None => None - } + | Some(version) => version->Util.Semver.parse + | None => lastStableVersion } let initialLang = switch Js.Dict.get(router.query, "ext") { @@ -1415,15 +1414,11 @@ let default = (~props: Try.props) => { | (None, Res) | (None, _) => switch initialVersion { - | Some(initialVersion) => - switch Util.Semver.parse(initialVersion) { - | Some({Util.Semver.major: major, minor, _}) => - if major >= 10 && minor >= 1 { - InitialContent.since_10_1 - } else { - InitialContent.original - } - | None => InitialContent.original + | Some({Util.Semver.major: major, minor, _}) => + if major >= 10 && minor >= 1 { + InitialContent.since_10_1 + } else { + InitialContent.original } | None => InitialContent.original } diff --git a/src/common/CompilerManagerHook.res b/src/common/CompilerManagerHook.res index 8d9919547..c601befa8 100644 --- a/src/common/CompilerManagerHook.res +++ b/src/common/CompilerManagerHook.res @@ -35,11 +35,11 @@ module LoadScript = { } module CdnMeta = { - let getCompilerUrl = (version: string): string => - j`https://cdn.rescript-lang.org/$version/compiler.js` + let getCompilerUrl = (version: Util.Semver.t): string => + `https://cdn.rescript-lang.org/${Util.Semver.toString(version)}/compiler.js` - let getLibraryCmijUrl = (version: string, libraryName: string): string => - j`https://cdn.rescript-lang.org/$version/$libraryName/cmij.js` + let getLibraryCmijUrl = (version: Util.Semver.t, libraryName: string): string => + `https://cdn.rescript-lang.org/${Util.Semver.toString(version)}/${libraryName}/cmij.js` } module FinalResult = { @@ -53,30 +53,23 @@ module FinalResult = { // This will a given list of libraries to a specific target version of the compiler. // E.g. starting from v9, @rescript/react instead of reason-react is used. // If the version can't be parsed, an empty array will be returned. -let getLibrariesForVersion = (~version: string): array => { - switch Js.String2.split(version, ".")->Belt.List.fromArray { - | list{major, ..._rest} => - let version = - Js.String2.replace(major, "v", "")->Belt.Int.fromString->Belt.Option.getWithDefault(0) - - let libraries = if version >= 9 { - ["@rescript/react"] - } else if version < 9 { - ["reason-react"] - } else { - [] - } - - // Since version 11, we ship the compiler-builtins as a separate file, and - // we also added @rescript/core as a pre-vendored package - if version >= 11 { - libraries->Js.Array2.push("@rescript/core")->ignore - libraries->Js.Array2.push("compiler-builtins")->ignore - } +let getLibrariesForVersion = (~version: Util.Semver.t): array => { + let libraries = if version.major >= 9 { + ["@rescript/react"] + } else if version.major < 9 { + ["reason-react"] + } else { + [] + } - libraries - | _ => [] + // Since version 11, we ship the compiler-builtins as a separate file, and + // we also added @rescript/core as a pre-vendored package + if version.major >= 11 { + libraries->Js.Array2.push("@rescript/core")->ignore + libraries->Js.Array2.push("compiler-builtins")->ignore } + + libraries } /* @@ -92,10 +85,11 @@ let getLibrariesForVersion = (~version: string): array => { We coupled the compiler / library loading to prevent ppl to try loading compiler / cmij files separately and cause all kinds of race conditions. */ -let attachCompilerAndLibraries = async (~version: string, ~libraries: array, ()): result< - unit, - array, -> => { +let attachCompilerAndLibraries = async ( + ~version: Util.Semver.t, + ~libraries: array, + (), +): result> => { let compilerUrl = CdnMeta.getCompilerUrl(version) // Useful for debugging our local build @@ -133,7 +127,7 @@ type error = | CompilerLoadingError(string) type selected = { - id: string, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) + id: Util.Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) apiVersion: Version.t, // The playground API version in use compilerVersion: string, ocamlVersion: string, @@ -153,12 +147,12 @@ type ready = { type state = | Init | SetupFailed(string) - | SwitchingCompiler(ready, string) // (ready, targetId, libraries) + | SwitchingCompiler(ready, Util.Semver.t) // (ready, targetId, libraries) | Ready(ready) | Compiling(ready, (Lang.t, string)) type action = - | SwitchToCompiler(string) // id + | SwitchToCompiler(Util.Semver.t) // id | SwitchLanguage({lang: Lang.t, code: string}) | Format(string) | CompileCode(Lang.t, string) @@ -176,7 +170,7 @@ type action = // component to give feedback to the user that an action happened (useful in // cases where the output didn't visually change) let useCompilerManager = ( - ~initialVersion: option=?, + ~initialVersion: option=?, ~initialLang: Lang.t=Res, ~onAction: option unit>=?, ~versions: array, diff --git a/src/common/CompilerManagerHook.resi b/src/common/CompilerManagerHook.resi index 039a207fb..58d408ca2 100644 --- a/src/common/CompilerManagerHook.resi +++ b/src/common/CompilerManagerHook.resi @@ -9,7 +9,7 @@ module FinalResult: { } type selected = { - id: string, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) + id: Util.Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) apiVersion: Version.t, // The playground API version in use compilerVersion: string, ocamlVersion: string, @@ -29,19 +29,19 @@ type ready = { type state = | Init | SetupFailed(string) - | SwitchingCompiler(ready, string) // (ready, targetId, libraries) + | SwitchingCompiler(ready, Util.Semver.t) // (ready, targetId, libraries) | Ready(ready) | Compiling(ready, (Lang.t, string)) type action = - | SwitchToCompiler(string) // id + | SwitchToCompiler(Util.Semver.t) // id | SwitchLanguage({lang: Lang.t, code: string}) | Format(string) | CompileCode(Lang.t, string) | UpdateConfig(Config.t) let useCompilerManager: ( - ~initialVersion: string=?, + ~initialVersion: Util.Semver.t=?, ~initialLang: Lang.t=?, ~onAction: action => unit=?, ~versions: array, From f8a1dc88bbc1db367ab1d085f7131b79cd591f15 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 20:01:22 -0300 Subject: [PATCH 06/15] refactor --- src/Try.res | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Try.res b/src/Try.res index c89accaf6..1a86212ce 100644 --- a/src/Try.res +++ b/src/Try.res @@ -25,22 +25,26 @@ let getStaticProps: Next.GetStaticProps.t = async _ => { let text = await Webapi.Fetch.Response.text(response) text ->Js.String2.split("\n") - ->Js.Array2.filter(line => line->Js.String2.startsWith("
Belt.Array.keepMap(line => { - // Adapted from https://semver.org/ - let semverRe = %re("/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-]+)*))?/ -") - let result = Js.Re.exec_(semverRe, line) - switch result { - | Some(r) => - switch Js.Re.captures(r)->Belt.Array.get(0) { - | Some(str) => Js.Nullable.toOption(str) + switch line->Js.String2.startsWith(" + // Adapted from https://semver.org/ + let semverRe = %re("/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-]+)*))?/ + ") + switch Js.Re.exec_(semverRe, line) { + | Some(result) => + switch Js.Re.captures(result)->Belt.Array.get(0) { + | Some(str) => Js.Nullable.toOption(str) + | None => None + } | None => None } - | None => None + | false => None } }) } + Js.log(versions) + {"props": {versions: versions}} } From 9a7b5f3c554d3dc78cbf5e52217f2bc0b6b1e400 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 20:06:45 -0300 Subject: [PATCH 07/15] format --- src/Try.res | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Try.res b/src/Try.res index 1a86212ce..6742476d7 100644 --- a/src/Try.res +++ b/src/Try.res @@ -29,8 +29,9 @@ let getStaticProps: Next.GetStaticProps.t = async _ => { switch line->Js.String2.startsWith(" // Adapted from https://semver.org/ - let semverRe = %re("/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-]+)*))?/ - ") + let semverRe = %re( + "/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-]+)*))?/" + ) switch Js.Re.exec_(semverRe, line) { | Some(result) => switch Js.Re.captures(result)->Belt.Array.get(0) { From fc9a7e022d717151481cdb8a31784b5262b215d0 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 30 May 2023 20:11:04 -0300 Subject: [PATCH 08/15] remove log --- src/Try.res | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Try.res b/src/Try.res index 6742476d7..704acd270 100644 --- a/src/Try.res +++ b/src/Try.res @@ -45,7 +45,5 @@ let getStaticProps: Next.GetStaticProps.t = async _ => { }) } - Js.log(versions) - {"props": {versions: versions}} } From 92e307c4b9238c80d888128e44777f7f2f75ae1f Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 8 Jun 2023 16:53:21 -0300 Subject: [PATCH 09/15] remove json binding --- src/bindings/Webapi.res | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bindings/Webapi.res b/src/bindings/Webapi.res index 9aaf7ef9c..5e92050dc 100644 --- a/src/bindings/Webapi.res +++ b/src/bindings/Webapi.res @@ -40,7 +40,6 @@ module Window = { module Fetch = { module Response = { type t - @send external json: t => promise = "json" @send external text: t => promise = "text" } From 5f799c37acca1e985dc7117dbe435bc93276c8ba Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 24 Oct 2023 18:44:41 -0300 Subject: [PATCH 10/15] add revalidate route --- pages/api/revalidate.js | 1 + src/others/Revalidate.res | 34 ++++++++++++++++++++++++++++++++++ src/others/Revalidate.resi | 8 ++++++++ 3 files changed, 43 insertions(+) create mode 100644 pages/api/revalidate.js create mode 100644 src/others/Revalidate.res create mode 100644 src/others/Revalidate.resi diff --git a/pages/api/revalidate.js b/pages/api/revalidate.js new file mode 100644 index 000000000..a2618b5d4 --- /dev/null +++ b/pages/api/revalidate.js @@ -0,0 +1 @@ +export { handler as default } from "src/others/Revalidate.mjs"; diff --git a/src/others/Revalidate.res b/src/others/Revalidate.res new file mode 100644 index 000000000..00ab41d5d --- /dev/null +++ b/src/others/Revalidate.res @@ -0,0 +1,34 @@ +module Req = { + type query = {secret: string} + + type req = {query: query} +} + +module Res = { + type res + + @send external revalidate: (res, string) => promise = "revalidate" + @send external json: (res, {..}) => res = "json" + + module Status = { + type t + @send external make: (res, int) => t = "status" + @send external send: (t, string) => res = "send" + @send external json: (t, {..}) => res = "json" + } +} + +@val external process: 'a = "process" + +let handler = async (req: Req.req, res: Res.res) => { + if req.query.secret !== process["env"]["NEXT_REVALIDATE_SECRET_TOKEN"] { + res->Res.Status.make(401)->Res.Status.json({"message": "Invalid secret"}) + } else { + try { + let () = await res->Res.revalidate("/try") + res->Res.json({"revalidated": true}) + } catch { + | Js.Exn.Error(_) => res->Res.Status.make(500)->Res.Status.send("Error revalidating") + } + } +} diff --git a/src/others/Revalidate.resi b/src/others/Revalidate.resi new file mode 100644 index 000000000..c2e74104d --- /dev/null +++ b/src/others/Revalidate.resi @@ -0,0 +1,8 @@ +module Req: { + type req +} +module Res: { + type res +} +@val external process: 'a = "process" +let handler: (Req.req, Res.res) => promise From 25d5670997e20d7611a8a7ffd855c1bf006f00fc Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 24 Oct 2023 20:39:47 -0300 Subject: [PATCH 11/15] parse rc --- pages/try.js | 12 +++++++----- src/common/Util.res | 4 +++- src/common/Util.resi | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pages/try.js b/pages/try.js index fb0d51113..fe297fd6c 100644 --- a/pages/try.js +++ b/pages/try.js @@ -5,13 +5,15 @@ import Try from "src/Try.mjs"; const Playground = dynamic(() => import("src/Playground.mjs"), { ssr: false, - loading: () => Loading..., -}) + loading: () => Loading... +}); function Comp(props) { - return - - ; + return ( + + + + ); } export default Comp; diff --git a/src/common/Util.res b/src/common/Util.res index 4e5bd9edf..d30c7dd50 100644 --- a/src/common/Util.res +++ b/src/common/Util.res @@ -90,7 +90,7 @@ Takes a `version` string starting with a "v" and ending in major.minor.patch or major.minor.patch-prerelease.identifier (e.g. "v10.1.0" or "v10.1.0-alpha.2") */ module Semver = { - type preRelease = Alpha(int) | Beta(int) | Dev(int) + type preRelease = Alpha(int) | Beta(int) | Dev(int) | Rc(int) type t = {major: int, minor: int, patch: int, preRelease: option} @@ -107,6 +107,7 @@ module Semver = { | "dev" => buildIdentifier->Dev->Some | "beta" => buildIdentifier->Beta->Some | "alpha" => buildIdentifier->Alpha->Some + | "rc" => buildIdentifier->Rc->Some | _ => None } } @@ -149,6 +150,7 @@ module Semver = { | Dev(number) => `dev.${number->Belt.Int.toString}` | Alpha(number) => `alpha.${number->Belt.Int.toString}` | Beta(number) => `beta.${number->Belt.Int.toString}` + | Rc(number) => `rc.${number->Belt.Int.toString}` } `${mainVersion}-${identifier}` diff --git a/src/common/Util.resi b/src/common/Util.resi index e2545b869..f7e74dc68 100644 --- a/src/common/Util.resi +++ b/src/common/Util.resi @@ -20,7 +20,7 @@ module Json: { } module Semver: { - type preRelease = Alpha(int) | Beta(int) | Dev(int) + type preRelease = Alpha(int) | Beta(int) | Dev(int) | Rc(int) type t = {major: int, minor: int, patch: int, preRelease: option} let parse: string => option From 14fe138f742a1a55d71dc44427ab0ee356ba6378 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 24 Oct 2023 21:59:33 -0300 Subject: [PATCH 12/15] order experimental versions --- src/Playground.res | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Playground.res b/src/Playground.res index df4af65da..600ea6b57 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -940,16 +940,44 @@ module Settings = { {switch experimentalVersions { | [] => React.null | experimentalVersions => + let versionByOrder = experimentalVersions->Js.Array2.sortInPlaceWith((a, b) => { + let cmp = ({Util.Semver.major: major, minor, patch, preRelease} as v) => { + let preRelease = switch preRelease { + | Some(preRelease) => + switch preRelease { + | Dev(id) => 0 + id + | Alpha(id) => 10 + id + | Beta(id) => 20 + id + | Rc(id) => 30 + id + } + | None => 0 + } + let number = + [major, minor, patch] + ->Js.Array2.map(v => v->Belt.Int.toString) + ->Js.Array2.joinWith("") + ->Belt.Int.fromString + ->Belt.Option.getWithDefault(0) + + let a = number + preRelease + Js.log((Util.Semver.toString(v), number + preRelease, [major, minor, patch])) + + a + } + cmp(b) - cmp(a) + }) <> - {Belt.Array.map(experimentalVersions, version => { + {versionByOrder + ->Belt.Array.map(version => { let version = Util.Semver.toString(version) - })->React.array} + }) + ->React.array} From c5505368384339371ee9d866d4546b88e9fc8b8b Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Wed, 25 Oct 2023 18:27:00 -0300 Subject: [PATCH 13/15] last adjusts --- src/others/Revalidate.res | 25 ++++++++++++++----------- src/others/Revalidate.resi | 1 - 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/others/Revalidate.res b/src/others/Revalidate.res index 00ab41d5d..f4d6dff4f 100644 --- a/src/others/Revalidate.res +++ b/src/others/Revalidate.res @@ -1,7 +1,5 @@ module Req = { - type query = {secret: string} - - type req = {query: query} + type req = {query: Js.Dict.t} } module Res = { @@ -21,14 +19,19 @@ module Res = { @val external process: 'a = "process" let handler = async (req: Req.req, res: Res.res) => { - if req.query.secret !== process["env"]["NEXT_REVALIDATE_SECRET_TOKEN"] { - res->Res.Status.make(401)->Res.Status.json({"message": "Invalid secret"}) - } else { - try { - let () = await res->Res.revalidate("/try") - res->Res.json({"revalidated": true}) - } catch { - | Js.Exn.Error(_) => res->Res.Status.make(500)->Res.Status.send("Error revalidating") + switch req.query->Js.Dict.get("secret") { + | Some(secret) => + if secret !== process["env"]["NEXT_REVALIDATE_SECRET_TOKEN"] { + res->Res.Status.make(401)->Res.Status.json({"message": "Invalid secret"}) + } else { + try { + let () = await res->Res.revalidate("/try") + res->Res.json({"revalidated": true}) + } catch { + | Js.Exn.Error(_) => res->Res.Status.make(500)->Res.Status.send("Error revalidating") + } } + | None => + res->Res.Status.make(500)->Res.Status.send("Error revalidating, param `secret` not found") } } diff --git a/src/others/Revalidate.resi b/src/others/Revalidate.resi index c2e74104d..694cd1958 100644 --- a/src/others/Revalidate.resi +++ b/src/others/Revalidate.resi @@ -4,5 +4,4 @@ module Req: { module Res: { type res } -@val external process: 'a = "process" let handler: (Req.req, Res.res) => promise From bdf56251a1c8582b4d4817ac2892676ab304841b Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 26 Oct 2023 13:18:08 -0300 Subject: [PATCH 14/15] cleanup --- src/Playground.res | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Playground.res b/src/Playground.res index 600ea6b57..e0ef0228e 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -941,7 +941,7 @@ module Settings = { | [] => React.null | experimentalVersions => let versionByOrder = experimentalVersions->Js.Array2.sortInPlaceWith((a, b) => { - let cmp = ({Util.Semver.major: major, minor, patch, preRelease} as v) => { + let cmp = ({Util.Semver.major: major, minor, patch, preRelease}) => { let preRelease = switch preRelease { | Some(preRelease) => switch preRelease { @@ -959,10 +959,7 @@ module Settings = { ->Belt.Int.fromString ->Belt.Option.getWithDefault(0) - let a = number + preRelease - Js.log((Util.Semver.toString(v), number + preRelease, [major, minor, patch])) - - a + number + preRelease } cmp(b) - cmp(a) }) From f8efd7d408beabdc7843765902a1c131c2df3803 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Fri, 27 Oct 2023 18:59:32 -0300 Subject: [PATCH 15/15] move Semver to CompilerManagerHook module --- src/Playground.res | 23 +++--- src/common/CompilerManagerHook.res | 104 +++++++++++++++++++++++----- src/common/CompilerManagerHook.resi | 28 ++++++-- src/common/Util.res | 73 ------------------- src/common/Util.resi | 8 --- 5 files changed, 124 insertions(+), 112 deletions(-) diff --git a/src/Playground.res b/src/Playground.res index e0ef0228e..ae5e937e9 100644 --- a/src/Playground.res +++ b/src/Playground.res @@ -915,11 +915,11 @@ module Settings = {
{React.string("ReScript Version")}
{ ReactEvent.Form.preventDefault(evt) let id: string = (evt->ReactEvent.Form.target)["value"] - switch id->Util.Semver.parse { + switch id->CompilerManagerHook.Semver.parse { | Some(v) => onCompilerSelect(v) | None => () } @@ -941,7 +941,12 @@ module Settings = { | [] => React.null | experimentalVersions => let versionByOrder = experimentalVersions->Js.Array2.sortInPlaceWith((a, b) => { - let cmp = ({Util.Semver.major: major, minor, patch, preRelease}) => { + let cmp = ({ + CompilerManagerHook.Semver.major: major, + minor, + patch, + preRelease, + }) => { let preRelease = switch preRelease { | Some(preRelease) => switch preRelease { @@ -969,7 +974,7 @@ module Settings = { {versionByOrder ->Belt.Array.map(version => { - let version = Util.Semver.toString(version) + let version = CompilerManagerHook.Semver.toString(version) @@ -984,7 +989,7 @@ module Settings = { | [] => React.null | stableVersions => Belt.Array.map(stableVersions, version => { - let version = Util.Semver.toString(version) + let version = CompilerManagerHook.Semver.toString(version) @@ -1408,9 +1413,9 @@ let default = (~props: Try.props) => { let versions = props.versions - ->Belt.Array.keepMap(v => v->Util.Semver.parse) + ->Belt.Array.keepMap(v => v->CompilerManagerHook.Semver.parse) ->Js.Array2.sortInPlaceWith((a, b) => { - let cmp = ({Util.Semver.major: major, minor, patch, _}) => { + let cmp = ({CompilerManagerHook.Semver.major: major, minor, patch, _}) => { [major, minor, patch] ->Js.Array2.map(v => v->Belt.Int.toString) ->Js.Array2.joinWith("") @@ -1424,7 +1429,7 @@ let default = (~props: Try.props) => { versions->Js.Array2.find(version => version.preRelease->Belt.Option.isNone) let initialVersion = switch Js.Dict.get(router.query, "version") { - | Some(version) => version->Util.Semver.parse + | Some(version) => version->CompilerManagerHook.Semver.parse | None => lastStableVersion } @@ -1439,7 +1444,7 @@ let default = (~props: Try.props) => { | (None, Res) | (None, _) => switch initialVersion { - | Some({Util.Semver.major: major, minor, _}) => + | Some({CompilerManagerHook.Semver.major: major, minor, _}) => if major >= 10 && minor >= 1 { InitialContent.since_10_1 } else { diff --git a/src/common/CompilerManagerHook.res b/src/common/CompilerManagerHook.res index c601befa8..4f753c5b3 100644 --- a/src/common/CompilerManagerHook.res +++ b/src/common/CompilerManagerHook.res @@ -34,12 +34,85 @@ module LoadScript = { } } +module Semver = { + type preRelease = Alpha(int) | Beta(int) | Dev(int) | Rc(int) + + type t = {major: int, minor: int, patch: int, preRelease: option} + + /** + Takes a `version` string starting with a "v" and ending in major.minor.patch or + major.minor.patch-prerelease.identifier (e.g. "v10.1.0" or "v10.1.0-alpha.2") + */ + let parse = (versionStr: string) => { + let parsePreRelease = str => { + switch str->Js.String2.split("-") { + | [_, identifier] => + switch identifier->Js.String2.split(".") { + | [name, number] => + switch Belt.Int.fromString(number) { + | None => None + | Some(buildIdentifier) => + switch name { + | "dev" => buildIdentifier->Dev->Some + | "beta" => buildIdentifier->Beta->Some + | "alpha" => buildIdentifier->Alpha->Some + | "rc" => buildIdentifier->Rc->Some + | _ => None + } + } + | _ => None + } + | _ => None + } + } + + // Some version contain a suffix. Example: v11.0.0-alpha.5, v11.0.0-beta.1 + let isPrerelease = versionStr->Js.String2.search(%re("/-/")) != -1 + + // Get the first part i.e vX.Y.Z + let versionNumber = + versionStr->Js.String2.split("-")->Belt.Array.get(0)->Belt.Option.getWithDefault(versionStr) + + switch versionNumber->Js.String2.replace("v", "")->Js.String2.split(".") { + | [major, minor, patch] => + switch (major->Belt.Int.fromString, minor->Belt.Int.fromString, patch->Belt.Int.fromString) { + | (Some(major), Some(minor), Some(patch)) => + let preReleaseIdentifier = if isPrerelease { + parsePreRelease(versionStr) + } else { + None + } + Some({major, minor, patch, preRelease: preReleaseIdentifier}) + | _ => None + } + | _ => None + } + } + + let toString = ({major, minor, patch, preRelease}) => { + let mainVersion = `v${major->Belt.Int.toString}.${minor->Belt.Int.toString}.${patch->Belt.Int.toString}` + + switch preRelease { + | None => mainVersion + | Some(identifier) => + let identifier = switch identifier { + | Dev(number) => `dev.${number->Belt.Int.toString}` + | Alpha(number) => `alpha.${number->Belt.Int.toString}` + | Beta(number) => `beta.${number->Belt.Int.toString}` + | Rc(number) => `rc.${number->Belt.Int.toString}` + } + + `${mainVersion}-${identifier}` + } + } +} + module CdnMeta = { - let getCompilerUrl = (version: Util.Semver.t): string => - `https://cdn.rescript-lang.org/${Util.Semver.toString(version)}/compiler.js` + let getCompilerUrl = (version): string => + `https://cdn.rescript-lang.org/${Semver.toString(version)}/compiler.js` - let getLibraryCmijUrl = (version: Util.Semver.t, libraryName: string): string => - `https://cdn.rescript-lang.org/${Util.Semver.toString(version)}/${libraryName}/cmij.js` + let getLibraryCmijUrl = (version, libraryName: string): string => + `https://cdn.rescript-lang.org/${Semver.toString(version)}/${libraryName}/cmij.js` } module FinalResult = { @@ -53,7 +126,7 @@ module FinalResult = { // This will a given list of libraries to a specific target version of the compiler. // E.g. starting from v9, @rescript/react instead of reason-react is used. // If the version can't be parsed, an empty array will be returned. -let getLibrariesForVersion = (~version: Util.Semver.t): array => { +let getLibrariesForVersion = (~version: Semver.t): array => { let libraries = if version.major >= 9 { ["@rescript/react"] } else if version.major < 9 { @@ -85,11 +158,10 @@ let getLibrariesForVersion = (~version: Util.Semver.t): array => { We coupled the compiler / library loading to prevent ppl to try loading compiler / cmij files separately and cause all kinds of race conditions. */ -let attachCompilerAndLibraries = async ( - ~version: Util.Semver.t, - ~libraries: array, - (), -): result> => { +let attachCompilerAndLibraries = async (~version, ~libraries: array, ()): result< + unit, + array, +> => { let compilerUrl = CdnMeta.getCompilerUrl(version) // Useful for debugging our local build @@ -127,7 +199,7 @@ type error = | CompilerLoadingError(string) type selected = { - id: Util.Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) + id: Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) apiVersion: Version.t, // The playground API version in use compilerVersion: string, ocamlVersion: string, @@ -137,7 +209,7 @@ type selected = { } type ready = { - versions: array, + versions: array, selected: selected, targetLang: Lang.t, errors: array, // For major errors like bundle loading @@ -147,12 +219,12 @@ type ready = { type state = | Init | SetupFailed(string) - | SwitchingCompiler(ready, Util.Semver.t) // (ready, targetId, libraries) + | SwitchingCompiler(ready, Semver.t) // (ready, targetId, libraries) | Ready(ready) | Compiling(ready, (Lang.t, string)) type action = - | SwitchToCompiler(Util.Semver.t) // id + | SwitchToCompiler(Semver.t) // id | SwitchLanguage({lang: Lang.t, code: string}) | Format(string) | CompileCode(Lang.t, string) @@ -170,10 +242,10 @@ type action = // component to give feedback to the user that an action happened (useful in // cases where the output didn't visually change) let useCompilerManager = ( - ~initialVersion: option=?, + ~initialVersion: option=?, ~initialLang: Lang.t=Res, ~onAction: option unit>=?, - ~versions: array, + ~versions: array, (), ) => { let (state, setState) = React.useState(_ => Init) diff --git a/src/common/CompilerManagerHook.resi b/src/common/CompilerManagerHook.resi index 58d408ca2..54b534b4c 100644 --- a/src/common/CompilerManagerHook.resi +++ b/src/common/CompilerManagerHook.resi @@ -8,8 +8,24 @@ module FinalResult: { | Nothing } +module Semver: { + type preRelease = + | Alpha(int) + | Beta(int) + | Dev(int) + | Rc(int) + type t = { + major: int, + minor: int, + patch: int, + preRelease: option, + } + let parse: string => option + let toString: t => string +} + type selected = { - id: Util.Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) + id: Semver.t, // The id used for loading the compiler bundle (ideally should be the same as compilerVersion) apiVersion: Version.t, // The playground API version in use compilerVersion: string, ocamlVersion: string, @@ -19,7 +35,7 @@ type selected = { } type ready = { - versions: array, + versions: array, selected: selected, targetLang: Lang.t, errors: array, // For major errors like bundle loading @@ -29,21 +45,21 @@ type ready = { type state = | Init | SetupFailed(string) - | SwitchingCompiler(ready, Util.Semver.t) // (ready, targetId, libraries) + | SwitchingCompiler(ready, Semver.t) // (ready, targetId, libraries) | Ready(ready) | Compiling(ready, (Lang.t, string)) type action = - | SwitchToCompiler(Util.Semver.t) // id + | SwitchToCompiler(Semver.t) // id | SwitchLanguage({lang: Lang.t, code: string}) | Format(string) | CompileCode(Lang.t, string) | UpdateConfig(Config.t) let useCompilerManager: ( - ~initialVersion: Util.Semver.t=?, + ~initialVersion: Semver.t=?, ~initialLang: Lang.t=?, ~onAction: action => unit=?, - ~versions: array, + ~versions: array, unit, ) => (state, action => unit) diff --git a/src/common/Util.res b/src/common/Util.res index d30c7dd50..b0c19da69 100644 --- a/src/common/Util.res +++ b/src/common/Util.res @@ -84,76 +84,3 @@ module Date = { dateTimeFormat("en-US", {"month": "short", "day": "numeric", "year": "numeric"})->format(date) } } - -/** -Takes a `version` string starting with a "v" and ending in major.minor.patch or -major.minor.patch-prerelease.identifier (e.g. "v10.1.0" or "v10.1.0-alpha.2") -*/ -module Semver = { - type preRelease = Alpha(int) | Beta(int) | Dev(int) | Rc(int) - - type t = {major: int, minor: int, patch: int, preRelease: option} - - let parse = (versionStr: string) => { - let parsePreRelease = str => { - switch str->Js.String2.split("-") { - | [_, identifier] => - switch identifier->Js.String2.split(".") { - | [name, number] => - switch Belt.Int.fromString(number) { - | None => None - | Some(buildIdentifier) => - switch name { - | "dev" => buildIdentifier->Dev->Some - | "beta" => buildIdentifier->Beta->Some - | "alpha" => buildIdentifier->Alpha->Some - | "rc" => buildIdentifier->Rc->Some - | _ => None - } - } - | _ => None - } - | _ => None - } - } - - // Some version contain a suffix. Example: v11.0.0-alpha.5, v11.0.0-beta.1 - let isPrerelease = versionStr->Js.String2.search(%re("/-/")) != -1 - - // Get the first part i.e vX.Y.Z - let versionNumber = - versionStr->Js.String2.split("-")->Belt.Array.get(0)->Belt.Option.getWithDefault(versionStr) - - switch versionNumber->Js.String2.replace("v", "")->Js.String2.split(".") { - | [major, minor, patch] => - switch (major->Belt.Int.fromString, minor->Belt.Int.fromString, patch->Belt.Int.fromString) { - | (Some(major), Some(minor), Some(patch)) => - let preReleaseIdentifier = if isPrerelease { - parsePreRelease(versionStr) - } else { - None - } - Some({major, minor, patch, preRelease: preReleaseIdentifier}) - | _ => None - } - | _ => None - } - } - - let toString = ({major, minor, patch, preRelease}) => { - let mainVersion = `v${major->Belt.Int.toString}.${minor->Belt.Int.toString}.${patch->Belt.Int.toString}` - - switch preRelease { - | None => mainVersion - | Some(identifier) => - let identifier = switch identifier { - | Dev(number) => `dev.${number->Belt.Int.toString}` - | Alpha(number) => `alpha.${number->Belt.Int.toString}` - | Beta(number) => `beta.${number->Belt.Int.toString}` - | Rc(number) => `rc.${number->Belt.Int.toString}` - } - - `${mainVersion}-${identifier}` - } - } -} diff --git a/src/common/Util.resi b/src/common/Util.resi index f7e74dc68..b1d2d4647 100644 --- a/src/common/Util.resi +++ b/src/common/Util.resi @@ -18,11 +18,3 @@ module Date: { module Json: { let prettyStringify: Js.Json.t => string } - -module Semver: { - type preRelease = Alpha(int) | Beta(int) | Dev(int) | Rc(int) - type t = {major: int, minor: int, patch: int, preRelease: option} - - let parse: string => option - let toString: t => string -}