diff options
author | eric thul <thul.eric@gmail.com> | 2015-12-25 18:41:33 -0500 |
---|---|---|
committer | eric thul <thul.eric@gmail.com> | 2015-12-25 18:41:33 -0500 |
commit | 63d6a244462d050e119bde54a7063bae8a17e987 (patch) | |
tree | cce47ed541fa9ee8b2950945a89608b1c06fb8c9 /src/PursLoader/Loader.purs | |
parent | 2e2da2be94720a739c595ec179a7ed49480ce753 (diff) | |
download | purs-loader-63d6a244462d050e119bde54a7063bae8a17e987.tar.gz purs-loader-63d6a244462d050e119bde54a7063bae8a17e987.tar.zst purs-loader-63d6a244462d050e119bde54a7063bae8a17e987.zip |
Splitting PSC functionality into a separate plugin
The loader creates shim modules that reference their corresponding
PureScript module that is bundled by the PureScript webpack plugin,
which invokes `psc` and `psc-bundle`.
Resolves #31 and resolves #32
Diffstat (limited to 'src/PursLoader/Loader.purs')
-rw-r--r-- | src/PursLoader/Loader.purs | 139 |
1 files changed, 46 insertions, 93 deletions
diff --git a/src/PursLoader/Loader.purs b/src/PursLoader/Loader.purs index a91667c..0cd077d 100644 --- a/src/PursLoader/Loader.purs +++ b/src/PursLoader/Loader.purs | |||
@@ -4,122 +4,75 @@ module PursLoader.Loader | |||
4 | , loaderFn | 4 | , loaderFn |
5 | ) where | 5 | ) where |
6 | 6 | ||
7 | import Prelude (Unit(), ($), (<>), (>>=), (<$>), (++), bind, flip, id, pure, return, unit, show) | 7 | import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (<<<), (++), bind, const) |
8 | 8 | ||
9 | import Control.Monad.Aff (Aff(), runAff) | 9 | import Control.Bind (join) |
10 | import Control.Monad.Eff (Eff()) | 10 | import Control.Monad.Eff (Eff()) |
11 | import Control.Monad.Eff.Class (liftEff) | 11 | import Control.Monad.Eff.Exception (Error(), error) |
12 | import Control.Monad.Eff.Exception (throwException, error, EXCEPTION()) | ||
13 | 12 | ||
14 | import Data.Array ((!!), concat) | 13 | import Data.Array ((!!)) |
15 | import Data.Function (Fn2(), mkFn2) | 14 | import Data.Function (Fn2(), mkFn2) |
16 | import Data.Maybe (Maybe(..), fromMaybe, maybe) | 15 | import Data.Maybe (Maybe(..), maybe) |
17 | import Data.Either (Either(..)) | 16 | import Data.Either (either) |
18 | import Data.String (joinWith) | 17 | import Data.Foreign (Foreign()) |
19 | import Data.String.Regex (Regex(), match, noFlags, regex, test) | ||
20 | import Data.Traversable (sequence) | ||
21 | import Data.Foreign (F()) | ||
22 | import Data.Foreign.Class (read) | 18 | import Data.Foreign.Class (read) |
19 | import Data.Foreign.Null (runNull) | ||
20 | import Data.String.Regex (Regex(), match, noFlags, regex) | ||
21 | |||
22 | import Unsafe.Coerce (unsafeCoerce) | ||
23 | |||
24 | import PursLoader.LoaderRef | ||
25 | ( LoaderRef() | ||
26 | , Loader() | ||
27 | , async | ||
28 | , cacheable | ||
29 | , query | ||
30 | , clearDependencies | ||
31 | , addDependency | ||
32 | , resourcePath | ||
33 | ) | ||
23 | 34 | ||
24 | import PursLoader.ChildProcess (ChildProcess(), spawn) | ||
25 | import PursLoader.FS (FS(), writeFileUtf8, findFileUtf8) | ||
26 | import PursLoader.Glob (Glob(), globAll) | ||
27 | import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, query, clearDependencies, addDependency, resourcePath) | ||
28 | import PursLoader.LoaderUtil (parseQuery) | 35 | import PursLoader.LoaderUtil (parseQuery) |
29 | import PursLoader.Options (loaderFFIOption, loaderSrcOption, pscOptions, Options(), output) | 36 | import PursLoader.Options (runOptions) |
37 | import PursLoader.Path (dirname, relative) | ||
30 | 38 | ||
31 | type Effects eff = (cp :: ChildProcess, fs :: FS, glob :: Glob, loader :: Loader, err :: EXCEPTION | eff) | 39 | type Effects eff = (loader :: Loader | eff) |
32 | 40 | ||
33 | moduleRegex :: Regex | 41 | type PurescriptWebpackPluginContext eff = { compile :: (Foreign -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit } |
34 | moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true } | ||
35 | 42 | ||
36 | foreignRegex :: Regex | 43 | loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit |
37 | foreignRegex = regex "(?:^|\\n)\\s*foreign import\\s+" noFlags { ignoreCase = true } | 44 | loader ref source = do |
38 | 45 | callback <- async ref | |
39 | pscCommand :: String | ||
40 | pscCommand = "psc" | ||
41 | |||
42 | psciCommand :: String | ||
43 | psciCommand = "psci" | ||
44 | |||
45 | psciFilename :: String | ||
46 | psciFilename = ".psci" | ||
47 | |||
48 | (!!!) :: forall a. Int -> Array a -> Maybe a | ||
49 | (!!!) = flip (!!) | ||
50 | |||
51 | foreign import cwd :: String | ||
52 | |||
53 | foreign import relative :: String -> String -> String | ||
54 | |||
55 | foreign import resolve :: String -> String | ||
56 | |||
57 | foreign import dirname :: String -> String | ||
58 | |||
59 | foreign import joinPath :: String -> String -> String | ||
60 | |||
61 | mkPsci :: Array (Array String) -> Array (Array String) -> String | ||
62 | mkPsci srcs ffis = joinWith "\n" ((loadModule <$> concat srcs) <> (loadForeign <$> concat ffis)) | ||
63 | where | ||
64 | loadModule :: String -> String | ||
65 | loadModule a = ":m " ++ relative cwd a | ||
66 | |||
67 | loadForeign :: String -> String | ||
68 | loadForeign a = ":f " ++ relative cwd a | ||
69 | |||
70 | findFFI :: forall eff. Array (Array String) -> String -> Aff (fs :: FS | eff) (Maybe String) | ||
71 | findFFI ffiss name = findFileUtf8 re (concat ffiss) | ||
72 | where | ||
73 | re = regex ("(?:^|\\n)//\\s*module\\s*" ++ name ++ "\\s*\\n") noFlags | ||
74 | 46 | ||
75 | loader' :: forall eff. LoaderRef -> String -> Aff (Effects eff) (Maybe String) | 47 | cacheable ref |
76 | loader' ref source = do | ||
77 | liftEff $ cacheable ref | ||
78 | 48 | ||
79 | let parsed = parseQuery $ query ref | 49 | let parsed = parseQuery $ query ref |
80 | srcs = fromMaybe [] (loaderSrcOption parsed) | ||
81 | ffis = fromMaybe [] (loaderFFIOption parsed) | ||
82 | 50 | ||
83 | case read parsed :: F Options of | 51 | options = either (const Nothing) (Just <<< runOptions) (read parsed) |
84 | Left e -> liftEff (throwException (error (show e))) | ||
85 | Right opts -> do | ||
86 | let pscOpts = pscOptions opts | ||
87 | 52 | ||
88 | srcss <- globAll srcs | 53 | moduleName = join $ match moduleRegex source >>= \as -> as !! 1 |
89 | ffiss <- globAll ffis | ||
90 | 54 | ||
91 | let psciFile = mkPsci srcss ffiss | 55 | resourceDir = dirname (resourcePath ref) |
92 | 56 | ||
93 | writeFileUtf8 psciFilename psciFile | 57 | modulePath = (\opts -> relative resourceDir opts.pscBundle) <$> options |
94 | 58 | ||
95 | let moduleName = match moduleRegex source >>= (!!!) 1 >>= id | 59 | result = (\path name -> "module.exports = require('" ++ path ++ "')['" ++ name ++ "'];") <$> modulePath <*> moduleName |
96 | hasForeign = test foreignRegex source | ||
97 | outputDir = resolve (output opts) | ||
98 | resourceDir = dirname (resourcePath ref) | ||
99 | result = (\a -> "module.exports = require('" ++ relative resourceDir (joinPath outputDir a) ++ "');") <$> moduleName | ||
100 | 60 | ||
101 | liftEff do | 61 | clearDependencies ref |
102 | clearDependencies ref | ||
103 | addDependency ref (resourcePath ref) | ||
104 | sequence $ (\src -> addDependency ref (resolve src)) <$> concat srcss | ||
105 | 62 | ||
106 | foreignPath <- if hasForeign | 63 | addDependency ref (resourcePath ref) |
107 | then fromMaybe (pure Nothing) (findFFI ffiss <$> moduleName) | ||
108 | else pure Nothing | ||
109 | 64 | ||
110 | fromMaybe (pure unit) ((\path -> liftEff (addDependency ref path)) <$> foreignPath) | 65 | pluginContext.compile (\err -> maybe (callback (Just $ error "Failed to run loader") "") |
111 | 66 | (callback (compileError err)) result) | |
112 | spawn pscCommand (srcs <> pscOpts) | 67 | where |
68 | moduleRegex :: Regex | ||
69 | moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true } | ||
113 | 70 | ||
114 | return result | 71 | pluginContext :: PurescriptWebpackPluginContext eff |
72 | pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext | ||
115 | 73 | ||
116 | loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit | 74 | compileError :: Foreign -> Maybe Error |
117 | loader ref source = do | 75 | compileError value = either (const $ Just (error "Failed to compile")) ((<$>) error) (runNull <$> read value) |
118 | callback <- async ref | ||
119 | runAff (\e -> callback (Just e) "") | ||
120 | (maybe (callback (Just (error "Loader has failed to run")) "") | ||
121 | (callback Nothing)) | ||
122 | (loader' ref source) | ||
123 | 76 | ||
124 | loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit) | 77 | loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit) |
125 | loaderFn = mkFn2 loader | 78 | loaderFn = mkFn2 loader |