From ded4db2f5e069996a42e775572ced39fc6bfd06a Mon Sep 17 00:00:00 2001 From: Ramiro Silveyra d'Avila Date: Sun, 19 Feb 2017 15:30:39 -0300 Subject: [PATCH] Add support for async rules (#2351) * Add support for async rules * Copy editing --- docs/developer-guide/plugins.md | 39 ++++++++++++++++++++++++-- lib/__tests__/fixtures/plugin-async.js | 30 ++++++++++++++++++++ lib/__tests__/plugins.test.js | 12 ++++++++ lib/lintSource.js | 2 +- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 lib/__tests__/fixtures/plugin-async.js diff --git a/docs/developer-guide/plugins.md b/docs/developer-guide/plugins.md index 4ffcf9b80f..43e69d4628 100644 --- a/docs/developer-guide/plugins.md +++ b/docs/developer-guide/plugins.md @@ -36,6 +36,39 @@ In order for your plugin rule to work with the [standard configuration format](. `ruleFunction` should return a function that is essentially a little [PostCSS plugin](https://github.com/postcss/postcss/blob/master/docs/writing-a-plugin.md): it takes 2 arguments: the PostCSS Root (the parsed AST), and the PostCSS LazyResult. You'll have to [learn about the PostCSS API](https://github.com/postcss/postcss/blob/master/docs/api.md). +### Asynchronous rules + +Rules with asynchronous PostCSS plugins are also possible! All you need to do is return a Promise instance from your plugin function. + +```js +// Abbreviated asynchronous example +var stylelint = require("stylelint") + +var ruleName = "plugin/foo-bar-async" +var messages = stylelint.utils.ruleMessages(ruleName, { + expected: "Expected ...", +}) + +module.exports = stylelint.createPlugin(ruleName, function(primaryOption, secondaryOptionObject) { + return function(postcssRoot, postcssResult) { + var validOptions = stylelint.utils.validateOptions(postcssResult, ruleName, { .. }) + if (!validOptions) { return } + + return new Promise(function(resolve) { + // some async operation + setTimeout(function() { + // ... some logic ... + stylelint.utils.report({ .. }) + resolve() + }, 1) + }) + } +}) + +module.exports.ruleName = ruleName +module.exports.messages = messages +``` + ## `stylelint.utils` stylelint exposes some utilities that are useful. *For details about the APIs of these functions, please look at comments in the source code and examples in the standard rules.* @@ -82,9 +115,9 @@ function myPluginRule(primaryOption, secondaryOptions) { root: root }, (warning) => { stylelint.utils.report({ - message: myMessage, - ruleName: myRuleName, - result: result, + message: myMessage, + ruleName: myRuleName, + result: result, node: warning.node, line: warning.line, column: warning.column, diff --git a/lib/__tests__/fixtures/plugin-async.js b/lib/__tests__/fixtures/plugin-async.js new file mode 100644 index 0000000000..9e8cf8826a --- /dev/null +++ b/lib/__tests__/fixtures/plugin-async.js @@ -0,0 +1,30 @@ +"use strict" + +const stylelint = require("../../") + +const ruleName = "plugin/async" + +const rule = enabled => (root, result) => { + const validOptions = stylelint.utils.validateOptions(result, ruleName, { + actual: enabled, + possible: [ true, false ], + }) + + if (!validOptions) { + return null + } + + return new Promise((resolve) => { + setTimeout(() => { + stylelint.utils.report({ + result, + ruleName, + message: "Async rule", + node: root, + }) + resolve() + }) + }, 1) +} + +module.exports = stylelint.createPlugin(ruleName, rule) diff --git a/lib/__tests__/plugins.test.js b/lib/__tests__/plugins.test.js index 1984350aa7..3c121207a3 100644 --- a/lib/__tests__/plugins.test.js +++ b/lib/__tests__/plugins.test.js @@ -199,6 +199,18 @@ it("plugin with primary option array within options array", () => { }) }) +it("plugin with async rule", () => { + const config = { + plugins: [path.join(__dirname, "fixtures/plugin-async")], + rules: { + "plugin/async": true, + }, + } + return postcss().use(stylelint(config)).process("a {}").then(result => { + expect(result.warnings().length).toBe(1) + }) +}) + describe("loading a plugin from process.cwd", () => { let actualCwd let result diff --git a/lib/lintSource.js b/lib/lintSource.js index 31efb039f0..073fdd5605 100644 --- a/lib/lintSource.js +++ b/lib/lintSource.js @@ -119,7 +119,7 @@ function lintPostcssResult( postcssResult.stylelint.customMessages[ruleName] = _.get(secondaryOptions, "message") const performRule = Promise.resolve().then(() => { - ruleFunction(primaryOption, secondaryOptions)(postcssRoot, postcssResult) + return ruleFunction(primaryOption, secondaryOptions)(postcssRoot, postcssResult) }) performRules.push(performRule) })