aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/PursLoader/Loader.purs
blob: 0dfa20ebe7fd8bbbd3d3c91d1cd7e9d78ead0fd2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
module PursLoader.Loader
  ( Effects()
  , loader
  , loaderFn
  ) where

import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (++), (<<<), bind, const, id, pure, unit)

import Control.Apply ((*>))
import Control.Alt ((<|>))
import Control.Bind (join)
import Control.Monad.Eff (Eff(), foreachE)
import Control.Monad.Eff.Exception (Error(), error)

import Data.Array ((!!))
import Data.Either (Either(..), either)
import Data.Function (Fn2(), mkFn2)
import Data.Maybe (Maybe(..), maybe)
import Data.Nullable (toMaybe)
import Data.String.Regex (Regex(), match, noFlags, regex)

import Unsafe.Coerce (unsafeCoerce)

import PursLoader.LoaderRef
  ( AsyncCallback()
  , LoaderRef()
  , Loader()
  , async
  , cacheable
  , clearDependencies
  , addDependency
  , resourcePath
  )

import PursLoader.Debug (debug)
import PursLoader.Path (dirname, joinPath, relative)
import PursLoader.Plugin as Plugin

type Effects eff = (loader :: Loader | eff)

loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
loader ref source = do
  callback <- async ref

  cacheable ref

  debug "Invoke PureScript plugin compilation"

  pluginContext.compile (compile callback)
  where
  pluginContext :: Plugin.Context (Effects eff)
  pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext

  compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
  compile callback error' { srcMap, ffiMap, graph } = do
    clearDependencies ref

    either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name

    addDependency ref (resourcePath ref)

    either (\err -> callback (toMaybe error' <|> Just err) "") id
           (handle <$> name <*> dependencies <*> exports)
    where
    handle :: String -> Array String -> String -> Eff (Effects eff) Unit
    handle name' deps res = do
      debug ("Adding PureScript transitive dependencies for " ++ name')
      addTransitive name'
      foreachE deps addTransitive
      debug "Generated loader result"
      debug res
      callback (toMaybe error') res

    exports :: Either Error String
    exports =
      if pluginContext.options.bundle
         then bundleExport <$> name
         else moduleExport <<< modulePath <$> name
      where
      bundleExport :: String -> String
      bundleExport name' = "module.exports = require('" ++ path ++ "')['" ++ name' ++ "'];"
        where
        path :: String
        path = relative resourceDir pluginContext.options.bundleOutput

      moduleExport :: String -> String
      moduleExport path = "module.exports = require('" ++ path ++ "');"

      modulePath :: String -> String
      modulePath = relative resourceDir <<< joinPath pluginContext.options.output

      resourceDir :: String
      resourceDir = dirname (resourcePath ref)

    dependencies :: Either Error (Array String)
    dependencies =
      if pluginContext.options.bundle
         then name >>= Plugin.dependenciesOf graph
         else pure []

    addTransitive :: String -> Eff (Effects eff) Unit
    addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
      where
      addDep :: Maybe String -> Eff (Effects eff) Unit
      addDep = maybe (pure unit) (addDependency ref)

    name :: Either Error String
    name =
      maybe (Left $ error "Failed to parse module name") Right
            (join $ match re source >>= \as -> as !! 1)
      where
      re :: Regex
      re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }

loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
loaderFn = mkFn2 loader