From c76e1438e4cb121a6db7026975ba5ef10255511d Mon Sep 17 00:00:00 2001 From: Gary Burgess Date: Mon, 29 Jun 2015 20:27:16 +0100 Subject: [PATCH 1/4] Updates for 0.7 --- MODULE.md | 89 ++++++++++++++++++--- README.md | 74 +++++------------- entry.js | 30 +++++-- package.json | 3 +- src/Options.purs | 200 +++++++++++++++++++---------------------------- src/Plugin.purs | 65 +++++++-------- 6 files changed, 231 insertions(+), 230 deletions(-) diff --git a/MODULE.md b/MODULE.md index 9bd324d..79b9ed4 100644 --- a/MODULE.md +++ b/MODULE.md @@ -156,10 +156,10 @@ instance isForeignPsc :: IsForeign Psc ``` -#### `isForeignPscMake` +#### `isForeignPscBundle` ``` purescript -instance isForeignPscMake :: IsForeign PscMake +instance isForeignPscBundle :: IsForeign PscBundle ``` @@ -170,6 +170,27 @@ instance isForeignPscDocs :: IsForeign PscDocs ``` +#### `isForeignDotPsci` + +``` purescript +instance isForeignDotPsci :: IsForeign DotPsci +``` + + +#### `isForeignPathArray` + +``` purescript +instance isForeignPathArray :: IsForeign PathArray +``` + + +#### `isForeignDocgen` + +``` purescript +instance isForeignDocgen :: IsForeign Docgen +``` + + #### `isForeignFormat` ``` purescript @@ -177,31 +198,73 @@ instance isForeignFormat :: IsForeign Format ``` -#### `pscOptions` +#### `commandLineOptionBoolean` + +``` purescript +instance commandLineOptionBoolean :: CommandLineOption Boolean +``` + + +#### `commandLineOptionString` ``` purescript -pscOptions :: Foreign -> [String] +instance commandLineOptionString :: CommandLineOption String ``` -#### `pscOptionsNoOutput` +#### `commandLineOptionEither` + +``` purescript +instance commandLineOptionEither :: (CommandLineOption a, CommandLineOption b) => CommandLineOption (Either a b) +``` + + +#### `commandLineOptionArray` + +``` purescript +instance commandLineOptionArray :: (CommandLineOption a) => CommandLineOption [a] +``` + + +#### `commandLineOptionPathArray` + +``` purescript +instance commandLineOptionPathArray :: CommandLineOption PathArray +``` + + +#### `commandLineOptionDocgen` + +``` purescript +instance commandLineOptionDocgen :: CommandLineOption Docgen +``` + + +#### `commandLineOptionFormat` + +``` purescript +instance commandLineOptionFormat :: CommandLineOption Format +``` + + +#### `pscOptions` ``` purescript -pscOptionsNoOutput :: Foreign -> Tuple (Maybe String) [String] +pscOptions :: Foreign -> Either ForeignError [String] ``` -#### `pscMakeOptions` +#### `pscBundleOptions` ``` purescript -pscMakeOptions :: Foreign -> [String] +pscBundleOptions :: Foreign -> Either ForeignError [String] ``` #### `pscDocsOptions` ``` purescript -pscDocsOptions :: Foreign -> [String] +pscDocsOptions :: Foreign -> Either ForeignError [String] ``` @@ -308,21 +371,21 @@ type Effects eff = (which :: Which, through2 :: Through2, resolveBin :: ResolveB #### `psc` ``` purescript -psc :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) +psc :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit ``` -#### `pscMake` +#### `pscBundle` ``` purescript -pscMake :: forall eff. Foreign -> Eff (Effects eff) (Stream File Unit) +pscBundle :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit ``` #### `pscDocs` ``` purescript -pscDocs :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) +pscDocs :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (File -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit ``` diff --git a/README.md b/README.md index b8b9af2..ae99553 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,13 @@ Refer to the PureScript [compiler usage](https://github.com/purescript/purescrip Invokes the `psc` command. The following options are supported. -###### `noPrelude` (Boolean) +###### `src` (String or String Array) -Toggles `--no-prelude` that omits the Prelude. +The location of the source files to compile. Glob syntax is supported. + +###### `ffi` (String or String Array) + +Sets one or more `--ffi=` that specifies files for code that is included with a `foreign import` in the PureScript source. ###### `noTco` (Boolean) @@ -48,10 +52,6 @@ Toggles `--no-tco` that disables tail-call optimizations. Toggles `--no-magic-do` that disables optimizations overloading the do keyword generating efficient code for the `Eff` monad. -###### `main` (Boolean or String) - -Toggles `--main` or sets `--main=` that generates code to run the `main` function in the specified module or the `Main` module by default. - ###### `noOpts` (Boolean) Toggles `--no-opts` that skips the optimization phase. @@ -64,73 +64,37 @@ Toggles `--verbose-errors` that displays verbose error messages. Toggles `--comments` that includes comments in generated code. -###### `browserNamespace` (String) - -Sets `--browser-namespace=` that specifies the namespace that PureScript modules will be exported to when running in the browser. - -###### `externs` (String) - -Sets `--externs=` that specifies the externs file. - -###### `module` (String Array) - -Sets one or more `--module=` that enables dead code elimination, removing all code without a transitive dependency of one of the specified modules. - -###### `codegen` (String Array) - -Sets one or more `--codegen=` that generates code and externs for the specified modules. - ###### `output` (String) -Sets the path value of the [File](https://github.com/wearefractal/vinyl) passed through the Gulp stream. Note that this will not set `--output=`. +Sets `--output=` the specifies the output directory, `output` by default. ###### `noPrefix` (Boolean) Toggles `--no-prefix` that does not include the comment header. -###### `ffi` (String Array) - -Sets one or more `--ffi=` that specifies the files for code that is included with a `foreign import` in the PureScript source. - -### `purescript.pscMake(options)` - -Invokes the `psc-make` command. The following options are supported. - -###### `noPrelude` (Boolean) - -Toggles `--no-prelude` that omits the Prelude. - -###### `noTco` (Boolean) - -Toggles `--no-tco` that disables tail-call optimizations. - -###### `noMagicDo` (Boolean) - -Toggles `--no-magic-do` that disables optimizations overloading the do keyword generating efficient code for the `Eff` monad. - -###### `noOpts` (Boolean) +### `purescript.pscBundle(options)` -Toggles `--no-opts` that skips the optimization phase. +Invokes the `psc-bundle` command. The following options are supported. -###### `verboseErrors` (Boolean) +###### `src` (String or String Array) -Toggles `--verbose-errors` that displays verbose error messages. +The location of the `psc`-produced javascript source files to bundle. Glob syntax is supported. -###### `comments` (Boolean) +###### `output` (String) -Toggles `--comments` that includes comments in generated code. +Sets `--output=` that specifies the output filename for the bundle. -###### `output` (String) +###### `module` (String or String Array) -Sets `--output=` the specifies the output directory, `output` by default. +The name of the module or modules to use as entry points for dead code elimination. -###### `noPrefix` (Boolean) +###### `main` (Boolean or String) -Toggles `--no-prefix` that does not include the comment header. +Toggles `--main` or sets `--main=` that generates code to run the `main` function in the specified module or the `Main` module by default. -###### `ffi` (String Array) +###### `browserNamespace` (String) -Sets one or more `--ffi=` that specifies files for code that is included with a `foreign import` in the PureScript source. +Sets `--browser-namespace=` that specifies the namespace that PureScript modules will be exported to when running in the browser. ### `purescript.pscDocs(options)` diff --git a/entry.js b/entry.js index edf7fec..1c98e42 100644 --- a/entry.js +++ b/entry.js @@ -1,20 +1,34 @@ 'use strict'; var gulpPurescript = require('GulpPurescript.Plugin'); +var Promise = require('promise'); + +function promisify(aff) { + return new Promise(function (resolve, reject) { + var errback = function (err) { + return function () { + reject(err); + }; + }; + var callback = function (x) { + return function () { + resolve(x); + }; + }; + aff(errback)(callback)(); + }); +} function psc(options) { - var result = gulpPurescript.psc(options); - return result(); + return promisify(gulpPurescript.psc(options)); } -function pscMake(options) { - var result = gulpPurescript.pscMake(options); - return result(); +function pscBundle(options) { + return promisify(gulpPurescript.pscBundle(options)); } function pscDocs(options) { - var result = gulpPurescript.pscDocs(options); - return result(); + return promisify(gulpPurescript.pscDocs(options)); } function dotPsci() { @@ -24,7 +38,7 @@ function dotPsci() { module.exports.psc = psc; -module.exports.pscMake = pscMake; +module.exports.pscBundle = pscBundle; module.exports.pscDocs = pscDocs; diff --git a/package.json b/package.json index 6cd810c..c4e26b5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gulp-purescript", "description": "Run the PureScript compiler", - "version": "0.5.0-rc.1", + "version": "0.5.0-rc.2", "license": "MIT", "repository": "purescript-contrib/gulp-purescript", "author": { @@ -35,6 +35,7 @@ "logalot": "^2.1.0", "minimist": "^1.1.1", "multipipe": "^0.1.2", + "promise": "^7.0.3", "resolve-bin": "^0.3.0", "through2": "^0.6.3", "which": "^1.0.9" diff --git a/src/Options.purs b/src/Options.purs index 9369f97..d6234a0 100644 --- a/src/Options.purs +++ b/src/Options.purs @@ -1,7 +1,6 @@ module GulpPurescript.Options ( pscOptions - , pscOptionsNoOutput - , pscMakeOptions + , pscBundleOptions , pscDocsOptions ) where @@ -18,9 +17,9 @@ import Data.Traversable (for) import Data.Tuple (Tuple()) import Data.Tuple.Nested (tuple2) -noPreludeOpt = "no-prelude" +srcOpt = "src" -noPreludeKey = "noPrelude" +srcKey = "src" noOptsOpt = "no-opts" @@ -62,14 +61,6 @@ moduleOpt = "module" moduleKey = moduleOpt -codegenOpt = "codegen" - -codegenKey = codegenOpt - -externsOpt = "externs" - -externsKey = externsOpt - formatOpt = "format" formatKey = formatOpt @@ -83,39 +74,36 @@ docgenOpt = "docgen" docgenKey = docgenOpt newtype Psc - = Psc { noPrelude :: NullOrUndefined Boolean + = Psc { src :: Either String [String] + , ffi :: NullOrUndefined (Either String [String]) + , output :: NullOrUndefined String , noTco :: NullOrUndefined Boolean , noMagicDo :: NullOrUndefined Boolean - , main :: NullOrUndefined (Either Boolean String) , noOpts :: NullOrUndefined Boolean , verboseErrors :: NullOrUndefined Boolean , comments :: NullOrUndefined Boolean - , browserNamespace :: NullOrUndefined String - , "module" :: NullOrUndefined [String] - , codegen :: NullOrUndefined [String] - , output :: NullOrUndefined String - , externs :: NullOrUndefined String , noPrefix :: NullOrUndefined Boolean - , ffi :: NullOrUndefined PathArray } -newtype PscMake - = PscMake { noPrelude :: NullOrUndefined Boolean - , noOpts :: NullOrUndefined Boolean - , noMagicDo :: NullOrUndefined Boolean - , noTco :: NullOrUndefined Boolean - , verboseErrors :: NullOrUndefined Boolean - , comments :: NullOrUndefined Boolean - , noPrefix :: NullOrUndefined Boolean - , output :: NullOrUndefined String - , ffi :: NullOrUndefined PathArray - } +newtype PscBundle + = PscBundle { src :: Either String [String] + , output :: NullOrUndefined String + , "module" :: NullOrUndefined (Either String [String]) + , main :: NullOrUndefined (Either Boolean String) + , browserNamespace :: NullOrUndefined String + } newtype PscDocs - = PscDocs { format :: NullOrUndefined Format + = PscDocs { src :: Either String [String] + , format :: NullOrUndefined Format , docgen :: NullOrUndefined Docgen } +newtype DotPsci + = DotPsci { src :: Either String PathArray + , ffi :: NullOrUndefined (Either String PathArray) + } + newtype Docgen = Docgen Foreign newtype PathArray = PathArray [String] @@ -128,63 +116,54 @@ instance isForeignEither :: (IsForeign a, IsForeign b) => IsForeign (Either a b) instance isForeignPsc :: IsForeign Psc where read obj = - Psc <$> ({ noPrelude: _ + Psc <$> ({ src: _ + , ffi: _ + , output: _ , noTco: _ , noMagicDo: _ - , main: _ , noOpts: _ , verboseErrors: _ , comments: _ - , browserNamespace: _ - , "module": _ - , codegen: _ - , output: _ - , externs: _ , noPrefix: _ - , ffi: _ - } <$> readProp noPreludeKey obj + } <$> readProp srcKey obj + <*> readProp ffiKey obj + <*> readProp outputKey obj <*> readProp noTcoKey obj <*> readProp noMagicDoKey obj - <*> readProp mainKey obj <*> readProp noOptsKey obj <*> readProp verboseErrorsKey obj <*> readProp commentsKey obj - <*> readProp browserNamespaceKey obj - <*> readProp moduleKey obj - <*> readProp codegenKey obj - <*> readProp outputKey obj - <*> readProp externsKey obj - <*> readProp noPrefixKey obj - <*> readProp ffiKey obj) + <*> readProp noPrefixKey obj) -instance isForeignPscMake :: IsForeign PscMake where +instance isForeignPscBundle :: IsForeign PscBundle where read obj = - PscMake <$> ({ output: _ - , noPrelude: _ - , noTco: _ - , noMagicDo: _ - , noOpts: _ - , verboseErrors: _ - , comments: _ - , noPrefix: _ - , ffi: _ - } <$> readProp outputKey obj - <*> readProp noPreludeKey obj - <*> readProp noTcoKey obj - <*> readProp noMagicDoKey obj - <*> readProp noOptsKey obj - <*> readProp verboseErrorsKey obj - <*> readProp commentsKey obj - <*> readProp noPrefixKey obj - <*> readProp ffiKey obj) + PscBundle <$> ({ src: _ + , output: _ + , "module": _ + , main: _ + , browserNamespace: _ + } <$> readProp srcKey obj + <*> readProp outputKey obj + <*> readProp moduleKey obj + <*> readProp mainKey obj + <*> readProp browserNamespaceKey obj) instance isForeignPscDocs :: IsForeign PscDocs where read obj = - PscDocs <$> ({ format: _ + PscDocs <$> ({ src: _ + , format: _ , docgen: _ - } <$> readProp formatKey obj + } <$> readProp srcKey obj + <*> readProp formatKey obj <*> readProp docgenOpt obj) +instance isForeignDotPsci :: IsForeign DotPsci where + read obj = + DotPsci <$> ({ src: _ + , ffi: _ + } <$> readProp srcKey obj + <*> readProp ffiKey obj) + instance isForeignPathArray :: IsForeign PathArray where read val = PathArray <$> read val @@ -217,20 +196,10 @@ instance commandLineOptionArray :: (CommandLineOption a) => CommandLineOption [a <$> (fromMaybe [] $ runNullOrUndefined val) instance commandLineOptionPathArray :: CommandLineOption PathArray where - opt key val = opt key (NullOrUndefined ((\(PathArray a) -> a >>= expandGlob) <$> (runNullOrUndefined val))) - -foreign import expandGlob - """ - var expandGlob = (function () { - var glob = require("glob"); - return function (pattern) { - return glob.sync(pattern); - }; - }()); - """ :: String -> [String] + opt key val = opt key (NullOrUndefined ((\(PathArray a) -> a >>= expandGlob) <$> (runNullOrUndefined val))) instance commandLineOptionDocgen :: CommandLineOption Docgen where - opt key val = opt key (NullOrUndefined (parseDocgen <$> (runNullOrUndefined val))) + opt key val = opt key (NullOrUndefined (parseDocgen <$> (runNullOrUndefined val))) parseDocgen :: Docgen -> [String] parseDocgen (Docgen obj) = either (const []) id $ parseName obj @@ -257,46 +226,41 @@ instance commandLineOptionFormat :: CommandLineOption Format where CTags -> NullOrUndefined (Just "ctags")) (runNullOrUndefined val)) -foldPscOptions :: Psc -> [String] -foldPscOptions (Psc a) = opt noPreludeOpt a.noPrelude <> - opt noTcoOpt a.noTco <> - opt noMagicDoOpt a.noMagicDo <> - opt mainOpt a.main <> - opt noOptsOpt a.noOpts <> - opt verboseErrorsOpt a.verboseErrors <> - opt commentsOpt a.comments <> - opt browserNamespaceOpt a.browserNamespace <> - opt moduleOpt a."module" <> - opt codegenOpt a.codegen <> - opt outputOpt a.output <> - opt externsOpt a.externs <> - opt noPrefixOpt a.noPrefix <> - opt ffiOpt a.ffi - pscOptions :: Foreign -> Either ForeignError [String] -pscOptions opts = foldPscOptions <$> (read opts :: F Psc) - -pscOptionsNoOutput :: Foreign -> Either ForeignError (Tuple (Maybe String) [String]) -pscOptionsNoOutput opts = fold <$> parsed +pscOptions opts = fold <$> parsed where parsed = read opts :: F Psc - fold (Psc a) = tuple2 (runNullOrUndefined a.output) - (foldPscOptions (Psc $ a { output = NullOrUndefined Nothing })) - -pscMakeOptions :: Foreign -> Either ForeignError [String] -pscMakeOptions opts = fold <$> parsed - where parsed = read opts :: F PscMake - fold (PscMake a) = opt outputOpt a.output <> - opt noPreludeOpt a.noPrelude <> - opt noTcoOpt a.noTco <> - opt noMagicDoOpt a.noMagicDo <> - opt noOptsOpt a.noOpts <> - opt verboseErrorsOpt a.verboseErrors <> - opt commentsOpt a.comments <> - opt noPrefixOpt a.noPrefix <> - opt ffiOpt a.ffi + fold (Psc a) = either pure id a.src <> + opt ffiOpt a.ffi <> + opt outputOpt a.output <> + opt noTcoOpt a.noTco <> + opt noMagicDoOpt a.noMagicDo <> + opt noOptsOpt a.noOpts <> + opt verboseErrorsOpt a.verboseErrors <> + opt commentsOpt a.comments <> + opt noPrefixOpt a.noPrefix + +pscBundleOptions :: Foreign -> Either ForeignError [String] +pscBundleOptions opts = fold <$> parsed + where parsed = read opts :: F PscBundle + fold (PscBundle a) = either pure id a.src <> + opt outputOpt a.output <> + opt moduleOpt a."module" <> + opt mainOpt a.main <> + opt browserNamespaceOpt a.browserNamespace pscDocsOptions :: Foreign -> Either ForeignError [String] pscDocsOptions opts = fold <$> parsed where parsed = read opts :: F PscDocs - fold (PscDocs a) = opt formatOpt a.format <> + fold (PscDocs a) = either pure id a.src <> + opt formatOpt a.format <> opt docgenOpt a.docgen + +foreign import expandGlob + """ + var expandGlob = (function () { + var glob = require("glob"); + return function (pattern) { + return glob.sync(pattern); + }; + }()); + """ :: String -> [String] diff --git a/src/Plugin.purs b/src/Plugin.purs index 48563c3..ef0dd47 100644 --- a/src/Plugin.purs +++ b/src/Plugin.purs @@ -1,12 +1,12 @@ module GulpPurescript.Plugin ( Effects() , psc - , pscMake + , pscBundle , pscDocs , dotPsci ) where -import Control.Monad.Aff (Aff()) +import Control.Monad.Aff (Aff(), runAff) import Control.Monad.Eff (Eff()) import Control.Monad.Eff.Class (liftEff) import Control.Monad.Eff.Exception (Error()) @@ -27,7 +27,7 @@ import GulpPurescript.Logalot (Logalot(), info) import GulpPurescript.Minimist (minimist) import GulpPurescript.Multipipe (multipipe2) import GulpPurescript.OS (OS(), Platform(Win32), platform) -import GulpPurescript.Options (pscOptionsNoOutput, pscMakeOptions, pscDocsOptions) +import GulpPurescript.Options (pscOptions, pscBundleOptions, pscDocsOptions) import GulpPurescript.Package (Pkg(), Package(..), package) import GulpPurescript.Path (relative) import GulpPurescript.ResolveBin (ResolveBin(), resolveBin) @@ -59,14 +59,14 @@ psciFilename = ".psci" psciLoadCommand = ":m" +psciLoadForeignCommand = ":f" + pscCommand = "psc" -pscMakeCommand = "psc-make" +pscBundleCommand = "psc-bundle" pscDocsCommand = "psc-docs" -pscOutputDefault = "psc.js" - isVerbose = maybe false (\(Argv a) -> a.verbose) (minimist argv) foreign import cwd "var cwd = process.cwd();" :: String @@ -100,35 +100,30 @@ execute cmd args = do result <- spawn cmd' args' return result -pathsStream :: forall eff. Eff (through2 :: Through2 | eff) (Stream File [String]) -pathsStream = accStream run - where run i = if fileIsStream i - then throwPluginError "Streaming is not supported" - else pure $ filePath i - -psc :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) -psc opts = multipipe2 <$> pathsStream <*> objStream run - where run i = case pscOptionsNoOutput opts of - Left e -> throwPluginError (show e) - Right (Tuple out opt) -> - mkFile (fromMaybe pscOutputDefault out) <$> mkBufferFromString - <$> execute pscCommand (i <> opt) - -pscMake :: forall eff. Foreign -> Eff (Effects eff) (Stream File Unit) -pscMake opts = multipipe2 <$> pathsStream <*> objStream run - where run i = do output <- either (throwPluginError <<< show) - (\a -> execute pscMakeCommand (i <> a)) - (pscMakeOptions opts) - if isVerbose - then liftEff $ info $ pscMakeCommand ++ "\n" ++ output - else pure unit - -pscDocs :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) -pscDocs opts = multipipe2 <$> pathsStream <*> objStream run - where run i = case pscDocsOptions opts of - Left e -> throwPluginError (show e) - Right a-> mkFile "." <$> mkBufferFromString - <$> execute pscDocsCommand (a <> i) +psc :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +psc opts eb cb = runAff eb cb $ do + output <- either (throwPluginError <<< show) + (execute pscCommand) + (pscOptions opts) + if isVerbose + then liftEff $ info $ pscCommand ++ "\n" ++ output + else pure unit + +pscBundle :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +pscBundle opts eb cb = runAff eb cb $ do + output <- either (throwPluginError <<< show) + (execute pscBundleCommand) + (pscBundleOptions opts) + if isVerbose + then liftEff $ info $ pscCommand ++ "\n" ++ output + else pure unit + +pscDocs :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (File -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +pscDocs opts eb cb = runAff eb cb $ do + case pscDocsOptions opts of + Left e -> throwPluginError (show e) + Right a -> mkFile "." <$> mkBufferFromString + <$> execute pscDocsCommand a dotPsci :: forall eff. Eff (Effects eff) (Stream File Unit) dotPsci = multipipe2 <$> objStream run <*> createWriteStream psciFilename From 938b3c43907e74f497007718d82bec1c44985880 Mon Sep 17 00:00:00 2001 From: eric thul Date: Mon, 29 Jun 2015 23:57:16 -0400 Subject: [PATCH 2/4] Updates to the psci task Renaming the task to `psci` and writing the result of the command to the `.psci` file. Note that previous commits resolved #40 --- MODULE.md | 86 ++++++++++++++++++++++++------------------------ entry.js | 22 ++++++------- package.json | 1 + src/FS.purs | 24 +++++++++++--- src/Glob.purs | 53 +++++++++++++++++++++++++++++ src/Options.purs | 21 ++++++------ src/Plugin.purs | 48 ++++++++++++++++++++------- test.js | 17 +++++----- 8 files changed, 183 insertions(+), 89 deletions(-) create mode 100644 src/Glob.purs diff --git a/MODULE.md b/MODULE.md index 79b9ed4..27f5351 100644 --- a/MODULE.md +++ b/MODULE.md @@ -140,6 +140,47 @@ multipipe2 :: forall a b c. Stream a b -> Stream b c -> Stream a c +## Module GulpPurescript.OS + +#### `OS` + +``` purescript +data OS :: ! +``` + + +#### `Platform` + +``` purescript +data Platform + = Darwin + | Linux + | Win32 +``` + + +#### `showPlatform` + +``` purescript +instance showPlatform :: Show Platform +``` + + +#### `isForeignPlatform` + +``` purescript +instance isForeignPlatform :: IsForeign Platform +``` + + +#### `platform` + +``` purescript +platform :: forall eff. Eff (os :: OS | eff) (Maybe Platform) +``` + + + ## Module GulpPurescript.Options #### `isForeignEither` @@ -269,47 +310,6 @@ pscDocsOptions :: Foreign -> Either ForeignError [String] -## Module GulpPurescript.OS - -#### `OS` - -``` purescript -data OS :: ! -``` - - -#### `Platform` - -``` purescript -data Platform - = Darwin - | Linux - | Win32 -``` - - -#### `showPlatform` - -``` purescript -instance showPlatform :: Show Platform -``` - - -#### `isForeignPlatform` - -``` purescript -instance isForeignPlatform :: IsForeign Platform -``` - - -#### `platform` - -``` purescript -platform :: forall eff. Eff (os :: OS | eff) (Maybe Platform) -``` - - - ## Module GulpPurescript.Package #### `Pkg` @@ -389,10 +389,10 @@ pscDocs :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (File -> ``` -#### `dotPsci` +#### `psci` ``` purescript -dotPsci :: forall eff. Eff (Effects eff) (Stream File Unit) +psci :: forall eff. Eff (Effects eff) (Stream File Unit) ``` diff --git a/entry.js b/entry.js index 1c98e42..26ffbc8 100644 --- a/entry.js +++ b/entry.js @@ -1,18 +1,19 @@ 'use strict'; var gulpPurescript = require('GulpPurescript.Plugin'); + var Promise = require('promise'); function promisify(aff) { - return new Promise(function (resolve, reject) { - var errback = function (err) { - return function () { - reject(err); + return new Promise(function(resolve, reject){ + var errback = function(error){ + return function(){ + reject(error); }; }; - var callback = function (x) { - return function () { - resolve(x); + var callback = function(result){ + return function(){ + resolve(result); }; }; aff(errback)(callback)(); @@ -31,9 +32,8 @@ function pscDocs(options) { return promisify(gulpPurescript.pscDocs(options)); } -function dotPsci() { - var result = gulpPurescript.dotPsci(); - return result; +function psci(options) { + return promisify(gulpPurescript.psci(options)); } module.exports.psc = psc; @@ -42,4 +42,4 @@ module.exports.pscBundle = pscBundle; module.exports.pscDocs = pscDocs; -module.exports.dotPsci = dotPsci; +module.exports.psci = psci; diff --git a/package.json b/package.json index c4e26b5..3b551e7 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "purescript" ], "dependencies": { + "async": "^1.3.0", "cross-spawn": "^0.4.0", "glob": "^5.0.5", "gulp-util": "^3.0.4", diff --git a/src/FS.purs b/src/FS.purs index 591606b..d3bc68e 100644 --- a/src/FS.purs +++ b/src/FS.purs @@ -1,20 +1,34 @@ module GulpPurescript.FS ( FS() , Stream() - , createWriteStream + , writeFile ) where +import Control.Monad.Aff (Aff(), makeAff) import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) + +import Data.Function foreign import data FS :: ! data Stream i o -foreign import createWriteStream """ -function createWriteStream(path) { +writeFile :: forall eff. String -> String -> Aff (fs :: FS | eff) Unit +writeFile filename contents = makeAff $ runFn4 writeFileFn filename contents + +foreign import writeFileFn """ +function writeFileFn(filename, contents, errback, callback) { return function(){ var fs = require('fs'); - return fs.createWriteStream(path); + fs.writeFile(filename, contents, function(error){ + if (error) errback(new Error(error))(); + else callback()(); + }); }; } -""" :: forall eff. String -> Eff (fs :: FS | eff) (Stream String Unit) +""" :: forall eff. Fn4 String + String + (Error -> Eff (fs :: FS | eff) Unit) + (Unit -> Eff (fs :: FS | eff) Unit) + (Eff (fs :: FS | eff) Unit) diff --git a/src/Glob.purs b/src/Glob.purs new file mode 100644 index 0000000..64190cf --- /dev/null +++ b/src/Glob.purs @@ -0,0 +1,53 @@ +module GulpPurescript.Glob + ( Glob() + , glob + , globAll + ) where + +import Control.Monad.Aff (Aff(), makeAff) +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) + +import Data.Function + +foreign import data Glob :: ! + +glob :: forall eff. String -> Aff (glob :: Glob | eff) [String] +glob pattern = makeAff $ runFn3 globFn pattern + +foreign import globFn """ +function globFn(pattern, errback, callback) { + return function(){ + var glob = require('glob'); + + glob(pattern, function(error, result){ + if (error) errback(new Error(error))(); + else callback(result)(); + }); + }; +} +""" :: forall eff. Fn3 String + (Error -> Eff (glob :: Glob | eff) Unit) + ([String] -> Eff (glob :: Glob | eff) Unit) + (Eff (glob :: Glob | eff) Unit) + +globAll :: forall eff. [String] -> Aff (glob :: Glob | eff) [[String]] +globAll patterns = makeAff $ runFn3 globAllFn patterns + +foreign import globAllFn """ +function globAllFn(patterns, errback, callback) { + return function(){ + var glob = require('glob'); + + var async = require('async'); + + async.map(patterns, glob, function(error, result){ + if (error) errback(new Error(error))(); + else callback(result)(); + }); + }; +} +""" :: forall eff. Fn3 [String] + (Error -> Eff (glob :: Glob | eff) Unit) + ([[String]] -> Eff (glob :: Glob | eff) Unit) + (Eff (glob :: Glob | eff) Unit) diff --git a/src/Options.purs b/src/Options.purs index d6234a0..36b3af7 100644 --- a/src/Options.purs +++ b/src/Options.purs @@ -1,5 +1,6 @@ module GulpPurescript.Options - ( pscOptions + ( Psci(..) + , pscOptions , pscBundleOptions , pscDocsOptions ) where @@ -99,10 +100,10 @@ newtype PscDocs , docgen :: NullOrUndefined Docgen } -newtype DotPsci - = DotPsci { src :: Either String PathArray - , ffi :: NullOrUndefined (Either String PathArray) - } +newtype Psci + = Psci { src :: Either String [String] + , ffi :: NullOrUndefined (Either String [String]) + } newtype Docgen = Docgen Foreign @@ -157,12 +158,12 @@ instance isForeignPscDocs :: IsForeign PscDocs where <*> readProp formatKey obj <*> readProp docgenOpt obj) -instance isForeignDotPsci :: IsForeign DotPsci where +instance isForeignPsci :: IsForeign Psci where read obj = - DotPsci <$> ({ src: _ - , ffi: _ - } <$> readProp srcKey obj - <*> readProp ffiKey obj) + Psci <$> ({ src: _ + , ffi: _ + } <$> readProp srcKey obj + <*> readProp ffiKey obj) instance isForeignPathArray :: IsForeign PathArray where read val = PathArray <$> read val diff --git a/src/Plugin.purs b/src/Plugin.purs index ef0dd47..b227779 100644 --- a/src/Plugin.purs +++ b/src/Plugin.purs @@ -1,9 +1,11 @@ module GulpPurescript.Plugin ( Effects() + , Errorback() + , Callback() , psc , pscBundle , pscDocs - , dotPsci + , psci ) where import Control.Monad.Aff (Aff(), runAff) @@ -12,22 +14,26 @@ import Control.Monad.Eff.Class (liftEff) import Control.Monad.Eff.Exception (Error()) import Control.Monad.Error.Class (catchError, throwError) +import Data.Array (concat) import Data.Either (Either(..), either) import Data.Foreign (Foreign()) import Data.Foreign.Class (IsForeign, read, readProp) +import Data.Foreign.NullOrUndefined (runNullOrUndefined) import Data.Maybe (Maybe(Just), maybe, fromMaybe) +import Data.String (joinWith) import Data.Tuple (Tuple(..)) import Data.Tuple.Nested (tuple2) import GulpPurescript.Buffer (Buffer(), mkBufferFromString) import GulpPurescript.ChildProcess (ChildProcess(), spawn) -import GulpPurescript.FS (FS(), Stream(), createWriteStream) +import GulpPurescript.FS (FS(), writeFile) +import GulpPurescript.Glob (Glob(), globAll) import GulpPurescript.GulpUtil (File(), fileIsNull, fileIsStream, filePath, mkFile, mkPluginError) import GulpPurescript.Logalot (Logalot(), info) import GulpPurescript.Minimist (minimist) import GulpPurescript.Multipipe (multipipe2) import GulpPurescript.OS (OS(), Platform(Win32), platform) -import GulpPurescript.Options (pscOptions, pscBundleOptions, pscDocsOptions) +import GulpPurescript.Options (Psci(..), pscOptions, pscBundleOptions, pscDocsOptions) import GulpPurescript.Package (Pkg(), Package(..), package) import GulpPurescript.Path (relative) import GulpPurescript.ResolveBin (ResolveBin(), resolveBin) @@ -42,6 +48,7 @@ instance isForeignArgv :: IsForeign Argv where type Effects eff = ( cp :: ChildProcess , fs :: FS + , glob :: Glob , logalot :: Logalot , os :: OS , package :: Pkg @@ -51,13 +58,17 @@ type Effects eff = | eff ) +type Errorback eff = Error -> Eff (Effects eff) Unit + +type Callback eff a = a -> Eff (Effects eff) Unit + nodeCommand = "node" pursPackage = "purescript" psciFilename = ".psci" -psciLoadCommand = ":m" +psciLoadModuleCommand = ":m" psciLoadForeignCommand = ":f" @@ -100,7 +111,7 @@ execute cmd args = do result <- spawn cmd' args' return result -psc :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +psc :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit psc opts eb cb = runAff eb cb $ do output <- either (throwPluginError <<< show) (execute pscCommand) @@ -109,7 +120,7 @@ psc opts eb cb = runAff eb cb $ do then liftEff $ info $ pscCommand ++ "\n" ++ output else pure unit -pscBundle :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (Unit -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +pscBundle :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit pscBundle opts eb cb = runAff eb cb $ do output <- either (throwPluginError <<< show) (execute pscBundleCommand) @@ -118,15 +129,28 @@ pscBundle opts eb cb = runAff eb cb $ do then liftEff $ info $ pscCommand ++ "\n" ++ output else pure unit -pscDocs :: forall eff. Foreign -> (Error -> Eff (Effects eff) Unit) -> (File -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit +pscDocs :: forall eff. Foreign -> Errorback eff -> Callback eff File -> Eff (Effects eff) Unit pscDocs opts eb cb = runAff eb cb $ do case pscDocsOptions opts of Left e -> throwPluginError (show e) Right a -> mkFile "." <$> mkBufferFromString <$> execute pscDocsCommand a -dotPsci :: forall eff. Eff (Effects eff) (Stream File Unit) -dotPsci = multipipe2 <$> objStream run <*> createWriteStream psciFilename - where run i = if fileIsStream i - then throwPluginError "Streaming is not supported" - else pure $ psciLoadCommand ++ " " ++ relative cwd (filePath i) ++ "\n" +psci :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit +psci opts eb cb = runAff eb cb (either (\e -> throwPluginError (show e)) write (read opts)) + where + write :: Psci -> Aff (Effects eff) Unit + write (Psci a) = do + srcs <- globAll (either pure id a.src) + ffis <- globAll (either pure id (fromMaybe (Right []) (runNullOrUndefined a.ffi))) + + let srcLines = joinWith "\n" (loadModule <$> concat srcs) + ffiLines = joinWith "\n" (loadForeign <$> concat ffis) + + writeFile psciFilename (srcLines ++ ffiLines) + + loadModule :: String -> String + loadModule a = psciLoadModuleCommand ++ " " ++ relative cwd a + + loadForeign :: String -> String + loadForeign a = psciLoadForeignCommand ++ " " ++ relative cwd a diff --git a/test.js b/test.js index eb017bd..9194bc6 100644 --- a/test.js +++ b/test.js @@ -79,17 +79,18 @@ test('psc - invalid option type', function(t){ test('psci - basic', function(t){ t.plan(1); - var stream = purescript.dotPsci(); - var fixture = 'Fixture1.purs'; - var output = ':m ' + fixture + '\n'; + var output = ':m ' + fixture; - gulp.src(fixture).pipe(stream). - pipe(through2.obj(function(chunk, encoding, callback){ - t.equal(output, chunk.toString()); - callback(); - })); + var promise = purescript.psci({src: fixture}); + + promise.then(function(){ + fs.readFile('.psci', function(error, result){ + if (error) t.fail(error); + else t.equal(result.toString(), output); + }); + }); }); test('psc-make - basic', function(t){ From d5a0ab6f261c231c5656f9abe473dbb07c60b4fb Mon Sep 17 00:00:00 2001 From: eric thul Date: Wed, 1 Jul 2015 00:27:37 -0400 Subject: [PATCH 3/4] Converting the pscBundle task to a stream Note that this is part of the updates for PureScript 0.7, which along with previous commits resolves #38 --- foreign.js | 2 + package.json | 3 +- src/FS.purs | 3 -- src/GulpUtil.purs | 21 -------- src/Multipipe.purs | 17 ------- src/Plugin.purs | 34 ++++++------- src/Stream.purs | 30 +++++++++++ src/Through2.purs | 96 ----------------------------------- test.js | 121 +++++++++++++-------------------------------- 9 files changed, 84 insertions(+), 243 deletions(-) create mode 100644 foreign.js delete mode 100644 src/Multipipe.purs create mode 100644 src/Stream.purs delete mode 100644 src/Through2.purs diff --git a/foreign.js b/foreign.js new file mode 100644 index 0000000..40e218c --- /dev/null +++ b/foreign.js @@ -0,0 +1,2 @@ +function test(){ +} diff --git a/package.json b/package.json index 3b551e7..e576258 100644 --- a/package.json +++ b/package.json @@ -35,10 +35,8 @@ "gulp-util": "^3.0.4", "logalot": "^2.1.0", "minimist": "^1.1.1", - "multipipe": "^0.1.2", "promise": "^7.0.3", "resolve-bin": "^0.3.0", - "through2": "^0.6.3", "which": "^1.0.9" }, "devDependencies": { @@ -50,6 +48,7 @@ "run-sequence": "^1.0.2", "tap-spec": "^2.2.2", "tape": "^3.5.0", + "through2": "^0.6.3", "webpack": "^1.8.9" } } diff --git a/src/FS.purs b/src/FS.purs index d3bc68e..55688a3 100644 --- a/src/FS.purs +++ b/src/FS.purs @@ -1,6 +1,5 @@ module GulpPurescript.FS ( FS() - , Stream() , writeFile ) where @@ -12,8 +11,6 @@ import Data.Function foreign import data FS :: ! -data Stream i o - writeFile :: forall eff. String -> String -> Aff (fs :: FS | eff) Unit writeFile filename contents = makeAff $ runFn4 writeFileFn filename contents diff --git a/src/GulpUtil.purs b/src/GulpUtil.purs index c3bdee7..6d527fb 100644 --- a/src/GulpUtil.purs +++ b/src/GulpUtil.purs @@ -2,9 +2,6 @@ module GulpPurescript.GulpUtil ( File() , mkPluginError , mkFile - , filePath - , fileIsNull - , fileIsStream ) where import Control.Monad.Eff.Exception (Error()) @@ -34,21 +31,3 @@ function mkFileFn(path, contents) { return new gutil.File({path: path, contents: contents}); } """ :: Fn2 String Buffer File - -foreign import filePath """ -function filePath(file) { - return file.path; -} -""" :: File -> String - -foreign import fileIsNull""" -function fileIsNull(file) { - return file.isNull(); -} -""" :: File -> Boolean - -foreign import fileIsStream """ -function fileIsStream(file) { - return file.isStream(); -} -""" :: File -> Boolean diff --git a/src/Multipipe.purs b/src/Multipipe.purs deleted file mode 100644 index 0c61fbf..0000000 --- a/src/Multipipe.purs +++ /dev/null @@ -1,17 +0,0 @@ -module GulpPurescript.Multipipe (multipipe2) where - -import Data.Function - -import GulpPurescript.FS (Stream()) - -foreign import multipipe2Fn """ -function multipipe2Fn(stream1, stream2) { - var multipipe = require('multipipe'); - return multipipe(stream1, stream2); -} -""" :: forall a b c. Fn2 (Stream a b) - (Stream b c) - (Stream a c) - -multipipe2 :: forall a b c. Stream a b -> Stream b c -> Stream a c -multipipe2 a b = runFn2 multipipe2Fn a b diff --git a/src/Plugin.purs b/src/Plugin.purs index b227779..c0eb1f3 100644 --- a/src/Plugin.purs +++ b/src/Plugin.purs @@ -28,16 +28,15 @@ import GulpPurescript.Buffer (Buffer(), mkBufferFromString) import GulpPurescript.ChildProcess (ChildProcess(), spawn) import GulpPurescript.FS (FS(), writeFile) import GulpPurescript.Glob (Glob(), globAll) -import GulpPurescript.GulpUtil (File(), fileIsNull, fileIsStream, filePath, mkFile, mkPluginError) +import GulpPurescript.GulpUtil (File(), mkFile, mkPluginError) import GulpPurescript.Logalot (Logalot(), info) import GulpPurescript.Minimist (minimist) -import GulpPurescript.Multipipe (multipipe2) import GulpPurescript.OS (OS(), Platform(Win32), platform) import GulpPurescript.Options (Psci(..), pscOptions, pscBundleOptions, pscDocsOptions) import GulpPurescript.Package (Pkg(), Package(..), package) import GulpPurescript.Path (relative) import GulpPurescript.ResolveBin (ResolveBin(), resolveBin) -import GulpPurescript.Through2 (Through2(), objStream, accStream) +import GulpPurescript.Stream (Stream(), ReadableStream(), mkReadableStreamFromBuffer) import GulpPurescript.Which (Which(), which) newtype Argv = Argv { verbose :: Boolean } @@ -53,7 +52,7 @@ type Effects eff = , os :: OS , package :: Pkg , resolveBin :: ResolveBin - , through2 :: Through2 + , stream :: Stream , which :: Which | eff ) @@ -120,24 +119,23 @@ psc opts eb cb = runAff eb cb $ do then liftEff $ info $ pscCommand ++ "\n" ++ output else pure unit -pscBundle :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit -pscBundle opts eb cb = runAff eb cb $ do - output <- either (throwPluginError <<< show) - (execute pscBundleCommand) - (pscBundleOptions opts) - if isVerbose - then liftEff $ info $ pscCommand ++ "\n" ++ output - else pure unit +pscBundle :: forall eff. Foreign -> Errorback eff -> Callback eff (ReadableStream Buffer) -> Eff (Effects eff) Unit +pscBundle opts eb cb = runAff eb cb (either (throwPluginError <<< show) run (pscBundleOptions opts)) + where + run :: [String] -> Aff (Effects eff) (ReadableStream Buffer) + run args = do + bundle <- execute pscBundleCommand args + liftEff (mkReadableStreamFromBuffer (mkBufferFromString bundle)) pscDocs :: forall eff. Foreign -> Errorback eff -> Callback eff File -> Eff (Effects eff) Unit -pscDocs opts eb cb = runAff eb cb $ do - case pscDocsOptions opts of - Left e -> throwPluginError (show e) - Right a -> mkFile "." <$> mkBufferFromString - <$> execute pscDocsCommand a +pscDocs opts eb cb = runAff eb cb (either (throwPluginError <<< show) run (pscDocsOptions opts)) + where + run :: [String] -> Aff (Effects eff) File + run args = mkFile "." <$> mkBufferFromString + <$> execute pscDocsCommand args psci :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit -psci opts eb cb = runAff eb cb (either (\e -> throwPluginError (show e)) write (read opts)) +psci opts eb cb = runAff eb cb (either (throwPluginError <<< show) write (read opts)) where write :: Psci -> Aff (Effects eff) Unit write (Psci a) = do diff --git a/src/Stream.purs b/src/Stream.purs new file mode 100644 index 0000000..7ec99e4 --- /dev/null +++ b/src/Stream.purs @@ -0,0 +1,30 @@ +module GulpPurescript.Stream + ( Stream() + , ReadableStream() + , mkReadableStreamFromBuffer + ) where + +import Control.Monad.Eff (Eff()) + +import GulpPurescript.Buffer (Buffer()) + +foreign import data Stream :: ! + +data ReadableStream o + +foreign import mkReadableStreamFromBuffer """ +function mkReadableStreamFromBuffer(buffer) { + return function(){ + var Readable = require('stream').Readable; + + var stream = Readable(); + + stream._read = function(){ + stream.push(buffer); + return stream.push(null); + }; + + return stream; + }; +} +""" :: forall eff. Buffer -> Eff (stream :: Stream | eff) (ReadableStream Buffer) diff --git a/src/Through2.purs b/src/Through2.purs deleted file mode 100644 index 64e164c..0000000 --- a/src/Through2.purs +++ /dev/null @@ -1,96 +0,0 @@ -module GulpPurescript.Through2 - ( Through2() - , RunAff() - , objStream - , accStream - ) where - -import Control.Monad.Aff (Aff(), runAff) -import Control.Monad.Eff (Eff()) -import Control.Monad.Eff.Exception (Error()) - -import Data.Function - -import GulpPurescript.FS (Stream()) - -foreign import data Through2 :: ! - -type RunAff eff a = (Error -> Eff eff Unit) -> (a -> Eff eff Unit) -> Aff eff a -> Eff eff Unit - -objStream :: forall eff1 eff2 input output. (input -> Aff eff1 output) -> Eff (through2 :: Through2 | eff2) (Stream input output) -objStream = runFn2 objStreamFn runAff - -foreign import objStreamFn """ - function objStreamFn(runAff, aff) { - return function(){ - var through2 = require('through2'); - - function transform(chunk, encoding, callback) { - function onError(e) { - return function(){ - callback(e); - }; - } - - function onSuccess(a) { - return function(){ - callback(null, a); - }; - } - - var aff$prime = aff(chunk); - - var eff = runAff(onError)(onSuccess)(aff$prime); - - return eff(); - } - - return through2.obj(transform); - }; - } -""" :: forall eff1 eff2 input output. Fn2 (RunAff eff1 output) - (input -> Aff eff1 output) - (Eff (through2 :: Through2 | eff2) (Stream input output)) - -accStream :: forall eff1 eff2 input output. (input -> Aff eff1 output) -> Eff (through2 :: Through2 | eff2) (Stream input [output]) -accStream = runFn2 accStreamFn runAff - -foreign import accStreamFn """ - function accStreamFn(runAff, aff) { - return function(){ - var through2 = require('through2'); - - var arr = []; - - function transform(chunk, encoding, callback) { - function onError(e) { - return function(){ - callback(e); - }; - } - - function onSuccess(a) { - return function(){ - arr.push(a); - callback(); - }; - } - - var aff$prime = aff(chunk); - - var eff = runAff(onError)(onSuccess)(aff$prime); - - return eff(); - } - - function flush(callback) { - this.push(arr); - callback(); - } - - return through2.obj(transform, flush); - }; - } -""" :: forall eff1 eff2 input output. Fn2 (RunAff eff1 output) - (input -> Aff eff1 output) - (Eff (through2 :: Through2 | eff2) (Stream input [output])) diff --git a/test.js b/test.js index 9194bc6..8c9f504 100644 --- a/test.js +++ b/test.js @@ -15,64 +15,63 @@ var rewire = require('rewire'); var purescript = require('./'); test('psc - basic', function(t){ - t.plan(2); - - var stream = purescript.psc({noPrelude: true}); + t.plan(1); - var fixture = 'Fixture1.purs'; + var purescript = rewire('./'); - gulp.src(fixture).pipe(stream). - pipe(through2.obj(function(chunk, encoding, callback){ - t.ok(/Fixture/.test(chunk.contents.toString()), 'should have a compiled result'); - t.equal('psc.js', chunk.path); - callback(); - })); -}); + var mock = { + success: function(){ + t.fail('Should not get a log message'); + } + }; -test('psc - output option', function(t){ - t.plan(2); + purescript.__set__('logalot', mock); var fixture = 'Fixture1.purs'; - var output = 'output.js'; - - var stream = purescript.psc({noPrelude: true, output: output}); + var promise = purescript.psc({src: fixture}); - gulp.src(fixture).pipe(stream). - pipe(through2.obj(function(chunk, encoding, callback){ - t.ok(!fs.existsSync(__dirname + '/' + output), 'output file should not exist'); - t.equal(output, chunk.path); - callback(); - })); + promise.then(function(){ + t.pass('should output a compiled result'); + }); }); -test('psc - failure', function(t){ +test('psc - error', function(t){ t.plan(2); - var stream = purescript.psc({noPrelude: true}); - var fixture = 'Fixture2.purs'; - gulp.src(fixture).pipe(stream). - on('error', function(e){ - t.ok(/"where"/.test(e.message), 'should have a failure message'); - t.equal('Error', e.name); + var promise = purescript.psc({src: fixture}); + + promise.catch(function(error){ + t.ok(/"where"/.test(error.message), 'should have a failure message'); + t.equal('Error', error.name); }); }); test('psc - invalid option type', function(t){ t.plan(2); - var fixture = 'Fixture1.purs'; + var promise = purescript.psc({src: 10}); - var moduleName = path.basename(fixture, '.purs'); + promise.catch(function(error){ + t.ok(/type mismatch/i.test(error.message), 'should have a failure message'); + t.equal('Error', error.name); + }); +}); - var stream = purescript.psc({noPrelude: true, module: moduleName}); +test('psc-bundle - basic', function(t){ + t.plan(1); - gulp.src(fixture).pipe(stream). - on('error', function(e){ - t.ok(/type mismatch/i.test(e.message), 'should have a failure message'); - t.equal('Error', e.name); + var fixture = 'foreign.js'; + + var promise = purescript.pscBundle({src: fixture}); + + promise.then(function(stream){ + stream.pipe(through2.obj(function(chunk, encoding, callback){ + t.ok(/psc-bundle/.test(chunk.toString()), 'should have a compiled result'); + callback(); + })); }); }); @@ -93,53 +92,3 @@ test('psci - basic', function(t){ }); }); -test('psc-make - basic', function(t){ - t.plan(1); - - var purescript = rewire('./'); - - var mock = { - success: function(){ - t.fail('Should not get a log message'); - } - }; - - purescript.__set__('logalot', mock); - - var stream = purescript.pscMake({noPrelude: true}); - - var fixture = 'Fixture1.purs'; - - gulp.src(fixture).pipe(stream). - on('finish', function(){ - t.pass('should output a compiled result'); - }); -}); - -test('psc-make - error', function(t){ - t.plan(2); - - var stream = purescript.pscMake({noPrelude: true}); - - var fixture = 'Fixture2.purs'; - - gulp.src(fixture).pipe(stream). - on('error', function(e){ - t.ok(/"where"/.test(e.message), 'should have a failure message'); - t.equal('Error', e.name); - }); -}); - -test('psc-make - invalid option type', function(t){ - t.plan(2); - - var stream = purescript.pscMake({noPrelude: 'invalid'}); - - var fixture = 'Fixture1.purs'; - - gulp.src(fixture).pipe(stream). - on('error', function(e){ - t.ok(/type mismatch/i.test(e.message), 'should have a failure message'); - t.equal('Error', e.name); - }); -}); From c8fb2971f841b8452fe4740c6e4d2829b06be761 Mon Sep 17 00:00:00 2001 From: eric thul Date: Thu, 2 Jul 2015 08:15:08 -0400 Subject: [PATCH 4/4] Refactoring promises to streams Migrating back to a stream implementation for the tasks to allow conventient piping with other streams such as `gulp.dest`. --- README.md | 34 ++++++++++++++++++++---------- entry.js | 26 ++++------------------- package.json | 1 - src/FS.purs | 31 ---------------------------- src/Plugin.purs | 39 ++++++++++++++++------------------- src/Stream.purs | 50 +++++++++++++++++++++++++++++++++----------- test.js | 55 ++++++++++++++++++++++++++----------------------- 7 files changed, 112 insertions(+), 124 deletions(-) delete mode 100644 src/FS.purs diff --git a/README.md b/README.md index ae99553..cb2bb23 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ var gulp = require('gulp'); var purescript = require('gulp-purescript'); -gulp.task('purescript', function(){ - return gulp.src('src/**/*.purs'). - pipe(purescript.psc({noPrelude: true})). - pipe(gulp.dest('build')); +gulp.task('psc', function(){ + return purescript.psc({ + src: 'src/*.purs' + }); }); ``` @@ -38,11 +38,11 @@ Invokes the `psc` command. The following options are supported. ###### `src` (String or String Array) -The location of the source files to compile. Glob syntax is supported. +Files to compile. Glob syntax is supported. ###### `ffi` (String or String Array) -Sets one or more `--ffi=` that specifies files for code that is included with a `foreign import` in the PureScript source. +Files for code that is included with a `foreign import` in the PureScript source. Glob syntax is supported. ###### `noTco` (Boolean) @@ -78,7 +78,7 @@ Invokes the `psc-bundle` command. The following options are supported. ###### `src` (String or String Array) -The location of the `psc`-produced javascript source files to bundle. Glob syntax is supported. +The `psc`-produced JavaScript source files to bundle. Glob syntax is supported. ###### `output` (String) @@ -98,7 +98,11 @@ Sets `--browser-namespace=` that specifies the namespace that PureScript ### `purescript.pscDocs(options)` -Invokes the `pscDocs` command. The following options are supported. +Invokes the `psc-docs` command. The following options are supported. + +###### `src` (String or String Array) + +Files to be used for generating the documentation. Glob syntax is supported. ###### `format` (markdown | etags | ctags) @@ -110,11 +114,19 @@ Sets `--docgen=...` that can be used to filter the modules documentation is gene - If a string value is provided, the documentation for that single module will be generated. - If a list of strings is provided, the documentation for all listed modules will be generated. -- If an object with module name/filename pairs (for example, `{ Module: "docs/Module.md" }`) is provided, files will be written for each of the modules. In this mode, the task requires no `dest` as no value is returned. +- If an object with module name/filename pairs (for example, `{ Module: 'docs/Module.md' }`) is provided, files will be written for each of the modules. In this mode, the task requires no `dest` as no value is returned. + +### `purescript.psci(options)` + +Generates a `.psci` file. -### `purescript.dotPsci()` +###### `src` (String or String Array) + +Files added to the `.psci` file with the `:m` command. Glob syntax is supported. + +###### `ffi` (String or String Array) -Generates a `.psci` file in the current directory. Each source file is added with the `:m` command. +Files added to the `.psci` file with the `:f` command. Glob syntax is supported. ## Command line arguments diff --git a/entry.js b/entry.js index 26ffbc8..1efd5d6 100644 --- a/entry.js +++ b/entry.js @@ -2,38 +2,20 @@ var gulpPurescript = require('GulpPurescript.Plugin'); -var Promise = require('promise'); - -function promisify(aff) { - return new Promise(function(resolve, reject){ - var errback = function(error){ - return function(){ - reject(error); - }; - }; - var callback = function(result){ - return function(){ - resolve(result); - }; - }; - aff(errback)(callback)(); - }); -} - function psc(options) { - return promisify(gulpPurescript.psc(options)); + return gulpPurescript.psc(options)(); } function pscBundle(options) { - return promisify(gulpPurescript.pscBundle(options)); + return gulpPurescript.pscBundle(options)(); } function pscDocs(options) { - return promisify(gulpPurescript.pscDocs(options)); + return gulpPurescript.pscDocs(options)(); } function psci(options) { - return promisify(gulpPurescript.psci(options)); + return gulpPurescript.psci(options)(); } module.exports.psc = psc; diff --git a/package.json b/package.json index e576258..182ea23 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "gulp-util": "^3.0.4", "logalot": "^2.1.0", "minimist": "^1.1.1", - "promise": "^7.0.3", "resolve-bin": "^0.3.0", "which": "^1.0.9" }, diff --git a/src/FS.purs b/src/FS.purs deleted file mode 100644 index 55688a3..0000000 --- a/src/FS.purs +++ /dev/null @@ -1,31 +0,0 @@ -module GulpPurescript.FS - ( FS() - , writeFile - ) where - -import Control.Monad.Aff (Aff(), makeAff) -import Control.Monad.Eff (Eff()) -import Control.Monad.Eff.Exception (Error()) - -import Data.Function - -foreign import data FS :: ! - -writeFile :: forall eff. String -> String -> Aff (fs :: FS | eff) Unit -writeFile filename contents = makeAff $ runFn4 writeFileFn filename contents - -foreign import writeFileFn """ -function writeFileFn(filename, contents, errback, callback) { - return function(){ - var fs = require('fs'); - fs.writeFile(filename, contents, function(error){ - if (error) errback(new Error(error))(); - else callback()(); - }); - }; -} -""" :: forall eff. Fn4 String - String - (Error -> Eff (fs :: FS | eff) Unit) - (Unit -> Eff (fs :: FS | eff) Unit) - (Eff (fs :: FS | eff) Unit) diff --git a/src/Plugin.purs b/src/Plugin.purs index c0eb1f3..078e360 100644 --- a/src/Plugin.purs +++ b/src/Plugin.purs @@ -8,7 +8,7 @@ module GulpPurescript.Plugin , psci ) where -import Control.Monad.Aff (Aff(), runAff) +import Control.Monad.Aff (Aff()) import Control.Monad.Eff (Eff()) import Control.Monad.Eff.Class (liftEff) import Control.Monad.Eff.Exception (Error()) @@ -26,7 +26,6 @@ import Data.Tuple.Nested (tuple2) import GulpPurescript.Buffer (Buffer(), mkBufferFromString) import GulpPurescript.ChildProcess (ChildProcess(), spawn) -import GulpPurescript.FS (FS(), writeFile) import GulpPurescript.Glob (Glob(), globAll) import GulpPurescript.GulpUtil (File(), mkFile, mkPluginError) import GulpPurescript.Logalot (Logalot(), info) @@ -36,7 +35,7 @@ import GulpPurescript.Options (Psci(..), pscOptions, pscBundleOptions, pscDocsOp import GulpPurescript.Package (Pkg(), Package(..), package) import GulpPurescript.Path (relative) import GulpPurescript.ResolveBin (ResolveBin(), resolveBin) -import GulpPurescript.Stream (Stream(), ReadableStream(), mkReadableStreamFromBuffer) +import GulpPurescript.Stream (Stream(), ReadableStream(), mkReadableStreamFromAff) import GulpPurescript.Which (Which(), which) newtype Argv = Argv { verbose :: Boolean } @@ -46,7 +45,6 @@ instance isForeignArgv :: IsForeign Argv where type Effects eff = ( cp :: ChildProcess - , fs :: FS , glob :: Glob , logalot :: Logalot , os :: OS @@ -110,8 +108,8 @@ execute cmd args = do result <- spawn cmd' args' return result -psc :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit -psc opts eb cb = runAff eb cb $ do +psc :: forall eff. Foreign -> Eff (Effects eff) (ReadableStream Unit) +psc opts = mkReadableStreamFromAff $ do output <- either (throwPluginError <<< show) (execute pscCommand) (pscOptions opts) @@ -119,33 +117,32 @@ psc opts eb cb = runAff eb cb $ do then liftEff $ info $ pscCommand ++ "\n" ++ output else pure unit -pscBundle :: forall eff. Foreign -> Errorback eff -> Callback eff (ReadableStream Buffer) -> Eff (Effects eff) Unit -pscBundle opts eb cb = runAff eb cb (either (throwPluginError <<< show) run (pscBundleOptions opts)) +pscBundle :: forall eff. Foreign -> Eff (Effects eff) (ReadableStream File) +pscBundle opts = mkReadableStreamFromAff (either (throwPluginError <<< show) run (pscBundleOptions opts)) where - run :: [String] -> Aff (Effects eff) (ReadableStream Buffer) - run args = do - bundle <- execute pscBundleCommand args - liftEff (mkReadableStreamFromBuffer (mkBufferFromString bundle)) + run :: [String] -> Aff (Effects eff) File + run args = mkFile "." <$> mkBufferFromString + <$> execute pscBundleCommand args -pscDocs :: forall eff. Foreign -> Errorback eff -> Callback eff File -> Eff (Effects eff) Unit -pscDocs opts eb cb = runAff eb cb (either (throwPluginError <<< show) run (pscDocsOptions opts)) +pscDocs :: forall eff. Foreign -> Eff (Effects eff) (ReadableStream File) +pscDocs opts = mkReadableStreamFromAff (either (throwPluginError <<< show) run (pscDocsOptions opts)) where run :: [String] -> Aff (Effects eff) File run args = mkFile "." <$> mkBufferFromString <$> execute pscDocsCommand args -psci :: forall eff. Foreign -> Errorback eff -> Callback eff Unit -> Eff (Effects eff) Unit -psci opts eb cb = runAff eb cb (either (throwPluginError <<< show) write (read opts)) +psci :: forall eff. Foreign -> Eff (Effects eff) (ReadableStream File) +psci opts = mkReadableStreamFromAff (either (throwPluginError <<< show) run (read opts)) where - write :: Psci -> Aff (Effects eff) Unit - write (Psci a) = do + run :: Psci -> Aff (Effects eff) File + run (Psci a) = do srcs <- globAll (either pure id a.src) ffis <- globAll (either pure id (fromMaybe (Right []) (runNullOrUndefined a.ffi))) - let srcLines = joinWith "\n" (loadModule <$> concat srcs) - ffiLines = joinWith "\n" (loadForeign <$> concat ffis) + let lines = (loadModule <$> concat srcs) <> (loadForeign <$> concat ffis) + buffer = mkBufferFromString (joinWith "\n" lines) - writeFile psciFilename (srcLines ++ ffiLines) + return (mkFile psciFilename buffer) loadModule :: String -> String loadModule a = psciLoadModuleCommand ++ " " ++ relative cwd a diff --git a/src/Stream.purs b/src/Stream.purs index 7ec99e4..1e6d3a8 100644 --- a/src/Stream.purs +++ b/src/Stream.purs @@ -1,30 +1,56 @@ module GulpPurescript.Stream ( Stream() , ReadableStream() - , mkReadableStreamFromBuffer + , mkReadableStreamFromAff ) where +import Control.Monad.Aff (Aff(), runAff) import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) -import GulpPurescript.Buffer (Buffer()) +import Data.Function foreign import data Stream :: ! -data ReadableStream o +data ReadableStream out -foreign import mkReadableStreamFromBuffer """ -function mkReadableStreamFromBuffer(buffer) { +type RunAff eff a = (Error -> Eff eff Unit) -> (a -> Eff eff Unit) -> Aff eff a -> Eff eff Unit + +mkReadableStreamFromAff :: forall eff1 eff2 out. Aff eff1 out -> Eff (stream :: Stream | eff2) (ReadableStream out) +mkReadableStreamFromAff = runFn2 mkReadableStreamFromAffFn runAff + +foreign import mkReadableStreamFromAffFn """ +function mkReadableStreamFromAffFn(runAff, aff) { return function(){ - var Readable = require('stream').Readable; + var stream = require('stream'); - var stream = Readable(); + var objectMode = true; - stream._read = function(){ - stream.push(buffer); - return stream.push(null); + var readable = new stream.Readable({objectMode: objectMode}); + + readable._read = function(){ }; - return stream; + function onError(e) { + return function(){ + readable.emit('error', e); + }; + } + + function onSuccess(a) { + return function(){ + readable.push(a); + readable.push(null); + }; + } + + var eff = runAff(onError)(onSuccess)(aff); + + eff(); + + return readable; }; } -""" :: forall eff. Buffer -> Eff (stream :: Stream | eff) (ReadableStream Buffer) +""" :: forall eff1 eff2 out. Fn2 (RunAff eff1 out) + (Aff eff1 out) + (Eff (stream :: Stream | eff2) (ReadableStream out)) diff --git a/test.js b/test.js index 8c9f504..82de401 100644 --- a/test.js +++ b/test.js @@ -29,11 +29,12 @@ test('psc - basic', function(t){ var fixture = 'Fixture1.purs'; - var promise = purescript.psc({src: fixture}); + var stream = purescript.psc({src: fixture}); - promise.then(function(){ + stream.pipe(through2.obj(function(chunk, encoding, callback){ t.pass('should output a compiled result'); - }); + callback(); + })); }); test('psc - error', function(t){ @@ -41,23 +42,29 @@ test('psc - error', function(t){ var fixture = 'Fixture2.purs'; - var promise = purescript.psc({src: fixture}); + var stream = purescript.psc({src: fixture}); - promise.catch(function(error){ - t.ok(/"where"/.test(error.message), 'should have a failure message'); - t.equal('Error', error.name); + stream.on('error', function(e){ + t.ok(/"where"/.test(e.message), 'should have a failure message'); + t.equal('Error', e.name); }); }); test('psc - invalid option type', function(t){ t.plan(2); - var promise = purescript.psc({src: 10}); + try { + var stream = purescript.psc({src: 10}); - promise.catch(function(error){ + stream.on('error', function(e){ + t.ok(/type mismatch/i.test(error.message), 'should have a failure message'); + t.equal('Error', error.name); + }); + } + catch (error) { t.ok(/type mismatch/i.test(error.message), 'should have a failure message'); t.equal('Error', error.name); - }); + } }); test('psc-bundle - basic', function(t){ @@ -65,30 +72,26 @@ test('psc-bundle - basic', function(t){ var fixture = 'foreign.js'; - var promise = purescript.pscBundle({src: fixture}); + var stream = purescript.pscBundle({src: fixture}); - promise.then(function(stream){ - stream.pipe(through2.obj(function(chunk, encoding, callback){ - t.ok(/psc-bundle/.test(chunk.toString()), 'should have a compiled result'); - callback(); - })); - }); + stream.pipe(through2.obj(function(chunk, encoding, callback){ + t.ok(/psc-bundle/.test(chunk.contents.toString()), 'should have a compiled result'); + callback(); + })); }); test('psci - basic', function(t){ - t.plan(1); + t.plan(2); var fixture = 'Fixture1.purs'; var output = ':m ' + fixture; - var promise = purescript.psci({src: fixture}); + var stream = purescript.psci({src: fixture}); - promise.then(function(){ - fs.readFile('.psci', function(error, result){ - if (error) t.fail(error); - else t.equal(result.toString(), output); - }); - }); + stream.pipe(through2.obj(function(chunk, encoding, callback){ + t.equal('.psci', chunk.path); + t.equal(output, chunk.contents.toString()); + callback(); + })); }); -