stylelint-webpack-plugin 3.3.0 → 4.1.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.
package/dist/linter.js CHANGED
@@ -5,75 +5,59 @@ const {
5
5
  isAbsolute,
6
6
  join
7
7
  } = require('path');
8
-
9
8
  const StylelintError = require('./StylelintError');
10
-
11
9
  const getStylelint = require('./getStylelint');
12
-
13
10
  const {
14
11
  arrify
15
12
  } = require('./utils');
16
- /** @typedef {import('stylelint')} Stylelint */
17
-
18
- /** @typedef {import('stylelint').LintResult} LintResult */
19
-
20
- /** @typedef {import('stylelint').InternalApi} InternalApi */
21
13
 
22
14
  /** @typedef {import('webpack').Compiler} Compiler */
23
-
24
15
  /** @typedef {import('webpack').Compilation} Compilation */
25
-
16
+ /** @typedef {import('./getStylelint').Stylelint} Stylelint */
17
+ /** @typedef {import('./getStylelint').LintResult} LintResult */
18
+ /** @typedef {import('./getStylelint').LinterResult} LinterResult */
19
+ /** @typedef {import('./getStylelint').Formatter} Formatter */
20
+ /** @typedef {import('./getStylelint').FormatterType} FormatterType */
21
+ /** @typedef {import('./getStylelint').isPathIgnored} isPathIgnored */
26
22
  /** @typedef {import('./options').Options} Options */
27
-
28
- /** @typedef {import('./options').FormatterType} FormatterType */
29
-
30
- /** @typedef {((results: LintResult[]) => string)} FormatterFunction */
31
-
32
23
  /** @typedef {(compilation: Compilation) => Promise<void>} GenerateReport */
33
-
34
24
  /** @typedef {{errors?: StylelintError, warnings?: StylelintError, generateReportAsset?: GenerateReport}} Report */
35
-
36
25
  /** @typedef {() => Promise<Report>} Reporter */
37
-
38
26
  /** @typedef {(files: string|string[]) => void} Linter */
39
-
40
27
  /** @typedef {{[files: string]: LintResult}} LintResultMap */
41
28
 
42
29
  /** @type {WeakMap<Compiler, LintResultMap>} */
43
-
44
-
45
30
  const resultStorage = new WeakMap();
31
+
46
32
  /**
47
33
  * @param {string|undefined} key
48
34
  * @param {Options} options
49
35
  * @param {Compilation} compilation
50
- * @returns {{api: InternalApi, lint: Linter, report: Reporter, threads: number}}
36
+ * @returns {{stylelint: Stylelint, isPathIgnored: isPathIgnored, lint: Linter, report: Reporter, threads: number}}
51
37
  */
52
-
53
38
  function linter(key, options, compilation) {
54
39
  /** @type {Stylelint} */
55
40
  let stylelint;
56
- /** @type {InternalApi} */
57
41
 
58
- let api;
59
- /** @type {(files: string|string[]) => Promise<LintResult[]>} */
42
+ /** @type {isPathIgnored} */
43
+ let isPathIgnored;
60
44
 
45
+ /** @type {(files: string|string[]) => Promise<LintResult[]>} */
61
46
  let lintFiles;
62
- /** @type {() => Promise<void>} */
63
47
 
48
+ /** @type {() => Promise<void>} */
64
49
  let cleanup;
65
- /** @type number */
66
50
 
51
+ /** @type number */
67
52
  let threads;
68
- /** @type {Promise<LintResult[]>[]} */
69
53
 
54
+ /** @type {Promise<LintResult[]>[]} */
70
55
  const rawResults = [];
71
56
  const crossRunResultStorage = getResultStorage(compilation);
72
-
73
57
  try {
74
58
  ({
75
59
  stylelint,
76
- api,
60
+ isPathIgnored,
77
61
  lintFiles,
78
62
  cleanup,
79
63
  threads
@@ -81,60 +65,68 @@ function linter(key, options, compilation) {
81
65
  } catch (e) {
82
66
  throw new StylelintError(e.message);
83
67
  }
84
-
85
68
  return {
69
+ stylelint,
86
70
  lint,
87
- api,
71
+ isPathIgnored,
88
72
  report,
89
73
  threads
90
74
  };
75
+
91
76
  /**
92
77
  * @param {string | string[]} files
93
78
  */
94
-
95
79
  function lint(files) {
96
80
  for (const file of arrify(files)) {
97
81
  delete crossRunResultStorage[file];
98
82
  }
99
-
100
83
  rawResults.push(lintFiles(files).catch(e => {
101
84
  // @ts-ignore
102
85
  compilation.errors.push(new StylelintError(e.message));
103
86
  return [];
104
87
  }));
105
88
  }
106
-
107
89
  async function report() {
108
90
  // Filter out ignored files.
109
- let results = removeIgnoredWarnings( // Get the current results, resetting the rawResults to empty
91
+ let results = removeIgnoredWarnings(
92
+ // Get the current results, resetting the rawResults to empty
110
93
  await flatten(rawResults.splice(0, rawResults.length)));
111
94
  await cleanup();
112
-
113
95
  for (const result of results) {
114
96
  crossRunResultStorage[String(result.source)] = result;
115
97
  }
98
+ results = Object.values(crossRunResultStorage);
116
99
 
117
- results = Object.values(crossRunResultStorage); // do not analyze if there are no results or stylelint config
118
-
100
+ // do not analyze if there are no results or stylelint config
119
101
  if (!results || results.length < 1) {
120
102
  return {};
121
103
  }
122
-
123
104
  const formatter = loadFormatter(stylelint, options.formatter);
105
+
106
+ /** @type {LinterResult} */
107
+ const returnValue = {
108
+ // @ts-ignore
109
+ cwd: options.cwd,
110
+ errored: false,
111
+ results: [],
112
+ output: '',
113
+ reportedDisables: [],
114
+ ruleMetadata: getRuleMetadata(results)
115
+ };
124
116
  const {
125
117
  errors,
126
118
  warnings
127
- } = formatResults(formatter, parseResults(options, results));
119
+ } = formatResults(formatter, parseResults(options, results), returnValue);
128
120
  return {
129
121
  errors,
130
122
  warnings,
131
123
  generateReportAsset
132
124
  };
125
+
133
126
  /**
134
127
  * @param {Compilation} compilation
135
128
  * @returns {Promise<void>}
136
129
  */
137
-
138
130
  async function generateReportAsset({
139
131
  compiler
140
132
  }) {
@@ -145,16 +137,14 @@ function linter(key, options, compilation) {
145
137
  * @param {string} name
146
138
  * @param {string | Buffer} content
147
139
  */
148
-
149
- const save = (name, content) =>
150
- /** @type {Promise<void>} */
140
+ const save = (name, content) => /** @type {Promise<void>} */
151
141
  new Promise((finish, bail) => {
152
142
  const {
153
143
  mkdir,
154
144
  writeFile
155
- } = compiler.outputFileSystem; // ensure directory exists
145
+ } = compiler.outputFileSystem;
146
+ // ensure directory exists
156
147
  // @ts-ignore - the types for `outputFileSystem` are missing the 3 arg overload
157
-
158
148
  mkdir(dirname(name), {
159
149
  recursive: true
160
150
  }, err => {
@@ -165,74 +155,67 @@ function linter(key, options, compilation) {
165
155
  });
166
156
  });
167
157
  });
168
-
169
158
  if (!outputReport || !outputReport.filePath) {
170
159
  return;
171
160
  }
172
-
173
- const content = outputReport.formatter ? loadFormatter(stylelint, outputReport.formatter)(results) : formatter(results);
161
+ const content = outputReport.formatter;
162
+ loadFormatter(stylelint, outputReport.formatter)(results, returnValue);
163
+ formatter(results, returnValue);
174
164
  let {
175
165
  filePath
176
166
  } = outputReport;
177
-
178
167
  if (!isAbsolute(filePath)) {
179
168
  filePath = join(compiler.outputPath, filePath);
180
169
  }
181
-
182
- await save(filePath, content);
170
+ await save(filePath, String(content));
183
171
  }
184
172
  }
185
173
  }
174
+
186
175
  /**
187
- * @param {FormatterFunction} formatter
176
+ * @param {Formatter} formatter
188
177
  * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results
178
+ * @param {LinterResult} returnValue
189
179
  * @returns {{errors?: StylelintError, warnings?: StylelintError}}
190
180
  */
191
-
192
-
193
- function formatResults(formatter, results) {
181
+ function formatResults(formatter, results, returnValue) {
194
182
  let errors;
195
183
  let warnings;
196
-
197
184
  if (results.warnings.length > 0) {
198
- warnings = new StylelintError(formatter(results.warnings));
185
+ warnings = new StylelintError(formatter(results.warnings, returnValue));
199
186
  }
200
-
201
187
  if (results.errors.length > 0) {
202
- errors = new StylelintError(formatter(results.errors));
188
+ errors = new StylelintError(formatter(results.errors, returnValue));
203
189
  }
204
-
205
190
  return {
206
191
  errors,
207
192
  warnings
208
193
  };
209
194
  }
195
+
210
196
  /**
211
197
  * @param {Options} options
212
198
  * @param {LintResult[]} results
213
199
  * @returns {{errors: LintResult[], warnings: LintResult[]}}
214
200
  */
215
-
216
-
217
201
  function parseResults(options, results) {
218
202
  /** @type {LintResult[]} */
219
203
  const errors = [];
220
- /** @type {LintResult[]} */
221
204
 
205
+ /** @type {LintResult[]} */
222
206
  const warnings = [];
223
207
  results.forEach(file => {
224
208
  const fileErrors = file.warnings.filter(message => options.emitError && message.severity === 'error');
225
-
226
209
  if (fileErrors.length > 0) {
227
- errors.push({ ...file,
210
+ errors.push({
211
+ ...file,
228
212
  warnings: fileErrors
229
213
  });
230
214
  }
231
-
232
215
  const fileWarnings = file.warnings.filter(message => options.emitWarning && message.severity === 'warning');
233
-
234
216
  if (fileWarnings.length > 0) {
235
- warnings.push({ ...file,
217
+ warnings.push({
218
+ ...file,
236
219
  warnings: fileWarnings
237
220
  });
238
221
  }
@@ -242,67 +225,75 @@ function parseResults(options, results) {
242
225
  warnings
243
226
  };
244
227
  }
228
+
245
229
  /**
246
230
  * @param {Stylelint} stylelint
247
231
  * @param {FormatterType=} formatter
248
- * @returns {FormatterFunction}
232
+ * @returns {Formatter}
249
233
  */
250
-
251
-
252
234
  function loadFormatter(stylelint, formatter) {
253
235
  if (typeof formatter === 'function') {
254
236
  return formatter;
255
237
  }
256
-
257
238
  if (typeof formatter === 'string') {
258
239
  try {
259
240
  return stylelint.formatters[formatter];
260
- } catch (_) {// Load the default formatter.
241
+ } catch (_) {
242
+ // Load the default formatter.
261
243
  }
262
244
  }
263
-
264
245
  return stylelint.formatters.string;
265
246
  }
247
+
266
248
  /**
267
249
  * @param {LintResult[]} results
268
250
  * @returns {LintResult[]}
269
251
  */
270
-
271
-
272
252
  function removeIgnoredWarnings(results) {
273
253
  return results.filter(result => !result.ignored);
274
254
  }
255
+
275
256
  /**
276
257
  * @param {Promise<LintResult[]>[]} results
277
258
  * @returns {Promise<LintResult[]>}
278
259
  */
279
-
280
-
281
260
  async function flatten(results) {
282
261
  /**
283
262
  * @param {LintResult[]} acc
284
263
  * @param {LintResult[]} list
285
264
  */
286
265
  const flat = (acc, list) => [...acc, ...list];
287
-
288
266
  return (await Promise.all(results)).reduce(flat, []);
289
267
  }
268
+
290
269
  /**
291
270
  * @param {Compilation} compilation
292
271
  * @returns {LintResultMap}
293
272
  */
294
-
295
-
296
273
  function getResultStorage({
297
274
  compiler
298
275
  }) {
299
276
  let storage = resultStorage.get(compiler);
300
-
301
277
  if (!storage) {
302
278
  resultStorage.set(compiler, storage = {});
303
279
  }
304
-
305
280
  return storage;
306
281
  }
307
282
 
283
+ /**
284
+ * @param {LintResult[]} lintResults
285
+ */
286
+ /* istanbul ignore next */
287
+ function getRuleMetadata(lintResults) {
288
+ const [lintResult] = lintResults;
289
+
290
+ // eslint-disable-next-line no-undefined
291
+ if (lintResult === undefined) return {};
292
+
293
+ // eslint-disable-next-line no-underscore-dangle, no-undefined
294
+ if (lintResult._postcssResult === undefined) return {};
295
+
296
+ // eslint-disable-next-line no-underscore-dangle
297
+ return lintResult._postcssResult.stylelint.ruleMetadata;
298
+ }
308
299
  module.exports = linter;
package/dist/options.js CHANGED
@@ -3,13 +3,10 @@
3
3
  const {
4
4
  validate
5
5
  } = require('schema-utils');
6
-
7
6
  const schema = require('./options.json');
8
- /** @typedef {import("stylelint")} stylelint */
9
-
10
- /** @typedef {import("stylelint").LinterOptions} StylelintOptions */
11
7
 
12
- /** @typedef {import("stylelint").FormatterType} FormatterType */
8
+ /** @typedef {import('./getStylelint').LinterOptions} StylelintOptions */
9
+ /** @typedef {import('./getStylelint').FormatterType} FormatterType */
13
10
 
14
11
  /**
15
12
  * @typedef {Object} OutputReport
@@ -41,8 +38,6 @@ const schema = require('./options.json');
41
38
  * @param {Options} pluginOptions
42
39
  * @returns {Partial<PluginOptions>}
43
40
  */
44
-
45
-
46
41
  function getOptions(pluginOptions) {
47
42
  const options = {
48
43
  extensions: ['css', 'scss', 'sass'],
@@ -54,39 +49,40 @@ function getOptions(pluginOptions) {
54
49
  emitError: true,
55
50
  emitWarning: false
56
51
  } : {})
57
- }; // @ts-ignore
52
+ };
58
53
 
54
+ // @ts-ignore
59
55
  validate(schema, options, {
60
56
  name: 'Stylelint Webpack Plugin',
61
57
  baseDataPath: 'options'
62
58
  });
63
59
  return options;
64
60
  }
61
+
65
62
  /**
66
63
  * @param {Options} pluginOptions
67
64
  * @returns {Partial<StylelintOptions>}
68
65
  */
69
-
70
-
71
66
  function getStylelintOptions(pluginOptions) {
72
- const stylelintOptions = { ...pluginOptions
73
- }; // Keep the files and formatter option because it is common to both the plugin and Stylelint.
67
+ const stylelintOptions = {
68
+ ...pluginOptions
69
+ };
74
70
 
71
+ // Keep the files and formatter option because it is common to both the plugin and Stylelint.
75
72
  const {
76
73
  files,
77
74
  formatter,
78
75
  ...stylelintOnlyOptions
79
- } = schema.properties; // No need to guard the for-in because schema.properties has hardcoded keys.
80
- // eslint-disable-next-line guard-for-in
76
+ } = schema.properties;
81
77
 
78
+ // No need to guard the for-in because schema.properties has hardcoded keys.
79
+ // eslint-disable-next-line guard-for-in
82
80
  for (const option in stylelintOnlyOptions) {
83
81
  // @ts-ignore
84
82
  delete stylelintOptions[option];
85
83
  }
86
-
87
84
  return stylelintOptions;
88
85
  }
89
-
90
86
  module.exports = {
91
87
  getOptions,
92
88
  getStylelintOptions
package/dist/options.json CHANGED
@@ -31,7 +31,7 @@
31
31
  "type": "boolean"
32
32
  },
33
33
  "files": {
34
- "description": "Specify directories, files, or globs. Must be relative to `options.context`. Directories are traveresed recursively looking for files matching `options.extensions`. File and glob patterns ignore `options.extensions`.",
34
+ "description": "Specify directories, files, or globs. Must be relative to `options.context`. Directories are traversed recursively looking for files matching `options.extensions`. File and glob patterns ignore `options.extensions`.",
35
35
  "anyOf": [{ "type": "string" }, { "type": "array" }]
36
36
  },
37
37
  "formatter": {
package/dist/utils.js CHANGED
@@ -3,12 +3,11 @@
3
3
  const {
4
4
  resolve
5
5
  } = require('path');
6
-
7
6
  const {
8
7
  statSync
9
8
  } = require('fs');
10
-
11
9
  const normalizePath = require('normalize-path');
10
+
12
11
  /**
13
12
  * @template T
14
13
  * @param {T} value
@@ -24,85 +23,70 @@ const normalizePath = require('normalize-path');
24
23
  : [T]
25
24
  }
26
25
  */
27
-
28
26
  /* istanbul ignore next */
29
-
30
-
31
27
  function arrify(value) {
32
28
  // eslint-disable-next-line no-undefined
33
29
  if (value === null || value === undefined) {
34
30
  // @ts-ignore
35
31
  return [];
36
32
  }
37
-
38
33
  if (Array.isArray(value)) {
39
34
  // @ts-ignore
40
35
  return value;
41
36
  }
42
-
43
37
  if (typeof value === 'string') {
44
38
  // @ts-ignore
45
39
  return [value];
46
- } // @ts-ignore
47
-
40
+ }
48
41
 
42
+ // @ts-ignore
49
43
  if (typeof value[Symbol.iterator] === 'function') {
50
44
  // @ts-ignore
51
45
  return [...value];
52
- } // @ts-ignore
53
-
46
+ }
54
47
 
48
+ // @ts-ignore
55
49
  return [value];
56
50
  }
51
+
57
52
  /**
58
53
  * @param {string|string[]} files
59
54
  * @param {string} context
60
55
  * @returns {string[]}
61
56
  */
62
-
63
-
64
57
  function parseFiles(files, context) {
65
- return arrify(files).map((
66
- /** @type {string} */
67
- file) => normalizePath(resolve(context, file)));
58
+ return arrify(files).map(( /** @type {string} */file) => normalizePath(resolve(context, file)));
68
59
  }
60
+
69
61
  /**
70
62
  * @param {string|string[]} patterns
71
63
  * @param {string|string[]} extensions
72
64
  * @returns {string[]}
73
65
  */
74
-
75
-
76
66
  function parseFoldersToGlobs(patterns, extensions = []) {
77
67
  const extensionsList = arrify(extensions);
78
68
  const [prefix, postfix] = extensionsList.length > 1 ? ['{', '}'] : ['', ''];
79
- const extensionsGlob = extensionsList.map((
80
- /** @type {string} */
81
- extension) => extension.replace(/^\./u, '')).join(',');
82
- return arrify(patterns).map((
83
- /** @type {string} */
84
- pattern) => {
69
+ const extensionsGlob = extensionsList.map(( /** @type {string} */extension) => extension.replace(/^\./u, '')).join(',');
70
+ return arrify(patterns).map(( /** @type {string} */pattern) => {
85
71
  try {
86
72
  // The patterns are absolute because they are prepended with the context.
87
73
  const stats = statSync(pattern);
88
74
  /* istanbul ignore else */
89
-
90
75
  if (stats.isDirectory()) {
91
76
  return pattern.replace(/[/\\]*?$/u, `/**${extensionsGlob ? `/*.${prefix + extensionsGlob + postfix}` : ''}`);
92
77
  }
93
- } catch (_) {// Return the pattern as is on error.
78
+ } catch (_) {
79
+ // Return the pattern as is on error.
94
80
  }
95
-
96
81
  return pattern;
97
82
  });
98
83
  }
84
+
99
85
  /**
100
86
  *
101
87
  * @param {string} _ key, but unused
102
88
  * @param {any} value
103
89
  */
104
-
105
-
106
90
  const jsonStringifyReplacerSortKeys = (_, value) => {
107
91
  /**
108
92
  * @param {{ [x: string]: any; }} sorted
@@ -113,10 +97,8 @@ const jsonStringifyReplacerSortKeys = (_, value) => {
113
97
  sorted[key] = value[key];
114
98
  return sorted;
115
99
  };
116
-
117
100
  return value instanceof Object && !(value instanceof Array) ? Object.keys(value).sort().reduce(insert, {}) : value;
118
101
  };
119
-
120
102
  module.exports = {
121
103
  arrify,
122
104
  parseFiles,
package/dist/worker.js CHANGED
@@ -1,42 +1,42 @@
1
1
  "use strict";
2
2
 
3
- /** @typedef {import('stylelint')} Stylelint */
4
-
5
- /** @typedef {import("stylelint").LinterOptions} StylelintOptions */
6
-
3
+ /** @typedef {import('./getStylelint').Stylelint} Stylelint */
4
+ /** @typedef {import('./getStylelint').LinterOptions} StylelintOptions */
7
5
  /** @typedef {import('./options').Options} Options */
6
+
8
7
  Object.assign(module.exports, {
9
8
  lintFiles,
10
9
  setup
11
10
  });
12
- /** @type {Stylelint} */
13
11
 
12
+ /** @type {Stylelint} */
14
13
  let stylelint;
15
- /** @type {Partial<StylelintOptions>} */
16
14
 
15
+ /** @type {Partial<StylelintOptions>} */
17
16
  let linterOptions;
17
+
18
18
  /**
19
19
  * @param {Options} options
20
20
  * @param {Partial<StylelintOptions>} stylelintOptions
21
21
  */
22
-
23
22
  function setup(options, stylelintOptions) {
24
23
  stylelint = require(options.stylelintPath || 'stylelint');
25
24
  linterOptions = stylelintOptions;
26
25
  return stylelint;
27
26
  }
27
+
28
28
  /**
29
29
  * @param {string | string[]} files
30
30
  */
31
-
32
-
33
31
  async function lintFiles(files) {
34
32
  const {
35
33
  results
36
- } = await stylelint.lint({ ...linterOptions,
34
+ } = await stylelint.lint({
35
+ ...linterOptions,
37
36
  files
38
- }); // Reset result to work with worker
37
+ });
39
38
 
39
+ // Reset result to work with worker
40
40
  return results.map(result => {
41
41
  return {
42
42
  source: result.source,