Skip to content
This repository was archived by the owner on Aug 7, 2023. It is now read-only.

Commit dcbf5cd

Browse files
authored
Merge pull request #337 from AtomLinter/arcanemagus/cleanup
General code refactor and cleanup
2 parents 9978496 + cc0a265 commit dcbf5cd

File tree

2 files changed

+330
-336
lines changed

2 files changed

+330
-336
lines changed

lib/helpers.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
'use babel';
2+
3+
import stylelint from 'stylelint';
4+
import escapeHTML from 'escape-html';
5+
import { generateRange } from 'atom-linter';
6+
7+
export function startMeasure(baseName) {
8+
const markName = `${baseName}-start`;
9+
// Clear any similar start mark from previous runs
10+
if (performance.getEntriesByName(markName).length) {
11+
performance.clearMarks(markName);
12+
}
13+
performance.mark(markName);
14+
}
15+
16+
export function endMeasure(baseName) {
17+
if (atom.inDevMode()) {
18+
performance.mark(`${baseName}-end`);
19+
performance.measure(baseName, `${baseName}-start`, `${baseName}-end`);
20+
const duration = Math.round(performance.getEntriesByName(baseName)[0].duration * 10000) / 10000;
21+
// eslint-disable-next-line no-console
22+
console.log(`${baseName} took ${duration} ms`);
23+
performance.clearMarks(`${baseName}-end`);
24+
performance.clearMeasures(baseName);
25+
}
26+
performance.clearMarks(`${baseName}-start`);
27+
}
28+
29+
export function createRange(editor, data) {
30+
if (!Object.hasOwnProperty.call(data, 'line') && !Object.hasOwnProperty.call(data, 'column')) {
31+
// data.line & data.column might be undefined for non-fatal invalid rules,
32+
// e.g.: "block-no-empty": "foo"
33+
// Return `false` so Linter will ignore the range
34+
return false;
35+
}
36+
37+
return generateRange(editor, data.line - 1, data.column - 1);
38+
}
39+
40+
export function generateHTMLMessage(message) {
41+
if (!message.rule || message.rule === 'CssSyntaxError') {
42+
return escapeHTML(message.text);
43+
}
44+
45+
const ruleParts = message.rule.split('/');
46+
let url;
47+
48+
if (ruleParts.length === 1) {
49+
// Core rule
50+
url = `http://stylelint.io/user-guide/rules/${ruleParts[0]}`;
51+
} else {
52+
// Plugin rule
53+
const pluginName = ruleParts[0];
54+
// const ruleName = ruleParts[1];
55+
56+
switch (pluginName) {
57+
case 'plugin':
58+
url = 'https://github.com/AtomLinter/linter-stylelint/tree/master/docs/noRuleNamespace.md';
59+
break;
60+
default:
61+
url = 'https://github.com/AtomLinter/linter-stylelint/tree/master/docs/linkingNewRule.md';
62+
}
63+
}
64+
65+
// Escape any HTML in the message, and replace the rule ID with a link
66+
return escapeHTML(message.text).replace(
67+
`(${message.rule})`, `(<a href="${url}">${message.rule}</a>)`
68+
);
69+
}
70+
71+
export const parseResults = (editor, results, filePath, showIgnored) => {
72+
startMeasure('linter-stylelint: Parsing results');
73+
if (!results) {
74+
endMeasure('linter-stylelint: Parsing results');
75+
endMeasure('linter-stylelint: Lint');
76+
return [];
77+
}
78+
79+
const invalidOptions = results.invalidOptionWarnings.map(msg => ({
80+
type: 'Error',
81+
severity: 'error',
82+
text: msg.text,
83+
filePath
84+
}));
85+
86+
const warnings = results.warnings.map((warning) => {
87+
// Stylelint only allows 'error' and 'warning' as severity values
88+
const severity = !warning.severity || warning.severity === 'error' ? 'Error' : 'Warning';
89+
return {
90+
type: severity,
91+
severity: severity.toLowerCase(),
92+
html: generateHTMLMessage(warning),
93+
filePath,
94+
range: createRange(editor, warning)
95+
};
96+
});
97+
98+
const deprecations = results.deprecations.map(deprecation => ({
99+
type: 'Warning',
100+
severity: 'warning',
101+
html: `${escapeHTML(deprecation.text)} (<a href="${deprecation.reference}">reference</a>)`,
102+
filePath
103+
}));
104+
105+
const ignored = [];
106+
if (showIgnored && results.ignored) {
107+
ignored.push({
108+
type: 'Warning',
109+
severity: 'warning',
110+
text: 'This file is ignored',
111+
filePath
112+
});
113+
}
114+
115+
const toReturn = []
116+
.concat(invalidOptions)
117+
.concat(warnings)
118+
.concat(deprecations)
119+
.concat(ignored);
120+
121+
endMeasure('linter-stylelint: Parsing results');
122+
endMeasure('linter-stylelint: Lint');
123+
return toReturn;
124+
};
125+
126+
export const runStylelint = async (editor, stylelintOptions, filePath, settings) => {
127+
startMeasure('linter-stylelint: Stylelint');
128+
let data;
129+
try {
130+
data = await stylelint.lint(stylelintOptions);
131+
} catch (error) {
132+
endMeasure('linter-stylelint: Stylelint');
133+
// Was it a code parsing error?
134+
if (error.line) {
135+
endMeasure('linter-stylelint: Lint');
136+
return [{
137+
type: 'Error',
138+
severity: 'error',
139+
text: error.reason || error.message,
140+
filePath,
141+
range: createRange(editor, error)
142+
}];
143+
}
144+
145+
// If we got here, stylelint found something really wrong with the
146+
// configuration, such as extending an invalid configuration
147+
atom.notifications.addError('Unable to run stylelint', {
148+
detail: error.reason || error.message,
149+
dismissable: true
150+
});
151+
152+
endMeasure('linter-stylelint: Lint');
153+
return [];
154+
}
155+
endMeasure('linter-stylelint: Stylelint');
156+
157+
const results = data.results.shift();
158+
159+
if (stylelintOptions.code !== editor.getText()) {
160+
// The editor contents have changed since the lint was requested, tell
161+
// Linter not to update the results
162+
endMeasure('linter-stylelint: Lint');
163+
return null;
164+
}
165+
return parseResults(editor, results, filePath, settings.showIgnored);
166+
};

0 commit comments

Comments
 (0)