1 | 'use strict';
|
2 |
|
3 | const LazyResult = require('postcss/lib/lazy-result').default;
|
4 | const path = require('path');
|
5 | const { default: postcss } = require('postcss');
|
6 | const { promises: fs } = require('fs');
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | const postcssProcessor = postcss();
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | module.exports = async function getPostcssResult(stylelint, options = {}) {
|
23 | const cached = options.filePath ? stylelint._postcssResultCache.get(options.filePath) : undefined;
|
24 |
|
25 | if (cached) {
|
26 | return cached;
|
27 | }
|
28 |
|
29 | if (stylelint._options.syntax) {
|
30 | let error = 'The "syntax" option is no longer available. ';
|
31 |
|
32 | error +=
|
33 | stylelint._options.syntax === 'css'
|
34 | ? 'You can remove the "--syntax" CLI flag as stylelint will now parse files as CSS by default'
|
35 | : `You should install an appropriate syntax, e.g. postcss-scss, and use the "customSyntax" option`;
|
36 |
|
37 | return Promise.reject(new Error(error));
|
38 | }
|
39 |
|
40 | const syntax = options.customSyntax
|
41 | ? getCustomSyntax(options.customSyntax)
|
42 | : cssSyntax(stylelint, options.filePath);
|
43 |
|
44 | const postcssOptions = {
|
45 | from: options.filePath,
|
46 | syntax,
|
47 | };
|
48 |
|
49 |
|
50 | let getCode;
|
51 |
|
52 | if (options.code !== undefined) {
|
53 | getCode = options.code;
|
54 | } else if (options.filePath) {
|
55 | getCode = await fs.readFile(options.filePath, 'utf8');
|
56 | }
|
57 |
|
58 | if (getCode === undefined) {
|
59 | return Promise.reject(new Error('code or filePath required'));
|
60 | }
|
61 |
|
62 | if (options.codeProcessors && options.codeProcessors.length) {
|
63 | if (stylelint._options.fix) {
|
64 | console.warn(
|
65 | 'Autofix is incompatible with processors and will be disabled. Are you sure you need a processor?',
|
66 | );
|
67 | stylelint._options.fix = false;
|
68 | }
|
69 |
|
70 | const sourceName = options.code ? options.codeFilename : options.filePath;
|
71 |
|
72 | for (const codeProcessor of options.codeProcessors) {
|
73 | getCode = codeProcessor(getCode, sourceName);
|
74 | }
|
75 | }
|
76 |
|
77 | const postcssResult = await new LazyResult(postcssProcessor, getCode, postcssOptions);
|
78 |
|
79 | if (options.filePath) {
|
80 | stylelint._postcssResultCache.set(options.filePath, postcssResult);
|
81 | }
|
82 |
|
83 | return postcssResult;
|
84 | };
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | function getCustomSyntax(customSyntax) {
|
91 | let resolved;
|
92 |
|
93 | if (typeof customSyntax === 'string') {
|
94 | try {
|
95 | resolved = require(customSyntax);
|
96 | } catch (error) {
|
97 | if (
|
98 | error &&
|
99 | typeof error === 'object' &&
|
100 |
|
101 | error.code === 'MODULE_NOT_FOUND' &&
|
102 |
|
103 | error.message.includes(customSyntax)
|
104 | ) {
|
105 | throw new Error(
|
106 | `Cannot resolve custom syntax module "${customSyntax}". Check that module "${customSyntax}" is available and spelled correctly.\n\nCaused by: ${error}`,
|
107 | );
|
108 | }
|
109 |
|
110 | throw error;
|
111 | }
|
112 |
|
113 | |
114 |
|
115 |
|
116 |
|
117 | if (!resolved.parse) {
|
118 | resolved = {
|
119 | parse: resolved,
|
120 | stringify: postcss.stringify,
|
121 | };
|
122 | }
|
123 |
|
124 | return resolved;
|
125 | }
|
126 |
|
127 | if (typeof customSyntax === 'object') {
|
128 | if (typeof customSyntax.parse === 'function') {
|
129 | resolved = { ...customSyntax };
|
130 | } else {
|
131 | throw new TypeError(
|
132 | `An object provided to the "customSyntax" option must have a "parse" property. Ensure the "parse" property exists and its value is a function.`,
|
133 | );
|
134 | }
|
135 |
|
136 | return resolved;
|
137 | }
|
138 |
|
139 | throw new Error(`Custom syntax must be a string or a Syntax object`);
|
140 | }
|
141 |
|
142 |
|
143 | const previouslyInferredExtensions = {
|
144 | html: 'postcss-html',
|
145 | js: '@stylelint/postcss-css-in-js',
|
146 | jsx: '@stylelint/postcss-css-in-js',
|
147 | less: 'postcss-less',
|
148 | md: 'postcss-markdown',
|
149 | sass: 'postcss-sass',
|
150 | sss: 'sugarss',
|
151 | scss: 'postcss-scss',
|
152 | svelte: 'postcss-html',
|
153 | ts: '@stylelint/postcss-css-in-js',
|
154 | tsx: '@stylelint/postcss-css-in-js',
|
155 | vue: 'postcss-html',
|
156 | xml: 'postcss-html',
|
157 | xst: 'postcss-html',
|
158 | };
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | function cssSyntax(stylelint, filePath) {
|
166 | const fileExtension = filePath ? path.extname(filePath).slice(1).toLowerCase() : '';
|
167 | const extensions = ['css', 'pcss', 'postcss'];
|
168 |
|
169 | if (previouslyInferredExtensions[fileExtension]) {
|
170 | console.warn(
|
171 | `${filePath}: When linting something other than CSS, you should install an appropriate syntax, e.g. "${previouslyInferredExtensions[fileExtension]}", and use the "customSyntax" option`,
|
172 | );
|
173 | }
|
174 |
|
175 | return {
|
176 | parse:
|
177 | stylelint._options.fix && extensions.includes(fileExtension)
|
178 | ? require('postcss-safe-parser')
|
179 | : postcss.parse,
|
180 | stringify: postcss.stringify,
|
181 | };
|
182 | }
|