Skip to content

Commit e2f33b8

Browse files
authored
refactor: lint dirty modules plugin (#59)
* refactor: use filter on filetimestamps' keys as opposed to reduce. also use lodash.defaultto for comparing numeric values to avoid falsy JS bugs * refactor: use Arrange Act Assert model for tests and clean up some assertions and specs * refactor: pulls out defaultFilesGlob constant * refactor: clean up typos * refactor: use .test.js file suffix to enable the recursive flag in mocha. * refactor: better names for all fixtures * tests: add coverage for without plugin config * tests: update NoErrorsPlugin tests Verify that existing behaviour works as expected * refactor: minor test tweaks * tests: correct test of empty plugin config * tests: remove extra context from lint dirty modules plugin
1 parent 7e60e9b commit e2f33b8

File tree

18 files changed

+289
-305
lines changed

18 files changed

+289
-305
lines changed

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var formatter = require('stylelint').formatters.string;
99
// Modules
1010
var runCompilation = require('./lib/run-compilation');
1111
var LintDirtyModulesPlugin = require('./lib/lint-dirty-modules-plugin');
12+
var defaultFilesGlob = require('./lib/constants').defaultFilesGlob;
1213

1314
function apply (options, compiler) {
1415
options = options || {};
@@ -19,7 +20,7 @@ function apply (options, compiler) {
1920
}, options, {
2021
// Default Glob is any directory level of scss and/or sass file,
2122
// under webpack's context and specificity changed via globbing patterns
22-
files: arrify(options.files || '**/*.s?(c|a)ss').map(function (file) {
23+
files: arrify(options.files || defaultFilesGlob).map(function (file) {
2324
return path.join(context, '/', file);
2425
}),
2526
context: context

lib/constants.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
3+
module.exports = {
4+
defaultFilesGlob: '**/*.s?(c|a)ss'
5+
};

lib/lint-dirty-modules-plugin.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
'use strict';
2-
var minimatch = require('minimatch');
3-
var reduce = require('lodash.reduce');
2+
43
var assign = require('object-assign');
4+
var defaultTo = require('lodash.defaultto');
5+
var minimatch = require('minimatch');
56
var runCompilation = require('./run-compilation');
67

78
/**
89
* Binds callback with provided options and stores initial values.
910
*
1011
* @param compiler - webpack compiler object
1112
* @param options - stylelint nodejs options
12-
* @param callback <function(options, compilitaion)> - callback to call on emit
1313
*/
1414
function LintDirtyModulesPlugin (compiler, options) {
1515
this.startTime = Date.now();
1616
this.prevTimestamps = {};
1717
this.isFirstRun = true;
1818
this.compiler = compiler;
1919
this.options = options;
20-
compiler.plugin('emit',
21-
this.lint.bind(this) // bind(this) is here to prevent context overriding by webpack
22-
);
20+
21+
// bind(this) is here to prevent context overriding by webpack
22+
compiler.plugin('emit', this.lint.bind(this));
2323
}
2424

2525
/**
@@ -31,16 +31,18 @@ function LintDirtyModulesPlugin (compiler, options) {
3131
* @param callback - to be called when execution is done
3232
* @returns {*}
3333
*/
34-
LintDirtyModulesPlugin.prototype.lint = function (compilation, callback) {
34+
LintDirtyModulesPlugin.prototype.lint = function lint (compilation, callback) {
3535
if (this.isFirstRun) {
3636
this.isFirstRun = false;
3737
this.prevTimestamps = compilation.fileTimestamps;
3838
return callback();
3939
}
40+
4041
var dirtyOptions = assign({}, this.options);
4142
var glob = dirtyOptions.files.join('|');
4243
var changedFiles = this.getChangedFiles(compilation.fileTimestamps, glob);
4344
this.prevTimestamps = compilation.fileTimestamps;
45+
4446
if (changedFiles.length) {
4547
dirtyOptions.files = changedFiles;
4648
runCompilation.call(this, dirtyOptions, this.compiler, callback);
@@ -57,18 +59,16 @@ LintDirtyModulesPlugin.prototype.lint = function (compilation, callback) {
5759
* @param fileTimestamps - an object with keys as filenames and values as their timestamps.
5860
* e.g. {'/filename.scss': 12444222000}
5961
* @param glob - glob pattern to match files
62+
* @returns {Array} list of globs that contain changed files
6063
*/
61-
LintDirtyModulesPlugin.prototype.getChangedFiles = function (fileTimestamps, glob) {
62-
return reduce(fileTimestamps, function (changedStyleFiles, timestamp, filename) {
63-
// Check if file has been changed first ...
64-
if ((this.prevTimestamps[filename] || this.startTime) < (fileTimestamps[filename] || Infinity) &&
65-
// ... then validate by the glob pattern.
66-
minimatch(filename, glob, {matchBase: true})
67-
) {
68-
changedStyleFiles = changedStyleFiles.concat(filename);
69-
}
70-
return changedStyleFiles;
71-
}.bind(this), []);
64+
LintDirtyModulesPlugin.prototype.getChangedFiles = function getChangedFiles (fileTimestamps, glob) {
65+
return Object.keys(fileTimestamps).filter(function (filename) {
66+
return hasFileChanged.call(this, filename, fileTimestamps[filename]) && minimatch(filename, glob, {matchBase: true});
67+
}.bind(this));
7268
};
7369

70+
function hasFileChanged (filename, timestamp) {
71+
return defaultTo(this.prevTimestamps[filename], this.startTime) < defaultTo(timestamp, Infinity);
72+
}
73+
7474
module.exports = LintDirtyModulesPlugin;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"dependencies": {
3434
"arrify": "^1.0.1",
3535
"chalk": "^1.1.3",
36-
"lodash.reduce": "^4.6.0",
36+
"lodash.defaultto": "^4.14.0",
3737
"minimatch": "^3.0.3",
3838
"object-assign": "^4.1.0",
3939
"stylelint": "^7.7.0"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)