UNPKG

3.73 kBJavaScriptView Raw
1'use strict';
2
3const lintPostcssResult = require('./lintPostcssResult');
4const path = require('path');
5
6/** @typedef {import('stylelint').StylelintInternalApi} StylelintInternalApi */
7/** @typedef {import('stylelint').GetLintSourceOptions} Options */
8/** @typedef {import('postcss').Result} Result */
9/** @typedef {import('stylelint').PostcssResult} PostcssResult */
10/** @typedef {import('stylelint').StylelintPostcssResult} StylelintPostcssResult */
11
12/**
13 * Run stylelint on a PostCSS Result, either one that is provided
14 * or one that we create
15 * @param {StylelintInternalApi} stylelint
16 * @param {Options} options
17 * @returns {Promise<PostcssResult>}
18 */
19module.exports = function lintSource(stylelint, options = {}) {
20 if (!options.filePath && options.code === undefined && !options.existingPostcssResult) {
21 return Promise.reject(new Error('You must provide filePath, code, or existingPostcssResult'));
22 }
23
24 const isCodeNotFile = options.code !== undefined;
25
26 const inputFilePath = isCodeNotFile ? options.codeFilename : options.filePath;
27
28 if (inputFilePath !== undefined && !path.isAbsolute(inputFilePath)) {
29 if (isCodeNotFile) {
30 return Promise.reject(new Error('codeFilename must be an absolute path'));
31 }
32
33 return Promise.reject(new Error('filePath must be an absolute path'));
34 }
35
36 const getIsIgnored = stylelint.isPathIgnored(inputFilePath).catch((err) => {
37 if (isCodeNotFile && err.code === 'ENOENT') return false;
38
39 throw err;
40 });
41
42 return getIsIgnored.then((isIgnored) => {
43 if (isIgnored) {
44 /** @type {PostcssResult} */
45 let postcssResult;
46
47 if (options.existingPostcssResult) {
48 postcssResult = Object.assign(options.existingPostcssResult, {
49 stylelint: createEmptyStylelintPostcssResult(),
50 });
51 } else {
52 postcssResult = createEmptyPostcssResult(inputFilePath);
53 }
54
55 return postcssResult;
56 }
57
58 const configSearchPath = stylelint._options.configFile || inputFilePath;
59
60 const getConfig = stylelint.getConfigForFile(configSearchPath).catch((err) => {
61 if (isCodeNotFile && err.code === 'ENOENT') return stylelint.getConfigForFile(process.cwd());
62
63 throw err;
64 });
65
66 return getConfig.then((result) => {
67 if (!result) {
68 throw new Error('Config file not found');
69 }
70
71 const config = result.config;
72 const existingPostcssResult = options.existingPostcssResult;
73 const stylelintResult = {
74 ruleSeverities: {},
75 customMessages: {},
76 disabledRanges: {},
77 };
78
79 if (existingPostcssResult) {
80 const stylelintPostcssResult = Object.assign(existingPostcssResult, {
81 stylelint: stylelintResult,
82 });
83
84 return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
85 () => stylelintPostcssResult,
86 );
87 }
88
89 return stylelint
90 ._getPostcssResult({
91 code: options.code,
92 codeFilename: options.codeFilename,
93 filePath: inputFilePath,
94 codeProcessors: config.codeProcessors,
95 })
96 .then((postcssResult) => {
97 const stylelintPostcssResult = Object.assign(postcssResult, {
98 stylelint: stylelintResult,
99 });
100
101 return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
102 () => stylelintPostcssResult,
103 );
104 });
105 });
106 });
107};
108
109/**
110 * @returns {StylelintPostcssResult}
111 */
112function createEmptyStylelintPostcssResult() {
113 return {
114 ruleSeverities: {},
115 customMessages: {},
116 disabledRanges: {},
117 ignored: true,
118 stylelintError: false,
119 };
120}
121
122/**
123 * @param {string} [filePath]
124 * @returns {PostcssResult}
125 */
126function createEmptyPostcssResult(filePath) {
127 return {
128 root: {
129 source: {
130 input: { file: filePath },
131 },
132 },
133 messages: [],
134 opts: undefined,
135 stylelint: createEmptyStylelintPostcssResult(),
136 warn: () => {},
137 };
138}