stylelint-webpack-plugin 5.0.0 → 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,33 +230,37 @@ 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) => {
240
+ if (!compiler.outputFileSystem) return;
135
241
  const {
136
242
  mkdir,
137
243
  writeFile
138
244
  } = compiler.outputFileSystem;
139
245
  // ensure directory exists
140
- // @ts-ignore - the types for `outputFileSystem` are missing the 3 arg overload
141
246
  mkdir(dirname(name), {
142
247
  recursive: true
143
248
  }, err => {
144
249
  /* istanbul ignore if */
145
- if (err) bail(err);else writeFile(name, content, err2 => {
146
- /* istanbul ignore if */
147
- if (err2) bail(err2);else finish();
148
- });
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
+ }
149
258
  });
150
259
  }));
151
260
  if (!outputReport || !outputReport.filePath) {
152
261
  return;
153
262
  }
154
- const content = outputReport.formatter;
155
- (await loadFormatter(stylelint, outputReport.formatter))(results, returnValue);
156
- formatter(results, returnValue);
263
+ const content = outputReport.formatter ? (await loadFormatter(getStylelint, outputReport.formatter))(results, returnValue) : formatter(results, returnValue);
157
264
  let {
158
265
  filePath
159
266
  } = outputReport;
@@ -162,131 +269,16 @@ function linter(key, options, compilation) {
162
269
  }
163
270
  await save(filePath, String(content));
164
271
  }
165
- }
166
- }
167
-
168
- /**
169
- * @param {Formatter} formatter
170
- * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results
171
- * @param {LinterResult} returnValue
172
- * @returns {{errors?: StylelintError, warnings?: StylelintError}}
173
- */
174
- function formatResults(formatter, results, returnValue) {
175
- let errors;
176
- let warnings;
177
- if (results.warnings.length > 0) {
178
- warnings = new StylelintError(formatter(results.warnings, returnValue));
179
- }
180
- if (results.errors.length > 0) {
181
- errors = new StylelintError(formatter(results.errors, returnValue));
272
+ return {
273
+ errors,
274
+ warnings,
275
+ generateReportAsset
276
+ };
182
277
  }
183
278
  return {
184
- errors,
185
- warnings
186
- };
187
- }
188
-
189
- /**
190
- * @param {Options} options
191
- * @param {LintResult[]} results
192
- * @returns {{errors: LintResult[], warnings: LintResult[]}}
193
- */
194
- function parseResults(options, results) {
195
- /** @type {LintResult[]} */
196
- const errors = [];
197
-
198
- /** @type {LintResult[]} */
199
- const warnings = [];
200
- results.forEach(file => {
201
- const fileErrors = file.warnings.filter(message => options.emitError && message.severity === 'error');
202
- if (fileErrors.length > 0) {
203
- errors.push({
204
- ...file,
205
- warnings: fileErrors
206
- });
207
- }
208
- const fileWarnings = file.warnings.filter(message => options.emitWarning && message.severity === 'warning');
209
- if (fileWarnings.length > 0) {
210
- warnings.push({
211
- ...file,
212
- warnings: fileWarnings
213
- });
214
- }
215
- });
216
- return {
217
- errors,
218
- warnings
279
+ lint,
280
+ report,
281
+ threads
219
282
  };
220
283
  }
221
-
222
- /**
223
- * @param {Stylelint} stylelint
224
- * @param {FormatterType=} formatter
225
- * @returns {Promise<Formatter>|Formatter}
226
- */
227
- function loadFormatter(stylelint, formatter) {
228
- if (typeof formatter === 'function') {
229
- return formatter;
230
- }
231
- if (typeof formatter === 'string') {
232
- try {
233
- return stylelint.formatters[formatter];
234
- } catch (_) {
235
- // Load the default formatter.
236
- }
237
- }
238
- return stylelint.formatters.string;
239
- }
240
-
241
- /**
242
- * @param {LintResult[]} results
243
- * @returns {LintResult[]}
244
- */
245
- function removeIgnoredWarnings(results) {
246
- return results.filter(result => !result.ignored);
247
- }
248
-
249
- /**
250
- * @param {Promise<LintResult[]>[]} results
251
- * @returns {Promise<LintResult[]>}
252
- */
253
- async function flatten(results) {
254
- /**
255
- * @param {LintResult[]} acc
256
- * @param {LintResult[]} list
257
- */
258
- const flat = (acc, list) => [...acc, ...list];
259
- return (await Promise.all(results)).reduce(flat, []);
260
- }
261
-
262
- /**
263
- * @param {Compilation} compilation
264
- * @returns {LintResultMap}
265
- */
266
- function getResultStorage({
267
- compiler
268
- }) {
269
- let storage = resultStorage.get(compiler);
270
- if (!storage) {
271
- resultStorage.set(compiler, storage = {});
272
- }
273
- return storage;
274
- }
275
-
276
- /**
277
- * @param {LintResult[]} lintResults
278
- */
279
- /* istanbul ignore next */
280
- function getRuleMetadata(lintResults) {
281
- const [lintResult] = lintResults;
282
-
283
- // eslint-disable-next-line no-undefined
284
- if (lintResult === undefined) return {};
285
-
286
- // eslint-disable-next-line no-underscore-dangle, no-undefined
287
- if (lintResult._postcssResult === undefined) return {};
288
-
289
- // eslint-disable-next-line no-underscore-dangle
290
- return lintResult._postcssResult.stylelint.ruleMetadata;
291
- }
292
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;