packages feed

duplo 1.6.19 → 1.8.0

raw patch · 15 files changed

+237/−189 lines, 15 filesdep ~HUnitdep ~MissingHdep ~QuickCheck

Dependency ranges changed: HUnit, MissingH, QuickCheck, aeson, aeson-pretty, ansi-terminal, base, base64-bytestring, bytestring, containers, directory, executable-path, filepath, fsnotify, http-types, language-javascript, lens, mtl, process, regex-compat, scotty, shake, system-fileio, system-filepath, tasty, tasty-hunit, tasty-quickcheck, text, text-format, transformers, unordered-containers, utf8-string, wai, warp

Files

README.md view
@@ -86,7 +86,7 @@                         replace those with the same name under `app/assets/`.     dev/modules/    --> Works just like `app/modules/`.     public/         --> Built files when developing. Not committed to source-    test/           --> Test files go here+    tests/          --> Test files go here   ## Development@@ -121,21 +121,27 @@  ``` root-|-- app/modules+|-- app/modules/     |-- a.js     |-- b.js-|-- test/modules+    |-- c/+        |- d.js+|-- tests/     |-- test-a.js     |-- test-b.js+    |-- c/+        |-- d.js ``` -When testing your codebase, structure your project like the above. And then, we-take a look at how to write a test file in directory `test/modules`:+When testing your codebase, structure your project like the above. Note that+the path relative to `tests/` should correspond to the path relative to+`app/modules/`. +An example of a test suite:+ ```js-define('name this to whatever but do not conflict with your module (e.g. test-a)',-['moduleA'],-function (a) {+define('name this to whatever but do not conflict with your module (e.g. `test-a`)',+['moduleA'], function (a) {    describe('some text', function () {     it('should ...', function () {@@ -148,14 +154,12 @@ }); ``` -Duplo's test suite includes [mocha](http://mochajs.org/) and-[chai.js](http://chaijs.com/).--By the way, it supports another powerful testing tool,+Duplo's test suite uses [mocha](http://mochajs.org/) and+[chai.js](http://chaijs.com/). It also supports another powerful testing tool, [SinonJS](http://sinonjs.org/), so you may fake/mock any functions, ajax-requests and timers yourself.+requests, and timers yourself. -As so far, Duplo's test environment includes these 3 modules:+You may therefore use these functions:  - mocha: `describe`, `it` and etc. - chai.js: `expect` and `assert`.@@ -386,6 +390,10 @@ 3. `$ util/publish.sh` 4. `$ npm publish` 5. [Publish to Hackage](http://hackage.haskell.org/upload)++Note: *ALWAYS* always use [Stackage](http://www.stackage.org/) while do not+specify versions in the Cabal file. Just specify the dependencies by name and+let Stackage manage the versions.   ## Copyright and License
duplo.cabal view
@@ -1,5 +1,5 @@ name:               duplo-version:            1.6.19+version:            1.8.0 synopsis:           Frontend development build tool description:        Intuitive, simple building blocks for building composable, completely self-managed web applications license:            MIT@@ -16,101 +16,101 @@   location: https://github.com/pixbi/duplo.git  library-  ghc-options        : -Wall-  hs-source-dirs     : src-  default-language   : Haskell2010-  default-extensions : OverloadedStrings-  exposed-modules    : Development.Duplo-                     , Development.Duplo.Component-                     , Development.Duplo.FileList-                     , Development.Duplo.Files-                     , Development.Duplo.Git-                     , Development.Duplo.JavaScript.Order-                     , Development.Duplo.Markups-                     , Development.Duplo.Scripts-                     , Development.Duplo.Server-                     , Development.Duplo.Static-                     , Development.Duplo.Styles-                     , Development.Duplo.Types.AppInfo-                     , Development.Duplo.Types.Builder-                     , Development.Duplo.Types.Config-                     , Development.Duplo.Types.JavaScript-                     , Development.Duplo.Types.Options-                     , Development.Duplo.Utilities-                     , Development.Duplo.Watcher-  build-depends      : base                               == 4.7.*-                     , aeson                              == 0.8.*-                     , aeson-pretty                       == 0.7.*-                     , ansi-terminal                      == 0.6.*-                     , bytestring                         == 0.10.*-                     , containers                         == 0.5.*-                     , directory                          == 1.2.*-                     , executable-path                    == 0.0.*-                     , filepath                           == 1.3.*-                     , fsnotify                           == 0.1.*-                     , http-types                         == 0.8.*-                     , language-javascript                == 0.5.*-                     , lens                               == 4.6.*-                     , mtl                                == 2.1.*-                     , regex-compat                       == 0.95.*-                     , scotty                             == 0.9.*-                     , shake                              == 0.14.*-                     , system-fileio                      == 0.3.*-                     , text                               == 1.2.*-                     , text-format                        == 0.3.*-                     , transformers                       == 0.3.*-                     , unordered-containers               == 0.2.*-                     , utf8-string                        == 0.3.*-                     , wai                                == 3.0.*-                     , warp                               == 3.0.*-                     , MissingH                           == 1.3.*+  ghc-options:          -Wall+  hs-source-dirs:       src+  default-language:     Haskell2010+  default-extensions:   OverloadedStrings+  exposed-modules:      Development.Duplo+                      , Development.Duplo.Component+                      , Development.Duplo.FileList+                      , Development.Duplo.Files+                      , Development.Duplo.Git+                      , Development.Duplo.JavaScript.Order+                      , Development.Duplo.Markups+                      , Development.Duplo.Scripts+                      , Development.Duplo.Server+                      , Development.Duplo.Static+                      , Development.Duplo.Styles+                      , Development.Duplo.Types.AppInfo+                      , Development.Duplo.Types.Builder+                      , Development.Duplo.Types.Config+                      , Development.Duplo.Types.JavaScript+                      , Development.Duplo.Types.Options+                      , Development.Duplo.Utilities+                      , Development.Duplo.Watcher+  build-depends:        base == 4.7.*+                      , aeson+                      , aeson-pretty+                      , ansi-terminal+                      , bytestring+                      , containers+                      , directory+                      , executable-path+                      , filepath+                      , fsnotify+                      , http-types+                      , language-javascript+                      , lens+                      , mtl+                      , regex-compat+                      , scotty+                      , shake+                      , system-fileio+                      , text+                      , text-format+                      , transformers+                      , unordered-containers+                      , utf8-string+                      , wai+                      , warp+                      , MissingH  executable duplo-  main-is            : CLI.hs-  ghc-options        : -rtsopts-  hs-source-dirs     : src-  default-language   : Haskell2010-  default-extensions : OverloadedStrings-  build-depends      : base                 == 4.7.*-                     , aeson                == 0.8.*-                     , aeson                == 0.8.*-                     , aeson-pretty         == 0.7.*-                     , ansi-terminal        == 0.6.*-                     , base64-bytestring    == 1.0.*-                     , bytestring           == 0.10.*-                     , containers           == 0.5.*-                     , directory            == 1.2.*-                     , duplo-                     , filepath             == 1.3.*-                     , fsnotify             == 0.1.*-                     , http-types           == 0.8.*-                     , language-javascript  == 0.5.*-                     , 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.2.*-                     , text-format          == 0.3.*-                     , transformers         == 0.3.*-                     , unordered-containers == 0.2.*-                     , wai                  == 3.0.*-                     , warp                 == 3.0.*-                     , MissingH             == 1.3.*+  main-is:              CLI.hs+  ghc-options:          -rtsopts+  hs-source-dirs:       src+  default-language:     Haskell2010+  default-extensions:   OverloadedStrings+  build-depends:        base == 4.7.*+                      , aeson+                      , aeson+                      , aeson-pretty+                      , ansi-terminal+                      , base64-bytestring+                      , bytestring+                      , containers+                      , directory+                      , duplo+                      , filepath+                      , fsnotify+                      , http-types+                      , language-javascript+                      , lens+                      , mtl+                      , process+                      , regex-compat+                      , scotty+                      , shake+                      , system-filepath+                      , text+                      , text-format+                      , transformers+                      , unordered-containers+                      , wai+                      , warp+                      , MissingH  test-suite tests-  main-is          : Tests.hs-  ghc-options      : -Wall-  hs-source-dirs   : tests-  default-language : Haskell2010-  type             : exitcode-stdio-1.0-  build-depends    : base-                   , duplo-                   , 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+  main-is:            Tests.hs+  ghc-options:        -Wall+  hs-source-dirs:     tests+  default-language:   Haskell2010+  type:               exitcode-stdio-1.0+  build-depends:      base == 4.7.*+                    , duplo+                    , HUnit+                    , MissingH+                    , QuickCheck+                    , tasty+                    , tasty-hunit+                    , tasty-quickcheck
src/CLI.hs view
@@ -80,7 +80,7 @@   let defaultsPath    = miscPath </> "static/"   let appPath         = cwd </> "app/"   let devPath         = cwd </> "dev/"-  let testPath        = cwd </> "test/"+  let testPath        = cwd </> "tests/"   let assetsPath      = appPath </> "assets/"   let depsPath        = cwd </> "components/"   let targetPath      = cwd </> "public/"@@ -90,7 +90,7 @@                     -- `build` is a special case. It takes `production` as the                     -- default.                     "build" -> fromMaybe "production" duploEnvMB-                    -- By default, `dev` is the default.+                    -- `dev` is the default.                     _ -> fromMaybe "development" duploEnvMB    -- Internal command translation@@ -108,7 +108,7 @@           "live"       -> ( "build"   , ""      , "production"  , True  )           "production" -> ( "build"   , ""      , "production"  , True  )           "build"      -> ( "build"   , ""      , duploEnv      , False )-          "test"       -> ( "build"   , ""      , "test"        , False )+          "test"       -> ( "test"    , ""      , "test"        , False )           _            -> ( cmdName   , ""      , duploEnv      , False )    -- Certain flags turn into commands.@@ -143,11 +143,7 @@   appVersion <- ignoreManifestError $ fmap AI.version CM.readManifest   appId <- ignoreManifestError $ fmap CM.appId CM.readManifest -  -- We may need custom builds with mode-  let depManifestPath = cwd </> "component.json"--  -- TODO(Yorkie): to be remove if verified by @Kenneth-  -- because the depIds is unnecessary in config+  -- Get all dependencies' names in dash-ified form   dependencies <- CM.getDependencies $ case duploMode of                                          "" -> Nothing                                          a  -> Just a@@ -212,8 +208,12 @@   when makefileExists $ void $ createProcess $ proc "make" [duploEnv]    -- Construct the Shake command.-  let shake' = build  cmdNameWithFlags cmdArgs buildConfig options+  let shake' = build cmdNameWithFlags cmdArgs buildConfig options   let shake  = shake' `catch` handleExc++  -- We should start with a clean slate.+  let noCleanActions = [ "clean", "bump", "init", "version" ]+  unless (cmdNameWithFlags `elem` noCleanActions) $ build "clean" [] buildConfig options    -- Watch or just build.   unless toWatch shake
src/Development/Duplo.hs view
@@ -14,7 +14,8 @@ import qualified Development.Duplo.Types.Builder as BD import qualified Development.Duplo.Types.Config  as TC import qualified Development.Duplo.Types.Options as OP-import           Development.Duplo.Utilities     (createStdEnv,+import           Development.Duplo.Utilities     (createIntermediaryDirectories,+                                                  createStdEnv,                                                   headerPrintSetter, logStatus,                                                   successPrintSetter) import           Development.Shake@@ -57,6 +58,7 @@       let actions = [ "static"                     , "clean"                     , "build"+                    , "test"                     , "bump"                     , "init"                     , "version"@@ -91,9 +93,6 @@       successPrinter "Clean completed"      "build" ~> do-      -- Always rebuild if we're building for production.-      unless (TC.isInDev config) $ need ["clean"]-       -- Make sure all static files and dependencies are there.       need ["static", "deps"]       -- Then compile, in parallel.@@ -101,8 +100,48 @@        successPrinter "Build completed" -      when (TC.isInTest config) $ need ["test"]+    "test" ~> do+      envOpt              <- createStdEnv config+      let appPath         =  config ^. TC.appPath+      let targetPath      =  config ^. TC.targetPath </> "tests"+      let utilPath        =  config ^. TC.utilPath+      let testPath        =  config ^. TC.testPath+      let testCompiler    =  utilPath </> "scripts-test.sh"+      let find path pttrn =  command [Cwd path] (utilPath </> "find.sh") [".", pttrn] +      -- There must be a test directory.+      testsExist <- doesDirectoryExist testPath+      unless testsExist $ throw BD.MissingTestDirectory++      -- Do a semi-full build+      need ["static", "deps"]+      need [targetScript, targetStyle]++      let prepareFile path =+            do+              let absPath = targetPath </> path+              -- Create intermediary directories+              createIntermediaryDirectories absPath+              -- Inject into each app file dependencies, AMD, etc in+              -- preparation for testing.+              Stdout compiled <- command [envOpt] testCompiler [path]+              -- Then write to the respective path in the output directory.+              writeFileChanged absPath compiled++      -- Each path is relative to the application root (most likely+      -- `app/`).+      Stdout codePaths' <- find testPath "*.js"+      mapM_ prepareFile $ lines codePaths'++      -- Build the markup once we have the script files in target.+      need [targetMarkup]++      -- Run the test suite+      command_ [envOpt] (utilPath </> "run-test.sh") []++      -- Copy over+      successPrinter "Tests completed"+     "bump" ~> do       (oldVersion, newVersion) <- Git.commit config bumpLevel @@ -112,7 +151,7 @@       let user = cmdArgs ^. element 0       let repo = cmdArgs ^. element 1       let name = user ++ "/" ++ repo-      let src = miscPath </> "boilerplate/"+      let src  = miscPath </> "boilerplate/"       let dest = cwd ++ "/"        -- Check prerequisites@@ -136,10 +175,6 @@       command_ [] (utilPath </> "init-git.sh") [name]        successPrinter $ "Project created at " ++ dest--    "test" ~> do-      envOpt <- createStdEnv config-      command_ [envOpt] (utilPath </> "run-test.sh") [duploPath]      -- Version should have already been displayed if requested     "version" ~> return ()
src/Development/Duplo/Component.hs view
@@ -4,7 +4,7 @@  import           Control.Exception               (throw) import           Control.Lens.Operators-import           Control.Monad                   (liftM)+import           Control.Monad                   (liftM, unless) import           Data.Aeson                      (decode, encode) import           Data.Aeson.Encode.Pretty        (encodePretty) import           Data.ByteString.Lazy.Char8      (ByteString)@@ -78,15 +78,14 @@ -- | Given a path, find all the `component.json` and return a JSON string extractCompVersions :: TC.BuildConfig -> Action String extractCompVersions config = do-    let path     = config ^. TC.cwd-    let utilPath = config ^. TC.utilPath+    let path = config ^. TC.cwd     -- Get all the relevant paths-    paths <- getAllManifestPaths utilPath path+    paths <- getAllManifestPaths config path     -- Construct the pipeline     let toVersion path'   = appInfoToVersion . decodeManifest path' . BS.pack     let takeVersion path' = liftM (toVersion path') (readFile path')     -- Go through it-    manifests <- mapM (liftIO . takeVersion) paths+    manifests <- mapM (liftIO . takeVersion) (paths ++ ["./component.json"])     -- Marshalling     return $ BS.unpack $ encode $ fromList manifests @@ -102,10 +101,17 @@ appInfoToVersion appInfo = (AI.name appInfo, AI.version appInfo)  -- | Given a path, find all the `component.json`s-getAllManifestPaths :: FilePath -> FilePath -> Action [FilePath]-getAllManifestPaths utilPath root = do-    Stdout out <- command [] (utilPath </> "find.sh") [root, manifestName]-    return $ lines out+getAllManifestPaths :: TC.BuildConfig -> FilePath -> Action [FilePath]+getAllManifestPaths config root = do+    let cwd      = config ^. TC.cwd+    let utilPath = config ^. TC.utilPath+    let depsPath = config ^. TC.depsPath+    -- Find all dependencies' manifests+    Stdout out <- command [] (utilPath </> "find.sh") [depsPath, manifestName]+    -- Get the current repo's manifest+    let currentRepoManifest = cwd </> "component.json"+    -- These should be all `component.json`s+    return $ lines out ++ [currentRepoManifest]  -- | Get the component dependency list by providing a mode, or not. getDependencies :: Maybe String -> IO [FilePath]
src/Development/Duplo/Git.hs view
@@ -91,26 +91,26 @@ -- | Read from the given directory and update the app manifest object. updateFileRegistry :: TC.BuildConfig -> AI.AppInfo -> Action AI.AppInfo updateFileRegistry config appInfo = do-    let cwd = config ^. TC.cwd-    let utilPath = config ^. TC.utilPath-    let appPath = cwd </> "app"+    let cwd       = config ^. TC.cwd+    let utilPath  = config ^. TC.utilPath+    let appPath   = cwd </> "app"     let assetPath = appPath </> "assets"     let imagePath = assetPath </> "images"-    let fontPath = assetPath </> "fonts"+    let fontPath  = assetPath </> "fonts"      -- Helper functions     let find path pttrn = command [] (utilPath </> "find.sh") [path, pttrn]-    let split = fmap unpack . splitOn "\n" . pack-    let makeRelative' = makeRelative cwd-    let filterNames = filter ((> 0) . length)+    let split           = fmap unpack . splitOn "\n" . pack+    let makeRelative'   = makeRelative cwd+    let filterNames     = filter ((> 0) . length)     let prepareFileList = filterNames . fmap (makeRelative cwd) . split      -- Collect eligible files     Stdout scripts <- find appPath "*.js"-    Stdout styles <- find appPath "*.styl"+    Stdout styles  <- find appPath "*.styl"     Stdout markups <- find appPath "*.jade"-    Stdout images <- find imagePath "*"-    Stdout fonts <- find fontPath "*"+    Stdout images  <- find imagePath "*"+    Stdout fonts   <- find fontPath "*"      -- Convert to arrays and make relative to cwd     let scripts' = prepareFileList scripts
src/Development/Duplo/JavaScript/Order.hs view
@@ -17,9 +17,6 @@ import           Language.JavaScript.Parser         (JSNode (..), Node (..),                                                      TokenPosn (..)) -import           Debug.Trace-trace' a = trace (show a) a- makeLenses ''Module  -- | Reorder modules within the root node.
src/Development/Duplo/Markups.hs view
@@ -51,7 +51,6 @@   let devAssetsPath = devPath </> "assets"   let devCodePath   = devPath </> "modules/index"   let depIds        = config ^. TC.dependencies-  let inTest        = TC.isInTest config    -- Preconditions   lift $ createIntermediaryDirectories devCodePath@@ -89,26 +88,16 @@   -- Inject compiled code into the index   let indexWithMarkup = replace "<body>" ("<body>" ++ compiled) compiledIndex -  -- Inject CSS/JS references-  refTags <- lift $ readFile' refTagsPath-  let indexWithRefs = replace "</head>" (refTags ++ "</head>") indexWithMarkup--  -- Inject CSS/JS references if in testing-  refTagsInTest <- lift $ readFile' (duploPath </> "etc/test/head.html")-  scriptsPaths  <- lift $ expandPaths cwd ".js" [] [ testPath </> "modules"-                                                   , appPath  </> "modules"-                                                   ]+  -- Inject CSS/JS references, if we're NOT in testing+  refTagsNormal <- lift $ readFile' refTagsPath -  let buildScriptTag path = "<script defer=\"defer\" src=\"" ++ makeRelative cwd path ++ "\"></script>"-  let scriptsTags         = concatMap buildScriptTag scriptsPaths-  let indexWithTestRefs   = if   inTest-                            then replace "</head>" (refTagsInTest ++ scriptsTags ++ "</head>") indexWithRefs-                            else indexWithRefs+  -- Inject CSS/JS references+  let indexWithTags = replace "</head>" (refTagsNormal ++ "</head>") indexWithMarkup    -- Path to the minifier   let minifier = utilPath </> "markups-minify.sh"   -- Minify it-  let postMinify _ = return indexWithTestRefs+  let postMinify _ = return indexWithTags   minified <- compile config minifier [] paths return postMinify    -- Write it to disk
src/Development/Duplo/Scripts.hs view
@@ -56,8 +56,6 @@   let devPath     = config ^. TC.devPath   let depsPath    = config ^. TC.depsPath   let devCodePath = devPath </> "modules/index.js"-  let inDev       = TC.isInDev config-  let inTest      = TC.isInTest config   let depIds      = config ^. TC.dependencies    -- Preconditions@@ -74,7 +72,7 @@   -- These paths don't need to be expanded.   let staticPaths = case buildMode of                       "development" -> [ "dev/index" ]-                      "test"        -> [ "test/index" ]+                      "test"        -> [ "dev/index" ]                       _             -> []                  ++ [ "app/index" ] @@ -107,7 +105,7 @@   -- Configure the compiler   let compiler = (util </>) $ case buildMode of                                 "development" -> "scripts-dev.sh"-                                "test"        -> "scripts-test.sh"+                                "test"        -> "scripts-dev.sh"                                 _             -> "scripts-optimize.sh"    -- Create a pseudo file that contains the environment variables and
src/Development/Duplo/Static.hs view
@@ -87,12 +87,13 @@ deps config = do   liftIO $ logStatus headerPrintSetter "Copying static files" -  let assetsPath = config ^. TC.assetsPath-  let depsPath   = config ^. TC.depsPath-  let targetPath = config ^. TC.targetPath-  let devPath    = config ^. TC.devPath-  let devAssetsPath = devPath </> "assets/"+  let assetsPath     = config ^. TC.assetsPath+  let depsPath       = config ^. TC.depsPath+  let targetPath     = config ^. TC.targetPath+  let devPath        = config ^. TC.devPath+  let devAssetsPath  = devPath </> "assets/"   let testAssetsPath = config ^. TC.duploPath </> "etc/test"+  let buildMode      = config ^. TC.buildMode    -- Make sure all these directories exist   createPathDirectories [assetsPath, depsPath, targetPath, devAssetsPath]@@ -103,10 +104,10 @@   depAssetFiles <- getDepAssets depsPath   -- Add dev files to the mix, if we're in dev mode   devFiles'     <- getDirectoryFiles devAssetsPath ["//*"]-  let devFiles   = if TC.isInDev config then devFiles' else []+  let devFiles   = if buildMode == "development" then devFiles' else []   -- Add test files to the mix, if we're in test mode   testFiles'    <- getDirectoryFiles testAssetsPath ["vendor//*"]-  let testFiles  = if TC.isInTest config then testFiles' else []+  let testFiles  = if buildMode == "test" then testFiles' else []   -- Mix them together   let allFiles   = nub $ concat [depAssetFiles, assetFiles, devFiles, testFiles]   -- We do NOT want index
src/Development/Duplo/Styles.hs view
@@ -22,6 +22,7 @@   let devCodePath = devPath </> "modules/index.styl"   let depIds      = config ^. TC.dependencies   let expandDeps' = expandDeps depIds+  let buildMode   = config ^. TC.buildMode    -- Preconditions   lift $ createIntermediaryDirectories devCodePath@@ -46,7 +47,7 @@   let dynamicPaths = [ "app/modules" ]                   ++ expandDeps' expandDepsDynamic                   -- Compile dev files in dev mode as well.-                  ++ [ "dev/modules" | TC.isInDev config ]+                  ++ [ "dev/modules" | buildMode == "development" ]    -- Merge both types of paths   paths <- lift $ expandPaths cwd ".styl" staticPaths dynamicPaths
src/Development/Duplo/Types/Builder.hs view
@@ -9,6 +9,7 @@                       | MissingGithubRepoException                       | MalformedManifestException String                       | MissingManifestException String+                      | MissingTestDirectory   deriving (Typeable)  instance Exception BuilderException@@ -22,3 +23,5 @@       "The manifest file `" ++ path ++ "` is not a valid duplo JSON."     show (MissingManifestException path) =       "`" ++ path ++ "` is expected at the current location."+    show MissingTestDirectory =+      "There must be a `tests/` directory in order to run tests."
src/Development/Duplo/Types/Config.hs view
@@ -38,9 +38,3 @@                                } deriving (Show)  makeLenses ''BuildConfig--isInDev :: BuildConfig -> Bool-isInDev config = config ^. buildMode == "development"--isInTest :: BuildConfig -> Bool-isInTest config = config ^. buildMode == "test"
src/Development/Duplo/Utilities.hs view
@@ -18,7 +18,8 @@                                                  ColorIntensity (..),                                                  ConsoleLayer (..), SGR (..),                                                  setSGR)-import           System.FilePath.Posix          (joinPath, splitPath)+import           System.FilePath.Posix          (dropTrailingPathSeparator,+                                                 joinPath, splitPath)  type CompiledContent = MaybeT DS.Action type FileProcessor = [File] -> CompiledContent [File]@@ -53,20 +54,22 @@ -- paths, in order. getDirectoryFilesInOrder :: FilePath -> String -> [DS.FilePattern] -> DS.Action [FilePath] getDirectoryFilesInOrder base extension patterns = do+    -- Make sure we have a clean base.+    let base' = dropTrailingPathSeparator base     -- We need to terminate the infinite list.     let listSize = length patterns     -- Make extension a list of itself.     let exts = replicate listSize extension     -- Turn file patterns into absolute patterns.-    let absPatterns = fmap (base </>) patterns+    let absPatterns = fmap (base' </>) patterns     -- Make sure we get all valid file patterns for dynamic paths.     validPatterns <- makeFilePatterns absPatterns exts     -- Remove the prefix that was needed for file pattern construction.-    let relPatterns = fmap (drop (length base + 1)) validPatterns+    let relPatterns = fmap (drop (length base' + 1)) validPatterns     -- We need to turn all elements into lists for each to be run independently.     let patternLists = fmap (replicate 1) relPatterns     -- Curry the function that gets the files given a list of paths.-    let getFiles = getDirectoryFiles base+    let getFiles = getDirectoryFiles base'     -- Map over the list monadically to get the paths in order.     allFiles <- mapM getFiles patternLists     -- Re-package the contents into the list of paths that we've wanted.@@ -206,10 +209,20 @@   let nodejs = config ^. TC.nodejsPath   let misc   = config ^. TC.miscPath   let target = config ^. TC.targetPath+  let duplo  = config ^. TC.duploPath+  let test   = config ^. TC.testPath+  let app    = config ^. TC.appPath+  let deps   = config ^. TC.depsPath+  let dev    = config ^. TC.devPath    DS.addEnv [ ("DUPLO_UTIL", util)             , ("DUPLO_NODEJS", nodejs)             , ("DUPLO_CWD", cwd)             , ("DUPLO_MISC", misc)             , ("DUPLO_TARGET", target)+            , ("DUPLO_PATH", duplo)+            , ("DUPLO_TEST", test)+            , ("DUPLO_APP", app)+            , ("DUPLO_DEPS", deps)+            , ("DUPLO_DEV", dev)             ]
tests/Tests.hs view
@@ -14,8 +14,11 @@ main :: IO () main = defaultMain tests +setMaxSuccess :: TestTree -> TestTree+setMaxSuccess = localOption $ QuickCheckTests 5000+ tests :: TestTree-tests = testGroup "Tests"+tests = setMaxSuccess $ testGroup "Tests"   [ testGroup "Component support"     [ QC.testProperty "slash is transformed into dash" $ \appInfo ->         let