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