stylelint-webpack-plugin 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,5 @@ class StylelintError extends Error {
9
9
  this.name = 'StylelintError';
10
10
  this.stack = '';
11
11
  }
12
-
13
12
  }
14
-
15
13
  module.exports = StylelintError;
@@ -3,94 +3,94 @@
3
3
  const {
4
4
  cpus
5
5
  } = require('os');
6
-
7
6
  const {
8
7
  Worker: JestWorker
9
- } = require('jest-worker'); // @ts-ignore
10
-
8
+ } = require('jest-worker');
11
9
 
10
+ // @ts-ignore
12
11
  const {
13
12
  setup,
14
13
  lintFiles
15
14
  } = require('./worker');
16
-
17
15
  const {
18
16
  jsonStringifyReplacerSortKeys
19
17
  } = require('./utils');
20
-
21
18
  const {
22
19
  getStylelintOptions
23
20
  } = require('./options');
24
- /** @type {{[key: string]: any}} */
25
-
26
21
 
22
+ /** @type {{[key: string]: any}} */
27
23
  const cache = {};
28
- /** @typedef {import('stylelint')} Stylelint */
29
24
 
25
+ /** @typedef {{lint: (options: LinterOptions) => Promise<LinterResult>, formatters: { [k: string]: Formatter }}} Stylelint */
30
26
  /** @typedef {import('stylelint').LintResult} LintResult */
31
-
27
+ /** @typedef {import('stylelint').LinterOptions} LinterOptions */
28
+ /** @typedef {import('stylelint').LinterResult} LinterResult */
29
+ /** @typedef {import('stylelint').Formatter} Formatter */
30
+ /** @typedef {import('stylelint').FormatterType} FormatterType */
32
31
  /** @typedef {import('./options').Options} Options */
33
-
32
+ /** @typedef {(stylelint: Stylelint, filePath: string) => Promise<boolean>} isPathIgnored */
34
33
  /** @typedef {() => Promise<void>} AsyncTask */
35
-
36
34
  /** @typedef {(files: string|string[]) => Promise<LintResult[]>} LintTask */
37
-
38
- /** @typedef {{api: import('stylelint').InternalApi, stylelint: Stylelint, lintFiles: LintTask, cleanup: AsyncTask, threads: number, }} Linter */
39
-
35
+ /** @typedef {{stylelint: Stylelint, isPathIgnored: isPathIgnored, lintFiles: LintTask, cleanup: AsyncTask, threads: number }} Linter */
40
36
  /** @typedef {JestWorker & {lintFiles: LintTask}} Worker */
41
37
 
42
38
  /**
43
39
  * @param {Options} options
44
40
  * @returns {Linter}
45
41
  */
46
-
47
42
  function loadStylelint(options) {
48
43
  const stylelintOptions = getStylelintOptions(options);
49
44
  const stylelint = setup(options, stylelintOptions);
45
+
46
+ /** @type {isPathIgnored} */
47
+ let isPathIgnored;
48
+ try {
49
+ isPathIgnored = require(`${options.stylelintPath}/lib/isPathIgnored`);
50
+ } catch (e) {
51
+ try {
52
+ // @ts-ignore
53
+ isPathIgnored = require('stylelint/lib/isPathIgnored');
54
+ } catch (_) {
55
+ isPathIgnored = () => Promise.resolve(false);
56
+ }
57
+ }
50
58
  return {
51
59
  stylelint,
52
- api: stylelint.createLinter(stylelintOptions),
60
+ isPathIgnored,
53
61
  lintFiles,
54
62
  cleanup: async () => {},
55
63
  threads: 1
56
64
  };
57
65
  }
66
+
58
67
  /**
59
68
  * @param {string|undefined} key
60
69
  * @param {number} poolSize
61
70
  * @param {Options} options
62
71
  * @returns {Linter}
63
72
  */
64
-
65
-
66
73
  function loadStylelintThreaded(key, poolSize, options) {
67
74
  const cacheKey = getCacheKey(key, options);
68
-
69
75
  const source = require.resolve('./worker');
70
-
71
76
  const workerOptions = {
72
77
  enableWorkerThreads: true,
73
78
  numWorkers: poolSize,
74
79
  setupArgs: [options, getStylelintOptions(options)]
75
80
  };
76
81
  const local = loadStylelint(options);
77
- let worker =
78
- /** @type {Worker?} */
79
- new JestWorker(source, workerOptions);
80
- /** @type {Linter} */
82
+ let worker = /** @type {Worker?} */new JestWorker(source, workerOptions);
81
83
 
82
- const context = { ...local,
84
+ /** @type {Linter} */
85
+ const context = {
86
+ ...local,
83
87
  threads: poolSize,
84
- lintFiles: async files =>
85
- /* istanbul ignore next */
88
+ lintFiles: async files => /* istanbul ignore next */
86
89
  worker ? worker.lintFiles(files) : local.lintFiles(files),
87
90
  cleanup: async () => {
88
91
  cache[cacheKey] = local;
89
-
90
92
  context.lintFiles = files => local.lintFiles(files);
91
93
  /* istanbul ignore next */
92
-
93
-
94
94
  if (worker) {
95
95
  worker.end();
96
96
  worker = null;
@@ -99,13 +99,12 @@ function loadStylelintThreaded(key, poolSize, options) {
99
99
  };
100
100
  return context;
101
101
  }
102
+
102
103
  /**
103
104
  * @param {string|undefined} key
104
105
  * @param {Options} options
105
106
  * @returns {Linter}
106
107
  */
107
-
108
-
109
108
  function getStylelint(key, {
110
109
  threads,
111
110
  ...options
@@ -115,25 +114,21 @@ function getStylelint(key, {
115
114
  threads,
116
115
  ...options
117
116
  });
118
-
119
117
  if (!cache[cacheKey]) {
120
118
  cache[cacheKey] = max > 1 ? loadStylelintThreaded(key, max, options) : loadStylelint(options);
121
119
  }
122
-
123
120
  return cache[cacheKey];
124
121
  }
122
+
125
123
  /**
126
124
  * @param {string|undefined} key
127
125
  * @param {Options} options
128
126
  * @returns {string}
129
127
  */
130
-
131
-
132
128
  function getCacheKey(key, options) {
133
129
  return JSON.stringify({
134
130
  key,
135
131
  options
136
132
  }, jsonStringifyReplacerSortKeys);
137
133
  }
138
-
139
134
  module.exports = getStylelint;
package/dist/index.js CHANGED
@@ -4,37 +4,27 @@ const {
4
4
  isAbsolute,
5
5
  join
6
6
  } = require('path');
7
-
8
7
  const arrify = require('arrify');
9
-
10
8
  const globby = require('globby');
11
-
12
9
  const {
13
10
  isMatch
14
11
  } = require('micromatch');
15
-
16
12
  const {
17
13
  getOptions
18
14
  } = require('./options');
19
-
20
15
  const linter = require('./linter');
21
-
22
16
  const {
23
17
  parseFiles,
24
18
  parseFoldersToGlobs
25
19
  } = require('./utils');
26
- /** @typedef {import('webpack').Compiler} Compiler */
27
20
 
21
+ /** @typedef {import('webpack').Compiler} Compiler */
28
22
  /** @typedef {import('webpack').Module} Module */
29
-
30
23
  /** @typedef {import('./options').Options} Options */
31
-
32
24
  /** @typedef {Partial<{timestamp:number} | number>} FileSystemInfoEntry */
33
25
 
34
-
35
26
  const STYLELINT_PLUGIN = 'StylelintWebpackPlugin';
36
27
  let counter = 0;
37
-
38
28
  class StylelintWebpackPlugin {
39
29
  /**
40
30
  * @param {Options} options
@@ -44,82 +34,82 @@ class StylelintWebpackPlugin {
44
34
  this.options = getOptions(options);
45
35
  this.run = this.run.bind(this);
46
36
  this.startTime = Date.now();
47
- /** @type {ReadonlyMap<string, null | FileSystemInfoEntry | "ignore" | undefined>} */
48
37
 
38
+ /** @type {ReadonlyMap<string, null | FileSystemInfoEntry | "ignore" | undefined>} */
49
39
  this.prevTimestamps = new Map();
50
40
  }
41
+
51
42
  /**
52
43
  * @param {Compiler} compiler
53
44
  * @returns {void}
54
45
  */
55
-
56
-
57
46
  apply(compiler) {
58
47
  // Generate key for each compilation,
59
48
  // this differentiates one from the other when being cached.
60
49
  this.key = compiler.name || `${this.key}_${counter += 1}`;
61
50
  const context = this.getContext(compiler);
62
51
  const excludeDefault = ['**/node_modules/**', String(compiler.options.output.path)];
63
- const options = { ...this.options,
52
+ const options = {
53
+ ...this.options,
64
54
  context,
65
55
  exclude: parseFiles(this.options.exclude || excludeDefault, context),
66
56
  extensions: arrify(this.options.extensions),
67
57
  files: parseFiles(this.options.files || '', context)
68
58
  };
69
59
  const wanted = parseFoldersToGlobs(options.files, options.extensions);
70
- const exclude = parseFoldersToGlobs(options.exclude); // If `lintDirtyModulesOnly` is disabled,
71
- // execute the linter on the build
60
+ const exclude = parseFoldersToGlobs(options.exclude);
72
61
 
62
+ // If `lintDirtyModulesOnly` is disabled,
63
+ // execute the linter on the build
73
64
  if (!this.options.lintDirtyModulesOnly) {
74
65
  compiler.hooks.run.tapPromise(this.key, c => this.run(c, options, wanted, exclude));
75
66
  }
76
-
77
67
  let isFirstRun = this.options.lintDirtyModulesOnly;
78
68
  compiler.hooks.watchRun.tapPromise(this.key, c => {
79
69
  if (isFirstRun) {
80
70
  isFirstRun = false;
81
71
  return Promise.resolve();
82
72
  }
83
-
84
73
  return this.run(c, options, wanted, exclude);
85
74
  });
86
75
  }
76
+
87
77
  /**
88
78
  * @param {Compiler} compiler
89
79
  * @param {Options} options
90
80
  * @param {string[]} wanted
91
81
  * @param {string[]} exclude
92
82
  */
93
-
94
-
95
83
  async run(compiler, options, wanted, exclude) {
96
84
  // Do not re-hook
97
-
98
85
  /* istanbul ignore if */
99
- if ( // @ts-ignore
86
+ if (
87
+ // @ts-ignore
100
88
  compiler.hooks.thisCompilation.taps.find(({
101
89
  name
102
90
  }) => name === this.key)) {
103
91
  return;
104
92
  }
105
-
106
93
  compiler.hooks.thisCompilation.tap(this.key, compilation => {
94
+ /** @type {import('./getStylelint').Stylelint} */
95
+ let stylelint;
96
+
107
97
  /** @type {import('./linter').Linter} */
108
98
  let lint;
109
- /** @type {import('stylelint').InternalApi} */
110
99
 
111
- let api;
112
- /** @type {import('./linter').Reporter} */
100
+ /** @type {import('./linter').isPathIgnored} */
101
+ let isPathIgnored;
113
102
 
103
+ /** @type {import('./linter').Reporter} */
114
104
  let report;
115
- /** @type number */
116
105
 
106
+ /** @type number */
117
107
  let threads;
118
-
119
108
  try {
120
109
  ({
110
+ stylelint,
121
111
  lint,
122
- api,
112
+ isPathIgnored,
123
113
  report,
124
114
  threads
125
115
  } = linter(this.key, options, compilation));
@@ -127,20 +117,16 @@ class StylelintWebpackPlugin {
127
117
  compilation.errors.push(e);
128
118
  return;
129
119
  }
130
-
131
120
  compilation.hooks.finishModules.tapPromise(this.key, async () => {
132
121
  /** @type {string[]} */
133
122
  // @ts-ignore
134
- const files = (await Promise.all(this.getFiles(compiler, wanted, exclude).map(async (
135
- /** @type {string | undefined} */
136
- file) => {
123
+ const files = (await Promise.all(this.getFiles(compiler, wanted, exclude).map(async ( /** @type {string} */file) => {
137
124
  try {
138
- return (await api.isPathIgnored(file)) ? false : file;
125
+ return (await isPathIgnored(stylelint, file)) ? false : file;
139
126
  } catch (e) {
140
127
  return file;
141
128
  }
142
129
  }))).filter(file => file !== false);
143
-
144
130
  if (threads > 1) {
145
131
  for (const file of files) {
146
132
  lint(parseFiles(file, options.context || ''));
@@ -148,17 +134,16 @@ class StylelintWebpackPlugin {
148
134
  } else if (files.length > 0) {
149
135
  lint(parseFiles(files, options.context || ''));
150
136
  }
151
- }); // await and interpret results
137
+ });
152
138
 
139
+ // await and interpret results
153
140
  compilation.hooks.additionalAssets.tapPromise(this.key, processResults);
154
-
155
141
  async function processResults() {
156
142
  const {
157
143
  errors,
158
144
  warnings,
159
145
  generateReportAsset
160
146
  } = await report();
161
-
162
147
  if (warnings && !options.failOnWarning) {
163
148
  // @ts-ignore
164
149
  compilation.warnings.push(warnings);
@@ -166,7 +151,6 @@ class StylelintWebpackPlugin {
166
151
  // @ts-ignore
167
152
  compilation.errors.push(warnings);
168
153
  }
169
-
170
154
  if (errors && options.failOnError) {
171
155
  // @ts-ignore
172
156
  compilation.errors.push(errors);
@@ -174,31 +158,28 @@ class StylelintWebpackPlugin {
174
158
  // @ts-ignore
175
159
  compilation.warnings.push(errors);
176
160
  }
177
-
178
161
  if (generateReportAsset) {
179
162
  await generateReportAsset(compilation);
180
163
  }
181
164
  }
182
165
  });
183
166
  }
167
+
184
168
  /**
185
169
  *
186
170
  * @param {Compiler} compiler
187
171
  * @returns {string}
188
172
  */
189
-
190
-
191
173
  getContext(compiler) {
192
174
  if (!this.options.context) {
193
175
  return String(compiler.options.context);
194
176
  }
195
-
196
177
  if (!isAbsolute(this.options.context)) {
197
178
  return join(String(compiler.options.context), this.options.context);
198
179
  }
199
-
200
180
  return this.options.context;
201
181
  }
182
+
202
183
  /**
203
184
  * @param {Compiler} compiler
204
185
  * @param {string[]} wanted
@@ -206,8 +187,6 @@ class StylelintWebpackPlugin {
206
187
  * @returns {string[]}
207
188
  */
208
189
  // eslint-disable-next-line no-unused-vars
209
-
210
-
211
190
  getFiles(compiler, wanted, exclude) {
212
191
  // webpack 5
213
192
  if (compiler.modifiedFiles) {
@@ -216,11 +195,10 @@ class StylelintWebpackPlugin {
216
195
  }) && !isMatch(file, exclude, {
217
196
  dot: true
218
197
  }));
219
- } // webpack 4
198
+ }
220
199
 
200
+ // webpack 4
221
201
  /* istanbul ignore next */
222
-
223
-
224
202
  if (compiler.fileTimestamps && compiler.fileTimestamps.size > 0) {
225
203
  return this.getChangedFiles(compiler.fileTimestamps).filter(file => isMatch(file, wanted, {
226
204
  dot: true
@@ -228,20 +206,17 @@ class StylelintWebpackPlugin {
228
206
  dot: true
229
207
  }));
230
208
  }
231
-
232
209
  return globby.sync(wanted, {
233
210
  dot: true,
234
211
  ignore: exclude
235
212
  });
236
213
  }
214
+
237
215
  /**
238
216
  * @param {ReadonlyMap<string, null | FileSystemInfoEntry | "ignore" | undefined>} fileTimestamps
239
217
  * @returns {string[]}
240
218
  */
241
-
242
219
  /* istanbul ignore next */
243
-
244
-
245
220
  getChangedFiles(fileTimestamps) {
246
221
  /**
247
222
  * @param {null | FileSystemInfoEntry | "ignore" | undefined} fileSystemInfoEntry
@@ -252,36 +227,30 @@ class StylelintWebpackPlugin {
252
227
  if (fileSystemInfoEntry && fileSystemInfoEntry.timestamp) {
253
228
  // @ts-ignore
254
229
  return fileSystemInfoEntry.timestamp;
255
- } // @ts-ignore
256
-
230
+ }
257
231
 
232
+ // @ts-ignore
258
233
  return fileSystemInfoEntry;
259
234
  };
235
+
260
236
  /**
261
237
  * @param {string} filename
262
238
  * @param {null | FileSystemInfoEntry | "ignore" | undefined} fileSystemInfoEntry
263
239
  * @returns {boolean}
264
240
  */
265
-
266
-
267
241
  const hasFileChanged = (filename, fileSystemInfoEntry) => {
268
242
  const prevTimestamp = getTimestamps(this.prevTimestamps.get(filename));
269
243
  const timestamp = getTimestamps(fileSystemInfoEntry);
270
244
  return (prevTimestamp || this.startTime) < (timestamp || Infinity);
271
245
  };
272
-
273
246
  const changedFiles = [];
274
-
275
247
  for (const [filename, timestamp] of fileTimestamps.entries()) {
276
248
  if (hasFileChanged(filename, timestamp)) {
277
249
  changedFiles.push(filename);
278
250
  }
279
251
  }
280
-
281
252
  this.prevTimestamps = fileTimestamps;
282
253
  return changedFiles;
283
254
  }
284
-
285
255
  }
286
-
287
256
  module.exports = StylelintWebpackPlugin;