From 1be45e6534b6c4c5fb35689bcce92f6a53de0475 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Mon, 27 Jul 2026 17:41:23 +0200 Subject: [PATCH] Support playground V7 and fix some module system incompatibilities --- apps/docs/e2e/Playground.cy.res | 86 ++++++++++++------- .../playground/src/CompilerManagerHook.res | 4 +- packages/shared/src/RescriptCompilerApi.res | 17 +++- packages/shared/src/RescriptCompilerApi.resi | 1 + 4 files changed, 72 insertions(+), 36 deletions(-) diff --git a/apps/docs/e2e/Playground.cy.res b/apps/docs/e2e/Playground.cy.res index be00f6df5..0cc0d4a8d 100644 --- a/apps/docs/e2e/Playground.cy.res +++ b/apps/docs/e2e/Playground.cy.res @@ -19,6 +19,43 @@ let clickNavLink = (~testId, ~text) => { ->ignore } +let compileAndRunImportedCode = () => { + waitForPlayground() + + get(".cm-content") + ->typeWithOptions( + "{selectall}{backspace}@module(\"react\") external reactVersion: string = \"version\"{enter}Console.log(\"React \" ++ reactVersion)", + {"force": true, "delay": 20}, + ) + ->ignore + + wait(3000) + + contains("JavaScript")->click->ignore + get("pre.whitespace-pre-wrap") + ->shouldContainText("from \"react\"") + ->shouldContainText("console.log") + ->ignore + + getByTestId("control-panel") + ->find("button") + ->containsChainable("Run") + ->click + ->ignore + + get("div.whitespace-pre-wrap pre") + ->shouldContainText("React 18.2.0") + ->ignore +} + +let v13Versions = [ + "v13.0.0-alpha.1", + "v13.0.0-alpha.2", + "v13.0.0-alpha.3", + "v13.0.0-alpha.4", + "v13.0.0-alpha.5", +] + describe("Playground", () => { beforeEach(() => { viewport(1280, 720) @@ -26,43 +63,30 @@ describe("Playground", () => { waitForHydration() }) - it("should compile and run Console.log in the playground", () => { + it("should compile and run imported code in the playground", () => { // Navigate to the playground from the homepage clickNavLink(~testId="navbar-primary-left-content", ~text="Playground") url()->shouldInclude("/try")->ignore - // Wait for the playground editor and compiler to fully load - waitForPlayground() + compileAndRunImportedCode() + }) - // Clear all existing code and type new ReScript source - get(".cm-content") - ->typeWithOptions( - "{selectall}{backspace}Console.log(\"Hello ReScript!\")", - {"force": true, "delay": 20}, + Array.forEach(v13Versions, version => { + it( + `should compile and run imported code with ${version}`, + () => { + clickNavLink(~testId="navbar-primary-left-content", ~text="Playground") + waitForPlayground() + + contains("Settings")->click->ignore + get(`select[name="compilerVersions"]`) + ->select(version) + ->shouldWithValue("have.value", version) + ->ignore + + compileAndRunImportedCode() + }, ) - ->ignore - - // Allow time for the compiler to process - wait(3000) - - // Switch to the JavaScript tab and verify compiled output - contains("JavaScript")->click->ignore - get("pre.whitespace-pre-wrap") - ->shouldContainText("console.log") - ->ignore - - // Click the Run button in the control panel - getByTestId("control-panel") - ->find("button") - ->containsChainable("Run") - ->click - ->ignore - - // The Run button auto-switches to the Output tab. - // Verify the console output panel contains the logged text. - get("div.whitespace-pre-wrap pre") - ->shouldContainText("Hello ReScript!") - ->ignore }) it("should open the landing page example in the playground with code and compiled output", () => { diff --git a/packages/playground/src/CompilerManagerHook.res b/packages/playground/src/CompilerManagerHook.res index 3e82102e8..65cf44aca 100644 --- a/packages/playground/src/CompilerManagerHook.res +++ b/packages/playground/src/CompilerManagerHook.res @@ -84,7 +84,7 @@ let getLibrariesForVersion = (~version: Semver.t): array => { let getOpenModules = (~apiVersion: Version.t, ~libraries: array): option> => switch apiVersion { | V1 | V2 | V3 | UnknownVersion(_) => None - | V4 | V5 | V6 => + | V4 | V5 | V6 | V7 => libraries->Array.some(el => el === "@rescript/core") ? Some(["RescriptCore"]) : None } @@ -565,7 +565,7 @@ let useCompilerManager = ( ) | Lang.Res => instance->Compiler.resCompile(code) } - | V5 | V6 => + | V5 | V6 | V7 => switch lang { | Lang.Res => instance->Compiler.resCompile(code) | _ => CompilationResult.UnexpectedError(`Can't handle with lang: ${lang->Lang.toString}`) diff --git a/packages/shared/src/RescriptCompilerApi.res b/packages/shared/src/RescriptCompilerApi.res index 66b8dcca5..5b2304e10 100644 --- a/packages/shared/src/RescriptCompilerApi.res +++ b/packages/shared/src/RescriptCompilerApi.res @@ -35,6 +35,7 @@ module Version = { | @as(4) V4 | @as(5) V5 | @as(6) V6 + | @as(7) V7 type t = | ...numbered @@ -62,6 +63,7 @@ module Version = { | list{"4"} => V4 | list{"5"} => V5 | list{"6"} => V6 + | list{"7"} => V7 | _ => UnknownVersion(apiVersion) } @@ -73,6 +75,7 @@ module Version = { | V4 => "4.0" | V5 => "5.0" | V6 => "6.0" + | V7 => "7.0" | UnknownVersion(version) => version } @@ -81,7 +84,7 @@ module Version = { let availableLanguages = t => switch t { | V1 => [Lang.Reason, Res] - | V2 | V3 | V4 | V5 | V6 => [Lang.Res] + | V2 | V3 | V4 | V5 | V6 | V7 => [Lang.Res] | UnknownVersion(_) => [Res] } @@ -476,8 +479,16 @@ module Compiler = { @send external setFilename: (t, string) => bool = "setFilename" - @send - external setModuleSystem: (t, [#es6 | #nodejs]) => bool = "setModuleSystem" + @send external setModuleSystemRaw: (t, string) => bool = "setModuleSystem" + + let setModuleSystem = (t, moduleSystem: [#es6 | #nodejs]) => { + let (current, legacy) = switch moduleSystem { + | #es6 => ("esmodule", "es6") + | #nodejs => ("commonjs", "nodejs") + } + + t->setModuleSystemRaw(current) || t->setModuleSystemRaw(legacy) + } @send external setWarnFlags: (t, string) => bool = "setWarnFlags" diff --git a/packages/shared/src/RescriptCompilerApi.resi b/packages/shared/src/RescriptCompilerApi.resi index 3d17b4193..827c4ecfa 100644 --- a/packages/shared/src/RescriptCompilerApi.resi +++ b/packages/shared/src/RescriptCompilerApi.resi @@ -26,6 +26,7 @@ module Version: { | @as(4) V4 | @as(5) V5 | @as(6) V6 + | @as(7) V7 type t = | ...numbered