Compare commits
	
		
			No commits in common. "aea4f3b654ad528443e39762cd772c030323644a" and "74a9cd4bb815dfdd9257700b2ad6585c73f4650d" have entirely different histories.
		
	
	
		
			aea4f3b654
			...
			74a9cd4bb8
		
	
		
							
								
								
									
										58
									
								
								dep/reexportsToStubs.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								dep/reexportsToStubs.hs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | {-# LANGUAGE RecordWildCards #-} | ||||||
|  | 
 | ||||||
|  | import Distribution.PackageDescription.Parsec | ||||||
|  | import Distribution.PackageDescription | ||||||
|  | import Distribution.Types.Library | ||||||
|  | import Distribution.Types.ModuleReexport | ||||||
|  | import Distribution.Verbosity | ||||||
|  | import Distribution.ModuleName (components) | ||||||
|  | import System.Environment (getArgs) | ||||||
|  | import System.Directory (createDirectoryIfMissing) | ||||||
|  | import System.FilePath ((</>), (<.>), joinPath, takeDirectory) | ||||||
|  | import Data.List.Split (splitOn) | ||||||
|  | import Data.List (intercalate) | ||||||
|  | 
 | ||||||
|  | -- Helper function to convert a module name to a file path | ||||||
|  | convertModuleToPath :: String -> FilePath | ||||||
|  | convertModuleToPath moduleName = "src" </> joinPath (splitOn "." moduleName) <.> "hs" | ||||||
|  | 
 | ||||||
|  | -- Function to write a file with the given module structure | ||||||
|  | writeModuleFile :: (String, String) -> IO () | ||||||
|  | writeModuleFile (originalModule, newModule) = do | ||||||
|  |     let content = unlines | ||||||
|  |             [ "module " ++ newModule ++ " (module X) where" | ||||||
|  |             , "" | ||||||
|  |             , "import " ++ originalModule ++ " as X" | ||||||
|  |             ] | ||||||
|  |         filePath = convertModuleToPath newModule | ||||||
|  |     createDirectoryIfMissing True (takeDirectory filePath) | ||||||
|  |     writeFile filePath content | ||||||
|  | 
 | ||||||
|  | main :: IO () | ||||||
|  | main = do | ||||||
|  |     args <- getArgs | ||||||
|  |     case args of | ||||||
|  |         [fileName] -> do | ||||||
|  |             result <- parseCabalFile fileName | ||||||
|  |             case result of | ||||||
|  |                 Left err -> putStrLn $ "Error: " ++ err | ||||||
|  |                 Right reexports -> mapM_ writeModuleFile reexports | ||||||
|  |         _ -> putStrLn "Usage: cabal-file-parser <filename.cabal>" | ||||||
|  | 
 | ||||||
|  | parseCabalFile :: FilePath -> IO (Either String [(String, String)]) | ||||||
|  | parseCabalFile filePath = do | ||||||
|  |     result <- readGenericPackageDescription silent filePath | ||||||
|  |     let maybeMainLib = case condLibrary result of | ||||||
|  |             Just (CondNode lib _ _) -> Just lib | ||||||
|  |             Nothing -> Nothing | ||||||
|  |         subLibs = [lib | (_, CondNode lib _ _) <- condSubLibraries result] | ||||||
|  |         libs = maybe subLibs (:subLibs) maybeMainLib | ||||||
|  |     return $ case libs of | ||||||
|  |         (lib:_) -> Right (extractReexportedModules lib) | ||||||
|  |         [] -> Left "No library found in .cabal file." | ||||||
|  | 
 | ||||||
|  | extractReexportedModules :: Library -> [(String, String)] | ||||||
|  | extractReexportedModules lib = | ||||||
|  |     map (\ModuleReexport{..} -> (moduleNameString moduleReexportOriginalName, moduleNameString moduleReexportName)) (reexportedModules lib) | ||||||
|  | 
 | ||||||
|  | moduleNameString = intercalate "." . components | ||||||
| @ -44,8 +44,3 @@ library | |||||||
|     build-depends: jsaddle-warp |     build-depends: jsaddle-warp | ||||||
| 
 | 
 | ||||||
|   default-language: Haskell2010 |   default-language: Haskell2010 | ||||||
|   default-extensions: |  | ||||||
|     FlexibleInstances |  | ||||||
|     GeneralizedNewtypeDeriving |  | ||||||
|     LambdaCase |  | ||||||
|     OverloadedStrings |  | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||||||
| module React.Component where | module React.Component where | ||||||
| 
 | 
 | ||||||
| import Control.Monad.Except | import Control.Monad.Except | ||||||
| @ -8,17 +9,15 @@ import React.JSaddle | |||||||
| import React.Types | import React.Types | ||||||
| 
 | 
 | ||||||
| --TODO: The Hook section shouldn't have any control flow to it; probably it also shouldn't depend on props except in specific ways | --TODO: The Hook section shouldn't have any control flow to it; probably it also shouldn't depend on props except in specific ways | ||||||
| component :: FromJSVal props => (props -> Hook Element) -> ReaderT React JSM (Component props ()) | component :: Hook (JSVal -> Render Element) -> ReaderT React JSM (Component JSVal ()) | ||||||
| component hook = do | component (Hook hook) = do | ||||||
|   react <- ask |   react <- ask | ||||||
|   f <- lift $ function' $ \_ _ args -> flip runReaderT react $ do |   f <- lift $ function' $ \_ _ args -> flip runReaderT react $ do | ||||||
|     let propsVal = case args of |     render <- hook | ||||||
|  |     let props = case args of | ||||||
|           [] -> jsUndefined |           [] -> jsUndefined | ||||||
|           arg0 : _ -> arg0 |           arg0 : _ -> arg0 | ||||||
|     props <- liftJSM $ fromJSVal propsVal >>= \case |     e <- unRender $ render props | ||||||
|       Nothing -> fail "Invalid props" |  | ||||||
|       Just props -> pure props |  | ||||||
|     e <- unHook $ hook props |  | ||||||
|     unElement e |     unElement e | ||||||
|   pure $ Component f |   pure $ Component f | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | {-# LANGUAGE OverloadedStrings #-} | ||||||
| module React.Element where | module React.Element where | ||||||
| 
 | 
 | ||||||
| import Control.Monad.Except | import Control.Monad.Except | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| {-# LANGUAGE CPP #-} | {-# LANGUAGE CPP #-} | ||||||
|  | {-# LANGUAGE OverloadedStrings #-} | ||||||
| {-# LANGUAGE TemplateHaskell #-} | {-# LANGUAGE TemplateHaskell #-} | ||||||
| module React.Export where | module React.Export where | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | {-# LANGUAGE OverloadedStrings #-} | ||||||
|  | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||||||
| module React.Hook where | module React.Hook where | ||||||
| 
 | 
 | ||||||
| import Prelude hiding ((!!)) | import Prelude hiding ((!!)) | ||||||
| @ -5,6 +7,7 @@ import Prelude hiding ((!!)) | |||||||
| import Control.Monad | import Control.Monad | ||||||
| import Control.Monad.Except | import Control.Monad.Except | ||||||
| import Control.Monad.Reader | import Control.Monad.Reader | ||||||
|  | import Data.Text (Text) | ||||||
| import Language.Javascript.JSaddle hiding (Ref) | import Language.Javascript.JSaddle hiding (Ref) | ||||||
| 
 | 
 | ||||||
| import React.JSaddle | import React.JSaddle | ||||||
| @ -13,7 +16,6 @@ import React.Types | |||||||
| 
 | 
 | ||||||
| --TODO: Input can be an initializer function rather than value | --TODO: Input can be an initializer function rather than value | ||||||
| --TODO: `set` can take `a -> a` instead of `a` | --TODO: `set` can take `a -> a` instead of `a` | ||||||
| --TODO: I bet React always returns the same function object for the setter; if we re-wrap the function using `useCallback` each time, we are probably hurting performance by making it be a new object each time and forcing rerendering of children |  | ||||||
| useState :: (ToJSVal a, FromJSVal a) => a -> Hook (a, a -> JSM ()) | useState :: (ToJSVal a, FromJSVal a) => a -> Hook (a, a -> JSM ()) | ||||||
| useState initialValue = Hook $ do | useState initialValue = Hook $ do | ||||||
|   react <- ask |   react <- ask | ||||||
| @ -66,3 +68,51 @@ useCallback f deps = Hook $ do | |||||||
|       depsArray <- lift $ toJSVal =<< sequence someDeps |       depsArray <- lift $ toJSVal =<< sequence someDeps | ||||||
|       pure [depsArray] |       pure [depsArray] | ||||||
|   lift $ (react # t "useCallback") $ [pToJSVal cb] <> depsArg |   lift $ (react # t "useCallback") $ [pToJSVal cb] <> depsArg | ||||||
|  | 
 | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | -- Not yet supported | ||||||
|  | -------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | type DispatchFunction a = a -> Effect () | ||||||
|  | 
 | ||||||
|  | type Reducer s a = s -> a -> s | ||||||
|  | 
 | ||||||
|  | useContext :: Context a -> Hook a | ||||||
|  | useContext = undefined | ||||||
|  | 
 | ||||||
|  | data Context a | ||||||
|  | 
 | ||||||
|  | createContext :: a -> IO (Context a) | ||||||
|  | createContext = undefined | ||||||
|  | 
 | ||||||
|  | provider :: Context a -> a -> Render b -> Render b | ||||||
|  | provider = undefined | ||||||
|  | 
 | ||||||
|  | data Ref a | ||||||
|  | 
 | ||||||
|  | forwardRef :: (props -> Ref refVal -> Hook (Render ())) -> Component props refVal | ||||||
|  | forwardRef = undefined | ||||||
|  | 
 | ||||||
|  | useImperativeHandle :: Ref a -> Effect a -> Maybe [JSVal] -> Hook () | ||||||
|  | useImperativeHandle = undefined | ||||||
|  | 
 | ||||||
|  | useReducer :: Reducer s a -> a -> Maybe (a -> a) -> Hook (a, DispatchFunction a) | ||||||
|  | useReducer = undefined | ||||||
|  | 
 | ||||||
|  | useTransition :: Hook (Bool, Effect () -> Effect ()) | ||||||
|  | useTransition = undefined | ||||||
|  | 
 | ||||||
|  | useDeferredValue :: a -> Hook a | ||||||
|  | useDeferredValue = undefined | ||||||
|  | 
 | ||||||
|  | useDebugValue :: a -> Maybe (a -> b) -> Hook () | ||||||
|  | useDebugValue = undefined | ||||||
|  | 
 | ||||||
|  | useId :: Hook Text | ||||||
|  | useId = undefined | ||||||
|  | 
 | ||||||
|  | useSyncExternalStore :: (IO () -> IO (IO ())) -> IO a -> Maybe (IO a) -> Hook () | ||||||
|  | useSyncExternalStore = undefined | ||||||
|  | 
 | ||||||
|  | newtype Effect a = Effect { unEffect :: JSM a } | ||||||
|  |   deriving (Functor, Applicative, Monad) | ||||||
|  | |||||||
| @ -1,4 +1,7 @@ | |||||||
| {-# LANGUAGE CPP #-} | {-# LANGUAGE CPP #-} | ||||||
|  | {-# LANGUAGE FlexibleInstances #-} | ||||||
|  | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||||||
|  | {-# LANGUAGE OverloadedStrings #-} | ||||||
| {-# OPTIONS_GHC -Wno-orphans #-} | {-# OPTIONS_GHC -Wno-orphans #-} | ||||||
| -- | Everything in this module belongs in JSaddle, GHCJS-DOM, or similar | -- | Everything in this module belongs in JSaddle, GHCJS-DOM, or similar | ||||||
| module React.JSaddle where | module React.JSaddle where | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| {-# LANGUAGE CPP #-} | {-# LANGUAGE CPP #-} | ||||||
|  | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||||||
| module React.Types where | module React.Types where | ||||||
| 
 | 
 | ||||||
| import Control.Monad.Reader | import Control.Monad.Reader | ||||||
| @ -30,6 +31,16 @@ newtype Hook a = Hook { unHook :: ReaderT React JSM a } | |||||||
| #endif | #endif | ||||||
|            ) |            ) | ||||||
| 
 | 
 | ||||||
|  | newtype Render a = Render { unRender :: ReaderT React JSM a } | ||||||
|  |   deriving ( Functor | ||||||
|  |            , Applicative | ||||||
|  |            , Monad | ||||||
|  |            , MonadJSM | ||||||
|  | #ifndef ghcjs_HOST_OS | ||||||
|  |            , MonadIO | ||||||
|  | #endif | ||||||
|  |            ) | ||||||
|  | 
 | ||||||
| newtype Element = Element { unElement :: ReaderT React JSM JSVal } | newtype Element = Element { unElement :: ReaderT React JSM JSVal } | ||||||
| 
 | 
 | ||||||
| instance IsString Element where | instance IsString Element where | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user