stylelint-webpack-plugin 5.0.1 → 5.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
@@ -4,12 +4,12 @@ const {
4
4
  dirname,
5
5
  isAbsolute,
6
6
  join
7
- } = require('path');
8
- const StylelintError = require('./StylelintError');
9
- const getStylelint = require('./getStylelint');
7
+ } = require("node:path");
8
+ const StylelintError = require("./StylelintError");
9
+ const getStylelintModule = require("./getStylelint");
10
10
  const {
11
11
  arrify
12
- } = require('./utils');
12
+ } = require("./utils");
13
13
 
14
14
  /** @typedef {import('webpack').Compiler} Compiler */
15
15
  /** @typedef {import('webpack').Compilation} Compilation */
@@ -18,6 +18,7 @@ const {
18
18
  /** @typedef {import('./getStylelint').LinterResult} LinterResult */
19
19
  /** @typedef {import('./getStylelint').Formatter} Formatter */
20
20
  /** @typedef {import('./getStylelint').FormatterType} FormatterType */
21
+ /** @typedef {import('./getStylelint').RuleMeta} RuleMeta */
21
22
  /** @typedef {import('./options').Options} Options */
22
23
  /** @typedef {(compilation: Compilation) => Promise<void>} GenerateReport */
23
24
  /** @typedef {{errors?: StylelintError, warnings?: StylelintError, generateReportAsset?: GenerateReport}} Report */
@@ -29,61 +30,169 @@ const {
29
30
  const resultStorage = new WeakMap();
30
31
 
31
32
  /**
32
- * @param {string|undefined} key
33
- * @param {Options} options
34
- * @param {Compilation} compilation
35
- * @returns {{lint: Linter, report: Reporter, threads: number}}
33
+ * @param {Compilation} compilation compilation
34
+ * @returns {LintResultMap} lint result map
36
35
  */
37
- function linter(key, options, compilation) {
38
- /** @type {Stylelint} */
39
- let stylelint;
36
+ function getResultStorage({
37
+ compiler
38
+ }) {
39
+ let storage = resultStorage.get(compiler);
40
+ if (!storage) {
41
+ resultStorage.set(compiler, storage = {});
42
+ }
43
+ return storage;
44
+ }
40
45
 
41
- /** @type {(files: string|string[]) => Promise<LintResult[]>} */
42
- let lintFiles;
46
+ /**
47
+ * @param {LintResult[]} results results
48
+ * @returns {LintResult[]} filtered results without ignored
49
+ */
50
+ function removeIgnoredWarnings(results) {
51
+ return results.filter(result => !result.ignored);
52
+ }
43
53
 
44
- /** @type {() => Promise<void>} */
45
- let cleanup;
54
+ /**
55
+ * @param {Promise<LintResult[]>[]} results results
56
+ * @returns {Promise<LintResult[]>} flatten results
57
+ */
58
+ async function flatten(results) {
59
+ /**
60
+ * @param {LintResult[]} acc acc
61
+ * @param {LintResult[]} list list
62
+ * @returns {LintResult[]} result
63
+ */
64
+ const flat = (acc, list) => [...acc, ...list];
65
+ return (await Promise.all(results)).reduce(flat, []);
66
+ }
46
67
 
47
- /** @type number */
48
- let threads;
68
+ /**
69
+ * @param {() => Promise<Stylelint>} getStylelint stylelint getter
70
+ * @param {FormatterType=} formatter formatter
71
+ * @returns {Promise<Formatter>} resolved formatter
72
+ */
73
+ async function loadFormatter(getStylelint, formatter) {
74
+ if (typeof formatter === "function") {
75
+ return formatter;
76
+ }
77
+ const stylelint = await getStylelint();
78
+ if (typeof formatter === "string") {
79
+ try {
80
+ const fmt = stylelint.formatters[formatter];
81
+ // Handle both sync (v13-v15) and promise-based (v16+) formatters
82
+ return fmt instanceof Promise ? await fmt : fmt;
83
+ } catch {
84
+ // Load the default formatter.
85
+ }
86
+ }
87
+ const defaultFmt = stylelint.formatters.string;
88
+ // Handle both sync (v13-v15) and promise-based (v16+) formatters
89
+ return defaultFmt instanceof Promise ? await defaultFmt : defaultFmt;
90
+ }
49
91
 
92
+ /* istanbul ignore next */
93
+ /**
94
+ * @param {LintResult[]} lintResults lint results
95
+ * @returns {{ [ruleName: string]: Partial<RuleMeta> }} a rule meta
96
+ */
97
+ function getRuleMetadata(lintResults) {
98
+ const [lintResult] = lintResults;
99
+ if (lintResult === undefined) return {};
100
+ if (lintResult._postcssResult === undefined) return {};
101
+ return lintResult._postcssResult.stylelint.ruleMetadata;
102
+ }
103
+
104
+ /**
105
+ * @param {Formatter} formatter formatter
106
+ * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results results
107
+ * @param {LinterResult} returnValue return value
108
+ * @returns {{ errors?: StylelintError, warnings?: StylelintError }} formatted result
109
+ */
110
+ function formatResults(formatter, results, returnValue) {
111
+ let errors;
112
+ let warnings;
113
+ if (results.warnings.length > 0) {
114
+ warnings = new StylelintError(formatter(results.warnings, returnValue));
115
+ }
116
+ if (results.errors.length > 0) {
117
+ errors = new StylelintError(formatter(results.errors, returnValue));
118
+ }
119
+ return {
120
+ errors,
121
+ warnings
122
+ };
123
+ }
124
+
125
+ /**
126
+ * @param {Options} options options
127
+ * @param {LintResult[]} results results
128
+ * @returns {{ errors: LintResult[], warnings: LintResult[] }} parsed results
129
+ */
130
+ function parseResults(options, results) {
131
+ /** @type {LintResult[]} */
132
+ const errors = [];
133
+
134
+ /** @type {LintResult[]} */
135
+ const warnings = [];
136
+ for (const file of results) {
137
+ const fileErrors = file.warnings.filter(message => options.emitError && message.severity === "error");
138
+ if (fileErrors.length > 0) {
139
+ errors.push({
140
+ ...file,
141
+ warnings: fileErrors
142
+ });
143
+ }
144
+ const fileWarnings = file.warnings.filter(message => options.emitWarning && message.severity === "warning");
145
+ if (fileWarnings.length > 0) {
146
+ warnings.push({
147
+ ...file,
148
+ warnings: fileWarnings
149
+ });
150
+ }
151
+ }
152
+ return {
153
+ errors,
154
+ warnings
155
+ };
156
+ }
157
+
158
+ /**
159
+ * @param {string | undefined} key a cache key
160
+ * @param {Options} options options
161
+ * @param {Compilation} compilation compilation
162
+ * @returns {{ lint: Linter, report: Reporter, threads: number }} the linter with additional functions
163
+ */
164
+ function linter(key, options, compilation) {
50
165
  /** @type {Promise<LintResult[]>[]} */
51
166
  const rawResults = [];
52
167
  const crossRunResultStorage = getResultStorage(compilation);
53
- try {
54
- ({
55
- stylelint,
56
- lintFiles,
57
- cleanup,
58
- threads
59
- } = getStylelint(key, options));
60
- } catch (e) {
61
- throw new StylelintError(e.message);
62
- }
63
- return {
64
- lint,
65
- report,
168
+ const {
169
+ getStylelint,
170
+ lintFiles,
171
+ cleanup,
66
172
  threads
67
- };
173
+ } = getStylelintModule(key, options);
68
174
 
69
175
  /**
70
- * @param {string | string[]} files
176
+ * @param {string | string[]} files files
71
177
  */
72
178
  function lint(files) {
73
179
  for (const file of arrify(files)) {
74
180
  delete crossRunResultStorage[file];
75
181
  }
76
- rawResults.push(lintFiles(files).catch(e => {
77
- // @ts-ignore
78
- compilation.errors.push(new StylelintError(e.message));
182
+ rawResults.push(lintFiles(files).catch(err => {
183
+ compilation.errors.push(new StylelintError(err.message));
79
184
  return [];
80
185
  }));
81
186
  }
187
+
188
+ /**
189
+ * @returns {Promise<Report>} report
190
+ */
82
191
  async function report() {
83
192
  // Filter out ignored files.
84
193
  let results = removeIgnoredWarnings(
85
194
  // Get the current results, resetting the rawResults to empty
86
- await flatten(rawResults.splice(0, rawResults.length)));
195
+ await flatten(rawResults.splice(0)));
87
196
  await cleanup();
88
197
  for (const result of results) {
89
198
  crossRunResultStorage[String(result.source)] = result;
@@ -94,15 +203,14 @@ function linter(key, options, compilation) {
94
203
  if (!results || results.length < 1) {
95
204
  return {};
96
205
  }
97
- const formatter = await loadFormatter(stylelint, options.formatter);
206
+ const formatter = await loadFormatter(getStylelint, options.formatter);
98
207
 
99
208
  /** @type {LinterResult} */
100
209
  const returnValue = {
101
- // @ts-ignore
102
- cwd: options.cwd,
210
+ cwd: (/** @type {string} */options.cwd),
103
211
  errored: false,
104
212
  results: [],
105
- output: '',
213
+ report: "",
106
214
  reportedDisables: [],
107
215
  ruleMetadata: getRuleMetadata(results)
108
216
  };
@@ -110,14 +218,9 @@ function linter(key, options, compilation) {
110
218
  errors,
111
219
  warnings
112
220
  } = formatResults(formatter, parseResults(options, results), returnValue);
113
- return {
114
- errors,
115
- warnings,
116
- generateReportAsset
117
- };
118
221
 
119
222
  /**
120
- * @param {Compilation} compilation
223
+ * @param {Compilation} compilation compilation
121
224
  * @returns {Promise<void>}
122
225
  */
123
226
  async function generateReportAsset({
@@ -127,10 +230,12 @@ function linter(key, options, compilation) {
127
230
  outputReport
128
231
  } = options;
129
232
  /**
130
- * @param {string} name
131
- * @param {string | Buffer} content
233
+ * @param {string} name name
234
+ * @param {string | Buffer} content content
235
+ * @returns {Promise<void>}
132
236
  */
133
- const save = (name, content) => ( /** @type {Promise<void>} */
237
+ const save = (name, content) => (/** @type {Promise<void>} */
238
+
134
239
  new Promise((finish, bail) => {
135
240
  if (!compiler.outputFileSystem) return;
136
241
  const {
@@ -138,21 +243,24 @@ function linter(key, options, compilation) {
138
243
  writeFile
139
244
  } = compiler.outputFileSystem;
140
245
  // ensure directory exists
141
- // @ts-ignore - the types for `outputFileSystem` are missing the 3 arg overload
142
246
  mkdir(dirname(name), {
143
247
  recursive: true
144
248
  }, err => {
145
249
  /* istanbul ignore if */
146
- if (err) bail(err);else writeFile(name, content, err2 => {
147
- /* istanbul ignore if */
148
- if (err2) bail(err2);else finish();
149
- });
250
+ if (err) {
251
+ bail(err);
252
+ } else {
253
+ writeFile(name, content, err2 => {
254
+ /* istanbul ignore if */
255
+ if (err2) bail(err2);else finish();
256
+ });
257
+ }
150
258
  });
151
259
  }));
152
260
  if (!outputReport || !outputReport.filePath) {
153
261
  return;
154
262
  }
155
- const content = outputReport.formatter ? (await loadFormatter(stylelint, outputReport.formatter))(results, returnValue) : formatter(results, returnValue);
263
+ const content = outputReport.formatter ? (await loadFormatter(getStylelint, outputReport.formatter))(results, returnValue) : formatter(results, returnValue);
156
264
  let {
157
265
  filePath
158
266
  } = outputReport;
@@ -161,131 +269,16 @@ function linter(key, options, compilation) {
161
269
  }
162
270
  await save(filePath, String(content));
163
271
  }
164
- }
165
- }
166
-
167
- /**
168
- * @param {Formatter} formatter
169
- * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results
170
- * @param {LinterResult} returnValue
171
- * @returns {{errors?: StylelintError, warnings?: StylelintError}}
172
- */
173
- function formatResults(formatter, results, returnValue) {
174
- let errors;
175
- let warnings;
176
- if (results.warnings.length > 0) {
177
- warnings = new StylelintError(formatter(results.warnings, returnValue));
178
- }
179
- if (results.errors.length > 0) {
180
- errors = new StylelintError(formatter(results.errors, returnValue));
272
+ return {
273
+ errors,
274
+ warnings,
275
+ generateReportAsset
276
+ };
181
277
  }
182
278
  return {
183
- errors,
184
- warnings
185
- };
186
- }
187
-
188
- /**
189
- * @param {Options} options
190
- * @param {LintResult[]} results
191
- * @returns {{errors: LintResult[], warnings: LintResult[]}}
192
- */
193
- function parseResults(options, results) {
194
- /** @type {LintResult[]} */
195
- const errors = [];
196
-
197
- /** @type {LintResult[]} */
198
- const warnings = [];
199
- results.forEach(file => {
200
- const fileErrors = file.warnings.filter(message => options.emitError && message.severity === 'error');
201
- if (fileErrors.length > 0) {
202
- errors.push({
203
- ...file,
204
- warnings: fileErrors
205
- });
206
- }
207
- const fileWarnings = file.warnings.filter(message => options.emitWarning && message.severity === 'warning');
208
- if (fileWarnings.length > 0) {
209
- warnings.push({
210
- ...file,
211
- warnings: fileWarnings
212
- });
213
- }
214
- });
215
- return {
216
- errors,
217
- warnings
279
+ lint,
280
+ report,
281
+ threads
218
282
  };
219
283
  }
220
-
221
- /**
222
- * @param {Stylelint} stylelint
223
- * @param {FormatterType=} formatter
224
- * @returns {Promise<Formatter>|Formatter}
225
- */
226
- function loadFormatter(stylelint, formatter) {
227
- if (typeof formatter === 'function') {
228
- return formatter;
229
- }
230
- if (typeof formatter === 'string') {
231
- try {
232
- return stylelint.formatters[formatter];
233
- } catch (_) {
234
- // Load the default formatter.
235
- }
236
- }
237
- return stylelint.formatters.string;
238
- }
239
-
240
- /**
241
- * @param {LintResult[]} results
242
- * @returns {LintResult[]}
243
- */
244
- function removeIgnoredWarnings(results) {
245
- return results.filter(result => !result.ignored);
246
- }
247
-
248
- /**
249
- * @param {Promise<LintResult[]>[]} results
250
- * @returns {Promise<LintResult[]>}
251
- */
252
- async function flatten(results) {
253
- /**
254
- * @param {LintResult[]} acc
255
- * @param {LintResult[]} list
256
- */
257
- const flat = (acc, list) => [...acc, ...list];
258
- return (await Promise.all(results)).reduce(flat, []);
259
- }
260
-
261
- /**
262
- * @param {Compilation} compilation
263
- * @returns {LintResultMap}
264
- */
265
- function getResultStorage({
266
- compiler
267
- }) {
268
- let storage = resultStorage.get(compiler);
269
- if (!storage) {
270
- resultStorage.set(compiler, storage = {});
271
- }
272
- return storage;
273
- }
274
-
275
- /**
276
- * @param {LintResult[]} lintResults
277
- */
278
- /* istanbul ignore next */
279
- function getRuleMetadata(lintResults) {
280
- const [lintResult] = lintResults;
281
-
282
- // eslint-disable-next-line no-undefined
283
- if (lintResult === undefined) return {};
284
-
285
- // eslint-disable-next-line no-underscore-dangle, no-undefined
286
- if (lintResult._postcssResult === undefined) return {};
287
-
288
- // eslint-disable-next-line no-underscore-dangle
289
- return lintResult._postcssResult.stylelint.ruleMetadata;
290
- }
291
284
  module.exports = linter;
package/dist/options.js CHANGED
@@ -2,47 +2,47 @@
2
2
 
3
3
  const {
4
4
  validate
5
- } = require('schema-utils');
6
- const schema = require('./options.json');
5
+ } = require("schema-utils");
6
+ const schema = require("./options.json");
7
7
 
8
8
  /** @typedef {import('./getStylelint').LinterOptions} StylelintOptions */
9
9
  /** @typedef {import('./getStylelint').FormatterType} FormatterType */
10
10
 
11
11
  /**
12
- * @typedef {Object} OutputReport
13
- * @property {string=} filePath
14
- * @property {FormatterType=} formatter
12
+ * @typedef {object} OutputReport
13
+ * @property {string=} filePath file path
14
+ * @property {FormatterType=} formatter formatter
15
15
  */
16
16
 
17
17
  /**
18
- * @typedef {Object} PluginOptions
19
- * @property {string} context
20
- * @property {boolean} emitError
21
- * @property {boolean} emitWarning
22
- * @property {string|string[]=} exclude
23
- * @property {string|string[]} extensions
24
- * @property {boolean} failOnError
25
- * @property {boolean} failOnWarning
26
- * @property {string|string[]} files
27
- * @property {FormatterType} formatter
28
- * @property {boolean} lintDirtyModulesOnly
29
- * @property {boolean} quiet
30
- * @property {string} stylelintPath
31
- * @property {OutputReport} outputReport
32
- * @property {number|boolean=} threads
18
+ * @typedef {object} PluginOptions
19
+ * @property {string} context a string indicating the root of your files
20
+ * @property {boolean} emitError the errors found will always be emitted
21
+ * @property {boolean} emitWarning the warnings found will always be emitted
22
+ * @property {string | string[]=} exclude specify the files and/or directories to exclude
23
+ * @property {string | string[]} extensions specify the extensions that should be checked
24
+ * @property {boolean} failOnError will cause the module build to fail if there are any errors
25
+ * @property {boolean} failOnWarning will cause the module build to fail if there are any warning
26
+ * @property {string | string[]} files specify directories, files, or globs
27
+ * @property {FormatterType} formatter specify the formatter you would like to use to format your results
28
+ * @property {boolean} lintDirtyModulesOnly lint only changed files, skip linting on start
29
+ * @property {boolean} quiet will process and report errors only and ignore warnings
30
+ * @property {string} stylelintPath path to `stylelint` instance that will be used for linting
31
+ * @property {OutputReport} outputReport writes the output of the errors to a file - for example, a `json` file for use for reporting
32
+ * @property {number | boolean=} threads number of worker threads
33
33
  */
34
34
 
35
35
  /** @typedef {Partial<PluginOptions & StylelintOptions>} Options */
36
36
 
37
37
  /**
38
- * @param {Options} pluginOptions
39
- * @returns {Partial<PluginOptions>}
38
+ * @param {Options} pluginOptions plugin options
39
+ * @returns {Partial<PluginOptions>} partial plugin options
40
40
  */
41
41
  function getOptions(pluginOptions) {
42
42
  const options = {
43
43
  cache: true,
44
- cacheLocation: 'node_modules/.cache/stylelint-webpack-plugin/.stylelintcache',
45
- extensions: ['css', 'scss', 'sass'],
44
+ cacheLocation: "node_modules/.cache/stylelint-webpack-plugin/.stylelintcache",
45
+ extensions: ["css", "scss", "sass"],
46
46
  emitError: true,
47
47
  emitWarning: true,
48
48
  failOnError: true,
@@ -53,17 +53,17 @@ function getOptions(pluginOptions) {
53
53
  } : {})
54
54
  };
55
55
 
56
- // @ts-ignore
56
+ // @ts-expect-error need better types
57
57
  validate(schema, options, {
58
- name: 'Stylelint Webpack Plugin',
59
- baseDataPath: 'options'
58
+ name: "Stylelint Webpack Plugin",
59
+ baseDataPath: "options"
60
60
  });
61
61
  return options;
62
62
  }
63
63
 
64
64
  /**
65
- * @param {Options} pluginOptions
66
- * @returns {Partial<StylelintOptions>}
65
+ * @param {Options} pluginOptions plugin options
66
+ * @returns {Partial<StylelintOptions>} stylelint options
67
67
  */
68
68
  function getStylelintOptions(pluginOptions) {
69
69
  const stylelintOptions = {
@@ -78,9 +78,8 @@ function getStylelintOptions(pluginOptions) {
78
78
  } = schema.properties;
79
79
 
80
80
  // No need to guard the for-in because schema.properties has hardcoded keys.
81
- // eslint-disable-next-line guard-for-in
82
81
  for (const option in stylelintOnlyOptions) {
83
- // @ts-ignore
82
+ // @ts-expect-error need better types
84
83
  delete stylelintOptions[option];
85
84
  }
86
85
  return stylelintOptions;