packages feed

duplo 1.6.18 → 1.6.19

raw patch · 23 files changed

+352/−307 lines, 23 filesdep +HUnitdep +tastydep +tasty-hunitdep −filepatherdep −hspecdep ~ansi-terminaldep ~lensdep ~mtlsetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: HUnit, tasty, tasty-hunit, tasty-quickcheck

Dependencies removed: filepather, hspec

Dependency ranges changed: ansi-terminal, lens, mtl, text, transformers

API changes (from Hackage documentation)

+ Development.Duplo.JavaScript.Order: matchDependencies :: String -> JSNode -> JSNode
+ Development.Duplo.JavaScript.Order: trace' :: Show a => a -> a
+ Development.Duplo.Types.JavaScript: MissingDependencies :: String -> JSCompilerException
- Development.Duplo.Component: extractCompVersions :: FilePath -> IO String
+ Development.Duplo.Component: extractCompVersions :: BuildConfig -> Action String
- Development.Duplo.Component: getAllManifestPaths :: FilePath -> IO [FilePath]
+ Development.Duplo.Component: getAllManifestPaths :: FilePath -> FilePath -> Action [FilePath]
- Development.Duplo.Files: readFile :: FilePath -> FilePath -> ExceptT String Action File
+ Development.Duplo.Files: readFile :: FilePath -> FilePath -> MaybeT Action File
- Development.Duplo.Utilities: type CompiledContent = ExceptT String Action
+ Development.Duplo.Utilities: type CompiledContent = MaybeT Action

Files

README.md view
@@ -100,6 +100,9 @@ `app/modules/`, that they would be concatenated/compiled into the respective output files (i.e. `index.html`, `index.css`, or `index.js`). +This repo is checked with [git-vogue](https://github.com/anchor/git-vogue).+It's highly recommended that you use it for duplo development as well.+  ## Testing 
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple+import           Distribution.Simple main = defaultMain
duplo.cabal view
@@ -1,5 +1,5 @@ name:               duplo-version:            1.6.18+version:            1.6.19 synopsis:           Frontend development build tool description:        Intuitive, simple building blocks for building composable, completely self-managed web applications license:            MIT@@ -41,25 +41,24 @@   build-depends      : base                               == 4.7.*                      , aeson                              == 0.8.*                      , aeson-pretty                       == 0.7.*-                     , ansi-terminal                      == 0.5.*+                     , ansi-terminal                      == 0.6.*                      , bytestring                         == 0.10.*                      , containers                         == 0.5.*                      , directory                          == 1.2.*                      , executable-path                    == 0.0.*                      , filepath                           == 1.3.*-                     , filepather                         == 0.3.*                      , fsnotify                           == 0.1.*                      , http-types                         == 0.8.*                      , language-javascript                == 0.5.*-                     , lens                               == 4.5.*-                     , mtl                                == 2.2.*+                     , lens                               == 4.6.*+                     , mtl                                == 2.1.*                      , regex-compat                       == 0.95.*                      , scotty                             == 0.9.*                      , shake                              == 0.14.*                      , system-fileio                      == 0.3.*-                     , text                               == 1.1.*+                     , text                               == 1.2.*                      , text-format                        == 0.3.*-                     , transformers                       == 0.4.*+                     , transformers                       == 0.3.*                      , unordered-containers               == 0.2.*                      , utf8-string                        == 0.3.*                      , wai                                == 3.0.*@@ -76,27 +75,26 @@                      , aeson                == 0.8.*                      , aeson                == 0.8.*                      , aeson-pretty         == 0.7.*-                     , ansi-terminal        == 0.5.*+                     , ansi-terminal        == 0.6.*                      , base64-bytestring    == 1.0.*                      , bytestring           == 0.10.*                      , containers           == 0.5.*                      , directory            == 1.2.*                      , duplo                      , filepath             == 1.3.*-                     , filepather           == 0.3.*                      , fsnotify             == 0.1.*                      , http-types           == 0.8.*                      , language-javascript  == 0.5.*-                     , lens                 == 4.5.*-                     , mtl                  == 2.2.*+                     , lens                 == 4.6.*+                     , mtl                  == 2.1.*                      , process              == 1.2.*                      , regex-compat         == 0.95.*                      , scotty               == 0.9.*                      , shake                == 0.14.*                      , system-filepath      == 0.4.*-                     , text                 == 1.1.*+                     , text                 == 1.2.*                      , text-format          == 0.3.*-                     , transformers         == 0.4.*+                     , transformers         == 0.3.*                      , unordered-containers == 0.2.*                      , wai                  == 3.0.*                      , warp                 == 3.0.*@@ -110,6 +108,9 @@   type             : exitcode-stdio-1.0   build-depends    : base                    , duplo-                   , hspec              == 2.1.*+                   , HUnit              == 1.2.5.2                    , MissingH           == 1.3.*                    , QuickCheck         == 2.7.*+                   , tasty              == 0.10.1+                   , tasty-hunit        == 0.9.0.1+                   , tasty-quickcheck   == 0.8.3.2
src/CLI.hs view
@@ -2,35 +2,40 @@  module Main where -import Control.Applicative ((<$>))-import Control.Exception (catch, handle, throw, Exception)-import Control.Lens.Operators-import Control.Monad (void, when, unless)-import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)-import Data.ByteString.Base64 (decode)-import Data.ByteString.Char8 (pack, unpack)-import Data.Maybe (fromMaybe)-import Development.Duplo (build)-import Development.Duplo.Server (serve)-import Development.Duplo.Utilities (logStatus, errorPrintSetter)-import Development.Duplo.Watcher (watch)-import Development.Shake (cmd, ShakeException(..))-import Development.Shake.FilePath ((</>))-import GHC.Conc (forkIO)-import System.Console.GetOpt (getOpt, OptDescr(..), ArgDescr(..), ArgOrder(..))-import System.Directory (getCurrentDirectory, createDirectoryIfMissing, doesFileExist)-import System.Environment (lookupEnv, getArgs, getExecutablePath)-import System.FilePath.Posix (takeDirectory)-import System.Process (proc, createProcess, waitForProcess)-import qualified Control.Lens-import qualified Development.Duplo.Component as CM+import           Control.Applicative             ((<$>))+import           Control.Exception               (Exception, catch, handle,+                                                  throw)+import qualified Control.Lens                    as LS+import           Control.Lens.Operators+import           Control.Monad                   (unless, void, when)+import           Data.ByteString.Base64          (decode)+import           Data.ByteString.Char8           (pack, unpack)+import           Data.List.Utils                 (replace)+import           Data.Maybe                      (fromMaybe)+import           Development.Duplo               (build)+import qualified Development.Duplo.Component     as CM+import           Development.Duplo.Server        (serve) import qualified Development.Duplo.Types.AppInfo as AI import qualified Development.Duplo.Types.Builder as TB-import qualified Development.Duplo.Types.Config as TC+import qualified Development.Duplo.Types.Config  as TC import qualified Development.Duplo.Types.Options as OP+import           Development.Duplo.Utilities     (errorPrintSetter, logStatus)+import           Development.Duplo.Watcher       (watch)+import           Development.Shake               (ShakeException (..), cmd)+import           Development.Shake.FilePath      ((</>)) import qualified Filesystem.Path+import           GHC.Conc                        (forkIO) import qualified GHC.IO-import Data.List.Utils (replace)+import           System.Console.GetOpt           (ArgDescr (..), ArgOrder (..),+                                                  OptDescr (..), getOpt)+import           System.Directory                (createDirectoryIfMissing,+                                                  doesFileExist,+                                                  getCurrentDirectory)+import           System.Environment              (getArgs, getExecutablePath,+                                                  lookupEnv)+import           System.FilePath.Posix           (takeDirectory)+import           System.Process                  (createProcess, proc,+                                                  waitForProcess)  main :: IO () main = do
src/Development/Duplo.hs view
@@ -1,25 +1,27 @@ module Development.Duplo where -import Control.Exception (throw)-import Control.Lens hiding (Action)-import Control.Monad (void, when, unless)-import Control.Monad.Except (runExceptT)-import Development.Duplo.Git as Git-import Development.Duplo.Markups as Markups-import Development.Duplo.Scripts as Scripts-import Development.Duplo.Static as Static-import Development.Duplo.Styles as Styles-import Development.Duplo.Utilities (logStatus, headerPrintSetter, successPrintSetter, createStdEnv)-import Development.Shake-import Development.Shake.FilePath ((</>))-import System.Console.GetOpt (OptDescr(..), ArgDescr(..))-import System.IO (readFile)-import qualified Development.Duplo.Component as CM+import           Control.Exception               (throw)+import           Control.Lens                    hiding (Action)+import           Control.Monad                   (unless, void, when)+import           Control.Monad.Trans.Maybe       (runMaybeT)+import qualified Development.Duplo.Component     as CM+import           Development.Duplo.Git           as Git+import           Development.Duplo.Markups       as Markups+import           Development.Duplo.Scripts       as Scripts+import           Development.Duplo.Static        as Static+import           Development.Duplo.Styles        as Styles import qualified Development.Duplo.Types.AppInfo as AI import qualified Development.Duplo.Types.Builder as BD-import qualified Development.Duplo.Types.Config as TC+import qualified Development.Duplo.Types.Config  as TC import qualified Development.Duplo.Types.Options as OP-import qualified Development.Shake as DS+import           Development.Duplo.Utilities     (createStdEnv,+                                                  headerPrintSetter, logStatus,+                                                  successPrintSetter)+import           Development.Shake+import qualified Development.Shake               as DS+import           Development.Shake.FilePath      ((</>))+import           System.Console.GetOpt           (ArgDescr (..), OptDescr (..))+import           System.IO                       (readFile)  shakeOpts = shakeOptions { shakeThreads = 4 } @@ -43,9 +45,9 @@     let targetScript = targetPath </> "index.js"     let targetStyle  = targetPath </> "index.css"     let targetMarkup = targetPath </> "index.html"-    targetScript *> (void . runExceptT . Scripts.build config)-    targetStyle  *> (void . runExceptT . Styles.build config)-    targetMarkup *> (void . runExceptT . Markups.build config)+    targetScript *> (void . runMaybeT . Scripts.build config)+    targetStyle  *> (void . runMaybeT . Styles.build config)+    targetMarkup *> (void . runMaybeT . Markups.build config)      -- Manually bootstrap Shake     action $ do
src/Development/Duplo/Component.hs view
@@ -2,35 +2,38 @@  module Development.Duplo.Component where -import Control.Applicative ((<$>), (<*>))-import Control.Exception (throw)-import Control.Monad (when, liftM)-import Control.Monad.Trans.Class (lift)-import Data.Aeson (encode, decode)-import Data.Aeson.Encode.Pretty (encodePretty)-import Data.ByteString.Lazy.Char8 (ByteString)-import Data.HashMap.Lazy (empty, keys, lookup)-import Data.List (isPrefixOf)-import Data.Map (fromList)-import Data.Maybe (fromJust, fromMaybe)-import Data.Text (breakOn)-import Development.Duplo.Types.AppInfo (AppInfo(..))-import Development.Shake hiding (doesFileExist, getDirectoryContents, doesDirectoryExist)-import Development.Shake.FilePath ((</>))-import Prelude hiding (lookup)-import System.Directory (doesFileExist, doesDirectoryExist, getDirectoryContents, getCurrentDirectory)-import System.FilePath.FilePather.FilterPredicate (filterPredicate)-import System.FilePath.FilePather.Find (findp)-import System.FilePath.FilePather.RecursePredicate (recursePredicate)-import System.FilePath.Posix (makeRelative, dropExtension, splitDirectories, equalFilePath, takeFileName, dropTrailingPathSeparator)-import qualified Data.ByteString.Lazy.Char8 as BS (unpack, pack)-import qualified Data.Text as T (unpack, pack)+import           Control.Exception               (throw)+import           Control.Lens.Operators+import           Control.Monad                   (liftM)+import           Data.Aeson                      (decode, encode)+import           Data.Aeson.Encode.Pretty        (encodePretty)+import           Data.ByteString.Lazy.Char8      (ByteString)+import qualified Data.ByteString.Lazy.Char8      as BS (pack, unpack)+import           Data.HashMap.Lazy               (lookup)+import           Data.List                       (isPrefixOf)+import           Data.Map                        (fromList)+import           Data.Maybe                      (fromMaybe)+import           Data.Text                       (breakOn)+import qualified Data.Text                       as T (pack, unpack)+import           Development.Duplo.Types.AppInfo (AppInfo (..)) import qualified Development.Duplo.Types.AppInfo as AI import qualified Development.Duplo.Types.Builder as BD+import qualified Development.Duplo.Types.Config  as TC+import           Development.Shake               hiding (doesDirectoryExist,+                                                  doesFileExist,+                                                  getDirectoryContents)+import           Development.Shake.FilePath      ((</>))+import           Prelude                         hiding (lookup)+import           System.Directory                (doesDirectoryExist,+                                                  doesFileExist,+                                                  getCurrentDirectory,+                                                  getDirectoryContents)+import           System.FilePath.Posix           (splitDirectories)  type Version = (String, String)  -- | Each application must have a `component.json`+manifestName :: FilePath manifestName = "component.json"  readManifest :: IO AppInfo@@ -66,22 +69,24 @@ -- constituents parseComponentId :: String -> Either String (String, String) parseComponentId cId-  | repoL > 0 = Right (T.unpack user, T.unpack repo)+  | repoL > 0 = Right (T.unpack user, T.unpack userRepo)   | otherwise = Left $ "No component ID found with " ++ cId   where-    (user, repo) = breakOn (T.pack "-") (T.pack cId)-    repoL = length $ T.unpack repo+    (user, userRepo) = breakOn (T.pack "-") (T.pack cId)+    repoL = length $ T.unpack userRepo  -- | Given a path, find all the `component.json` and return a JSON string-extractCompVersions :: FilePath -> IO String-extractCompVersions path = do+extractCompVersions :: TC.BuildConfig -> Action String+extractCompVersions config = do+    let path     = config ^. TC.cwd+    let utilPath = config ^. TC.utilPath     -- Get all the relevant paths-    paths <- getAllManifestPaths path+    paths <- getAllManifestPaths utilPath path     -- Construct the pipeline-    let toVersion path = appInfoToVersion . decodeManifest path . BS.pack-    let takeVersion path = liftM (toVersion path) (readFile path)+    let toVersion path'   = appInfoToVersion . decodeManifest path' . BS.pack+    let takeVersion path' = liftM (toVersion path') (readFile path')     -- Go through it-    manifests <- mapM takeVersion paths+    manifests <- mapM (liftIO . takeVersion) paths     -- Marshalling     return $ BS.unpack $ encode $ fromList manifests @@ -97,19 +102,10 @@ appInfoToVersion appInfo = (AI.name appInfo, AI.version appInfo)  -- | Given a path, find all the `component.json`s-getAllManifestPaths :: FilePath -> IO [FilePath]-getAllManifestPaths root = allPaths-  where-    -- Filter for `component.json`.-    matchName path t = takeFileName path == takeFileName manifestName-    filterP          = filterPredicate matchName-    -- We only care about the root directory and the `components/` directory.-    componentsPath   = dropTrailingPathSeparator $ root </> "components/"-    proceed absPath  = equalFilePath root absPath-                    || componentsPath `isPrefixOf` absPath-    recurseP         = recursePredicate proceed-    -- Collect the paths here.-    allPaths         = findp filterP recurseP root+getAllManifestPaths :: FilePath -> FilePath -> Action [FilePath]+getAllManifestPaths utilPath root = do+    Stdout out <- command [] (utilPath </> "find.sh") [root, manifestName]+    return $ lines out  -- | Get the component dependency list by providing a mode, or not. getDependencies :: Maybe String -> IO [FilePath]@@ -136,9 +132,9 @@ -- dependency list, all modes, and the target mode to select the list by. getDependencies' :: AI.Dependencies -> Maybe [String] -> IO [FilePath] -- If somehow there isn't a mode defined, switch over to `Nothing`.-getDependencies' deps Nothing = getDependencies Nothing+getDependencies' _ Nothing = getDependencies Nothing -- If there is something, fetch only those dependencies.-getDependencies' deps (Just modeDeps) = return modeDeps+getDependencies' _ (Just modeDeps) = return modeDeps  -- | Regular file != *nix-style hidden file isRegularFile :: FilePath -> Bool
src/Development/Duplo/FileList.hs view
@@ -2,13 +2,13 @@  module Development.Duplo.FileList where -import Control.Lens hiding (Action)-import Control.Lens.TH (makeLenses)-import Control.Monad (liftM, msum)-import Data.Maybe (Maybe(..), catMaybes)-import Development.Shake-import Development.Shake.FilePath ((</>))-import System.FilePath.Posix (makeRelative)+import           Control.Lens               hiding (Action)+import           Control.Lens.TH            (makeLenses)+import           Control.Monad              (liftM, msum)+import           Data.Maybe                 (Maybe (..), catMaybes)+import           Development.Shake+import           Development.Shake.FilePath ((</>))+import           System.FilePath.Posix      (makeRelative)  data File = File { _filePath :: FilePath                  , _fileBase :: FilePath
src/Development/Duplo/Files.hs view
@@ -2,19 +2,14 @@  module Development.Duplo.Files where -import Control.Exception (throw)-import Control.Lens hiding (Action)-import Control.Lens.TH (makeLenses)-import Control.Monad.Except (ExceptT(..), runExceptT)-import Control.Monad.Trans.Class (lift)-import Data.List (intercalate)-import Data.Text (split, pack, unpack)-import Development.Duplo.Component (appId)-import Development.Shake hiding (readFile)-import Prelude hiding (readFile)-import System.FilePath.Posix (makeRelative, splitDirectories, joinPath)+import           Control.Lens                hiding (Action)+import           Control.Monad.Trans.Class   (lift)+import           Control.Monad.Trans.Maybe   (MaybeT (..))+import           Development.Duplo.Component (appId) import qualified Development.Duplo.Component as CM-import qualified Development.Duplo.Types.Builder as BD+import           Development.Shake           (Action, liftIO, readFile')+import           System.FilePath.Posix       (joinPath, makeRelative,+                                              splitDirectories)  type FileName    = String type FileContent = String@@ -28,6 +23,7 @@                         , _isRoot      :: Bool                         } deriving (Show) +pseudoFile :: File pseudoFile = File { _filePath    = ""                   , _fileDir     = ""                   , _fileName    = ""@@ -38,24 +34,24 @@  makeLenses ''File -readFile :: FilePath -> FilePath -> ExceptT String Action File+readFile :: FilePath -> FilePath -> MaybeT Action File readFile cwd path = do-  let (fileDir, fileName) = parseFilePath path-  fileContent <- lift $ readFile' path-  appInfo <- liftIO CM.readManifest-  let appId' = appId appInfo-  let componentId = parseComponentId cwd appId' fileDir-  let isRoot = componentId == appId'-  return $ File path fileDir fileName componentId fileContent isRoot+  let (fDir, fName) = parseFilePath path+  fContent <- lift $ readFile' path+  appInfo  <- liftIO CM.readManifest+  let appId'  = appId appInfo+  let cId     = parseComponentId cwd appId' fDir+  let isRoot' = cId == appId'+  return $ File path fDir fName cId fContent isRoot'  parseFilePath :: FilePath -> (FilePath, FileName)-parseFilePath path = (fileDir, fileName)+parseFilePath path = (fDir, fName)   where     segments  = splitDirectories path     segLength = length segments     dirLength = segLength - 1-    fileDir   = joinPath $ take dirLength segments-    fileName  = segments !! dirLength+    fDir      = joinPath $ take dirLength segments+    fName     = segments !! dirLength  -- | Given a default component ID (usually the ID of the project on which -- duplo is run) and the file path, deduce the component ID of a particular@@ -67,5 +63,5 @@     segments = splitDirectories relPath   in     case segments of-      ("components" : appId : xs) -> appId-      _                           -> defaultId+      ("components" : aId : _) -> aId+      _                        -> defaultId
src/Development/Duplo/Git.hs view
@@ -1,16 +1,15 @@ module Development.Duplo.Git where -import Control.Applicative ((<$>))-import Control.Lens hiding (Action, Level)-import Control.Monad.Except (runExceptT)-import Data.List (intercalate, filter)-import Data.Text (unpack, pack, splitOn)-import Development.Shake-import Development.Shake.FilePath ((</>))-import System.FilePath.Posix (makeRelative)-import qualified Development.Duplo.Component as CM+import           Control.Applicative             ((<$>))+import           Control.Lens                    hiding (Action, Level)+import           Data.List                       (filter, intercalate)+import           Data.Text                       (pack, splitOn, unpack)+import qualified Development.Duplo.Component     as CM import qualified Development.Duplo.Types.AppInfo as AI-import qualified Development.Duplo.Types.Config as TC+import qualified Development.Duplo.Types.Config  as TC+import           Development.Shake+import           Development.Shake.FilePath      ((</>))+import           System.FilePath.Posix           (makeRelative)  type Level         = String type Version       = String
src/Development/Duplo/JavaScript/Order.hs view
@@ -2,19 +2,24 @@  module Development.Duplo.JavaScript.Order where -import Control.Applicative ((<$>))-import Control.Exception (throw)-import Control.Lens (makeLenses, ix)-import Control.Lens.Operators-import Control.Monad (liftM, when, void)-import Control.Monad.State.Lazy (get, put, state, execState)-import Control.Monad.Writer.Lazy (Writer, tell, runWriter)-import Data.Function (on)-import Data.List (findIndex, sortBy, nubBy)-import Data.Maybe (isJust, fromJust, fromMaybe)-import Development.Duplo.Types.JavaScript-import Language.JavaScript.Parser (JSNode(..), Node(..), TokenPosn(..))+import           Control.Applicative                ((<$>))+import           Control.Exception                  (throw)+import           Control.Lens                       (ix, makeLenses)+import           Control.Lens.Operators+import           Control.Monad                      (liftM, void, when)+import           Control.Monad.State.Lazy           (execState, get, put, state)+import           Control.Monad.Writer.Lazy          (Writer, runWriter, tell)+import           Data.Function                      (on)+import           Data.List                          (findIndex, nubBy, sortBy)+import           Data.Maybe                         (fromJust, fromMaybe,+                                                     isJust)+import           Development.Duplo.Types.JavaScript+import           Language.JavaScript.Parser         (JSNode (..), Node (..),+                                                     TokenPosn (..)) +import           Debug.Trace+trace' a = trace (show a) a+ makeLenses ''Module  -- | Reorder modules within the root node.@@ -68,11 +73,15 @@     (nameNT:_:depsNT:_) = argNTs     -- Extract the name, always first argument.     (NT (JSStringLiteral _ moduleName) _ _) = nameNT-    -- Extract the module dependencies, always the third argument (second-    -- being the comma separator).-    (NN (JSArrayLiteral _ depsNodes _)) = depsNT+    -- Extract the module dependencies. The dependency list is always the+    -- third argument; otherwise, there's an issue.+    (NN (JSArrayLiteral _ depsNodes _)) = matchDependencies moduleName depsNT     -- Only take the strings.     deps = map fromJust $ filter isJust $ map stringLiteralNT depsNodes++matchDependencies :: String -> JSNode -> JSNode+matchDependencies _ node@(NN (JSArrayLiteral _ depsNodes _)) = node+matchDependencies moduleName _ = throw $ MissingDependencies moduleName  -- | Given a JSNode, return just the string literal, or nothing stringLiteralNT :: JSNode -> Maybe String
src/Development/Duplo/Markups.hs view
@@ -1,22 +1,29 @@ module Development.Duplo.Markups where -import Control.Applicative ((<$>))-import Control.Exception (throw)-import Control.Lens hiding (Action)-import Control.Monad.Trans.Class (lift)-import Data.Maybe (fromMaybe)-import Development.Duplo.Component (parseComponentId)-import Development.Duplo.FileList (collapseFileList, makeFile)-import Development.Duplo.Files (File(..), filePath, fileDir, fileName, componentId, fileContent, isRoot, ComponentId)-import Development.Duplo.Utilities (logStatus, headerPrintSetter, expandPaths, compile, createIntermediaryDirectories, CompiledContent, expandDeps)-import Development.Shake-import Development.Shake.FilePath ((</>))-import System.Directory (findFile)-import System.FilePath.Posix (makeRelative, splitDirectories, joinPath)-import qualified Development.Duplo.FileList as FileList (filePath)+import           Control.Applicative             ((<$>))+import           Control.Exception               (throw)+import           Control.Lens                    hiding (Action)+import           Control.Monad.Trans.Class       (lift)+import           Data.List.Utils                 (replace)+import           Data.Maybe                      (fromMaybe)+import           Development.Duplo.Component     (parseComponentId)+import           Development.Duplo.FileList      (collapseFileList, makeFile)+import qualified Development.Duplo.FileList      as FileList (filePath)+import           Development.Duplo.Files         (ComponentId, File (..),+                                                  componentId, fileContent,+                                                  fileDir, fileName, filePath,+                                                  isRoot) import qualified Development.Duplo.Types.Builder as BD-import qualified Development.Duplo.Types.Config as TC-import Data.List.Utils (replace)+import qualified Development.Duplo.Types.Config  as TC+import           Development.Duplo.Utilities     (CompiledContent, compile,+                                                  createIntermediaryDirectories,+                                                  expandDeps, expandPaths,+                                                  headerPrintSetter, logStatus)+import           Development.Shake+import           Development.Shake.FilePath      ((</>))+import           System.Directory                (findFile)+import           System.FilePath.Posix           (joinPath, makeRelative,+                                                  splitDirectories)  build :: TC.BuildConfig       -> FilePath@@ -93,7 +100,7 @@                                                    ]    let buildScriptTag path = "<script defer=\"defer\" src=\"" ++ makeRelative cwd path ++ "\"></script>"-  let scriptsTags         = concat $ map buildScriptTag scriptsPaths+  let scriptsTags         = concatMap buildScriptTag scriptsPaths   let indexWithTestRefs   = if   inTest                             then replace "</head>" (refTagsInTest ++ scriptsTags ++ "</head>") indexWithRefs                             else indexWithRefs
src/Development/Duplo/Scripts.hs view
@@ -2,28 +2,36 @@  module Development.Duplo.Scripts where -import Control.Applicative ((<*>), (<$>))-import Control.Exception (throw, SomeException(..))-import Control.Lens hiding (Action)-import Control.Monad (filterM)-import Control.Monad.Trans.Class (lift)-import Data.Function (on)-import Data.List (intercalate, nubBy)-import Data.Text.Format (left)-import Data.Text.Lazy (Text, pack, unpack, replace, splitOn)-import Data.Text.Lazy.Builder (toLazyText)-import Development.Duplo.Component (extractCompVersions)-import Development.Duplo.Files (File(..), pseudoFile)-import Development.Duplo.JavaScript.Order (order)-import Development.Duplo.Types.JavaScript-import Development.Duplo.Utilities (logStatus, headerPrintSetter, expandPaths, compile, createIntermediaryDirectories, CompiledContent, expandDeps)-import Development.Shake-import Development.Shake.FilePath ((</>))-import Language.JavaScript.Parser.SrcLocation (TokenPosn(..))-import Text.Regex (mkRegex, matchRegex)-import qualified Development.Duplo.Component as CM-import qualified Development.Duplo.Types.Config as TC-import qualified Language.JavaScript.Parser as JS+import           Control.Applicative                    ((<$>), (<*>))+import           Control.Exception                      (SomeException (..),+                                                         throw)+import           Control.Lens                           hiding (Action)+import           Control.Monad                          (filterM)+import           Control.Monad.Trans.Class              (lift)+import           Control.Monad.Trans.Maybe              (MaybeT (..))+import           Data.Function                          (on)+import           Data.List                              (intercalate, nubBy)+import           Data.Text.Format                       (left)+import           Data.Text.Lazy                         (Text, pack, replace,+                                                         splitOn, unpack)+import           Data.Text.Lazy.Builder                 (toLazyText)+import           Development.Duplo.Component            (extractCompVersions)+import qualified Development.Duplo.Component            as CM+import           Development.Duplo.Files                (File (..), pseudoFile)+import           Development.Duplo.JavaScript.Order     (order)+import qualified Development.Duplo.Types.Config         as TC+import           Development.Duplo.Types.JavaScript+import           Development.Duplo.Utilities            (CompiledContent,+                                                         compile, createIntermediaryDirectories,+                                                         expandDeps,+                                                         expandPaths,+                                                         headerPrintSetter,+                                                         logStatus)+import           Development.Shake+import           Development.Shake.FilePath             ((</>))+import qualified Language.JavaScript.Parser             as JS+import           Language.JavaScript.Parser.SrcLocation (TokenPosn (..))+import           Text.Regex                             (matchRegex, mkRegex)  -- | How many lines to display around the source of error (both ways). errorDisplayRange :: Int@@ -87,7 +95,7 @@   let duploIn = if not (null input) then input else ""    -- Figure out each component's version-  compVers <- liftIO $ extractCompVersions cwd+  compVers <- lift $ extractCompVersions config    -- Inject global/environment variables   let envVars = "var DUPLO_ENV = '" ++ env ++ "';\n"
src/Development/Duplo/Server.hs view
@@ -1,18 +1,18 @@ module Development.Duplo.Server where -import Control.Monad.Trans (liftIO)-import Data.List (intercalate)-import Data.Text (Text)-import Data.Text.Lazy (Text)-import Network.HTTP.Types (status200)-import Network.Wai (pathInfo)-import Network.Wai.Handler.Warp (Port)-import System.Directory (doesFileExist)-import System.Environment (getArgs)-import System.FilePath.Posix (takeExtension)-import Web.Scotty-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT+import           Control.Monad.Trans      (liftIO)+import           Data.List                (intercalate)+import           Data.Text                (Text)+import qualified Data.Text                as T+import           Data.Text.Lazy           (Text)+import qualified Data.Text.Lazy           as LT+import           Network.HTTP.Types       (status200)+import           Network.Wai              (pathInfo)+import           Network.Wai.Handler.Warp (Port)+import           System.Directory         (doesFileExist)+import           System.Environment       (getArgs)+import           System.FilePath.Posix    (takeExtension)+import           Web.Scotty  serve :: Port -> IO () serve port = do
src/Development/Duplo/Static.hs view
@@ -1,16 +1,21 @@ module Development.Duplo.Static where -import Control.Applicative ((<$>))-import Control.Lens hiding (Action)-import Control.Monad (zipWithM_, filterM)-import Data.List (transpose, nub)-import Development.Duplo.FileList (makeFile, makeFiles, toCopies, collapseFileLists, Copy)-import Development.Duplo.Utilities (logStatus, headerPrintSetter, createIntermediaryDirectories, createPathDirectories, getDirectoryFiles)-import Development.Shake hiding (getDirectoryFiles)-import Development.Shake.FilePath ((</>))-import System.FilePath.Posix (splitExtension, splitDirectories, makeRelative)-import qualified Development.Duplo.FileList as FileList (filePath)+import           Control.Applicative            ((<$>))+import           Control.Lens                   hiding (Action)+import           Control.Monad                  (filterM, zipWithM_)+import           Data.List                      (nub, transpose)+import           Development.Duplo.FileList     (Copy, collapseFileLists,+                                                 makeFile, makeFiles, toCopies)+import qualified Development.Duplo.FileList     as FileList (filePath) import qualified Development.Duplo.Types.Config as TC+import           Development.Duplo.Utilities    (createIntermediaryDirectories,+                                                 createPathDirectories,+                                                 getDirectoryFiles,+                                                 headerPrintSetter, logStatus)+import           Development.Shake              hiding (getDirectoryFiles)+import           Development.Shake.FilePath     ((</>))+import           System.FilePath.Posix          (makeRelative, splitDirectories,+                                                 splitExtension)  build :: TC.BuildConfig       -> [FilePath]
src/Development/Duplo/Styles.hs view
@@ -1,11 +1,14 @@ module Development.Duplo.Styles where -import Control.Lens hiding (Action)-import Control.Monad.Trans.Class (lift)-import Development.Duplo.Utilities (logStatus, headerPrintSetter, expandPaths, compile, createIntermediaryDirectories, CompiledContent, expandDeps)-import Development.Shake-import Development.Shake.FilePath ((</>))+import           Control.Lens                   hiding (Action)+import           Control.Monad.Trans.Class      (lift) import qualified Development.Duplo.Types.Config as TC+import           Development.Duplo.Utilities    (CompiledContent, compile,+                                                 createIntermediaryDirectories,+                                                 expandDeps, expandPaths,+                                                 headerPrintSetter, logStatus)+import           Development.Shake+import           Development.Shake.FilePath     ((</>))  build :: TC.BuildConfig       -> FilePath
src/Development/Duplo/Types/AppInfo.hs view
@@ -2,9 +2,9 @@  module Development.Duplo.Types.AppInfo where -import Data.Aeson (FromJSON, ToJSON)-import Data.HashMap.Strict (HashMap, empty)-import GHC.Generics (Generic)+import           Data.Aeson          (FromJSON, ToJSON)+import           Data.HashMap.Strict (HashMap, empty)+import           GHC.Generics        (Generic)  type Dependencies = HashMap String String type Modes = HashMap String [String]
src/Development/Duplo/Types/Builder.hs view
@@ -2,8 +2,8 @@  module Development.Duplo.Types.Builder where -import Control.Exception (Exception)-import Data.Typeable (Typeable)+import           Control.Exception (Exception)+import           Data.Typeable     (Typeable)  data BuilderException = MissingGithubUserException                       | MissingGithubRepoException
src/Development/Duplo/Types/Config.hs view
@@ -2,10 +2,10 @@  module Development.Duplo.Types.Config where -import Control.Lens hiding (Action)-import Control.Lens.TH (makeLenses)-import Development.Shake-import Network.Wai.Handler.Warp (Port)+import           Control.Lens             hiding (Action)+import           Control.Lens.TH          (makeLenses)+import           Development.Shake+import           Network.Wai.Handler.Warp (Port)  data BuildConfig = BuildConfig { _appName      :: String                                , _appVersion   :: String
src/Development/Duplo/Types/JavaScript.hs view
@@ -2,15 +2,16 @@  module Development.Duplo.Types.JavaScript where -import Control.Exception (Exception)-import Control.Monad.State.Lazy (State)-import Data.List (intercalate)-import Data.Typeable (Typeable)-import Language.JavaScript.Parser (JSNode(..))+import           Control.Exception          (Exception)+import           Control.Monad.State.Lazy   (State)+import           Data.List                  (intercalate)+import           Data.Typeable              (Typeable)+import           Language.JavaScript.Parser (JSNode (..))  data JSCompilerException = ModuleNotFoundException ModuleName                          | CircularDependencyException [ModuleName]                          | ParseException [String]+                         | MissingDependencies String                          -- When the compiler itself is buggy                          | InternalParserException String                          -- When language-javascript somehow produces@@ -31,6 +32,8 @@       "Uh oh. The parser itself is misbehaving: " ++ e     show (LanguageJavaScriptException element) =       "language-javascript is not parsing the file correctly:\n" ++ show element+    show (MissingDependencies name) =+      "Module `" ++ name ++ "` is missing a dependency array in its `define()`."  type LineNumber = Int type ModuleName = String
src/Development/Duplo/Types/Options.hs view
@@ -1,6 +1,6 @@ module Development.Duplo.Types.Options where -import System.Console.GetOpt (OptDescr(..), ArgDescr(..))+import           System.Console.GetOpt (ArgDescr (..), OptDescr (..))  data Options = Options { optVerbose :: Bool                        , optVersion :: Bool
src/Development/Duplo/Utilities.hs view
@@ -1,25 +1,26 @@ module Development.Duplo.Utilities where -import Control.Applicative ((<$>))-import Control.Lens.Operators-import Control.Monad (filterM, zipWithM)-import Control.Monad.Except (ExceptT(..), runExceptT)-import Control.Monad.IO.Class (MonadIO)-import Control.Monad.Trans.Class (lift)-import Data.List (intercalate, isSuffixOf)-import Development.Duplo.Files (readFile, File(..), fileContent)-import Development.Shake (CmdOption(..))-import Development.Shake.FilePath ((</>))-import Prelude hiding (readFile)-import System.Console.ANSI (setSGR, SGR(..), ConsoleLayer(..), ColorIntensity(..), Color(..))-import System.FilePath.Posix (joinPath, splitPath)-import qualified Control.Lens as CL-import qualified Development.Duplo.Component as CM-import qualified Development.Duplo.Types.AppInfo as AI+import           Control.Applicative            ((<$>))+import           Control.Lens.Operators+import           Control.Monad                  (filterM, zipWithM)+import           Control.Monad.IO.Class         (MonadIO)+import           Control.Monad.Trans.Class      (lift)+import           Control.Monad.Trans.Maybe      (MaybeT (..))+import           Data.List                      (intercalate)+import           Development.Duplo.Files        (File (..), fileContent,+                                                 readFile) import qualified Development.Duplo.Types.Config as TC-import qualified Development.Shake as DS+import           Development.Shake              (CmdOption (..))+import qualified Development.Shake              as DS+import           Development.Shake.FilePath     ((</>))+import           Prelude                        hiding (readFile)+import           System.Console.ANSI            (Color (..),+                                                 ColorIntensity (..),+                                                 ConsoleLayer (..), SGR (..),+                                                 setSGR)+import           System.FilePath.Posix          (joinPath, splitPath) -type CompiledContent = ExceptT String DS.Action+type CompiledContent = MaybeT DS.Action type FileProcessor = [File] -> CompiledContent [File] type StringProcessor = String -> CompiledContent String @@ -40,12 +41,12 @@ -- for a list of file patterns. makeFilePatterns :: [FilePath] -> [String] -> DS.Action [DS.FilePattern] makeFilePatterns bases exts = do-    patternList  <- zipWithM makeValidPattern bases exts-    let concat   =  foldl1 (++)+    patternList <- zipWithM makeValidPattern bases exts+    let conc =  foldl1 (++)     -- Avoid infinite list.     let patterns =  if   null patternList                     then return []-                    else concat patternList+                    else conc patternList     return patterns  -- | Given a working directory and a list of patterns, expand all the
src/Development/Duplo/Watcher.hs view
@@ -1,15 +1,20 @@ module Development.Duplo.Watcher where -import Control.Concurrent (threadDelay, forkIO, forkFinally, ThreadId(..), killThread)-import Control.Concurrent.Chan (Chan, newChan, readChan, getChanContents)-import Control.Exception (try)-import Control.Monad (forever, void, when, unless)-import Data.Foldable (forM_)-import Data.IORef (newIORef, readIORef, writeIORef, IORef)-import Data.Maybe (isJust, fromJust)-import Data.String (fromString)-import System.FSNotify (withManagerConf, watchTreeChan, WatchConfig(..), Debounce(..), Action, Event)-import System.FilePath.Posix (FilePath)+import           Control.Concurrent      (ThreadId (..), forkFinally, forkIO,+                                          killThread, threadDelay)+import           Control.Concurrent.Chan (Chan, getChanContents, newChan,+                                          readChan)+import           Control.Exception       (try)+import           Control.Monad           (forever, unless, void, when)+import           Data.Foldable           (forM_)+import           Data.IORef              (IORef, newIORef, readIORef,+                                          writeIORef)+import           Data.Maybe              (fromJust, isJust)+import           Data.String             (fromString)+import           System.FilePath.Posix   (FilePath)+import           System.FSNotify         (Action, Debounce (..), Event,+                                          WatchConfig (..), watchTreeChan,+                                          withManagerConf)  -- | Given some paths to watch and something to do, watch every 100ms -- without debouncing but would interrupt the action when there is a new
tests/Tests.hs view
@@ -1,30 +1,43 @@-{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  module Main where -import Development.Duplo.Types.AppInfo-import Test.Hspec-import Test.QuickCheck-import qualified Development.Duplo.Component as DC-import Data.Functor (fmap)+import qualified Development.Duplo.Component     as DC+import           Development.Duplo.Types.AppInfo+import           Test.HUnit                      ()+import           Test.QuickCheck                 () -runTests = $verboseCheckAll+import           Test.Tasty+import           Test.Tasty.HUnit+import           Test.Tasty.QuickCheck           as QC  main :: IO ()-main = do-  -- First QuickCheck-  verboseCheck prop_slashToDash+main = defaultMain tests -  -- Then HSpec-  hspec $-    describe "Component support" $ do-      it "extracts component ID" $ do-        let appInfo = defaultAppInfo { repo = "pixbi/duplo" }-        let appId   = DC.appId appInfo-        appId `shouldBe` "pixbi-duplo"+tests :: TestTree+tests = testGroup "Tests"+  [ testGroup "Component support"+    [ QC.testProperty "slash is transformed into dash" $ \appInfo ->+        let+          value        = DC.appId appInfo+          repo'        = repo appInfo+          onlyOneSlash = (== 1) . length . filter (== '/')+        in+          not (null repo')    ==>+          (head repo' /= '/') ==>+          (last repo' /= '/') ==>+          onlyOneSlash repo'  ==>+            value == replaceFirst '/' '-' repo' -  return ()+    , testCase "extracts component ID" $ do+      let appInfo = defaultAppInfo { repo = "pixbi/duplo" }+      let appId   = DC.appId appInfo+      appId @?= "pixbi-duplo" +    ]+  ]++ newtype NameString = NameString                      { unwrapNameString :: String                      } deriving Show@@ -32,24 +45,13 @@ instance Arbitrary NameString where     arbitrary = fmap NameString $ listOf $ elements $ ['a'..'z']                                                     ++ ['A'..'Z']-                                                    ++ ['/', '-']+                                                    ++ "/-"  instance Arbitrary AppInfo where     arbitrary = do       nameString  <- arbitrary :: Gen NameString       let string = unwrapNameString nameString       return defaultAppInfo { repo = string }--prop_slashToDash appInfo =-    (not (null repo'))   ==>-    (head repo' /= '/')  ==>-    (last repo' /= '/')  ==>-    (onlyOneSlash repo') ==>-      value == replaceFirst '/' '-' repo'-  where-    value        = DC.appId appInfo-    repo'        = repo appInfo-    onlyOneSlash = (== 1) . length . filter (== '/')  -- | Replace the first occurence of a character in a string. replaceFirst :: Char -> Char -> String -> String