diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a7ea30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 57b51b2..55a1d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /node_modules/ /example/out/ +.idea +npm-debug.log diff --git a/README.md b/README.md index bdda0ae..6c61af8 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ module.exports = { }, plugins: [ new FlowtypePlugin() - // new FlowtypePlugin({cwd: '/path/'}) + // new FlowtypePlugin({checkAll: true}) // new FlowtypePlugin({failOnError: true}) ] // ... @@ -51,7 +51,7 @@ module.exports = { }, plugins: [ new FlowtypePlugin() - // new FlowtypePlugin({cwd: '/path/'}) + // new FlowtypePlugin({checkAll: true}) // new FlowtypePlugin({failOnError: true}) ] // ... diff --git a/example/entry.js b/example/entry.js index d2c8184..96e7331 100644 --- a/example/entry.js +++ b/example/entry.js @@ -1,4 +1,9 @@ -/* @flow */ const { add } = require('./test'); add('x', 5); + +function sub (a: number, b: number) { + return a - b; +} + +sub('1', 2); diff --git a/example/test.js b/example/test.js index 7a94d9e..8b4c8f0 100644 --- a/example/test.js +++ b/example/test.js @@ -1,10 +1,10 @@ -/* @flow */ +// @flow function add (a: number, b: number) { return a + b; } -function sub (a, b: number) { +function sub (a, b) { return a - b; } diff --git a/example/webpack.config.js b/example/webpack.config.js index 517a545..db01171 100644 --- a/example/webpack.config.js +++ b/example/webpack.config.js @@ -16,6 +16,6 @@ module.exports = { ] }, plugins: [ - new FlowtypePlugin() + new FlowtypePlugin({failOnError: true, checkAll: true}) ] }; diff --git a/index.js b/index.js index 1037dd7..6a3036e 100644 --- a/index.js +++ b/index.js @@ -1,23 +1,29 @@ -var prettyPrintError = require('./lib/flowResult').prettyPrintError; +const util = require('util') module.exports = function (source) { this.cacheable(); - if (typeof (this.flowtypeCheck) !== 'function') { - throw new Error('You need to configure FlowtypePlugin'); + const options = this.flowtypeLoaderCheckOptions; + const checkAll = options && options.checkAll; + const failOnError = options && options.failOnError; + const callback = this.async(); + + if (!checkAll) { + const flowAnnotation = source.slice(0, 8); + if (flowAnnotation !== '/* @flow' && flowAnnotation !== '// @flow') { + callback(null, source); + return; + } } - var callback = this.async(); - this.flowtypeCheck(this.resourcePath, function (errors, options) { - var flowErrors = errors.map(prettyPrintError); - if (flowErrors.length > 0) { - flowErrors.map(this.emitError); - if (options.failOnError) { - throw new Error('Module failed because of a Flow error.\n' - + flowErrors.join('\n')); + this.flowtypeLoaderCheckContent(source, this.resourcePath, function (errors, options) { + if (errors.length > 0) { + errors.map(this.emitError); + if (failOnError) { + throw new Error('Module failed because of a Flow error.\n' + errors.join('\n')); } - } + callback(null, source); }.bind(this)); }; diff --git a/lib/flowCheckContent.js b/lib/flowCheckContent.js new file mode 100644 index 0000000..b0e3a76 --- /dev/null +++ b/lib/flowCheckContent.js @@ -0,0 +1,41 @@ +const flowBin = require('flow-bin'); +const spawn = require('child_process').spawn; + +const flowCheckConetent = (content, path, callback) => { + const flow = spawn(flowBin, ['check-contents', path, '--show-all-errors', '--json']); + var result = ''; + + flow.stdout.on('data', function (data) { + result += data.toString(); + }); + + flow.stderr.on('data', function (data) { + throw new Error(data.toString()); + }); + + flow.on('error', function (e) { + throw e; + }); + + flow.on('close', function (code) { + if (code !== 12 && result !== '') { + try { + callback(JSON.parse(result)); + } catch (e) { + throw e; + } + } else { + callback(null); + } + }); + + try { + flow.stdin.write(content); + flow.stdin.end(); + } catch (e) { + throw e; + } + +}; + +module.exports = flowCheckConetent; diff --git a/lib/flowStatus.js b/lib/flowStatus.js deleted file mode 100644 index 8406e33..0000000 --- a/lib/flowStatus.js +++ /dev/null @@ -1,29 +0,0 @@ -var flowBin = require('flow-bin'); -var spawn = require('child_process').spawn; - -function flowStatus(cwd, callback) { - var flow = spawn(flowBin, ['status', '--json'], {cwd: cwd}); - var flowJson = ''; - - flow.stdout.on('data', function (data) { - flowJson += data.toString(); - }); - - flow.on('error', function(e) { - throw e; - }); - - flow.on('close', function (code) { - if (code !== 12 && flowJson !== '') { - try { - callback(JSON.parse(flowJson)); - } catch (e) { - throw e; - } - } else { - callback(null); - } - }); -} - -module.exports = flowStatus; diff --git a/package.json b/package.json index ccb19e6..4d75358 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "0.2.2", "description": "Flow loader for webpack", "main": "index.js", - "scripts": {}, + "scripts": { + "dev": "cd example; ../node_modules/.bin/webpack" + }, "repository": { "type": "git", "url": "git+https://github.com/torifat/flowtype-loader.git" diff --git a/plugin.js b/plugin.js index 66ba443..6bffc90 100644 --- a/plugin.js +++ b/plugin.js @@ -1,72 +1,21 @@ -var flowStatus = require('./lib/flowStatus'); +const flowCheckConetent = require('./lib/flowCheckContent'); +const prettyPrintError = require('./lib/flowResult').prettyPrintError; function FlowtypePlugin(options) { this._options = options || {}; - if (!this._options.cwd) { - this._options.cwd = process.cwd(); - } - this._resources = []; - this._isFlowRunning = false; - this._flowStatus = null; } -FlowtypePlugin.prototype.getFlowStatus = function () { - if (this._isFlowRunning) { - return true; - } - - this._isFlowRunning = true; - - flowStatus(this._options.cwd, function (status) { - this._flowStatus = status; - this._isFlowRunning = false; - this._notifyResources(); - }.bind(this)); -}; - -FlowtypePlugin.prototype.addResource = function (resourcePath, callback) { - var resource = {path: resourcePath, callback: callback}; - if (this._isFlowRunning) { - this._resources.push(resource); - } else { - this._notifyResourceError(resource); - } -}; - -FlowtypePlugin.prototype.clearResources = function () { - this._resources = []; -}; - -FlowtypePlugin.prototype._notifyResources = function () { - for (var i = 0; i < this._resources.length; i++) { - var resource = this._resources[i]; - this._notifyResourceError(resource); - } - this.clearResources(); -}; - -FlowtypePlugin.prototype._notifyResourceError = function(resource) { - if (resource.callback) { - var errors = []; - if (this._flowStatus && !this._flowStatus.passed) { - errors = this._flowStatus.errors - } - resource.callback(errors, this._options); - } -}; - FlowtypePlugin.prototype.apply = function (compiler) { - var plugin = this; - - compiler.plugin('compile', function () { - plugin.clearResources(); - plugin.getFlowStatus(); - }); + const plugin = this; compiler.plugin('compilation', function (compilation) { compilation.plugin('normal-module-loader', function (context, module) { - context.flowtypeCheck = function(resourcePath, callback) { - plugin.addResource(resourcePath, callback); + context.flowtypeLoaderCheckOptions = plugin._options; + context.flowtypeLoaderCheckContent = function(content, path, callback) { + flowCheckConetent(content, path, function(result) { + const errors = result.errors.map(prettyPrintError); + callback(errors); + }) }; }); });