Skip to content

Commit 0121332

Browse files
Playground toggles for jsx preserve mode and experimental features (#1107)
* Playground toggles for jsx preserve and experimental features * Make compiler config camelCase * Check apiVersion to ensure only supported methods are called
1 parent 4e4fabe commit 0121332

File tree

5 files changed

+233
-64
lines changed

5 files changed

+233
-64
lines changed

src/Playground.res

Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,38 @@ module Api = RescriptCompilerApi
1313

1414
type layout = Column | Row
1515
type tab = JavaScript | Output | Problems | Settings
16+
17+
module JsxCompilation = {
18+
type t =
19+
| Plain
20+
| PreserveJsx
21+
22+
let getLabel = (mode: t): string =>
23+
switch mode {
24+
| Plain => "Plain JS functions"
25+
| PreserveJsx => "Preserve JSX"
26+
}
27+
28+
let toBool = (mode: t): bool =>
29+
switch mode {
30+
| Plain => false
31+
| PreserveJsx => true
32+
}
33+
34+
let fromBool = (bool): t => bool ? PreserveJsx : Plain
35+
}
36+
37+
module ExperimentalFeatures = {
38+
type t = LetUnwrap
39+
40+
let getLabel = (feature: t): string =>
41+
switch feature {
42+
| LetUnwrap => "let?"
43+
}
44+
45+
let list = [LetUnwrap]
46+
}
47+
1648
let breakingPoint = 1024
1749

1850
module DropdownSelect = {
@@ -31,23 +63,23 @@ module DropdownSelect = {
3163
}
3264
}
3365

34-
module ToggleSelection = {
35-
module SelectionOption = {
36-
@react.component
37-
let make = (~label, ~isActive, ~disabled, ~onClick) => {
38-
<button
39-
className={"mr-1 px-2 py-1 rounded inline-block " ++ if isActive {
40-
"bg-fire text-white font-bold"
41-
} else {
42-
"bg-gray-80 opacity-50 hover:opacity-80"
43-
}}
44-
onClick
45-
disabled>
46-
{React.string(label)}
47-
</button>
48-
}
66+
module SelectionOption = {
67+
@react.component
68+
let make = (~label, ~isActive, ~disabled, ~onClick) => {
69+
<button
70+
className={"mr-1 px-2 py-1 rounded inline-block " ++ if isActive {
71+
"bg-fire text-white font-bold"
72+
} else {
73+
"bg-gray-80 opacity-50 hover:opacity-80"
74+
}}
75+
onClick
76+
disabled>
77+
{React.string(label)}
78+
</button>
4979
}
80+
}
5081

82+
module ToggleSelection = {
5183
@react.component
5284
let make = (
5385
~onChange: 'a => unit,
@@ -842,7 +874,7 @@ module Settings = {
842874
~config: Api.Config.t,
843875
~keyMapState: (CodeMirror.KeyMap.t, (CodeMirror.KeyMap.t => CodeMirror.KeyMap.t) => unit),
844876
) => {
845-
let {Api.Config.warn_flags: warn_flags} = config
877+
let {Api.Config.warnFlags: warnFlags} = config
846878
let (keyMap, setKeyMap) = keyMapState
847879

848880
let availableTargetLangs = Api.Version.availableLanguages(readyState.selected.apiVersion)
@@ -857,22 +889,41 @@ module Settings = {
857889
}
858890
let config = {
859891
...config,
860-
warn_flags: flags->normalizeEmptyFlags->WarningFlagDescription.Parser.tokensToString,
892+
warnFlags: flags->normalizeEmptyFlags->WarningFlagDescription.Parser.tokensToString,
861893
}
862894
setConfig(config)
863895
}
864896

865-
let onModuleSystemUpdate = module_system => {
866-
let config = {...config, module_system}
897+
let onModuleSystemUpdate = moduleSystem => {
898+
let config = {...config, moduleSystem}
899+
setConfig(config)
900+
}
901+
902+
let onJsxPreserveModeUpdate = compilation => {
903+
let jsxPreserveMode = JsxCompilation.toBool(compilation)
904+
let config = {...config, jsxPreserveMode}
905+
setConfig(config)
906+
}
907+
908+
let onExperimentalFeaturesUpdate = feature => {
909+
let features = config.experimentalFeatures->Option.getOr([])
910+
911+
let experimentalFeatures = if features->Array.includes(feature) {
912+
features->Array.filter(x => x !== feature)
913+
} else {
914+
[...features, feature]
915+
}
916+
917+
let config = {...config, experimentalFeatures}
867918
setConfig(config)
868919
}
869920

870-
let warnFlagTokens = WarningFlagDescription.Parser.parse(warn_flags)->Result.getOr([])
921+
let warnFlagTokens = WarningFlagDescription.Parser.parse(warnFlags)->Result.getOr([])
871922

872923
let onWarningFlagsResetClick = _evt => {
873924
setConfig({
874925
...config,
875-
warn_flags: "+a-4-9-20-40-41-42-50-61-102-109",
926+
warnFlags: "+a-4-9-20-40-41-42-50-61-102-109",
876927
})
877928
}
878929

@@ -996,10 +1047,42 @@ module Settings = {
9961047
<ToggleSelection
9971048
values=["commonjs", "esmodule"]
9981049
toLabel={value => value}
999-
selected=config.module_system
1050+
selected=config.moduleSystem
10001051
onChange=onModuleSystemUpdate
10011052
/>
10021053
</div>
1054+
{readyState.selected.apiVersion->RescriptCompilerApi.Version.isMinimumVersion(V6)
1055+
? <>
1056+
<div className="mt-6">
1057+
<div className=titleClass> {React.string("JSX")} </div>
1058+
<ToggleSelection
1059+
values=[JsxCompilation.Plain, PreserveJsx]
1060+
toLabel=JsxCompilation.getLabel
1061+
selected={config.jsxPreserveMode->Option.getOr(false)->JsxCompilation.fromBool}
1062+
onChange=onJsxPreserveModeUpdate
1063+
/>
1064+
</div>
1065+
<div className="mt-6">
1066+
<div className=titleClass> {React.string("Experimental Features")} </div>
1067+
{ExperimentalFeatures.list
1068+
->Array.map(feature => {
1069+
let key = (feature :> string)
1070+
1071+
<SelectionOption
1072+
key
1073+
disabled=false
1074+
label={feature->ExperimentalFeatures.getLabel}
1075+
isActive={config.experimentalFeatures
1076+
->Option.getOr([])
1077+
->Array.includes(key)}
1078+
onClick={_evt => onExperimentalFeaturesUpdate(key)}
1079+
/>
1080+
})
1081+
->React.array}
1082+
</div>
1083+
</>
1084+
: React.null}
1085+
10031086
<div className="mt-6">
10041087
<div className=titleClass> {React.string("Loaded Libraries")} </div>
10051088
<ul>
@@ -1440,7 +1523,7 @@ let make = (~bundleBaseUrl: string, ~versions: array<string>) => {
14401523
| [v] => Some(v) // only single version available. maybe local dev.
14411524
| versions => {
14421525
let lastStableVersion = versions->Array.find(version => version.preRelease->Option.isNone)
1443-
switch Dict.get(router.query, "version") {
1526+
switch Dict.get(router.query, (CompilerManagerHook.Version :> string)) {
14441527
| Some(version) => version->Semver.parse
14451528
| None =>
14461529
switch Url.getVersionFromStorage(Playground) {
@@ -1451,14 +1534,20 @@ let make = (~bundleBaseUrl: string, ~versions: array<string>) => {
14511534
}
14521535
}
14531536

1454-
let initialLang = switch Dict.get(router.query, "ext") {
1537+
let initialLang = switch Dict.get(router.query, (CompilerManagerHook.Ext :> string)) {
14551538
| Some("re") => Api.Lang.Reason
14561539
| _ => Api.Lang.Res
14571540
}
14581541

1459-
let initialModuleSystem = Dict.get(router.query, "module")
1542+
let initialModuleSystem = Dict.get(router.query, (Module :> string))
1543+
let initialJsxPreserveMode = Dict.get(router.query, (JsxPreserve :> string))->Option.isSome
1544+
1545+
let initialExperimentalFeatures =
1546+
Dict.get(router.query, (Experiments :> string))->Option.mapOr([], str =>
1547+
str->String.split(",")->Array.map(String.trim)
1548+
)
14601549

1461-
let initialContent = switch (Dict.get(router.query, "code"), initialLang) {
1550+
let initialContent = switch (Dict.get(router.query, (Code :> string)), initialLang) {
14621551
| (Some(compressedCode), _) => LzString.decompressToEncodedURIComponent(compressedCode)
14631552
| (None, Reason) => initialReContent
14641553
| (None, Res) =>
@@ -1477,6 +1566,8 @@ let make = (~bundleBaseUrl: string, ~versions: array<string>) => {
14771566
~bundleBaseUrl,
14781567
~initialVersion?,
14791568
~initialModuleSystem?,
1569+
~initialJsxPreserveMode,
1570+
~initialExperimentalFeatures,
14801571
~initialLang,
14811572
~onAction,
14821573
~versions,

src/bindings/RescriptCompilerApi.res

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ module Lang = {
2828
}
2929

3030
module Version = {
31+
type numbered =
32+
| @as(1) V1
33+
| @as(2) V2
34+
| @as(3) V3
35+
| @as(4) V4
36+
| @as(5) V5
37+
| @as(6) V6
38+
3139
type t =
32-
| V1
33-
| V2
34-
| V3
35-
| V4
36-
| V5
40+
| ...numbered
3741
| UnknownVersion(string)
3842

3943
// Helps finding the right API version
@@ -57,6 +61,7 @@ module Version = {
5761
| list{"3"} => V3
5862
| list{"4"} => V4
5963
| list{"5"} => V5
64+
| list{"6"} => V6
6065
| _ => UnknownVersion(apiVersion)
6166
}
6267

@@ -67,6 +72,7 @@ module Version = {
6772
| V3 => "3.0"
6873
| V4 => "4.0"
6974
| V5 => "5.0"
75+
| V6 => "6.0"
7076
| UnknownVersion(version) => version
7177
}
7278

@@ -75,9 +81,15 @@ module Version = {
7581
let availableLanguages = t =>
7682
switch t {
7783
| V1 => [Lang.Reason, Res]
78-
| V2 | V3 | V4 | V5 => [Lang.Res]
84+
| V2 | V3 | V4 | V5 | V6 => [Lang.Res]
7985
| UnknownVersion(_) => [Res]
8086
}
87+
88+
let isMinimumVersion = (version: t, minimum: numbered) =>
89+
switch version {
90+
| ...numbered as version => version >= minimum
91+
| UnknownVersion(_) => false
92+
}
8193
}
8294

8395
module LocMsg = {
@@ -392,10 +404,12 @@ module ConversionResult = {
392404

393405
module Config = {
394406
type t = {
395-
module_system: string,
396-
warn_flags: string,
407+
@as("module_system") moduleSystem: string,
408+
@as("warn_flags") warnFlags: string,
397409
uncurried?: bool,
398-
open_modules?: array<string>,
410+
@as("open_modules") openModules?: array<string>,
411+
@as("experimental_features") experimentalFeatures?: array<string>,
412+
@as("jsx_preserve_mode") jsxPreserveMode?: bool,
399413
}
400414
}
401415

@@ -469,17 +483,31 @@ module Compiler = {
469483

470484
@send external setOpenModules: (t, array<string>) => bool = "setOpenModules"
471485

472-
let setConfig = (t: t, config: Config.t): unit => {
473-
let moduleSystem = switch config.module_system {
486+
@send external setExperimentalFeatures: (t, array<string>) => bool = "setExperimentalFeatures"
487+
488+
@send external setJsxPreserveMode: (t, bool) => bool = "setJsxPreserveMode"
489+
490+
let setConfig = (t: t, config: Config.t, version: Version.t): unit => {
491+
let moduleSystem = switch config.moduleSystem {
474492
| "commonjs" => #nodejs->Some
475493
| "esmodule" => #es6->Some
476494
| _ => None
477495
}
478496

479497
Option.forEach(moduleSystem, moduleSystem => t->setModuleSystem(moduleSystem)->ignore)
480-
Option.forEach(config.open_modules, modules => t->setOpenModules(modules)->ignore)
481498

482-
t->setWarnFlags(config.warn_flags)->ignore
499+
if version->Version.isMinimumVersion(V4) {
500+
Option.forEach(config.openModules, modules => t->setOpenModules(modules)->ignore)
501+
}
502+
503+
if version->Version.isMinimumVersion(V6) {
504+
Option.forEach(config.experimentalFeatures, features =>
505+
t->setExperimentalFeatures(features)->ignore
506+
)
507+
Option.forEach(config.jsxPreserveMode, toggle => t->setJsxPreserveMode(toggle)->ignore)
508+
}
509+
510+
t->setWarnFlags(config.warnFlags)->ignore
483511
}
484512

485513
@send

src/bindings/RescriptCompilerApi.resi

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ module Lang: {
1919
}
2020

2121
module Version: {
22+
type numbered =
23+
| @as(1) V1
24+
| @as(2) V2
25+
| @as(3) V3
26+
| @as(4) V4
27+
| @as(5) V5
28+
| @as(6) V6
29+
2230
type t =
23-
| V1
24-
| V2
25-
| V3
26-
| V4
27-
| V5
31+
| ...numbered
2832
| UnknownVersion(string)
2933

3034
// Helps finding the right API version
@@ -35,6 +39,8 @@ module Version: {
3539
let defaultTargetLang: Lang.t
3640

3741
let availableLanguages: t => array<Lang.t>
42+
43+
let isMinimumVersion: (t, numbered) => bool
3844
}
3945

4046
module LocMsg: {
@@ -158,11 +164,14 @@ module ConversionResult: {
158164

159165
module Config: {
160166
type t = {
161-
module_system: string,
162-
warn_flags: string,
167+
@as("module_system") moduleSystem: string,
168+
@as("warn_flags") warnFlags: string,
163169
/** Only available in apiVersion > 3 (= ReScript 11+) */
164170
uncurried?: bool,
165-
open_modules?: array<string>,
171+
@as("open_modules") openModules?: array<string>,
172+
/** Only available in apiVersion >= 6 (= ReScript 12+) */
173+
@as("experimental_features") experimentalFeatures?: array<string>,
174+
@as("jsx_preserve_mode") jsxPreserveMode?: bool,
166175
}
167176
}
168177

@@ -201,7 +210,7 @@ module Compiler: {
201210

202211
let setWarnFlags: (t, string) => bool
203212
let setOpenModules: (t, array<string>) => bool
204-
let setConfig: (t, Config.t) => unit
213+
let setConfig: (t, Config.t, Version.t) => unit
205214

206215
// General format function
207216
let convertSyntax: (~fromLang: Lang.t, ~toLang: Lang.t, ~code: string, t) => ConversionResult.t

0 commit comments

Comments
 (0)