From a7833e6dab582a80f0f716b5f69ac9e94f4c7113 Mon Sep 17 00:00:00 2001 From: eric thul Date: Mon, 20 Apr 2015 23:29:51 -0400 Subject: [PATCH 1/2] Rewrite using PureScript for the implementation --- .gitignore | 10 +- MODULE.md | 378 ++++++++++++++++++++++++++++++++++++++++++ README.md | 26 +-- bower.json | 15 ++ entry.js | 31 ++++ gulpfile.js | 68 ++++++++ index.js | 228 ------------------------- options.js | 39 ----- package.json | 20 ++- src/Buffer.purs | 12 ++ src/ChildProcess.purs | 46 +++++ src/FS.purs | 20 +++ src/GulpUtil.purs | 54 ++++++ src/Logalot.purs | 17 ++ src/Minimist.purs | 17 ++ src/Multipipe.purs | 17 ++ src/OS.purs | 38 +++++ src/Options.purs | 227 +++++++++++++++++++++++++ src/Package.purs | 30 ++++ src/Path.purs | 13 ++ src/Plugin.purs | 132 +++++++++++++++ src/ResolveBin.purs | 35 ++++ src/Through2.purs | 96 +++++++++++ src/Which.purs | 31 ++++ test.js | 2 +- webpack.config.js | 33 ++++ 26 files changed, 1347 insertions(+), 288 deletions(-) create mode 100644 MODULE.md create mode 100644 bower.json create mode 100644 entry.js create mode 100644 gulpfile.js delete mode 100644 index.js delete mode 100644 options.js create mode 100644 src/Buffer.purs create mode 100644 src/ChildProcess.purs create mode 100644 src/FS.purs create mode 100644 src/GulpUtil.purs create mode 100644 src/Logalot.purs create mode 100644 src/Minimist.purs create mode 100644 src/Multipipe.purs create mode 100644 src/OS.purs create mode 100644 src/Options.purs create mode 100644 src/Package.purs create mode 100644 src/Path.purs create mode 100644 src/Plugin.purs create mode 100644 src/ResolveBin.purs create mode 100644 src/Through2.purs create mode 100644 src/Which.purs create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index c29c77b..48935d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ -.DS_Store -*.log .psci -node_modules -output +npm-debug.log +index.js +node_modules/ +bower_components/ +build/ +output/ diff --git a/MODULE.md b/MODULE.md new file mode 100644 index 0000000..54ebb47 --- /dev/null +++ b/MODULE.md @@ -0,0 +1,378 @@ +# Module Documentation + +## Module GulpPurescript.ChildProcess + +#### `ChildProcess` + +``` purescript +data ChildProcess :: ! +``` + + +#### `spawn` + +``` purescript +spawn :: forall eff. String -> [String] -> Aff (cp :: ChildProcess | eff) String +``` + + + +## Module GulpPurescript.FS + +#### `FS` + +``` purescript +data FS :: ! +``` + + +#### `Stream` + +``` purescript +data Stream i o +``` + + +#### `createWriteStream` + +``` purescript +createWriteStream :: forall eff. String -> Eff (fs :: FS | eff) (Stream String Unit) +``` + + + +## Module GulpPurescript.GulpUtil + +#### `File` + +``` purescript +data File +``` + + +#### `mkPluginError` + +``` purescript +mkPluginError :: String -> String -> Error +``` + + +#### `mkFile` + +``` purescript +mkFile :: String -> String -> File +``` + + +#### `filePath` + +``` purescript +filePath :: File -> String +``` + + +#### `fileIsNull` + +``` purescript +fileIsNull :: File -> Boolean +``` + + +#### `fileIsStream` + +``` purescript +fileIsStream :: File -> Boolean +``` + + + +## Module GulpPurescript.Logalot + +#### `Logalot` + +``` purescript +data Logalot :: ! +``` + + +#### `info` + +``` purescript +info :: forall eff. String -> Eff (logalot :: Logalot | eff) Unit +``` + + + +## Module GulpPurescript.Minimist + +#### `minimist` + +``` purescript +minimist :: forall a. (IsForeign a) => [String] -> Maybe a +``` + + + +## Module GulpPurescript.Multipipe + +#### `multipipe2` + +``` purescript +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 + +#### `isForeignPsc` + +``` purescript +instance isForeignPsc :: IsForeign Psc +``` + + +#### `isForeignPscMake` + +``` purescript +instance isForeignPscMake :: IsForeign PscMake +``` + + +#### `isForeignPscDocs` + +``` purescript +instance isForeignPscDocs :: IsForeign PscDocs +``` + + +#### `isForeignFormat` + +``` purescript +instance isForeignFormat :: IsForeign Format +``` + + +#### `pscOptions` + +``` purescript +pscOptions :: Foreign -> [String] +``` + + +#### `pscMakeOptions` + +``` purescript +pscMakeOptions :: Foreign -> [String] +``` + + +#### `pscDocsOptions` + +``` purescript +pscDocsOptions :: Foreign -> [String] +``` + + + +## Module GulpPurescript.Package + +#### `Pkg` + +``` purescript +data Pkg :: ! +``` + + +#### `Package` + +``` purescript +newtype Package + = Package { name :: String } +``` + + +#### `isForeignPackage` + +``` purescript +instance isForeignPackage :: IsForeign Package +``` + + +#### `package` + +``` purescript +package :: forall eff. Eff (package :: Pkg | eff) (Maybe Package) +``` + + + +## Module GulpPurescript.Path + +#### `relative` + +``` purescript +relative :: String -> String -> String +``` + + + +## Module GulpPurescript.Plugin + +#### `isForeignArgv` + +``` purescript +instance isForeignArgv :: IsForeign Argv +``` + + +#### `Effects` + +``` purescript +type Effects eff = (which :: Which, through2 :: Through2, resolveBin :: ResolveBin, package :: Pkg, os :: OS, logalot :: Logalot, fs :: FS, cp :: ChildProcess | eff) +``` + + +#### `psc` + +``` purescript +psc :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) +``` + + +#### `pscMake` + +``` purescript +pscMake :: forall eff. Foreign -> Eff (Effects eff) (Stream File Unit) +``` + + +#### `pscDocs` + +``` purescript +pscDocs :: forall eff. Foreign -> Eff (Effects eff) (Stream File File) +``` + + +#### `dotPsci` + +``` purescript +dotPsci :: forall eff. Eff (Effects eff) (Stream File Unit) +``` + + + +## Module GulpPurescript.ResolveBin + +#### `ResolveBin` + +``` purescript +data ResolveBin :: ! +``` + + +#### `Options` + +``` purescript +type Options = { executable :: String } +``` + + +#### `resolveBin` + +``` purescript +resolveBin :: forall eff. String -> Options -> Aff (resolveBin :: ResolveBin | eff) String +``` + + + +## Module GulpPurescript.Through2 + +#### `Through2` + +``` purescript +data Through2 :: ! +``` + + +#### `RunAff` + +``` purescript +type RunAff eff a = (Error -> Eff eff Unit) -> (a -> Eff eff Unit) -> Aff eff a -> Eff eff Unit +``` + + +#### `objStream` + +``` purescript +objStream :: forall eff1 eff2 input output. (input -> Aff eff1 output) -> Eff (through2 :: Through2 | eff2) (Stream input output) +``` + + +#### `accStream` + +``` purescript +accStream :: forall eff1 eff2 input output. (input -> Aff eff1 output) -> Eff (through2 :: Through2 | eff2) (Stream input [output]) +``` + + + +## Module GulpPurescript.Which + +#### `Which` + +``` purescript +data Which :: ! +``` + + +#### `which` + +``` purescript +which :: forall eff. String -> Aff (which :: Which | eff) String +``` + + + + diff --git a/README.md b/README.md index e632307..36ad73e 100644 --- a/README.md +++ b/README.md @@ -40,26 +40,30 @@ Invokes the `psc` command. - **noPrelude**: Boolean value that toggles `--no-prelude` - Do not include the Prelude in the generated Javascript. - - **noOpts**: Boolean value that toggles `--no-opts` - - Disable all optimizations. - - **noMagicDo**: Boolean value that toggles `--no-magic-do` - - Turn off optimizations which inline calls to >>= for the Eff monad. - **noTco**: Boolean value that toggles `--no-tco` - Turn off tail-call elimination. - - **verboseErrors**: Boolean value that toggles `--verbose-errors` - - Generate verbose error messages. + - **noMagicDo**: Boolean value that toggles `--no-magic-do` + - Turn off optimizations which inline calls to >>= for the Eff monad. - **main**: Boolean or string value that sets `--main` or `--main=` - Generate a call to main in the specified module after all other generated Javascript. Defaults to Main if the option is used but no value is provided. + - **noOpts**: Boolean value that toggles `--no-opts` + - Disable all optimizations. + - **verboseErrors**: Boolean value that toggles `--verbose-errors` + - Generate verbose error messages. + - **comments**: Boolean value that toggles `--comments` + - Include comments in generated code. - **browserNamespace**: String value that sets `--browser-namespace=` - Specify the namespace that PureScript modules will be exported to when running in the browser. - **externs**: String value that sets `--externs=` - Write a list of foreign imports declarations to the specified file in addition to generating Javascript output. - - **modules**: String or array value that sets one or more `--module=` - - If specified, any code which is not referenced transitively from this module will be removed. This argument can be used multiple times. - - **codegen**: String or array value that sets one or more `--codegen=` - - A list of modules for which Javascript and externs should be generated. This argument can be used multiple times. - - **output**: String value that specifies the output file(this won't set'`--output=`) + - **module**: Array of string values that sets one or more `--module=` + - If specified, any code which is not referenced transitively from this module will be removed. + - **codegen**: Array of string values that sets one or more `--codegen=` + - A array of modules for which JavaScript and externs should be generated. + - **output**: String value that specifies the output file. Note that this will not set `--output=` because the resulting file is piped through the Gulp stream. - Write the generated Javascript to the specified file. + - **noPrefix**: Boolean value that toggles `--no-prefix` + - Do not include the comment header. ### purescript.pscMake(options) diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..4712f5c --- /dev/null +++ b/bower.json @@ -0,0 +1,15 @@ +{ + "name": "gulp-purescript", + "private": true, + "devDependencies": { + "purescript-foreign": "0.4.2", + "purescript-maybe": "0.2.2", + "purescript-either": "0.1.8", + "purescript-aff": "0.10.1", + "purescript-exceptions": "0.2.3", + "purescript-arrays": "0.3.7", + "purescript-transformers": "0.5.5", + "purescript-monad-eff": "0.1.0", + "purescript-tuples": "0.3.4" + } +} diff --git a/entry.js b/entry.js new file mode 100644 index 0000000..edf7fec --- /dev/null +++ b/entry.js @@ -0,0 +1,31 @@ +'use strict'; + +var gulpPurescript = require('GulpPurescript.Plugin'); + +function psc(options) { + var result = gulpPurescript.psc(options); + return result(); +} + +function pscMake(options) { + var result = gulpPurescript.pscMake(options); + return result(); +} + +function pscDocs(options) { + var result = gulpPurescript.pscDocs(options); + return result(); +} + +function dotPsci() { + var result = gulpPurescript.dotPsci(); + return result; +} + +module.exports.psc = psc; + +module.exports.pscMake = pscMake; + +module.exports.pscDocs = pscDocs; + +module.exports.dotPsci = dotPsci; diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..e217480 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,68 @@ +'use strict'; + +var path = require('path'); + +var gulp = require('gulp'); + +var gutil = require('gulp-util'); + +var plumber = require('gulp-plumber'); + +var purescript = require('gulp-purescript'); + +var sequence = require('run-sequence'); + +var del = require('del'); + +var config = { del: ['build', 'index.js'] + , purescript: { src: [ 'bower_components/purescript-*/src/**/*.purs*' + , 'src/**/*.purs' + ] + , dest: 'build' + , docs: 'MODULE.md' + } + } + ; + +function error(e) { + gutil.log(gutil.colors.magenta('>>>> Error <<<<') + '\n' + e.toString().trim()); + this.emit('end'); +} + +gulp.task('del', function(cb){ + del(config.del, cb); +}); + +gulp.task('make', function(){ + return gulp.src(config.purescript.src). + pipe(plumber()). + pipe(purescript.pscMake({output: config.purescript.dest})). + on('error', error); +}); + +gulp.task('psci', function(){ + return gulp.src(config.purescript.src). + pipe(plumber()). + pipe(purescript.dotPsci()). + on('error', error); +}); + +gulp.task('docs', function(){ + return gulp.src(config.purescript.src[1]). + pipe(plumber()). + pipe(purescript.pscDocs()). + on('error', error). + pipe(gulp.dest(config.purescript.docs)); +}); + +gulp.task('watch', function(){ + gulp.watch(config.purescript.src, ['make']); +}); + +gulp.task('default', function(callback){ + sequence('del', 'make', ['psci', 'docs'], callback); +}); + +gulp.task('build', function(callback){ + sequence('del', 'make', callback); +}); diff --git a/index.js b/index.js deleted file mode 100644 index 0cf7454..0000000 --- a/index.js +++ /dev/null @@ -1,228 +0,0 @@ -'use strict'; - -var os = require('os'); - -var fs = require('fs'); - -var path = require('path'); - -var child_process = require('child_process'); - -var gutil = require('gulp-util'); - -var through2 = require('through2'); - -var lodash = require('lodash'); - -var which = require('which'); - -var minimist = require('minimist'); - -var logalot = require('logalot'); - -var multipipe = require('multipipe'); - -var resolveBin = require('resolve-bin'); - -var options = require('./options'); - -var packageJson = require('./package.json'); - -var pluginName = packageJson.name; - -var purescriptPackage = 'purescript'; - -var psciFilename = '.psci'; - -var psciLoadCommand = ':m'; - -var argv = minimist(process.argv.slice(2)); - -var isVerbose = argv.verbose; - -var cwd = process.cwd(); - -var PluginError = gutil.PluginError; - -var File = gutil.File; - -function resolve(cmd, args, callback) { - var err = 'Failed to find ' + gutil.colors.cyan(cmd) + '. Please ensure it is available on your system.'; - - resolveBin(purescriptPackage, {executable: cmd}, function(e, bin){ - if (!e && os.platform() === 'win32') callback(null, 'node', [bin].concat(args)) - else if (!e) callback(null, bin, args); - else { - which(cmd, function(e){ - if (e) callback(err); - else callback(null, cmd, args); - }); - } - }); -} - -function execute(cmd, args, callback) { - resolve(cmd, args, function(e, bin, args$prime){ - if (e) callback(new PluginError(pluginName, e)); - else callback(null, child_process.spawn(bin, args$prime)); - }); -} - -function mkOptions(o, opts) { - return Object.keys(opts || {}).reduce(function(b, a){ - if (a in o.flags && opts[a] === true) return b.concat([o.flags[a]]); - else if (a in o.single && typeof opts[a] === 'string') return b.concat([o.single[a] + '=' + opts[a]]); - else if (a in o.multi) { - if (typeof opts[a] === 'string') return b.concat([o.multi[a] + '=' + opts[a]]); - else { - return b.concat(opts[a].map(function(x){ - return o.multi[a] + '=' + x; - })); - } - } - else return b; - }, []); -} - -function collectPaths() { - var paths = []; - - function transform(chunk, encoding, callback) { - if (chunk.isNull()) callback(null, chunk); - else if (chunk.isStream()) callback(new PluginError(pluginName, 'Streaming not supported')); - else { - paths.push(chunk.path); - callback(); - } - } - - function flush(callback){ - this.push(paths); - callback(); - }; - - return through2.obj(transform, flush); -} - -function psc(opts) { - var output = opts && opts.output ? opts.output : 'psc.js'; - - var opts$prime = lodash.omit(opts || {}, 'output'); - - // The `output` given there will be passed to gulp, not `psc` command. - // If it was passed to `psc` command, the file will be created and gulp - // won't receive any input stream from this function. - function transform(chunk, encoding, callback) { - var args = chunk.concat(mkOptions(options.psc, opts$prime)); - - var buffero = new Buffer(0); - - var buffere = new Buffer(0); - - execute(options.psc.cmd, args, function(e, cmd){ - if (e) callback(e); - else { - cmd.stdout.on('data', function(stdout){buffero = Buffer.concat([buffero, new Buffer(stdout)]);}); - - cmd.stderr.on('data', function(stderr){buffere = Buffer.concat([buffere, new Buffer(stderr)]);}); - - cmd.on('close', function(code){ - if (code !== 0) callback(new PluginError(pluginName, buffere.toString())); - else { - callback(null, new File({ - path: output, - contents: buffero - })); - } - }); - } - }); - } - - return multipipe(collectPaths(), through2.obj(transform)); -} - -function pscMake(opts) { - function transform(chunk, encoding, callback) { - var args = mkOptions(options.pscMake, opts).concat(chunk); - - var buffero = new Buffer(0); - - var buffere = new Buffer(0); - - execute(options.pscMake.cmd, args, function(e, cmd){ - if (e) callback(e); - else { - cmd.stdout.on('data', function(stdout){buffero = Buffer.concat([buffero, new Buffer(stdout)]);}); - - cmd.stderr.on('data', function(stderr){buffere = Buffer.concat([buffere, new Buffer(stderr)]);}); - - cmd.on('close', function(code){ - var message = - function() { return [ gutil.colors.cyan(options.pscMake.cmd) - , buffero.toString() - , buffere.toString() ].join('\n') }; - - if (code !== 0) callback(new PluginError(pluginName, message())); - else { - if (isVerbose) logalot.info(message()); - callback(); - } - }); - } - }); - }; - - return multipipe(collectPaths(), through2.obj(transform)); -} - -function pscDocs(opts) { - function transform(chunk, encoding, callback) { - var args = mkOptions(options.pscDocs, opts).concat(chunk); - - var buffero = new Buffer(0); - - var buffere = new Buffer(0); - - execute(options.pscDocs.cmd, args, function(e, cmd){ - if (e) callback(e); - else { - cmd.stdout.on('data', function(stdout){buffero = Buffer.concat([buffero, new Buffer(stdout)]);}); - - cmd.stderr.on('data', function(stderr){buffere = Buffer.concat([buffere, new Buffer(stderr)]);}); - - cmd.on('close', function(code){ - if (code !== 0) callback(new PluginError(pluginName, buffere.toString())); - else { - callback(null, new File({ - path: '.', - contents: buffero - })); - } - }); - } - }); - } - - return multipipe(collectPaths(), through2.obj(transform)); -} - -function dotPsci(opts) { - function transform(chunk, encoding, callback) { - if (chunk.isNull()) callback(null, chunk); - else if (chunk.isStream()) callback(new PluginError(pluginName, 'Streaming not supported')); - else { - var buffer = new Buffer(psciLoadCommand + ' ' + path.relative(cwd, chunk.path) + '\n'); - callback(null, buffer); - } - } - - return multipipe(through2.obj(transform), fs.createWriteStream(psciFilename)); -} - -module.exports = { - psc: psc, - pscMake: pscMake, - pscDocs: pscDocs, - dotPsci: dotPsci -} diff --git a/options.js b/options.js deleted file mode 100644 index 0a6fa67..0000000 --- a/options.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -var options = { - psc: { - cmd: 'psc', - flags: { - noPrelude: '--no-prelude', - noOpts: '--no-opts', - noMagicDo: '--no-magic-do', - noTco: '--no-tco', - main: '--main', - verboseErrors: '--verbose-errors' - } - , single: {browserNamespace: '--browser-namespace', externs: '--externs', main: '--main', output: '--output'} - , multi: {modules: '--module', codegen: '--codegen'} - }, - pscMake: { - cmd: 'psc-make', - flags: { - noPrelude: '--no-prelude', - noOpts: '--no-opts', - noMagicDo: '--no-magic-do', - noTco: '--no-tco', - verboseErrors: '--verbose-errors' - } - , single: {browserNamespace: '--browser-namespace', output: '--output'} - , multi: {} - }, - pscDocs: { - cmd: 'psc-docs', - flags: { - hierarchy: '--hierarchy-images' - } - , single: {} - , multi: {} - } -}; - -module.exports = options; diff --git a/package.json b/package.json index b8b0a9f..4ad98ad 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,17 @@ "node": ">=0.10.0" }, "files": [ - "index.js", - "options.js" + "index.js" ], "scripts": { - "test": "node test.js | tap-spec" + "test:run": "node test.js | tap-spec", + "test": "npm run-script build && npm run-script test:run", + "build:bootstrap": "npm install gulp-purescript@0.3.1", + "build": "npm run-script build:bootstrap && npm run-script build:compile && npm run-script build:package", + "build:compile": "gulp build", + "build:package": "./node_modules/.bin/webpack --progress --colors --profile --bail", + "build:json": "./node_modules/.bin/webpack --progress --colors --profile --bail --json > index.json", + "prepublish": "npm run-script build" }, "keywords": [ "gulpplugin", @@ -24,7 +30,6 @@ ], "dependencies": { "gulp-util": "^3.0.4", - "lodash": "^3.5.0", "logalot": "^2.1.0", "minimist": "^1.1.1", "multipipe": "^0.1.2", @@ -33,9 +38,14 @@ "which": "^1.0.9" }, "devDependencies": { + "del": "^1.1.1", "gulp": "^3.8.11", + "gulp-plumber": "^1.0.0", + "json-loader": "^0.5.1", "rewire": "^2.3.1", + "run-sequence": "^1.0.2", "tap-spec": "^2.2.2", - "tape": "^3.5.0" + "tape": "^3.5.0", + "webpack": "^1.8.9" } } diff --git a/src/Buffer.purs b/src/Buffer.purs new file mode 100644 index 0000000..5d35383 --- /dev/null +++ b/src/Buffer.purs @@ -0,0 +1,12 @@ +module GulpPurescript.Buffer + ( Buffer() + , mkBufferFromString + ) where + +data Buffer + +foreign import mkBufferFromString """ +function mkBufferFromString(str) { + return new Buffer(str); +} +""" :: String -> Buffer diff --git a/src/ChildProcess.purs b/src/ChildProcess.purs new file mode 100644 index 0000000..0e7dfaf --- /dev/null +++ b/src/ChildProcess.purs @@ -0,0 +1,46 @@ +module GulpPurescript.ChildProcess + ( ChildProcess() + , spawn + ) where + +import Control.Monad.Aff (Aff(), makeAff) +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) + +import Data.Function + +foreign import data ChildProcess :: ! + +spawn :: forall eff. String -> [String] -> Aff (cp :: ChildProcess | eff) String +spawn command args = makeAff $ runFn4 spawnFn command args + +foreign import spawnFn """ +function spawnFn(command, args, errback, callback) { + return function(){ + var child_process = require('child_process'); + + var process = child_process.spawn(command, args); + + var stdout = new Buffer(0); + + var stderr = new Buffer(0); + + process.stdout.on('data', function(data){ + stdout = Buffer.concat([stdout, new Buffer(data)]); + }); + + process.stderr.on('data', function(data){ + stdout = Buffer.concat([stderr, new Buffer(data)]); + }); + + process.on('close', function(code){ + if (code !== 0) errback(new Error(Buffer.concat([stdout, stderr]).toString()))(); + else callback(stdout.toString())(); + }); + }; +} +""" :: forall eff. Fn4 String + [String] + (Error -> Eff (cp :: ChildProcess | eff) Unit) + (String -> Eff (cp :: ChildProcess | eff) Unit) + (Eff (cp :: ChildProcess | eff) Unit) diff --git a/src/FS.purs b/src/FS.purs new file mode 100644 index 0000000..591606b --- /dev/null +++ b/src/FS.purs @@ -0,0 +1,20 @@ +module GulpPurescript.FS + ( FS() + , Stream() + , createWriteStream + ) where + +import Control.Monad.Eff (Eff()) + +foreign import data FS :: ! + +data Stream i o + +foreign import createWriteStream """ +function createWriteStream(path) { + return function(){ + var fs = require('fs'); + return fs.createWriteStream(path); + }; +} +""" :: forall eff. String -> Eff (fs :: FS | eff) (Stream String Unit) diff --git a/src/GulpUtil.purs b/src/GulpUtil.purs new file mode 100644 index 0000000..c3bdee7 --- /dev/null +++ b/src/GulpUtil.purs @@ -0,0 +1,54 @@ +module GulpPurescript.GulpUtil + ( File() + , mkPluginError + , mkFile + , filePath + , fileIsNull + , fileIsStream + ) where + +import Control.Monad.Eff.Exception (Error()) + +import Data.Function + +import GulpPurescript.Buffer (Buffer()) + +data File + +mkPluginError :: String -> String -> Error +mkPluginError name msg = runFn2 mkPluginErrorFn name msg + +foreign import mkPluginErrorFn """ +function mkPluginErrorFn(name, message) { + var gutil = require('gulp-util'); + return new gutil.PluginError(name, message); +} +""" :: Fn2 String String Error + +mkFile :: String -> Buffer -> File +mkFile path contents = runFn2 mkFileFn path contents + +foreign import mkFileFn """ +function mkFileFn(path, contents) { + var gutil = require('gulp-util'); + 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/Logalot.purs b/src/Logalot.purs new file mode 100644 index 0000000..91d7c47 --- /dev/null +++ b/src/Logalot.purs @@ -0,0 +1,17 @@ +module GulpPurescript.Logalot + ( Logalot() + , info + ) where + +import Control.Monad.Eff (Eff()) + +foreign import data Logalot :: ! + +foreign import info """ +function info(message) { + return function(){ + var logalot = require('logalot'); + logalot.info(message); + }; +} +""" :: forall eff. String -> Eff (logalot :: Logalot | eff) Unit diff --git a/src/Minimist.purs b/src/Minimist.purs new file mode 100644 index 0000000..99f1d52 --- /dev/null +++ b/src/Minimist.purs @@ -0,0 +1,17 @@ +module GulpPurescript.Minimist (minimist) where + +import Data.Either (either) +import Data.Foreign (Foreign()) +import Data.Foreign.Class (IsForeign, read) +import Data.Function +import Data.Maybe (Maybe(..)) + +minimist :: forall a. (IsForeign a) => [String] -> (Maybe a) +minimist argv = either (const Nothing) Just (read $ minimistFn argv) + +foreign import minimistFn """ +function minimistFn(argv) { + var minimist = require('minimist'); + return minimist(argv); +} +""" :: [String] -> Foreign diff --git a/src/Multipipe.purs b/src/Multipipe.purs new file mode 100644 index 0000000..0c61fbf --- /dev/null +++ b/src/Multipipe.purs @@ -0,0 +1,17 @@ +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/OS.purs b/src/OS.purs new file mode 100644 index 0000000..5051a02 --- /dev/null +++ b/src/OS.purs @@ -0,0 +1,38 @@ +module GulpPurescript.OS + ( OS() + , Platform(..) + , platform + ) where + +import Control.Monad.Eff (Eff()) + +import Data.Either (either) +import Data.Foreign (Foreign()) +import Data.Foreign.Class (IsForeign, read) +import Data.Maybe (Maybe(..)) + +foreign import data OS :: ! + +data Platform = Darwin | Linux | Win32 + +instance showPlatform :: Show Platform where + show a = case a of + Darwin -> "darwin" + Linux -> "linux" + Win32 -> "win32" + +instance isForeignPlatform :: IsForeign Platform where + read a = (\a -> case a of + "darwin" -> Darwin + "linux" -> Linux + "win32" -> Win32) <$> read a + +platform :: forall eff. Eff (os :: OS | eff) (Maybe Platform) +platform = either (const Nothing) Just <$> read <$> platformFn + +foreign import platformFn """ +function platformFn() { + var os = require('os'); + return os.platform(); +} +""" :: forall eff. Eff (os :: OS | eff) Foreign diff --git a/src/Options.purs b/src/Options.purs new file mode 100644 index 0000000..6175340 --- /dev/null +++ b/src/Options.purs @@ -0,0 +1,227 @@ +module GulpPurescript.Options + ( pscOptions + , pscOptionsNoOutput + , pscMakeOptions + , pscDocsOptions + ) where + +import Data.Array (concat) +import Data.Either (Either(..), either) +import Data.Foreign (Foreign(), ForeignError(TypeMismatch), F()) +import Data.Foreign.Class (IsForeign, read, readProp) +import Data.Foreign.NullOrUndefined (NullOrUndefined(..), runNullOrUndefined) +import Data.Maybe (Maybe(..), fromMaybe, maybe) +import Data.Tuple (Tuple()) +import Data.Tuple.Nested (tuple2) + +noPreludeOpt = "no-prelude" + +noPreludeKey = "noPrelude" + +noOptsOpt = "no-opts" + +noOptsKey = "noOpts" + +noMagicDoOpt = "no-magic-do" + +noMagicDoKey = "noMagicDo" + +noTcoOpt = "no-tco" + +noTcoKey = "noTco" + +verboseErrorsOpt = "verbose-errors" + +verboseErrorsKey = "verboseErrors" + +outputOpt = "output" + +outputKey = outputOpt + +browserNamespaceOpt = "browser-namespace" + +browserNamespaceKey = "browserNamespace" + +commentsOpt = "comments" + +commentsKey = commentsOpt + +noPrefixOpt = "no-prefix" + +noPrefixKey = "noPrefix" + +mainOpt = "main" + +mainKey = mainOpt + +moduleOpt = "module" + +moduleKey = moduleOpt + +codegenOpt = "codegen" + +codegenKey = codegenOpt + +externsOpt = "externs" + +externsKey = externsOpt + +formatOpt = "format" + +formatKey = formatOpt + +newtype Psc + = Psc { noPrelude :: NullOrUndefined Boolean + , noTco :: NullOrUndefined Boolean + , noMagicDo :: NullOrUndefined Boolean + , mainNoArg :: NullOrUndefined Boolean + , mainWithArg :: NullOrUndefined 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 + } + +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 + } + +newtype PscDocs + = PscDocs { format :: NullOrUndefined Format } + +data Format = Markdown | ETags | CTags + +instance isForeignPsc :: IsForeign Psc where + read obj = + (\a b c d e f g h i j k l m n -> + Psc { noPrelude: a + , noTco: b + , noMagicDo: c + , mainNoArg: d + , mainWithArg: e + , noOpts: f + , verboseErrors: g + , comments: h + , browserNamespace: i + , "module": j + , codegen: k + , output: l + , externs: m + , noPrefix: n + }) <$> readProp noPreludeKey obj + <*> readProp noTcoKey obj + <*> readProp noMagicDoKey obj + <*> readProp mainKey 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 + +instance isForeignPscMake :: IsForeign PscMake where + read obj = + (\a b c d e f g h -> + PscMake { output: a + , noPrelude: b + , noTco: c + , noMagicDo: d + , noOpts: e + , verboseErrors: f + , comments: g + , noPrefix: h + }) <$> readProp outputKey obj + <*> readProp noPreludeKey obj + <*> readProp noTcoKey obj + <*> readProp noMagicDoKey obj + <*> readProp noOptsKey obj + <*> readProp verboseErrorsKey obj + <*> readProp commentsKey obj + <*> readProp noPrefixKey obj + +instance isForeignPscDocs :: IsForeign PscDocs where + read obj = (\a -> PscDocs { format: a }) <$> readProp formatKey obj + +instance isForeignFormat :: IsForeign Format where + read val = read val >>= (\a -> case a of + "markdown" -> Right Markdown + "etags" -> Right ETags + "ctags" -> Right CTags + a -> Left $ TypeMismatch "Format" a) + +mkBoolean :: String -> NullOrUndefined Boolean -> [String] +mkBoolean key opt = maybe [] (\a -> if a then ["--" ++ key] else []) (runNullOrUndefined opt) + +mkString :: String -> NullOrUndefined String -> [String] +mkString key opt = maybe [] (\a -> ["--" ++ key ++ "=" ++ a]) (runNullOrUndefined opt) + +mkStringArray :: String -> NullOrUndefined [String] -> [String] +mkStringArray key opt = concat $ mkString key <$> (NullOrUndefined <<< Just) + <$> (fromMaybe [] $ runNullOrUndefined opt) + +mkFormat :: String -> NullOrUndefined Format -> [String] +mkFormat key opt = mkString key (maybe j (\a -> case a of + Markdown -> i "markdown" + ETags -> i "etags" + CTags -> i "ctags") $ runNullOrUndefined opt) + where i a = NullOrUndefined $ Just a + j = NullOrUndefined Nothing + +foldPscOptions :: Psc -> [String] +foldPscOptions (Psc a) = mkBoolean noPreludeOpt a.noPrelude <> + mkBoolean noTcoOpt a.noTco <> + mkBoolean noMagicDoOpt a.noMagicDo <> + mkBoolean mainOpt a.mainNoArg <> + mkString mainOpt a.mainWithArg <> + mkBoolean noOptsOpt a.noOpts <> + mkBoolean verboseErrorsOpt a.verboseErrors <> + mkBoolean commentsOpt a.comments <> + mkString browserNamespaceOpt a.browserNamespace <> + mkStringArray moduleOpt a."module" <> + mkStringArray codegenOpt a.codegen <> + mkString outputOpt a.output <> + mkString externsOpt a.externs <> + mkBoolean noPrefixOpt a.noPrefix + +pscOptions :: Foreign -> [String] +pscOptions opts = either (const []) foldPscOptions parsed + where parsed = read opts :: F Psc + +pscOptionsNoOutput :: Foreign -> Tuple (Maybe String) [String] +pscOptionsNoOutput opts = either (const $ tuple2 Nothing []) fold parsed + where parsed = read opts :: F Psc + fold (Psc a) = tuple2 (runNullOrUndefined a.output) + (foldPscOptions (Psc $ a { output = NullOrUndefined Nothing })) + +pscMakeOptions :: Foreign -> [String] +pscMakeOptions opts = either (const []) fold parsed + where parsed = read opts :: F PscMake + fold (PscMake a) = mkString outputOpt a.output <> + mkBoolean noPreludeOpt a.noPrelude <> + mkBoolean noTcoOpt a.noTco <> + mkBoolean noMagicDoOpt a.noMagicDo <> + mkBoolean noOptsOpt a.noOpts <> + mkBoolean verboseErrorsOpt a.verboseErrors <> + mkBoolean commentsOpt a.comments <> + mkBoolean noPrefixOpt a.noPrefix + +pscDocsOptions :: Foreign -> [String] +pscDocsOptions opts = either (const []) fold parsed + where parsed = read opts :: F PscDocs + fold (PscDocs a) = mkFormat formatOpt a.format diff --git a/src/Package.purs b/src/Package.purs new file mode 100644 index 0000000..063274f --- /dev/null +++ b/src/Package.purs @@ -0,0 +1,30 @@ +module GulpPurescript.Package + ( Pkg() + , Package(..) + , package + ) where + +import Control.Monad.Eff (Eff()) + +import Data.Either (either) +import Data.Foreign (Foreign()) +import Data.Foreign.Class (IsForeign, read, readProp) +import Data.Function +import Data.Maybe (Maybe(..)) + +foreign import data Pkg :: ! + +newtype Package = Package { name :: String } + +instance isForeignPackage :: IsForeign Package where + read a = (\a -> Package { name: a }) <$> readProp "name" a + +package :: forall eff. Eff (package :: Pkg | eff) (Maybe Package) +package = either (const Nothing) Just <$> read <$> packageFn + +foreign import packageFn """ +function packageFn() { + var pkg = require('../../package.json'); + return pkg; +} +""" :: forall eff. Eff (package :: Pkg | eff) Foreign diff --git a/src/Path.purs b/src/Path.purs new file mode 100644 index 0000000..dd9dbc9 --- /dev/null +++ b/src/Path.purs @@ -0,0 +1,13 @@ +module GulpPurescript.Path (relative) where + +import Data.Function + +relative :: String -> String -> String +relative from to = runFn2 relativeFn from to + +foreign import relativeFn """ +function relativeFn(from, to) { + var path = require('path'); + return path.relative(from, to); +} +""" :: Fn2 String String String diff --git a/src/Plugin.purs b/src/Plugin.purs new file mode 100644 index 0000000..2cb5166 --- /dev/null +++ b/src/Plugin.purs @@ -0,0 +1,132 @@ +module GulpPurescript.Plugin + ( Effects() + , psc + , pscMake + , pscDocs + , dotPsci + ) where + +import Control.Monad.Aff (Aff()) +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Class (liftEff) +import Control.Monad.Eff.Exception (Error()) +import Control.Monad.Error.Class (catchError, throwError) + +import Data.Foreign (Foreign()) +import Data.Foreign.Class (IsForeign, read, readProp) +import Data.Maybe (Maybe(Just), maybe, fromMaybe) +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.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 (pscOptionsNoOutput, pscMakeOptions, pscDocsOptions) +import GulpPurescript.Package (Pkg(), Package(..), package) +import GulpPurescript.Path (relative) +import GulpPurescript.ResolveBin (ResolveBin(), resolveBin) +import GulpPurescript.Through2 (Through2(), objStream, accStream) +import GulpPurescript.Which (Which(), which) + +newtype Argv = Argv { verbose :: Boolean } + +instance isForeignArgv :: IsForeign Argv where + read obj = (\a -> Argv { verbose: a }) <$> readProp "verbose" obj + +type Effects eff = + ( cp :: ChildProcess + , fs :: FS + , logalot :: Logalot + , os :: OS + , package :: Pkg + , resolveBin :: ResolveBin + , through2 :: Through2 + , which :: Which + | eff + ) + +nodeCommand = "node" + +pursPackage = "purescript" + +psciFilename = ".psci" + +psciLoadCommand = ":m" + +pscCommand = "psc" + +pscMakeCommand = "psc-make" + +pscDocsCommand = "psc-docs" + +pscOutputDefault = "psc.js" + +isVerbose = maybe false (\(Argv a) -> a.verbose) (minimist argv) + +foreign import cwd "var cwd = process.cwd();" :: String + +foreign import argv "var argv = process.argv.slice(2);" :: [String] + +pluginError :: forall eff. String -> Aff (Effects eff) Error +pluginError msg = liftEff $ flip mkPluginError msg <$> (maybe "" (\(Package a) -> a.name)) <$> package + +resolve :: forall eff. String -> [String] -> Aff (Effects eff) (Tuple String [String]) +resolve cmd args = catchError primary fallback + where + primary :: Aff (Effects eff) (Tuple String [String]) + primary = do + bin <- resolveBin pursPackage { executable: cmd } + os <- liftEff platform + return $ case os of + Just Win32 -> tuple2 nodeCommand ([bin] <> args) + _ -> tuple2 bin args + + fallback :: Error -> Aff (Effects eff) (Tuple String [String]) + fallback _ = (const $ tuple2 cmd args) <$> catchError (which cmd) mapError + + mapError :: Error -> Aff (Effects eff) String + mapError _ = pluginError ( "Failed to find " ++ cmd ++ ". " ++ + "Please ensure it is available on your system." + ) >>= throwError + +execute :: forall eff. String -> [String] -> Aff (Effects eff) String +execute cmd args = do + Tuple cmd' args' <- resolve cmd args + 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 pluginError "Streaming is not supported" >>= throwError + 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 + 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 <- execute pscMakeCommand (i <> 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 = mkFile "." <$> mkBufferFromString + <$> execute pscDocsCommand (pscDocsOptions opts <> i) + +dotPsci :: forall eff. Eff (Effects eff) (Stream File Unit) +dotPsci = multipipe2 <$> objStream run <*> createWriteStream psciFilename + where run i = if fileIsStream i + then pluginError "Streaming is not supported" >>= throwError + else pure $ psciLoadCommand ++ " " ++ relative cwd (filePath i) ++ "\n" diff --git a/src/ResolveBin.purs b/src/ResolveBin.purs new file mode 100644 index 0000000..364ebfc --- /dev/null +++ b/src/ResolveBin.purs @@ -0,0 +1,35 @@ +module GulpPurescript.ResolveBin + ( ResolveBin() + , Options(..) + , resolveBin + ) where + +import Control.Monad.Aff (Aff(), makeAff) +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) + +import Data.Function + +foreign import data ResolveBin :: ! + +type Options = { executable :: String } + +resolveBin :: forall eff. String -> Options -> Aff (resolveBin :: ResolveBin | eff) String +resolveBin pkg opts = makeAff $ runFn4 resolveBinFn pkg opts + +foreign import resolveBinFn """ +function resolveBinFn(pkg, options, errback, callback) { + return function(){ + var resolveBin = require('resolve-bin'); + + resolveBin(pkg, options, function(e, bin){ + if (e) errback(e)(); + else callback(bin)(); + }) + }; +} +""" :: forall eff. Fn4 String + Options + (Error -> Eff (resolveBin :: ResolveBin | eff) Unit) + (String -> Eff (resolveBin :: ResolveBin | eff) Unit) + (Eff (resolveBin :: ResolveBin | eff) Unit) diff --git a/src/Through2.purs b/src/Through2.purs new file mode 100644 index 0000000..64e164c --- /dev/null +++ b/src/Through2.purs @@ -0,0 +1,96 @@ +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/src/Which.purs b/src/Which.purs new file mode 100644 index 0000000..a9f2a16 --- /dev/null +++ b/src/Which.purs @@ -0,0 +1,31 @@ +module GulpPurescript.Which + ( Which() + , which + ) where + +import Control.Monad.Aff (Aff(), makeAff) +import Control.Monad.Eff (Eff()) +import Control.Monad.Eff.Exception (Error()) + +import Data.Function + +foreign import data Which :: ! + +which :: forall eff. String -> Aff (which :: Which | eff) String +which cmd = makeAff $ runFn3 whichFn cmd + +foreign import whichFn """ +function whichFn(command, errback, callback) { + return function(){ + var which = require('which'); + + which(command, function(e, path){ + if (e) errback(e)(); + else callback(path)(); + }) + }; +} +""" :: forall eff. Fn3 String + (Error -> Eff (which :: Which | eff) Unit) + (String -> Eff (which :: Which | eff) Unit) + (Eff (which :: Which | eff) Unit) diff --git a/test.js b/test.js index 3826a89..18a3264 100644 --- a/test.js +++ b/test.js @@ -53,7 +53,7 @@ test('psc - failure', function(t){ gulp.src(fixture).pipe(stream). on('error', function(e){ - t.ok(/"where"/.test(e.message), 'should have a failure message'); + t.ok(e.message && e.message !== '', 'should have a failure message'); t.equal('Error', e.name); }); }); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..52944c9 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,33 @@ +'use strict'; + +var path = require('path'); + +var webpack = require('webpack'); + +var packageJson = require('./package.json'); + +var noErrorsPlugin = webpack.NoErrorsPlugin; + +var dedupePlugin = webpack.optimize.DedupePlugin; + +var config + = { cache: true + , target: 'node' + , entry: { index: './entry' } + , externals: Object.keys(packageJson.dependencies).reduce(function(b, a){ + b[a] = 'commonjs ' + a; + return b; + }, {}) + , module: { loaders: [ { test: /\.json$/, loader: 'json-loader' } ] } + , output: { path: __dirname + , filename: '[name].js' + , libraryTarget: 'commonjs2' + } + , plugins: [ new noErrorsPlugin() + , new dedupePlugin() + ] + , resolve: { modulesDirectories: [ 'build' ] } + } + ; + +module.exports = config; From 641ff62f37c69ba57ef9b9f84d3eb0f7e234ee7d Mon Sep 17 00:00:00 2001 From: eric thul Date: Sat, 25 Apr 2015 15:10:05 -0400 Subject: [PATCH 2/2] Updating the README --- LICENSE | 2 +- README.md | 172 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 105 insertions(+), 69 deletions(-) diff --git a/LICENSE b/LICENSE index aaed7de..05b0016 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014 Eric Thul +Copyright (c) 2015 Eric Thul Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 36ad73e..8291d01 100644 --- a/README.md +++ b/README.md @@ -32,74 +32,110 @@ gulp.task('purescript', function(){ Refer to the PureScript [compiler usage](https://github.com/purescript/purescript/wiki/Language-Guide:-Getting-Started#compiler-usage) section of the Github wiki for additional details on the behaviour of each option below. -### purescript.psc(options) - -Invokes the `psc` command. - -#### options - - - **noPrelude**: Boolean value that toggles `--no-prelude` - - Do not include the Prelude in the generated Javascript. - - **noTco**: Boolean value that toggles `--no-tco` - - Turn off tail-call elimination. - - **noMagicDo**: Boolean value that toggles `--no-magic-do` - - Turn off optimizations which inline calls to >>= for the Eff monad. - - **main**: Boolean or string value that sets `--main` or `--main=` - - Generate a call to main in the specified module after all other generated Javascript. Defaults to Main if the option is used but no value is provided. - - **noOpts**: Boolean value that toggles `--no-opts` - - Disable all optimizations. - - **verboseErrors**: Boolean value that toggles `--verbose-errors` - - Generate verbose error messages. - - **comments**: Boolean value that toggles `--comments` - - Include comments in generated code. - - **browserNamespace**: String value that sets `--browser-namespace=` - - Specify the namespace that PureScript modules will be exported to when running in the browser. - - **externs**: String value that sets `--externs=` - - Write a list of foreign imports declarations to the specified file in addition to generating Javascript output. - - **module**: Array of string values that sets one or more `--module=` - - If specified, any code which is not referenced transitively from this module will be removed. - - **codegen**: Array of string values that sets one or more `--codegen=` - - A array of modules for which JavaScript and externs should be generated. - - **output**: String value that specifies the output file. Note that this will not set `--output=` because the resulting file is piped through the Gulp stream. - - Write the generated Javascript to the specified file. - - **noPrefix**: Boolean value that toggles `--no-prefix` - - Do not include the comment header. - -### purescript.pscMake(options) - -Invokes the `psc-make` command. - -#### options - - - **noPrelude**: Boolean value that toggles `--no-prelude` - - Do not include the Prelude in the generated Javascript. - - **noOpts**: Boolean value that toggles `--no-opts` - - Disable all optimizations. - - **noMagicDo**: Boolean value that toggles `--no-magic-do` - - Turn off optimizations which inline calls to >>= for the Eff monad. - - **noTco**: Boolean value that toggles `--no-tco` - - Turn off tail-call elimination. - - **verboseErrors**: Boolean value that toggles `--verbose-errors` - - Generate verbose error messages. - - **browserNamespace**: String value that sets `--browser-namespace=` - - Specify the namespace that PureScript modules will be exported to when running in the browser. - - **output**: String value that sets `--output=` - - Write the generated Javascript to the specified file. - -### purescript.pscDocs(options) - -Invokes the `pscDocs` command. - -#### options - - - hierarchy: Boolean value that toggles `--hierarchy-images` - -### purescript.dotPsci() - -Generates a `.psci` file in the current directory. Each source file is -added with the `:m` command. +### `purescript.psc(options)` + +Invokes the `psc` 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. + +###### `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. + +###### `verboseErrors` (Boolean) + +Toggles `--verbose-errors` that displays verbose error messages. + +###### `comments` (Boolean) + +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 extenrs 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=`. + +###### `noPrefix` (Boolean) + +Toggles `--no-prefix` that does not include the comment header. + +### `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) + +Toggles `--no-opts` that skips the optimization phase. + +###### `verboseErrors` (Boolean) + +Toggles `--verbose-errors` that displays verbose error messages. + +###### `comments` (Boolean) + +Toggles `--comments` that includes comments in generated code. + +###### `output` (String) + +Sets `--output=` the specifies the output directory, `output` by default. + +###### `noPrefix` (Boolean) + +Toggles `--no-prefix` that does not include the comment header. + +### `purescript.pscDocs(options)` + +Invokes the `pscDocs` command. The following options are supported. + +###### `format` (markdown | etags | ctags) + +Sets `--output=` that specifies the output format. + +### `purescript.dotPsci()` + +Generates a `.psci` file in the current directory. Each source file is added with the `:m` command. ## Command line arguments -The `--verbose` argument will display the output during the `psc-make` -command. For example `gulp --verbose`. +The `--verbose` argument will display the output during the `psc-make` command. For example `gulp --verbose`.