diff --git a/README.md b/README.md index 1c6c49f..657a060 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ When combined with a watching task (such as [grunt-contrib-watch][watch]), even ## Options +### `threads` + +* Type: `String`, `Boolean`, `Number` +* Default: `auto`, which is the number of threads -1 + +Use this option to control the number of threads that grunt-htmllint will use when validating a big number of files. This will spawn as many Java processes as the number of threads. + ### `ignore` * Type: `Array`, `String`, or `RegExp` diff --git a/lib/getThreads.js b/lib/getThreads.js new file mode 100644 index 0000000..651d6c3 --- /dev/null +++ b/lib/getThreads.js @@ -0,0 +1,31 @@ +'use strict'; + +const os = require('os'); + +// eslint-disable-next-line unicorn/explicit-length-check +const CPUS = os.cpus() && os.cpus().length; +const THREADS = CPUS > 2 ? CPUS - 1 : 1; + +function getThreads(config) { + const { threads } = config; + + switch (threads) { + case 'auto': + case -1: + case '': + case true: + case null: + case undefined: + return THREADS; + case 0: + case 1: + case false: + return 1; + default: + if (threads > 1) { + return threads; + } + } +} + +module.exports = getThreads; diff --git a/lib/htmllint.js b/lib/htmllint.js index a3b9783..c7cdb60 100644 --- a/lib/htmllint.js +++ b/lib/htmllint.js @@ -1,12 +1,12 @@ 'use strict'; -const os = require('os'); const path = require('path'); const { execFile } = require('child_process'); const async = require('async'); const chunkify = require('./chunkify.js'); -const javaDetect = require('./javaDetect.js'); +const getThreads = require('./getThreads.js'); const javaArgs = require('./javaArgs.js'); +const javaDetect = require('./javaDetect.js'); const parseErrorMessages = require('./parseErrorMessages.js'); const processErrorMessages = require('./processErrorMessages.js'); @@ -20,10 +20,6 @@ const MAX_CHARS = 5000; */ const MAX_BUFFER = 20_000 * 1024; -// eslint-disable-next-line unicorn/explicit-length-check -const CPUS = os.cpus() && os.cpus().length; -const THREADS = CPUS > 2 ? CPUS - 1 : 1; - function htmllint(config, done) { if (config.files.length === 0) { return done(null, []); @@ -42,8 +38,9 @@ function htmllint(config, done) { const files = config.files.map(file => path.normalize(file)); const chunks = chunkify(files, MAX_CHARS); + const threads = getThreads(config); - async.mapLimit(chunks, THREADS, (chunk, cb) => { + async.mapLimit(chunks, threads, (chunk, cb) => { const args = javaArgs(java, chunk, config); execFile('java', args, { maxBuffer: MAX_BUFFER, shell: true }, (error, stdout, stderr) => { diff --git a/tasks/html.js b/tasks/html.js index 75761ce..a82bc2d 100644 --- a/tasks/html.js +++ b/tasks/html.js @@ -21,7 +21,8 @@ module.exports = grunt => { force: false, absoluteFilePathsForReporter: false, errorlevels: ['info', 'warning', 'error'], - noLangDetect: false + noLangDetect: false, + threads: 'auto' }); const { force } = options; let { reporterOutput } = options; diff --git a/test/threads_test.js b/test/threads_test.js new file mode 100644 index 0000000..c2e627c --- /dev/null +++ b/test/threads_test.js @@ -0,0 +1,49 @@ +'use strict'; + +const assert = require('assert').strict; +const os = require('os'); +const getThreads = require('../lib/getThreads.js'); + +// eslint-disable-next-line unicorn/explicit-length-check +const CPUS = os.cpus() && os.cpus().length; +const THREADS = CPUS > 2 ? CPUS - 1 : 1; + +describe('getThreads', () => { + it('should use the number of available threads -1', done => { + const config = {}; + + for (const option of ['auto', -1, '', true, null, undefined]) { + config.threads = option; + const expected = THREADS; + const actual = getThreads(config); + + assert.equal(actual, expected, `"thread: ${option}" failed!`); + } + + done(); + }); + + it('should return 1 with false, 0, or 1', done => { + const config = {}; + + for (const option of [0, 1, false]) { + config.threads = option; + const expected = 1; + const actual = getThreads(config); + assert.equal(actual, expected); + } + + done(); + }); + + it('should return the number of threads', done => { + const config = { + threads: 4 + }; + const expected = 4; + const actual = getThreads(config); + + assert.equal(actual, expected); + done(); + }); +});