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