From 1efd698dbad82250e5b54d74a590529c9dfd3541 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 Aug 2025 11:21:52 +0000 Subject: [PATCH 1/5] Initial plan From 16923271d14276283d0b9142342d738ea329ab76 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 Aug 2025 11:34:24 +0000 Subject: [PATCH 2/5] Add WebGL.Texture support to wire format and type hash validation Co-authored-by: supermario <102781+supermario@users.noreply.github.com> --- extra/Lamdera/TypeHash.hs | 6 ++ extra/Lamdera/Wire3/Decoder.hs | 1 + extra/Lamdera/Wire3/Encoder.hs | 2 + extra/Lamdera/Wire3/Helpers.hs | 1 + test/Test/WebGL.hs | 9 +++ test/scenario-webgl-texture/elm.json | 27 ++++++++ test/scenario-webgl-texture/src/Backend.elm | 42 +++++++++++ test/scenario-webgl-texture/src/Frontend.elm | 73 ++++++++++++++++++++ test/scenario-webgl-texture/src/Types.elm | 36 ++++++++++ 9 files changed, 197 insertions(+) create mode 100644 test/scenario-webgl-texture/elm.json create mode 100644 test/scenario-webgl-texture/src/Backend.elm create mode 100644 test/scenario-webgl-texture/src/Frontend.elm create mode 100644 test/scenario-webgl-texture/src/Types.elm diff --git a/extra/Lamdera/TypeHash.hs b/extra/Lamdera/TypeHash.hs index fc070b0c3..4066f3b89 100644 --- a/extra/Lamdera/TypeHash.hs +++ b/extra/Lamdera/TypeHash.hs @@ -394,6 +394,12 @@ canonicalToDiffableType targetName interfaces recursionSet canonical tvarMap = else kernelErrorBrowserOnly + ("elm-explorations", "webgl", "WebGL.Texture", "Texture") -> + if targetName `elem` ["FrontendMsg", "FrontendModel"] then + DKernelBrowser "WebGL.Texture.Texture" + else + kernelErrorBrowserOnly + -- Lamdera codecs types shouldn't be used in the core type tree, as the core types must be serialisable, -- which means they need the auto-gen encoders/decoders, but those can only be generated by depending on -- qualified references to the lamdera/codecs module helpers. diff --git a/extra/Lamdera/Wire3/Decoder.hs b/extra/Lamdera/Wire3/Decoder.hs index 66aa16977..b7d056b75 100644 --- a/extra/Lamdera/Wire3/Decoder.hs +++ b/extra/Lamdera/Wire3/Decoder.hs @@ -350,6 +350,7 @@ decoderForType ifaces cname tipe = -- Frontend only JS reference types TType (Module.Canonical (Name "elm" "file") "File") "File" params -> callDecoder "decodeRef" tipe + TType (Module.Canonical (Name "elm-explorations" "webgl") "WebGL.Texture") "Texture" params -> callDecoder "decodeRef" tipe TType moduleName typeName params -> diff --git a/extra/Lamdera/Wire3/Encoder.hs b/extra/Lamdera/Wire3/Encoder.hs index a06bb90fd..8786f4bc8 100644 --- a/extra/Lamdera/Wire3/Encoder.hs +++ b/extra/Lamdera/Wire3/Encoder.hs @@ -214,6 +214,8 @@ encoderForType depth ifaces cname tipe = -- Frontend only JS reference types TType (Module.Canonical (Name "elm" "file") "File") "File" _ -> (a (VarForeign mLamdera_Wire "encodeRef" (Forall Map.empty (TLambda tipe tLamdera_Wire_Encoder)))) + TType (Module.Canonical (Name "elm-explorations" "webgl") "WebGL.Texture") "Texture" _ -> + (a (VarForeign mLamdera_Wire "encodeRef" (Forall Map.empty (TLambda tipe tLamdera_Wire_Encoder)))) TType moduleName typeName params -> diff --git a/extra/Lamdera/Wire3/Helpers.hs b/extra/Lamdera/Wire3/Helpers.hs index 1f0e19f42..471143aa2 100644 --- a/extra/Lamdera/Wire3/Helpers.hs +++ b/extra/Lamdera/Wire3/Helpers.hs @@ -123,6 +123,7 @@ isUnsupportedKernelType tipe = -- JS types we are supporting through JS ref encodings. These serialisations -- CANNOT BE DECODED OUTSIDE OF THE JS SCOPE THEY WERE ENCODED IN! TType (Module.Canonical (Name "elm" "file") "File") "File" _ -> False + TType (Module.Canonical (Name "elm-explorations" "webgl") "WebGL.Texture") "Texture" _ -> False TAlias moduleName typeName tvars (Holey tipe) -> isUnsupportedKernelType tipe diff --git a/test/Test/WebGL.hs b/test/Test/WebGL.hs index 12b4d4446..0880dbcd0 100644 --- a/test/Test/WebGL.hs +++ b/test/Test/WebGL.hs @@ -37,4 +37,13 @@ suite = tests actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Triangle.elm" ] expectTextContains actual "Success! Compiled 1 module." + + , scope "compile Elm app with WebGL.Texture in FrontendModel" $ do + project <- io $ Lamdera.Relative.requireDir "test/scenario-webgl-texture" + + _ <- io $ rmdir (project "elm-stuff") + + actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Frontend.elm", "src/Backend.elm", "src/Types.elm" ] + + expectTextContains actual "Success! Compiled 3 modules." ] diff --git a/test/scenario-webgl-texture/elm.json b/test/scenario-webgl-texture/elm.json new file mode 100644 index 000000000..9a241e7cb --- /dev/null +++ b/test/scenario-webgl-texture/elm.json @@ -0,0 +1,27 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/url": "1.0.0", + "elm-explorations/webgl": "1.1.3", + "elm-explorations/linear-algebra": "1.0.3", + "lamdera/core": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} \ No newline at end of file diff --git a/test/scenario-webgl-texture/src/Backend.elm b/test/scenario-webgl-texture/src/Backend.elm new file mode 100644 index 000000000..572ab126b --- /dev/null +++ b/test/scenario-webgl-texture/src/Backend.elm @@ -0,0 +1,42 @@ +module Backend exposing (..) + +import Lamdera exposing (ClientId, SessionId) +import Types exposing (..) + + +type alias Model = BackendModel + + +app = + Lamdera.backend + { init = init + , update = update + , updateFromFrontend = updateFromFrontend + , subscriptions = subscriptions + } + + +init : ( Model, Cmd BackendMsg ) +init = + ( { message = "Hello from backend!" } + , Cmd.none + ) + + +update : BackendMsg -> Model -> ( Model, Cmd BackendMsg ) +update msg model = + case msg of + NoOpBackendMsg -> + ( model, Cmd.none ) + + +updateFromFrontend : SessionId -> ClientId -> ToBackend -> Model -> ( Model, Cmd BackendMsg ) +updateFromFrontend sessionId clientId msg model = + case msg of + NoOpToBackend -> + ( model, Cmd.none ) + + +subscriptions : Model -> Sub BackendMsg +subscriptions model = + Sub.none \ No newline at end of file diff --git a/test/scenario-webgl-texture/src/Frontend.elm b/test/scenario-webgl-texture/src/Frontend.elm new file mode 100644 index 000000000..d26c9f695 --- /dev/null +++ b/test/scenario-webgl-texture/src/Frontend.elm @@ -0,0 +1,73 @@ +module Frontend exposing (..) + +import Browser exposing (UrlRequest) +import Browser.Navigation as Nav +import Html +import Url +import WebGL.Texture as Texture +import Lamdera +import Types exposing (..) + + +type alias Model = FrontendModel + + +app = + Lamdera.frontend + { init = init + , onUrlRequest = UrlClicked + , onUrlChange = UrlChanged + , update = update + , updateFromBackend = updateFromBackend + , subscriptions = \m -> Sub.none + , view = view + } + + +init : Url.Url -> Nav.Key -> ( Model, Cmd FrontendMsg ) +init url key = + ( { key = key + , texture = Nothing + } + , Cmd.none + ) + + +update : FrontendMsg -> Model -> ( Model, Cmd FrontendMsg ) +update msg model = + case msg of + UrlClicked urlRequest -> + case urlRequest of + Browser.Internal url -> + ( model, Nav.pushUrl model.key (Url.toString url) ) + + Browser.External url -> + ( model, Nav.load url ) + + UrlChanged url -> + ( model, Cmd.none ) + + TextureLoaded result -> + case result of + Ok texture -> + ( { model | texture = Just texture }, Cmd.none ) + + Err _ -> + ( model, Cmd.none ) + + NoOpFrontendMsg -> + ( model, Cmd.none ) + + +updateFromBackend : ToFrontend -> Model -> ( Model, Cmd FrontendMsg ) +updateFromBackend msg model = + case msg of + NoOpToFrontend -> + ( model, Cmd.none ) + + +view : Model -> Browser.Document FrontendMsg +view model = + { title = "" + , body = [ Html.text "Hello" ] + } \ No newline at end of file diff --git a/test/scenario-webgl-texture/src/Types.elm b/test/scenario-webgl-texture/src/Types.elm new file mode 100644 index 000000000..29357c289 --- /dev/null +++ b/test/scenario-webgl-texture/src/Types.elm @@ -0,0 +1,36 @@ +module Types exposing (..) + +import Browser exposing (UrlRequest) +import Browser.Navigation exposing (Key) +import Url exposing (Url) +import WebGL.Texture as Texture + + +type alias FrontendModel = + { key : Key + , texture : Maybe Texture.Texture + } + + +type alias BackendModel = + { message : String + } + + +type FrontendMsg + = UrlClicked UrlRequest + | UrlChanged Url + | TextureLoaded (Result Texture.Error Texture.Texture) + | NoOpFrontendMsg + + +type ToBackend + = NoOpToBackend + + +type BackendMsg + = NoOpBackendMsg + + +type ToFrontend + = NoOpToFrontend \ No newline at end of file From 199766f6e8930c0949332cebd9bf3c615c4ad806 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 Aug 2025 11:40:08 +0000 Subject: [PATCH 3/5] Add WebGL.Texture support to Evergreen snapshot generation Co-authored-by: supermario <102781+supermario@users.noreply.github.com> --- extra/Lamdera/Evergreen/Snapshot.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/extra/Lamdera/Evergreen/Snapshot.hs b/extra/Lamdera/Evergreen/Snapshot.hs index 715263fa5..0c54d98f9 100644 --- a/extra/Lamdera/Evergreen/Snapshot.hs +++ b/extra/Lamdera/Evergreen/Snapshot.hs @@ -649,6 +649,7 @@ canonicalToFt version scope interfaces recursionSet canonical tvarMap = -- Kernel concessions for Frontend Model and Msg ("elm", "file", "File", "File") -> ("File.File", Set.singleton moduleName, Map.empty) + ("elm-explorations", "webgl", "WebGL.Texture", "Texture") -> ("WebGL.Texture.Texture", Set.singleton moduleName, Map.empty) -- @TODO improve; These aliases will show up as VirtualDom errors which might confuse users From 673d1a3700babd774b75e39d8676bb3c08337a25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 Aug 2025 11:42:14 +0000 Subject: [PATCH 4/5] Add comprehensive WebGL.Texture test validation for both success and error cases Co-authored-by: supermario <102781+supermario@users.noreply.github.com> --- test/Test.hs | 3 --- test/Test/WebGL.hs | 10 ++++++++++ test/scenario-webgl-texture/src/TestBadWebGL.elm | 13 +++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 test/scenario-webgl-texture/src/TestBadWebGL.elm diff --git a/test/Test.hs b/test/Test.hs index f3871cf92..45a7ae687 100644 --- a/test/Test.hs +++ b/test/Test.hs @@ -21,11 +21,8 @@ import qualified Test.Ext.ElmPages.Check import qualified Test.TypeHashes import qualified Test.JsOutput import qualified Test.WebGL -<<<<<<< HEAD import qualified Test.Lamdera.Live -======= import qualified Test.BackwardsCompat ->>>>>>> bdcb71f7 (Test Lamdera HTML injections don't happen on vanilla Elm projects) import qualified Test.Lamdera.Evergreen.TestMigrationHarness import qualified Test.Lamdera.Evergreen.TestMigrationGenerator diff --git a/test/Test/WebGL.hs b/test/Test/WebGL.hs index 0880dbcd0..b0f0fe034 100644 --- a/test/Test/WebGL.hs +++ b/test/Test/WebGL.hs @@ -46,4 +46,14 @@ suite = tests actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Frontend.elm", "src/Backend.elm", "src/Types.elm" ] expectTextContains actual "Success! Compiled 3 modules." + + , scope "compilation should fail with WebGL.Texture in backend contexts" $ do + project <- io $ Lamdera.Relative.requireDir "test/scenario-webgl-texture" + + _ <- io $ rmdir (project "elm-stuff") + + actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/TestBadWebGL.elm" ] + + -- Should fail with kernel error for browser-only types + expectTextContains actual "can only be used in the frontend" ] diff --git a/test/scenario-webgl-texture/src/TestBadWebGL.elm b/test/scenario-webgl-texture/src/TestBadWebGL.elm new file mode 100644 index 000000000..8c3d920d9 --- /dev/null +++ b/test/scenario-webgl-texture/src/TestBadWebGL.elm @@ -0,0 +1,13 @@ +module TestBadWebGL exposing (..) + +-- This should fail compilation because WebGL.Texture is in ToBackend +import WebGL.Texture as Texture + + +type ToBackend + = SendTexture Texture.Texture -- This should cause an error + + +type alias BackendModel = + { texture : Maybe Texture.Texture -- This should also cause an error + } \ No newline at end of file From 9e7f6e3c38ce3ec7c45462a50e18d6cadf3312c2 Mon Sep 17 00:00:00 2001 From: Mario Rogic Date: Sat, 9 Aug 2025 16:12:47 +1000 Subject: [PATCH 5/5] Neuter tests, they will require more comprehensive work --- extra/Lamdera/TypeHash.hs | 2 +- test/Test/WebGL.hs | 13 +++++++++---- test/scenario-webgl-texture/elm.json | 12 ++++++++---- test/scenario-webgl-texture/src/Backend.elm | 7 ++++--- test/scenario-webgl-texture/src/TestBadWebGL.elm | 13 ------------- test/scenario-webgl-texture/src/Types.elm | 3 ++- 6 files changed, 24 insertions(+), 26 deletions(-) delete mode 100644 test/scenario-webgl-texture/src/TestBadWebGL.elm diff --git a/extra/Lamdera/TypeHash.hs b/extra/Lamdera/TypeHash.hs index 4066f3b89..a29f0023e 100644 --- a/extra/Lamdera/TypeHash.hs +++ b/extra/Lamdera/TypeHash.hs @@ -275,7 +275,7 @@ canonicalToDiffableType targetName interfaces recursionSet canonical tvarMap = kernelErrorBrowserOnly = case identifier of (author, pkg, module_, tipe) -> - DError $ "must not contain the Frontent-only type `" <> tipe <> "` from " <> author <> "/" <> pkg <> ":" <> module_ + DError $ "must not contain the Frontend-only type `" <> tipe <> "` from " <> author <> "/" <> pkg <> ":" <> module_ lamderaCodecsError = case identifier of diff --git a/test/Test/WebGL.hs b/test/Test/WebGL.hs index b0f0fe034..0cf521700 100644 --- a/test/Test/WebGL.hs +++ b/test/Test/WebGL.hs @@ -38,21 +38,26 @@ suite = tests expectTextContains actual "Success! Compiled 1 module." - , scope "compile Elm app with WebGL.Texture in FrontendModel" $ do + + -- @TODO currently the type restriction checks only happen in lamdera check + -- We should probably move them to lamdera make now that we have the isLamdera detection + -- but that's a fair bit of work – so revisit these tests when that's done + + , pending $ scope "compile Elm app with WebGL.Texture in FrontendModel" $ do project <- io $ Lamdera.Relative.requireDir "test/scenario-webgl-texture" _ <- io $ rmdir (project "elm-stuff") - actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Frontend.elm", "src/Backend.elm", "src/Types.elm" ] + actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Frontend.elm", "src/Types.elm" ] expectTextContains actual "Success! Compiled 3 modules." - , scope "compilation should fail with WebGL.Texture in backend contexts" $ do + , pending $ scope "compilation should fail with WebGL.Texture in backend contexts" $ do project <- io $ Lamdera.Relative.requireDir "test/scenario-webgl-texture" _ <- io $ rmdir (project "elm-stuff") - actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/TestBadWebGL.elm" ] + actual <- catchOutput $ Lamdera.Compile.makeDev project [ "src/Backend.elm" ] -- Should fail with kernel error for browser-only types expectTextContains actual "can only be used in the frontend" diff --git a/test/scenario-webgl-texture/elm.json b/test/scenario-webgl-texture/elm.json index 9a241e7cb..1d646564f 100644 --- a/test/scenario-webgl-texture/elm.json +++ b/test/scenario-webgl-texture/elm.json @@ -9,19 +9,23 @@ "elm/browser": "1.0.2", "elm/core": "1.0.5", "elm/html": "1.0.0", + "elm/json": "1.1.3", "elm/url": "1.0.0", - "elm-explorations/webgl": "1.1.3", "elm-explorations/linear-algebra": "1.0.3", + "elm-explorations/webgl": "1.1.3", "lamdera/core": "1.0.0" }, "indirect": { - "elm/json": "1.1.3", + "elm/bytes": "1.0.8", + "elm/file": "1.0.5", + "elm/http": "2.0.0", "elm/time": "1.0.0", - "elm/virtual-dom": "1.0.3" + "elm/virtual-dom": "1.0.4", + "lamdera/codecs": "1.0.0" } }, "test-dependencies": { "direct": {}, "indirect": {} } -} \ No newline at end of file +} diff --git a/test/scenario-webgl-texture/src/Backend.elm b/test/scenario-webgl-texture/src/Backend.elm index 572ab126b..216a5fb38 100644 --- a/test/scenario-webgl-texture/src/Backend.elm +++ b/test/scenario-webgl-texture/src/Backend.elm @@ -4,7 +4,8 @@ import Lamdera exposing (ClientId, SessionId) import Types exposing (..) -type alias Model = BackendModel +type alias Model = + BackendModel app = @@ -18,7 +19,7 @@ app = init : ( Model, Cmd BackendMsg ) init = - ( { message = "Hello from backend!" } + ( { message = "Hello from backend!", texture = Nothing } , Cmd.none ) @@ -39,4 +40,4 @@ updateFromFrontend sessionId clientId msg model = subscriptions : Model -> Sub BackendMsg subscriptions model = - Sub.none \ No newline at end of file + Sub.none diff --git a/test/scenario-webgl-texture/src/TestBadWebGL.elm b/test/scenario-webgl-texture/src/TestBadWebGL.elm deleted file mode 100644 index 8c3d920d9..000000000 --- a/test/scenario-webgl-texture/src/TestBadWebGL.elm +++ /dev/null @@ -1,13 +0,0 @@ -module TestBadWebGL exposing (..) - --- This should fail compilation because WebGL.Texture is in ToBackend -import WebGL.Texture as Texture - - -type ToBackend - = SendTexture Texture.Texture -- This should cause an error - - -type alias BackendModel = - { texture : Maybe Texture.Texture -- This should also cause an error - } \ No newline at end of file diff --git a/test/scenario-webgl-texture/src/Types.elm b/test/scenario-webgl-texture/src/Types.elm index 29357c289..d7b6a0abc 100644 --- a/test/scenario-webgl-texture/src/Types.elm +++ b/test/scenario-webgl-texture/src/Types.elm @@ -14,6 +14,7 @@ type alias FrontendModel = type alias BackendModel = { message : String + , texture : Maybe Texture.Texture -- This should also cause an error } @@ -33,4 +34,4 @@ type BackendMsg type ToFrontend - = NoOpToFrontend \ No newline at end of file + = NoOpToFrontend