UNPKG

4.1 kBJavaScriptView Raw
1/* @flow */
2"use strict";
3
4const autoSyntax = require("postcss-syntax");
5const dynamicRequire = require("./dynamicRequire");
6const fs = require("fs");
7const LazyResult = require("postcss/lib/lazy-result");
8const postcss = require("postcss");
9
10const postcssProcessor = postcss();
11
12module.exports = function(
13 stylelint /*: stylelint$internalApi*/
14) /*: Promise<?Object>*/ {
15 const options /*: {
16 code?: string,
17 codeFilename?: string,
18 filePath?: string,
19 codeProcessors?: Array<Function>,
20 syntax?: stylelint$syntaxes,
21 customSyntax?: string
22 }*/ =
23 arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
24
25 const cached /*: ?postcss$result*/ = stylelint._postcssResultCache.get(
26 options.filePath
27 );
28
29 if (cached) return Promise.resolve(cached);
30
31 let getCode;
32
33 if (options.code !== undefined) {
34 getCode = Promise.resolve(options.code);
35 } else if (options.filePath) {
36 getCode = readFile(options.filePath);
37 }
38
39 if (!getCode) {
40 throw new Error("code or filePath required");
41 }
42
43 return getCode
44 .then(code => {
45 const customSyntax = stylelint._options.customSyntax;
46 let syntax = stylelint._options.syntax;
47
48 if (customSyntax) {
49 try {
50 syntax = dynamicRequire(customSyntax);
51 } catch (e) {
52 throw new Error(
53 `Cannot resolve custom syntax module ${customSyntax}`
54 );
55 }
56
57 /*
58 * PostCSS allows for syntaxes that only contain a parser, however,
59 * it then expects the syntax to be set as the `parser` option rather than `syntax.
60 */
61 if (!syntax.parse) {
62 syntax = {
63 parse: syntax,
64 stringify: postcss.stringify
65 };
66 }
67 } else if (syntax) {
68 switch (syntax) {
69 case "css-in-js": {
70 syntax = "postcss-jsx";
71 break;
72 }
73 case "html":
74 case "less":
75 case "markdown":
76 case "sass":
77 case "scss": {
78 syntax = "postcss-" + syntax;
79 break;
80 }
81 case "sugarss": {
82 break;
83 }
84 default: {
85 throw new Error(
86 "You must use a valid syntax option, either: css-in-js, html, less, markdown, sass, scss or sugarss"
87 );
88 }
89 }
90
91 syntax = dynamicRequire(syntax);
92 } else if (
93 !(options.codeProcessors && options.codeProcessors.length) ||
94 (options.filePath && /\.(scss|sass|less)$/.test(options.filePath))
95 ) {
96 syntax = autoSyntax({
97 css: {
98 parse: stylelint._options.fix
99 ? dynamicRequire("postcss-safe-parser")
100 : postcss.parse,
101 stringify: postcss.stringify
102 }
103 });
104 }
105
106 const postcssOptions /*: postcss$options*/ = {
107 from: options.filePath,
108 syntax
109 };
110
111 const source = options.code ? options.codeFilename : options.filePath;
112 let preProcessedCode = code;
113
114 if (options.codeProcessors && options.codeProcessors.length) {
115 if (stylelint._options.fix) {
116 // eslint-disable-next-line no-console
117 console.warn(
118 "Autofix is incompatible with processors and will be disabled. Are you sure you need a processor?"
119 );
120 stylelint._options.fix = false;
121 }
122
123 options.codeProcessors.forEach(codeProcessor => {
124 preProcessedCode = codeProcessor(preProcessedCode, source);
125 });
126 }
127
128 const result = new LazyResult(
129 postcssProcessor,
130 preProcessedCode,
131 postcssOptions
132 );
133
134 return result;
135 })
136 .then(postcssResult => {
137 stylelint._postcssResultCache.set(options.filePath, postcssResult);
138
139 return postcssResult;
140 });
141};
142
143function readFile(filePath /*: string*/) /*: Promise<string>*/ {
144 return new Promise((resolve, reject) => {
145 fs.readFile(filePath, "utf8", (err, content) => {
146 if (err) {
147 return reject(err);
148 }
149
150 resolve(content);
151 });
152 });
153}