-
Notifications
You must be signed in to change notification settings - Fork 11
/
stylelint-vscode.js
157 lines (132 loc) · 4.2 KB
/
stylelint-vscode.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict';
const arrayToError = require('array-to-error');
const arrayToSentence = require('array-to-sentence');
const {at, has, intersection, isPlainObject, map, stubString} = require('lodash');
const {Files, TextDocument} = require('vscode-languageserver');
const inspectWithKind = require('inspect-with-kind');
const stylelintWarningToVscodeDiagnostic = require('stylelint-warning-to-vscode-diagnostic');
// https://github.com/stylelint/stylelint/blob/10.0.1/lib/getPostcssResult.js#L69-L81
const SUPPORTED_SYNTAXES = new Set([
'css-in-js',
'html',
'less',
'markdown',
'sass',
'scss',
'sugarss'
]);
const LANGUAGE_EXTENSION_EXCEPTION_PAIRS = new Map([
['javascript', 'css-in-js'],
['javascriptreact', 'css-in-js'],
['source.css.styled', 'css-in-js'],
['source.markdown.math', 'markdown'],
['styled-css', 'css-in-js'],
['svelte', 'html'],
['typescript', 'css-in-js'],
['typescriptreact', 'css-in-js'],
['vue-html', 'html'],
['xml', 'html'],
['xsl', 'html']
]);
const UNSUPPORTED_OPTIONS = [
'code',
'codeFilename',
'files',
'formatter'
];
function quote(str) {
return `\`${str}\``;
}
function processResults({results}) {
// https://github.com/stylelint/stylelint/blob/10.0.1/lib/standalone.js#L114-L122
if (results.length === 0) {
return [];
}
const [{invalidOptionWarnings, warnings}] = results;
if (invalidOptionWarnings.length !== 0) {
throw arrayToError(map(invalidOptionWarnings, 'text'), SyntaxError);
}
return warnings.map(stylelintWarningToVscodeDiagnostic);
}
module.exports = async function stylelintVSCode(...args) {
const argLen = args.length;
if (argLen !== 1 && argLen !== 2) {
throw new RangeError(`Expected 1 or 2 arguments (<TextDocument>[, <Object>]), but got ${
argLen === 0 ? 'no' : argLen
} arguments.`);
}
const [textDocument, options = {}] = args;
if (!TextDocument.is(textDocument)) {
throw new TypeError(`Expected a TextDocument https://code.visualstudio.com/docs/extensionAPI/vscode-api#TextDocument, but got ${
inspectWithKind(textDocument)
}.`);
}
if (argLen === 2) {
if (!isPlainObject(options)) {
throw new TypeError(`Expected an object containing stylelint API options, but got ${
inspectWithKind(options)
}.`);
}
const providedUnsupportedOptions = intersection(Object.keys(options), UNSUPPORTED_OPTIONS);
if (providedUnsupportedOptions.length !== 0) {
throw new TypeError(`${
arrayToSentence(map(UNSUPPORTED_OPTIONS, quote))
} options are not supported because they will be derived from a document and there is no need to set them manually, but ${
arrayToSentence(map(providedUnsupportedOptions, quote))
} was provided.`);
}
}
const priorOptions = {
formatter: stubString
};
const codeFilename = Files.uriToFilePath(textDocument.uri);
let resultContainer;
if (codeFilename) {
if (options.fix) {
priorOptions.files = [codeFilename];
priorOptions.allowEmptyInput = true;
} else {
priorOptions.code = textDocument.getText();
priorOptions.codeFilename = codeFilename;
}
} else {
priorOptions.code = textDocument.getText();
if (!has(options, 'syntax')) {
if (SUPPORTED_SYNTAXES.has(textDocument.languageId)) {
priorOptions.syntax = textDocument.languageId;
} else {
const syntax = LANGUAGE_EXTENSION_EXCEPTION_PAIRS.get(textDocument.languageId);
if (syntax) {
priorOptions.syntax = syntax;
}
}
}
if (!at(options, 'config.rules')[0]) {
priorOptions.config = {rules: {}};
}
}
const {lint} = require(options.path || 'stylelint')
try {
resultContainer = await lint({
...options,
...priorOptions,
quietDeprecationWarnings: true,
});
} catch (err) {
if (
err.message.startsWith('No configuration provided for') ||
err.message.includes('No rules found within configuration')
) {
// Check only CSS syntax errors without applying any stylelint rules
return processResults(await lint({
...options,
...priorOptions,
config: {
rules: {}
}
}));
}
throw err;
}
return processResults(resultContainer);
};