regroup some of lint* data and code
* all lint-related js files are prefixed by lint- * config-related stuff is grouped in linterConfig * CM helper is rewritten and moved in /edit now that CSSLint supports these features * chromeSync methods that apply LZString got LZ in their names * empty string is used for 'disabled' in linter selector
This commit is contained in:
parent
dfc3deaf01
commit
9946f3c781
|
@ -46,7 +46,7 @@ var chromeLocal = {
|
||||||
var chromeSync = {
|
var chromeSync = {
|
||||||
get(options) {
|
get(options) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
chrome.storage.sync.get(options, data => resolve(data));
|
chrome.storage.sync.get(options, resolve);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
set(data) {
|
set(data) {
|
||||||
|
@ -54,10 +54,15 @@ var chromeSync = {
|
||||||
chrome.storage.sync.set(data, () => resolve(data));
|
chrome.storage.sync.set(data, () => resolve(data));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getValue(key) {
|
getLZValue(key) {
|
||||||
return chromeSync.get(key).then(data => tryJSONparse(LZString.decompressFromUTF16(data[key])));
|
return chromeSync.get(key).then(data => tryJSONparse(LZString.decompressFromUTF16(data[key])));
|
||||||
},
|
},
|
||||||
setValue(key, value) {
|
getLZValues(keys) {
|
||||||
|
return chromeSync.get(keys).then(data =>
|
||||||
|
Object.assign({}, ...keys.map(key =>
|
||||||
|
({[key]: tryJSONparse(LZString.decompressFromUTF16(data[key]))}))));
|
||||||
|
},
|
||||||
|
setLZValue(key, value) {
|
||||||
return chromeSync.set({[key]: LZString.compressToUTF16(JSON.stringify(value))});
|
return chromeSync.set({[key]: LZString.compressToUTF16(JSON.stringify(value))});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -187,7 +187,7 @@
|
||||||
<select id="editor.linter">
|
<select id="editor.linter">
|
||||||
<option value="csslint" selected>CSSLint</option>
|
<option value="csslint" selected>CSSLint</option>
|
||||||
<option value="stylelint">Stylelint</option>
|
<option value="stylelint">Stylelint</option>
|
||||||
<option value="null" i18n-text="genericDisabledLabel"></option>
|
<option value="" i18n-text="genericDisabledLabel"></option>
|
||||||
</select>
|
</select>
|
||||||
<span class="linter-settings" i18n-title="linterConfigTooltip">
|
<span class="linter-settings" i18n-title="linterConfigTooltip">
|
||||||
<svg id="linter-settings" class="svg-icon settings">
|
<svg id="linter-settings" class="svg-icon settings">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint brace-style: 0, operator-linebreak: 0 */
|
/* eslint brace-style: 0, operator-linebreak: 0 */
|
||||||
/* global CodeMirror parserlib */
|
/* global CodeMirror parserlib */
|
||||||
/* global exports css_beautify onDOMscripted */
|
/* global exports css_beautify onDOMscripted */
|
||||||
/* global CSSLint initLint getLinterConfigForCodeMirror updateLintReport renderLintReport updateLinter */
|
/* global CSSLint initLint linterConfig updateLintReport renderLintReport updateLinter */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let styleId = null;
|
let styleId = null;
|
||||||
|
@ -161,8 +161,7 @@ function initCodeMirror() {
|
||||||
const CM = CodeMirror;
|
const CM = CodeMirror;
|
||||||
const isWindowsOS = navigator.appVersion.indexOf('Windows') > 0;
|
const isWindowsOS = navigator.appVersion.indexOf('Windows') > 0;
|
||||||
// lint.js is not loaded initially
|
// lint.js is not loaded initially
|
||||||
const hasLinter = typeof getLinterConfigForCodeMirror !== 'undefined' ?
|
const hasLinter = window.linterConfig ? linterConfig.getForCodeMirror() : false;
|
||||||
getLinterConfigForCodeMirror(prefs.get('editor.linter')) : false;
|
|
||||||
|
|
||||||
// CodeMirror miserably fails on keyMap='' so let's ensure it's not
|
// CodeMirror miserably fails on keyMap='' so let's ensure it's not
|
||||||
if (!prefs.get('editor.keyMap')) {
|
if (!prefs.get('editor.keyMap')) {
|
||||||
|
@ -1955,7 +1954,7 @@ function showCodeMirrorPopup(title, html, options) {
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||||
matchBrackets: true,
|
matchBrackets: true,
|
||||||
lint: getLinterConfigForCodeMirror(prefs.get('editor.linter')),
|
lint: linterConfig.getForCodeMirror(),
|
||||||
styleActiveLine: true,
|
styleActiveLine: true,
|
||||||
theme: prefs.get('editor.theme'),
|
theme: prefs.get('editor.theme'),
|
||||||
keyMap: prefs.get('editor.keyMap')
|
keyMap: prefs.get('editor.keyMap')
|
||||||
|
|
31
edit/lint-codemirror-helper.js
Normal file
31
edit/lint-codemirror-helper.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* global CodeMirror CSSLint stylelint linterConfig */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
CodeMirror.registerHelper('lint', 'csslint', code =>
|
||||||
|
CSSLint.verify(code, linterConfig.getCurrent('csslint'))
|
||||||
|
.messages.map(message => ({
|
||||||
|
from: CodeMirror.Pos(message.line - 1, message.col - 1),
|
||||||
|
to: CodeMirror.Pos(message.line - 1, message.col),
|
||||||
|
message: message.message + ` (${message.rule.id})`,
|
||||||
|
severity : message.type
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
CodeMirror.registerHelper('lint', 'stylelint', code =>
|
||||||
|
stylelint.lint({
|
||||||
|
code,
|
||||||
|
config: linterConfig.getCurrent('stylelint'),
|
||||||
|
}).then(({results}) => {
|
||||||
|
if (!results[0]) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return results[0].warnings.map(warning => ({
|
||||||
|
from: CodeMirror.Pos(warning.line - 1, warning.column - 1),
|
||||||
|
to: CodeMirror.Pos(warning.line - 1, warning.column),
|
||||||
|
message: warning.text
|
||||||
|
.replace('Unexpected ', '')
|
||||||
|
.replace(/^./, firstLetter => firstLetter.toUpperCase()),
|
||||||
|
severity : warning.severity
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
);
|
|
@ -4,7 +4,7 @@
|
||||||
* CSSLint Config values
|
* CSSLint Config values
|
||||||
* 0 = disabled; 1 = warning; 2 = error
|
* 0 = disabled; 1 = warning; 2 = error
|
||||||
*/
|
*/
|
||||||
window.csslintDefaultConfig = {
|
window.linterConfig.defaults.csslint = {
|
||||||
// Default warnings
|
// Default warnings
|
||||||
'display-property-grouping': 1,
|
'display-property-grouping': 1,
|
||||||
'duplicate-properties': 1,
|
'duplicate-properties': 1,
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
window.stylelintDefaultConfig = (defaultSeverity => ({
|
window.linterConfig.defaults.stylelint = (defaultSeverity => ({
|
||||||
// 'sugarss' is a indent-based syntax like Sass or Stylus
|
// 'sugarss' is a indent-based syntax like Sass or Stylus
|
||||||
// ref: https://github.com/postcss/postcss#syntaxes
|
// ref: https://github.com/postcss/postcss#syntaxes
|
||||||
syntax: 'sugarss',
|
syntax: 'sugarss',
|
279
edit/lint.js
279
edit/lint.js
|
@ -1,51 +1,141 @@
|
||||||
/* global CodeMirror messageBox */
|
/* global CodeMirror messageBox */
|
||||||
/* global editors makeSectionVisible showCodeMirrorPopup showHelp */
|
/* global editors makeSectionVisible showCodeMirrorPopup showHelp */
|
||||||
/* global stylelintDefaultConfig csslintDefaultConfig onDOMscripted injectCSS require */
|
/* global onDOMscripted injectCSS require CSSLint stylelint */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var linterConfig = {
|
||||||
|
csslint: {},
|
||||||
|
stylelint: {},
|
||||||
|
defaults: {
|
||||||
|
// set in lint-defaults-csslint.js
|
||||||
|
csslint: {},
|
||||||
|
// set in lint-defaults-stylelint.js
|
||||||
|
stylelint: {},
|
||||||
|
},
|
||||||
|
storageName: {
|
||||||
|
csslint: 'editorCSSLintConfig',
|
||||||
|
stylelint: 'editorStylelintConfig',
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrent(linter = prefs.get('editor.linter')) {
|
||||||
|
return this.fallbackToDefaults(this[linter] || {});
|
||||||
|
},
|
||||||
|
|
||||||
|
getForCodeMirror(linter = prefs.get('editor.linter')) {
|
||||||
|
return CodeMirror.lint && CodeMirror.lint[linter] ? {
|
||||||
|
getAnnotations: CodeMirror.lint[linter],
|
||||||
|
delay: prefs.get('editor.lintDelay'),
|
||||||
|
} : false;
|
||||||
|
},
|
||||||
|
|
||||||
|
fallbackToDefaults(config, linter = prefs.get('editor.linter')) {
|
||||||
|
if (config && Object.keys(config).length) {
|
||||||
|
if (linter === 'stylelint') {
|
||||||
|
// always use default syntax because we don't expose it in config UI
|
||||||
|
config.syntax = this.defaults.stylelint.syntax;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
} else {
|
||||||
|
return deepCopy(this.defaults[linter] || {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setLinter(linter = prefs.get('editor.linter')) {
|
||||||
|
linter = linter.toLowerCase();
|
||||||
|
linter = linter === 'csslint' || linter === 'stylelint' ? linter : '';
|
||||||
|
if (prefs.get('editor.linter') !== linter) {
|
||||||
|
prefs.set('editor.linter', linter);
|
||||||
|
}
|
||||||
|
return linter;
|
||||||
|
},
|
||||||
|
|
||||||
|
findInvalidRules(config, linter = prefs.get('editor.linter')) {
|
||||||
|
const rules = linter === 'stylelint' ? config.rules : config;
|
||||||
|
const allRules = new Set(
|
||||||
|
linter === 'stylelint'
|
||||||
|
? Object.keys(stylelint.rules)
|
||||||
|
: CSSLint.getRules().map(rule => rule.id)
|
||||||
|
);
|
||||||
|
return Object.keys(rules).filter(rule => !allRules.has(rule));
|
||||||
|
},
|
||||||
|
|
||||||
|
stringify(config = this.getCurrent()) {
|
||||||
|
if (prefs.get('editor.linter') === 'stylelint') {
|
||||||
|
config.syntax = undefined;
|
||||||
|
}
|
||||||
|
return JSON.stringify(config, null, 2)
|
||||||
|
.replace(/,\n\s+\{\n\s+("severity":\s"\w+")\n\s+\}/g, ', {$1}');
|
||||||
|
},
|
||||||
|
|
||||||
|
save(config) {
|
||||||
|
config = this.fallbackToDefaults(config);
|
||||||
|
const linter = prefs.get('editor.linter');
|
||||||
|
this[linter] = config;
|
||||||
|
BG.chromeSync.setLZValue(this.storageName[linter], config);
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
|
||||||
|
loadAll() {
|
||||||
|
return BG.chromeSync.getLZValues([
|
||||||
|
'editorCSSLintConfig',
|
||||||
|
'editorStylelintConfig',
|
||||||
|
]).then(data => {
|
||||||
|
this.csslint = this.fallbackToDefaults(data.editorCSSLintConfig, 'csslint');
|
||||||
|
this.stylelint = this.fallbackToDefaults(data.editorStylelintConfig, 'stylelint');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
watchStorage() {
|
||||||
|
chrome.storage.onChanged.addListener((changes, area) => {
|
||||||
|
if (area === 'sync') {
|
||||||
|
for (const name of ['editorCSSLintConfig', 'editorStylelintConfig']) {
|
||||||
|
if (name in changes && changes[name].newValue !== changes[name].oldValue) {
|
||||||
|
this.loadAll().then(() => debounce(updateLinter));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// this is an event listener so it can't refer to self via 'this'
|
||||||
|
openOnClick() {
|
||||||
|
setupLinterPopup(linterConfig.stringify());
|
||||||
|
},
|
||||||
|
|
||||||
|
showSavedMessage() {
|
||||||
|
$('#help-popup .saved-message').classList.add('show');
|
||||||
|
clearTimeout($('#help-popup .contents').timer);
|
||||||
|
$('#help-popup .contents').timer = setTimeout(() => {
|
||||||
|
// popup may be closed at this point
|
||||||
|
const msg = $('#help-popup .saved-message');
|
||||||
|
if (msg) {
|
||||||
|
msg.classList.remove('show');
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
function initLint() {
|
function initLint() {
|
||||||
$('#lint-help').addEventListener('click', showLintHelp);
|
$('#lint-help').addEventListener('click', showLintHelp);
|
||||||
$('#lint').addEventListener('click', gotoLintIssue);
|
$('#lint').addEventListener('click', gotoLintIssue);
|
||||||
|
$('#linter-settings').addEventListener('click', linterConfig.openOnClick);
|
||||||
window.addEventListener('resize', resizeLintReport);
|
window.addEventListener('resize', resizeLintReport);
|
||||||
$('#linter-settings').addEventListener('click', openStylelintSettings);
|
|
||||||
|
|
||||||
// touch devices don't have onHover events so the element we'll be toggled via clicking (touching)
|
// touch devices don't have onHover events so the element we'll be toggled via clicking (touching)
|
||||||
if ('ontouchstart' in document.body) {
|
if ('ontouchstart' in document.body) {
|
||||||
$('#lint h2').addEventListener('click', toggleLintReport);
|
$('#lint h2').addEventListener('click', toggleLintReport);
|
||||||
}
|
}
|
||||||
// initialize storage of linter config
|
|
||||||
BG.chromeSync.getValue('editorStylelintConfig').then(config => setStylelintConfig(config));
|
linterConfig.loadAll();
|
||||||
BG.chromeSync.getValue('editorCSSLintConfig').then(config => setCSSLintConfig(config));
|
linterConfig.watchStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStylelintConfig(config) {
|
function updateLinter(linter = prefs.get('editor.linter')) {
|
||||||
// can't use default parameters, because config may be null
|
|
||||||
if (Object.keys(config || []).length === 0 && typeof stylelintDefaultConfig !== 'undefined') {
|
|
||||||
config = deepCopy(stylelintDefaultConfig.rules);
|
|
||||||
}
|
|
||||||
BG.chromeSync.setValue('editorStylelintConfig', config);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCSSLintConfig(config) {
|
|
||||||
if (Object.keys(config || []).length === 0 && typeof csslintDefaultConfig !== 'undefined') {
|
|
||||||
config = Object.assign({}, csslintDefaultConfig);
|
|
||||||
}
|
|
||||||
BG.chromeSync.setValue('editorCSSLintConfig', config);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLinterConfigForCodeMirror(name) {
|
|
||||||
return CodeMirror.lint && CodeMirror.lint[name] ? {
|
|
||||||
getAnnotations: CodeMirror.lint[name],
|
|
||||||
delay: prefs.get('editor.lintDelay')
|
|
||||||
} : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLinter(linter) {
|
|
||||||
function updateEditors() {
|
function updateEditors() {
|
||||||
const options = getLinterConfigForCodeMirror(linter);
|
const options = linterConfig.getForCodeMirror(linter);
|
||||||
CodeMirror.defaults.lint = options === 'null' ? false : options;
|
CodeMirror.defaults.lint = options;
|
||||||
editors.forEach(cm => {
|
editors.forEach(cm => {
|
||||||
// set lint to "null" to disable
|
// set lint to "null" to disable
|
||||||
cm.setOption('lint', options);
|
cm.setOption('lint', options);
|
||||||
|
@ -58,7 +148,7 @@ function updateLinter(linter) {
|
||||||
loadSelectedLinter(linter).then(() => {
|
loadSelectedLinter(linter).then(() => {
|
||||||
updateEditors();
|
updateEditors();
|
||||||
});
|
});
|
||||||
$('#linter-settings').style.display = linter === 'null' ? 'none' : 'inline-block';
|
$('#linter-settings').style.display = !linter ? 'none' : 'inline-block';
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLintReport(cm, delay) {
|
function updateLintReport(cm, delay) {
|
||||||
|
@ -215,7 +305,7 @@ function showLintHelp() {
|
||||||
let list = '<ul class="rules">';
|
let list = '<ul class="rules">';
|
||||||
let header = '';
|
let header = '';
|
||||||
if (linter === 'csslint') {
|
if (linter === 'csslint') {
|
||||||
const CSSLintRules = window.CSSLint.getRules();
|
const CSSLintRules = CSSLint.getRules();
|
||||||
const findCSSLintRule = id => CSSLintRules.find(rule => rule.id === id);
|
const findCSSLintRule = id => CSSLintRules.find(rule => rule.id === id);
|
||||||
header = t('linterIssuesHelp', makeLink('https://github.com/CSSLint/csslint/wiki/Rules-by-ID', 'CSSLint'));
|
header = t('linterIssuesHelp', makeLink('https://github.com/CSSLint/csslint/wiki/Rules-by-ID', 'CSSLint'));
|
||||||
template = ruleID => {
|
template = ruleID => {
|
||||||
|
@ -246,64 +336,27 @@ function showLinterErrorMessage(title, contents) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSavedMessage() {
|
|
||||||
$('#help-popup .saved-message').classList.add('show');
|
|
||||||
clearTimeout($('#help-popup .contents').timer);
|
|
||||||
$('#help-popup .contents').timer = setTimeout(() => {
|
|
||||||
// popup may be closed at this point
|
|
||||||
const msg = $('#help-popup .saved-message');
|
|
||||||
if (msg) {
|
|
||||||
msg.classList.remove('show');
|
|
||||||
}
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkLinter(linter = prefs.get('editor.linter')) {
|
|
||||||
linter = linter.toLowerCase();
|
|
||||||
if (prefs.get('editor.linter') !== linter) {
|
|
||||||
prefs.set('editor.linter', linter);
|
|
||||||
}
|
|
||||||
return linter;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkConfigRules(linter, config) {
|
|
||||||
const invalid = [];
|
|
||||||
const linterRules = linter === 'stylelint'
|
|
||||||
? Object.keys(window.stylelint.rules)
|
|
||||||
: window.CSSLint.getRules().map(rule => rule.id);
|
|
||||||
Object.keys(config).forEach(setting => {
|
|
||||||
if (!linterRules.includes(setting)) {
|
|
||||||
invalid.push(setting);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringifyConfig(config) {
|
|
||||||
return JSON.stringify(config, null, 2)
|
|
||||||
.replace(/,\n\s+\{\n\s+("severity":\s"\w+")\n\s+\}/g, ', {$1}');
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupLinterSettingsEvents(popup) {
|
function setupLinterSettingsEvents(popup) {
|
||||||
$('.save', popup).addEventListener('click', event => {
|
$('.save', popup).addEventListener('click', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const linter = checkLinter(event.target.dataset.linter);
|
const linter = linterConfig.setLinter(event.target.dataset.linter);
|
||||||
const json = tryJSONparse(popup.codebox.getValue());
|
const json = tryJSONparse(popup.codebox.getValue());
|
||||||
if (json) {
|
if (json) {
|
||||||
const invalid = checkConfigRules(linter, json);
|
const invalid = linterConfig.findInvalidRules(json, linter);
|
||||||
if (invalid.length) {
|
if (invalid.length) {
|
||||||
return showLinterErrorMessage(
|
showLinterErrorMessage(linter, [
|
||||||
linter,
|
t('linterInvalidConfigError'),
|
||||||
t('linterInvalidConfigError') + `<ul><li>${invalid.join('</li><li>')}</li></ul>`
|
$element({
|
||||||
);
|
tag: 'ul',
|
||||||
|
appendChild: invalid.map(name =>
|
||||||
|
$element({tag: 'li', textContent: name})),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (linter === 'stylelint') {
|
linterConfig.save(json);
|
||||||
setStylelintConfig(json);
|
linterConfig.showSavedMessage();
|
||||||
} else {
|
debounce(updateLinter, 0, linter);
|
||||||
setCSSLintConfig(json);
|
|
||||||
}
|
|
||||||
updateLinter(linter);
|
|
||||||
showSavedMessage();
|
|
||||||
} else {
|
} else {
|
||||||
showLinterErrorMessage(linter, t('linterJSONError'));
|
showLinterErrorMessage(linter, t('linterJSONError'));
|
||||||
}
|
}
|
||||||
|
@ -311,16 +364,8 @@ function setupLinterSettingsEvents(popup) {
|
||||||
});
|
});
|
||||||
$('.reset', popup).addEventListener('click', event => {
|
$('.reset', popup).addEventListener('click', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const linter = checkLinter(event.target.dataset.linter);
|
const linter = linterConfig.setLinter(event.target.dataset.linter);
|
||||||
let config;
|
popup.codebox.setValue(linterConfig.stringify(linterConfig.defaults[linter] || {}));
|
||||||
if (linter === 'stylelint') {
|
|
||||||
setStylelintConfig();
|
|
||||||
config = stylelintDefaultConfig.rules;
|
|
||||||
} else {
|
|
||||||
setCSSLintConfig();
|
|
||||||
config = csslintDefaultConfig;
|
|
||||||
}
|
|
||||||
popup.codebox.setValue(stringifyConfig(config));
|
|
||||||
popup.codebox.focus();
|
popup.codebox.focus();
|
||||||
});
|
});
|
||||||
$('.cancel', popup).addEventListener('click', event => {
|
$('.cancel', popup).addEventListener('click', event => {
|
||||||
|
@ -329,23 +374,6 @@ function setupLinterSettingsEvents(popup) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openStylelintSettings() {
|
|
||||||
const linter = prefs.get('editor.linter');
|
|
||||||
BG.chromeSync.getValue(
|
|
||||||
linter === 'stylelint'
|
|
||||||
? 'editorStylelintConfig'
|
|
||||||
: 'editorCSSLintConfig'
|
|
||||||
).then(config => {
|
|
||||||
if (!config || config.length === 0) {
|
|
||||||
config = linter === 'stylelint'
|
|
||||||
? setStylelintConfig(config)
|
|
||||||
: setCSSLintConfig(config);
|
|
||||||
}
|
|
||||||
const configString = stringifyConfig(config);
|
|
||||||
setupLinterPopup(configString);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupLinterPopup(config) {
|
function setupLinterPopup(config) {
|
||||||
const linter = prefs.get('editor.linter');
|
const linter = prefs.get('editor.linter');
|
||||||
const linterTitle = linter === 'stylelint' ? 'Stylelint' : 'CSSLint';
|
const linterTitle = linter === 'stylelint' ? 'Stylelint' : 'CSSLint';
|
||||||
|
@ -406,26 +434,25 @@ function setupLinterPopup(config) {
|
||||||
|
|
||||||
function loadSelectedLinter(name) {
|
function loadSelectedLinter(name) {
|
||||||
const scripts = [];
|
const scripts = [];
|
||||||
if (name !== 'null' && !$('script[src*="css-lint.js"]')) {
|
|
||||||
// inject css
|
|
||||||
injectCSS('vendor/codemirror/addon/lint/lint.css');
|
|
||||||
injectCSS('msgbox/msgbox.css');
|
|
||||||
// load CodeMirror lint code
|
|
||||||
scripts.push(
|
|
||||||
'vendor/codemirror/addon/lint/lint.js',
|
|
||||||
'vendor-overwrites/codemirror/addon/lint/css-lint.js',
|
|
||||||
'msgbox/msgbox.js'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (name === 'csslint' && !window.CSSLint) {
|
if (name === 'csslint' && !window.CSSLint) {
|
||||||
scripts.push(
|
scripts.push(
|
||||||
'edit/csslint-config.js',
|
'vendor-overwrites/csslint/csslint-worker.js',
|
||||||
'vendor-overwrites/csslint/csslint-worker.js'
|
'edit/lint-defaults-csslint.js'
|
||||||
);
|
);
|
||||||
} else if (name === 'stylelint' && !window.stylelint) {
|
} else if (name === 'stylelint' && !window.stylelint) {
|
||||||
scripts.push(
|
scripts.push(
|
||||||
'vendor-overwrites/stylelint/stylelint-bundle.min.js',
|
'vendor-overwrites/stylelint/stylelint-bundle.min.js',
|
||||||
'edit/stylelint-config.js'
|
() => (window.stylelint = require('stylelint')),
|
||||||
|
'edit/lint-defaults-stylelint.js'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (name && !$('script[src$="vendor/codemirror/addon/lint/lint.js"]')) {
|
||||||
|
injectCSS('vendor/codemirror/addon/lint/lint.css');
|
||||||
|
injectCSS('msgbox/msgbox.css');
|
||||||
|
scripts.push(
|
||||||
|
'vendor/codemirror/addon/lint/lint.js',
|
||||||
|
'edit/lint-codemirror-helper.js',
|
||||||
|
'msgbox/msgbox.js'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return onDOMscripted(scripts);
|
return onDOMscripted(scripts);
|
||||||
|
|
|
@ -42,7 +42,7 @@ var prefs = new function Prefs() {
|
||||||
indent_conditional: true,
|
indent_conditional: true,
|
||||||
},
|
},
|
||||||
'editor.lintDelay': 500, // lint gutter marker update delay, ms
|
'editor.lintDelay': 500, // lint gutter marker update delay, ms
|
||||||
'editor.linter': 'csslint', // Choose csslint or stylelint
|
'editor.linter': 'csslint', // 'csslint' or 'stylelint' or ''
|
||||||
'editor.lintReportDelay': 4500, // lint report update delay, ms
|
'editor.lintReportDelay': 4500, // lint report update delay, ms
|
||||||
'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected
|
'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected
|
||||||
// selection = only when something is selected
|
// selection = only when something is selected
|
||||||
|
|
114
vendor-overwrites/codemirror/addon/lint/css-lint.js
vendored
114
vendor-overwrites/codemirror/addon/lint/css-lint.js
vendored
|
@ -1,114 +0,0 @@
|
||||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
||||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
|
||||||
|
|
||||||
// Depends on csslint.js from https://github.com/stubbornella/csslint
|
|
||||||
|
|
||||||
/* global CodeMirror require define */
|
|
||||||
/* global CSSLint stylelint stylelintDefaultConfig csslintDefaultConfig */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
(mod => {
|
|
||||||
if (typeof exports === 'object' && typeof module === 'object') {
|
|
||||||
// CommonJS
|
|
||||||
mod(require('../../lib/codemirror'));
|
|
||||||
} else if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD
|
|
||||||
define(['../../lib/codemirror'], mod);
|
|
||||||
} else {
|
|
||||||
// Plain browser env
|
|
||||||
mod(CodeMirror);
|
|
||||||
}
|
|
||||||
})(CodeMirror => {
|
|
||||||
CodeMirror.registerHelper('lint', 'csslint', text => {
|
|
||||||
const found = [];
|
|
||||||
if (!window.CSSLint) {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
/* STYLUS: hack start (part 1) */
|
|
||||||
return BG.chromeSync.getValue('editorCSSLintConfig').then(config => {
|
|
||||||
// csslintDefaultConfig stored in csslint-config.js & loaded by edit/lint.js
|
|
||||||
if (Object.keys(config || []).length === 0) {
|
|
||||||
config = Object.assign({}, csslintDefaultConfig);
|
|
||||||
}
|
|
||||||
const results = CSSLint.verify(text, config);
|
|
||||||
const messages = results.messages;
|
|
||||||
const hslRegex = /hsla?\(\s*(-?\d+)%?\s*,\s*(-?\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%(\s*,\s*(-?\d+|-?\d*.\d+))?\s*\)/;
|
|
||||||
let message = null;
|
|
||||||
/* STYLUS: hack end */
|
|
||||||
|
|
||||||
for (let i = 0; i < messages.length; i++) {
|
|
||||||
message = messages[i];
|
|
||||||
|
|
||||||
/* STYLUS: hack start (part 2) */
|
|
||||||
if (message.type === 'warning') {
|
|
||||||
// @font-face {font-family: 'Ampersand'; unicode-range: U+26;}
|
|
||||||
if (message.message.indexOf('unicode-range') !== -1) {
|
|
||||||
continue;
|
|
||||||
} else if (
|
|
||||||
// color: hsl(210, 100%, 2.2%); or color: hsla(210, 100%, 2.2%, 0.3);
|
|
||||||
message.message.startsWith('Expected (<color>) but found \'hsl') &&
|
|
||||||
hslRegex.test(message.message)
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const startLine = message.line - 1;
|
|
||||||
const endLine = message.line - 1;
|
|
||||||
const startCol = message.col - 1;
|
|
||||||
const endCol = message.col;
|
|
||||||
/* STYLUS: hack end */
|
|
||||||
|
|
||||||
found.push({
|
|
||||||
from: CodeMirror.Pos(startLine, startCol),
|
|
||||||
to: CodeMirror.Pos(endLine, endCol),
|
|
||||||
message: message.message + ` (${message.rule.id})`,
|
|
||||||
severity : message.type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeMirror.registerHelper('lint', 'stylelint', text => {
|
|
||||||
const found = [];
|
|
||||||
window.stylelint = require('stylelint');
|
|
||||||
if (window.stylelint) {
|
|
||||||
return BG.chromeSync.getValue('editorStylelintConfig').then(rules => {
|
|
||||||
// stylelintDefaultConfig stored in stylelint-config.js & loaded by edit/lint.js
|
|
||||||
if (Object.keys(rules || []).length === 0) {
|
|
||||||
rules = stylelintDefaultConfig.rules;
|
|
||||||
}
|
|
||||||
return stylelint.lint({
|
|
||||||
code: text,
|
|
||||||
config: {
|
|
||||||
syntax: stylelintDefaultConfig.syntax,
|
|
||||||
rules: rules
|
|
||||||
}
|
|
||||||
}).then(output => {
|
|
||||||
const warnings = output.results.length ? output.results[0].warnings : [];
|
|
||||||
const len = warnings.length;
|
|
||||||
let warning;
|
|
||||||
let message;
|
|
||||||
if (len) {
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
warning = warnings[i];
|
|
||||||
message = warning.text
|
|
||||||
.replace('Unexpected ', '')
|
|
||||||
.replace(/^./, function (firstLetter) {
|
|
||||||
return firstLetter.toUpperCase();
|
|
||||||
});
|
|
||||||
found.push({
|
|
||||||
from: CodeMirror.Pos(warning.line - 1, warning.column - 1),
|
|
||||||
to: CodeMirror.Pos(warning.line - 1, warning.column),
|
|
||||||
message,
|
|
||||||
severity : warning.severity
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user