UNPKG

3.64 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
46 return options.existingPostcssResult
47 ? Object.assign(options.existingPostcssResult, {
48 stylelint: createEmptyStylelintPostcssResult(),
49 })
50 : createEmptyPostcssResult(inputFilePath);
51 }
52
53 const configSearchPath = stylelint._options.configFile || inputFilePath;
54
55 const getConfig = stylelint.getConfigForFile(configSearchPath).catch((err) => {
56 if (isCodeNotFile && err.code === 'ENOENT') return stylelint.getConfigForFile(process.cwd());
57
58 throw err;
59 });
60
61 return getConfig.then((result) => {
62 if (!result) {
63 throw new Error('Config file not found');
64 }
65
66 const config = result.config;
67 const existingPostcssResult = options.existingPostcssResult;
68 const stylelintResult = {
69 ruleSeverities: {},
70 customMessages: {},
71 disabledRanges: {},
72 };
73
74 if (existingPostcssResult) {
75 const stylelintPostcssResult = Object.assign(existingPostcssResult, {
76 stylelint: stylelintResult,
77 });
78
79 return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
80 () => stylelintPostcssResult,
81 );
82 }
83
84 return stylelint
85 ._getPostcssResult({
86 code: options.code,
87 codeFilename: options.codeFilename,
88 filePath: inputFilePath,
89 codeProcessors: config.codeProcessors,
90 })
91 .then((postcssResult) => {
92 const stylelintPostcssResult = Object.assign(postcssResult, {
93 stylelint: stylelintResult,
94 });
95
96 return lintPostcssResult(stylelint._options, stylelintPostcssResult, config).then(
97 () => stylelintPostcssResult,
98 );
99 });
100 });
101 });
102};
103
104/**
105 * @returns {StylelintPostcssResult}
106 */
107function createEmptyStylelintPostcssResult() {
108 return {
109 ruleSeverities: {},
110 customMessages: {},
111 disabledRanges: {},
112 ignored: true,
113 stylelintError: false,
114 };
115}
116
117/**
118 * @param {string} [filePath]
119 * @returns {PostcssResult}
120 */
121function createEmptyPostcssResult(filePath) {
122 return {
123 root: {
124 source: {
125 input: { file: filePath },
126 },
127 },
128 messages: [],
129 opts: undefined,
130 stylelint: createEmptyStylelintPostcssResult(),
131 warn: () => {},
132 };
133}