blob: caf877b44b103f38a334bf06305606ef5fb535f8 [file] [log] [blame]
Mathias Bynens79e2cf02020-05-29 16:46:17 +02001'use strict';
2
Tim van der Lippe16b82282021-11-08 13:50:26 +00003const isPathNotFoundError = require('./utils/isPathNotFoundError');
Tim van der Lippeefb716a2020-12-01 12:54:04 +00004const lintPostcssResult = require('./lintPostcssResult');
Mathias Bynens79e2cf02020-05-29 16:46:17 +02005const path = require('path');
Mathias Bynens79e2cf02020-05-29 16:46:17 +02006
Tim van der Lippe16b82282021-11-08 13:50:26 +00007/** @typedef {import('stylelint').InternalApi} StylelintInternalApi */
Tim van der Lippeefb716a2020-12-01 12:54:04 +00008/** @typedef {import('stylelint').GetLintSourceOptions} Options */
9/** @typedef {import('postcss').Result} Result */
Mathias Bynens79e2cf02020-05-29 16:46:17 +020010/** @typedef {import('stylelint').PostcssResult} PostcssResult */
11/** @typedef {import('stylelint').StylelintPostcssResult} StylelintPostcssResult */
Mathias Bynens79e2cf02020-05-29 16:46:17 +020012
13/**
14 * Run stylelint on a PostCSS Result, either one that is provided
15 * or one that we create
16 * @param {StylelintInternalApi} stylelint
17 * @param {Options} options
18 * @returns {Promise<PostcssResult>}
19 */
Tim van der Lippe16b82282021-11-08 13:50:26 +000020module.exports = async function lintSource(stylelint, options = {}) {
Mathias Bynens79e2cf02020-05-29 16:46:17 +020021 if (!options.filePath && options.code === undefined && !options.existingPostcssResult) {
22 return Promise.reject(new Error('You must provide filePath, code, or existingPostcssResult'));
23 }
24
25 const isCodeNotFile = options.code !== undefined;
26
27 const inputFilePath = isCodeNotFile ? options.codeFilename : options.filePath;
28
29 if (inputFilePath !== undefined && !path.isAbsolute(inputFilePath)) {
30 if (isCodeNotFile) {
31 return Promise.reject(new Error('codeFilename must be an absolute path'));
32 }
33
34 return Promise.reject(new Error('filePath must be an absolute path'));
35 }
36
Tim van der Lippe16b82282021-11-08 13:50:26 +000037 const isIgnored = await stylelint.isPathIgnored(inputFilePath).catch((err) => {
38 if (isCodeNotFile && isPathNotFoundError(err)) return false;
Mathias Bynens79e2cf02020-05-29 16:46:17 +020039
40 throw err;
41 });
42
Tim van der Lippe16b82282021-11-08 13:50:26 +000043 if (isIgnored) {
44 return options.existingPostcssResult
45 ? Object.assign(options.existingPostcssResult, {
46 stylelint: createEmptyStylelintPostcssResult(),
47 })
48 : createEmptyPostcssResult(inputFilePath);
49 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020050
Tim van der Lippe16b82282021-11-08 13:50:26 +000051 const configSearchPath = stylelint._options.configFile || inputFilePath;
Tim van der Lippe4cb09742022-01-07 14:25:03 +010052 const cwd = stylelint._options.cwd;
Mathias Bynens79e2cf02020-05-29 16:46:17 +020053
Tim van der Lippe16b82282021-11-08 13:50:26 +000054 const configForFile = await stylelint
55 .getConfigForFile(configSearchPath, inputFilePath)
56 .catch((err) => {
Tim van der Lippe4cb09742022-01-07 14:25:03 +010057 if (isCodeNotFile && isPathNotFoundError(err)) return stylelint.getConfigForFile(cwd);
Mathias Bynens79e2cf02020-05-29 16:46:17 +020058
59 throw err;
60 });
61
Tim van der Lippe16b82282021-11-08 13:50:26 +000062 if (!configForFile) {
63 return Promise.reject(new Error('Config file not found'));
64 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020065
Tim van der Lippe16b82282021-11-08 13:50:26 +000066 const config = configForFile.config;
67 const existingPostcssResult = options.existingPostcssResult;
68 const stylelintResult = {
69 ruleSeverities: {},
70 customMessages: {},
71 disabledRanges: {},
72 };
Mathias Bynens79e2cf02020-05-29 16:46:17 +020073
Tim van der Lippe16b82282021-11-08 13:50:26 +000074 const postcssResult =
75 existingPostcssResult ||
76 (await stylelint._getPostcssResult({
77 code: options.code,
78 codeFilename: options.codeFilename,
79 filePath: inputFilePath,
80 codeProcessors: config.codeProcessors,
81 customSyntax: config.customSyntax,
82 }));
Mathias Bynens79e2cf02020-05-29 16:46:17 +020083
Tim van der Lippe16b82282021-11-08 13:50:26 +000084 const stylelintPostcssResult = Object.assign(postcssResult, {
85 stylelint: stylelintResult,
Mathias Bynens79e2cf02020-05-29 16:46:17 +020086 });
Tim van der Lippe16b82282021-11-08 13:50:26 +000087
88 await lintPostcssResult(stylelint._options, stylelintPostcssResult, config);
89
90 return stylelintPostcssResult;
Mathias Bynens79e2cf02020-05-29 16:46:17 +020091};
92
93/**
Mathias Bynens79e2cf02020-05-29 16:46:17 +020094 * @returns {StylelintPostcssResult}
95 */
96function createEmptyStylelintPostcssResult() {
97 return {
98 ruleSeverities: {},
99 customMessages: {},
100 disabledRanges: {},
101 ignored: true,
102 stylelintError: false,
103 };
104}
105
106/**
107 * @param {string} [filePath]
108 * @returns {PostcssResult}
109 */
110function createEmptyPostcssResult(filePath) {
111 return {
112 root: {
113 source: {
114 input: { file: filePath },
115 },
116 },
117 messages: [],
118 opts: undefined,
119 stylelint: createEmptyStylelintPostcssResult(),
120 warn: () => {},
121 };
122}