use CSSLint in a web werkker
This commit is contained in:
parent
f3cf6e1856
commit
99512da9da
|
@ -40,6 +40,8 @@ body {
|
||||||
box-shadow: 0 0 3rem -1.2rem black;
|
box-shadow: 0 0 3rem -1.2rem black;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#header h1 {
|
#header h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
@ -468,9 +470,9 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
||||||
}
|
}
|
||||||
|
|
||||||
/************ lint ************/
|
/************ lint ************/
|
||||||
#lint > div {
|
#lint {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
overflow-x: hidden;}
|
||||||
#lint table {
|
#lint table {
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
|
@ -505,6 +507,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
||||||
}
|
}
|
||||||
#lint td[role="message"] {
|
#lint td[role="message"] {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#message-box.center.lint-config #message-box-contents {
|
#message-box.center.lint-config #message-box-contents {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
|
@ -1,38 +1,20 @@
|
||||||
/* global CodeMirror CSSLint parserlib stylelint linterConfig */
|
/* global CodeMirror CSSLint parserlib stylelint linterConfig */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
CodeMirror.registerHelper('lint', 'csslint', code => {
|
CodeMirror.registerHelper('lint', 'csslint', code => new Promise(resolve => {
|
||||||
if (!CSSLint.suppressUsoVarError) {
|
CSSLint.onmessage = ({data}) => {
|
||||||
CSSLint.suppressUsoVarError = true;
|
resolve(
|
||||||
parserlib.css.Tokens[parserlib.css.Tokens.COMMENT].hide = false;
|
data.map(({line, col, message, rule, type}) => line && {
|
||||||
const isUsoVar = ({value}) => value.startsWith('/*[[') && value.endsWith(']]*/');
|
message,
|
||||||
CSSLint.addRule({
|
from: {line: line - 1, ch: col - 1},
|
||||||
id: 'uso-vars',
|
to: {line: line - 1, ch: col},
|
||||||
init(parser, reporter) {
|
rule: rule.id,
|
||||||
parser.addListener('error', function ({message, line, col}) {
|
severity: type
|
||||||
if (!isUsoVar(this._tokenStream._token)) {
|
}).filter(Boolean));
|
||||||
const {_lt, _ltIndex: i} = this._tokenStream;
|
};
|
||||||
if (i < 2 || !_lt.slice(0, i - 1).reverse().some(isUsoVar)) {
|
const config = deepCopy(linterConfig.getCurrent('csslint'));
|
||||||
reporter.error(message, line, col);
|
CSSLint.postMessage({action: 'verify', code, config});
|
||||||
}
|
}));
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const rules = deepCopy(linterConfig.getCurrent('csslint'));
|
|
||||||
Object.defineProperty(rules, 'errors', {get: () => 0, set: () => 0});
|
|
||||||
rules['uso-vars'] = 1;
|
|
||||||
return CSSLint.verify(code, rules).messages
|
|
||||||
.map(({line, col, message, rule, type}) => line && {
|
|
||||||
message,
|
|
||||||
from: {line: line - 1, ch: col - 1},
|
|
||||||
to: {line: line - 1, ch: col},
|
|
||||||
rule: rule.id,
|
|
||||||
severity: type
|
|
||||||
})
|
|
||||||
.filter(Boolean);
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeMirror.registerHelper('lint', 'stylelint', code =>
|
CodeMirror.registerHelper('lint', 'stylelint', code =>
|
||||||
stylelint.lint({
|
stylelint.lint({
|
||||||
|
|
52
edit/lint.js
52
edit/lint.js
|
@ -38,6 +38,9 @@ var linterConfig = {
|
||||||
return CodeMirror.lint && CodeMirror.lint[linter] ? {
|
return CodeMirror.lint && CodeMirror.lint[linter] ? {
|
||||||
getAnnotations: CodeMirror.lint[linter],
|
getAnnotations: CodeMirror.lint[linter],
|
||||||
delay: prefs.get('editor.lintDelay'),
|
delay: prefs.get('editor.lintDelay'),
|
||||||
|
onUpdateLinting(annotationsNotSorted, annotations, cm) {
|
||||||
|
updateLintReport(cm, 0);
|
||||||
|
},
|
||||||
} : false;
|
} : false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -64,12 +67,18 @@ var linterConfig = {
|
||||||
|
|
||||||
findInvalidRules(config, linter = linterConfig.getDefault()) {
|
findInvalidRules(config, linter = linterConfig.getDefault()) {
|
||||||
const rules = linter === 'stylelint' ? config.rules : config;
|
const rules = linter === 'stylelint' ? config.rules : config;
|
||||||
const allRules = new Set(
|
return new Promise(resolve => {
|
||||||
linter === 'stylelint'
|
if (linter === 'stylelint') {
|
||||||
? Object.keys(stylelint.rules)
|
resolve(Object.keys(stylelint.rules));
|
||||||
: CSSLint.getRules().map(rule => rule.id)
|
} else {
|
||||||
);
|
CSSLint.onmessage = ({data}) =>
|
||||||
return Object.keys(rules).filter(rule => !allRules.has(rule));
|
resolve(data.map(rule => rule.id));
|
||||||
|
CSSLint.postMessage({action: 'getRules'});
|
||||||
|
}
|
||||||
|
}).then(allRules => {
|
||||||
|
allRules = new Set(allRules);
|
||||||
|
return Object.keys(rules).filter(rule => !allRules.has(rule));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
stringify(config = this.getCurrent()) {
|
stringify(config = this.getCurrent()) {
|
||||||
|
@ -140,7 +149,6 @@ 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);
|
$('#linter-settings').addEventListener('click', linterConfig.openOnClick);
|
||||||
window.addEventListener('resize', resizeLintReport);
|
|
||||||
|
|
||||||
updateLinter();
|
updateLinter();
|
||||||
linterConfig.watchStorage();
|
linterConfig.watchStorage();
|
||||||
|
@ -332,22 +340,6 @@ function renderLintReport(someBlockChanged) {
|
||||||
$('#issue-count').textContent = issueCount;
|
$('#issue-count').textContent = issueCount;
|
||||||
container.replaceChild(newContent, content);
|
container.replaceChild(newContent, content);
|
||||||
container.classList.toggle('hidden', !newContent.children.length);
|
container.classList.toggle('hidden', !newContent.children.length);
|
||||||
resizeLintReport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resizeLintReport() {
|
|
||||||
// subtracted value to prevent scrollbar
|
|
||||||
const magicBuffer = 20;
|
|
||||||
const content = $('#lint table');
|
|
||||||
if (content) {
|
|
||||||
const bounds = content.getBoundingClientRect();
|
|
||||||
const newMaxHeight = bounds.bottom <= window.innerHeight ? '' :
|
|
||||||
// subtract out a bit of padding or the vertical scrollbar extends beyond the viewport
|
|
||||||
(window.innerHeight - bounds.top - magicBuffer) + 'px';
|
|
||||||
if (newMaxHeight !== content.style.maxHeight) {
|
|
||||||
content.parentNode.style.maxHeight = newMaxHeight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +413,11 @@ function setupLinterSettingsEvents(popup) {
|
||||||
const linter = linterConfig.setLinter(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 = linterConfig.findInvalidRules(json, linter);
|
showLinterErrorMessage(linter, t('linterJSONError'));
|
||||||
|
popup.codebox.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
linterConfig.findInvalidRules(json, linter).then(invalid => {
|
||||||
if (invalid.length) {
|
if (invalid.length) {
|
||||||
showLinterErrorMessage(linter, [
|
showLinterErrorMessage(linter, [
|
||||||
t('linterInvalidConfigError'),
|
t('linterInvalidConfigError'),
|
||||||
|
@ -436,10 +432,8 @@ function setupLinterSettingsEvents(popup) {
|
||||||
linterConfig.save(json);
|
linterConfig.save(json);
|
||||||
linterConfig.showSavedMessage();
|
linterConfig.showSavedMessage();
|
||||||
popup.codebox.markClean();
|
popup.codebox.markClean();
|
||||||
} else {
|
popup.codebox.focus();
|
||||||
showLinterErrorMessage(linter, t('linterJSONError'));
|
});
|
||||||
}
|
|
||||||
popup.codebox.focus();
|
|
||||||
});
|
});
|
||||||
$('.reset', popup).addEventListener('click', event => {
|
$('.reset', popup).addEventListener('click', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -524,8 +518,8 @@ function loadLinterAssets(name = linterConfig.getDefault()) {
|
||||||
|
|
||||||
function loadLibrary() {
|
function loadLibrary() {
|
||||||
if (name === 'csslint' && !window.CSSLint) {
|
if (name === 'csslint' && !window.CSSLint) {
|
||||||
|
window.CSSLint = new Worker('/vendor-overwrites/csslint/csslint-worker.js');
|
||||||
return loadScript([
|
return loadScript([
|
||||||
'/vendor-overwrites/csslint/csslint-worker.js',
|
|
||||||
'/edit/lint-defaults-csslint.js'
|
'/edit/lint-defaults-csslint.js'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10931,31 +10931,40 @@ CSSLint.addFormatter({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
if (!CSSLint.suppressUsoVarError) {
|
||||||
* Web worker for CSSLint
|
CSSLint.suppressUsoVarError = true;
|
||||||
*/
|
parserlib.css.Tokens[parserlib.css.Tokens.COMMENT].hide = false;
|
||||||
|
const isUsoVar = ({value}) => value.startsWith('/*[[') && value.endsWith(']]*/');
|
||||||
|
CSSLint.addRule({
|
||||||
|
id: 'uso-vars',
|
||||||
|
init(parser, reporter) {
|
||||||
|
parser.addListener('error', function ({message, line, col}) {
|
||||||
|
if (!isUsoVar(this._tokenStream._token)) {
|
||||||
|
const {_lt, _ltIndex: i} = this._tokenStream;
|
||||||
|
if (i < 2 || !_lt.slice(0, i - 1).reverse().some(isUsoVar)) {
|
||||||
|
reporter.error(message, line, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* global self, JSON */
|
self.onmessage = ({data: {action, code, config}}) => {
|
||||||
|
switch (action) {
|
||||||
|
|
||||||
// message indicates to start linting
|
case 'getRules':
|
||||||
self.onmessage = function(event) {
|
self.postMessage(CSSLint.getRules());
|
||||||
"use strict";
|
return;
|
||||||
var data = event.data,
|
|
||||||
message,
|
|
||||||
text,
|
|
||||||
ruleset,
|
|
||||||
results;
|
|
||||||
|
|
||||||
try {
|
case 'verify':
|
||||||
message = JSON.parse(data);
|
Object.defineProperty(config, 'errors', {get: () => 0, set: () => 0});
|
||||||
text = message.text;
|
config['uso-vars'] = 1;
|
||||||
ruleset = message.ruleset;
|
self.postMessage(CSSLint.verify(code, config).messages.map(m => {
|
||||||
} catch (ex) {
|
// the functions are non-tranferable and we need only an id
|
||||||
text = data;
|
m.rule = {id: m.rule.id};
|
||||||
}
|
return m;
|
||||||
|
}));
|
||||||
results = CSSLint.verify(text, ruleset);
|
return;
|
||||||
|
}
|
||||||
// Not all browsers support structured clone, so JSON stringify results
|
|
||||||
self.postMessage(JSON.stringify(results));
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user