Dynamically load linter when selected

This commit is contained in:
Rob Garrison 2017-08-20 09:06:17 -05:00
parent b1a7f8d4a2
commit 29851a8de9
7 changed files with 71 additions and 101484 deletions

View File

@ -34,16 +34,6 @@
<script src="vendor/codemirror/addon/edit/matchbrackets.js"></script> <script src="vendor/codemirror/addon/edit/matchbrackets.js"></script>
<!-- CSSLint -->
<script src="vendor/csslint/csslint-worker.js"></script>
<!-- stylelint -->
<script src="vendor-overwrites/stylelint/stylelint-bundle.min.js"></script>
<script src="vendor-overwrites/codemirror/addon/lint/stylelint-config.js"></script>
<!-- linter -->
<link rel="stylesheet" href="vendor/codemirror/addon/lint/lint.css" />
<script src="vendor/codemirror/addon/lint/lint.js"></script>
<script src="vendor-overwrites/codemirror/addon/lint/css-lint.js"></script>
<link rel="stylesheet" href="vendor/codemirror/addon/hint/show-hint.css" /> <link rel="stylesheet" href="vendor/codemirror/addon/hint/show-hint.css" />
<script src="vendor/codemirror/addon/hint/show-hint.js"></script> <script src="vendor/codemirror/addon/hint/show-hint.js"></script>
<script src="vendor/codemirror/addon/hint/css-hint.js"></script> <script src="vendor/codemirror/addon/hint/css-hint.js"></script>
@ -196,12 +186,13 @@
<label id="linter-label" for="editor.linter" i18n-text="cm_linter"></label> <label id="linter-label" for="editor.linter" i18n-text="cm_linter"></label>
<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>
</select> </select>
<span class="linter-settings" i18n-title="stylelintConfig"> <span class="linter-settings" i18n-title="stylelintConfig">
<svg id="stylelint-settings" class="svg-icon settings"> <svg id="stylelint-settings" class="svg-icon settings">
<use xlink:href="#svg-icon-settings"/> <use xlink:href="#svg-icon-settings"/>
</svg> </svg>&nbsp;
</span> </span>
</section> </section>
<section id="lint"><h2 i18n-text="issues">: <span id="issue-count"></span><svg id="lint-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2><div></div></section> <section id="lint"><h2 i18n-text="issues">: <span id="issue-count"></span><svg id="lint-help" class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg></h2><div></div></section>

View File

@ -154,6 +154,9 @@ function setCleanSection(section) {
function initCodeMirror() { 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
const hasLinter = typeof getLinterConfigForCodeMirror !== 'undefined' ?
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')) {
@ -170,7 +173,7 @@ function initCodeMirror() {
matchBrackets: true, matchBrackets: true,
highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true}, highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true},
hintOptions: {}, hintOptions: {},
lint: getLinterConfigForCodeMirror(prefs.get('editor.linter')), lint: hasLinter,
lintReportDelay: prefs.get('editor.lintReportDelay'), lintReportDelay: prefs.get('editor.lintReportDelay'),
styleActiveLine: true, styleActiveLine: true,
theme: 'default', theme: 'default',
@ -352,9 +355,7 @@ function acmeEventListener(event) {
} }
break; break;
case 'linter': case 'linter':
if (value !== null && editors.length) {
updateLinter(value); updateLinter(value);
}
break; break;
} }
CodeMirror.setOption(option, value); CodeMirror.setOption(option, value);
@ -427,7 +428,7 @@ function indicateCodeChange(cm) {
const section = cm.getSection(); const section = cm.getSection();
setCleanItem(section, cm.isClean(section.savedValue)); setCleanItem(section, cm.isClean(section.savedValue));
updateTitle(); updateTitle();
updateLintReport(cm); updateLintReportIfEnabled(cm);
} }
function getSectionForChild(e) { function getSectionForChild(e) {
@ -554,7 +555,7 @@ window.onbeforeunload = () => {
if (isCleanGlobal()) { if (isCleanGlobal()) {
return; return;
} }
updateLintReport(null, 0); updateLintReportIfEnabled(null, 0);
return confirm(t('styleChangesNotSaved')); return confirm(t('styleChangesNotSaved'));
}; };
@ -1223,6 +1224,7 @@ function initWithStyle({style, codeIsUpdated}) {
const sectionDiv = addSection(null, queue.shift()); const sectionDiv = addSection(null, queue.shift());
maximizeCodeHeight(sectionDiv, !queue.length); maximizeCodeHeight(sectionDiv, !queue.length);
const cm = sectionDiv.CodeMirror; const cm = sectionDiv.CodeMirror;
if (CodeMirror.lint) {
setTimeout(() => { setTimeout(() => {
cm.setOption('lint', CodeMirror.defaults.lint); cm.setOption('lint', CodeMirror.defaults.lint);
// update lint issue table after a short delay // update lint issue table after a short delay
@ -1230,6 +1232,7 @@ function initWithStyle({style, codeIsUpdated}) {
}, prefs.get('editor.lintDelay')); }, prefs.get('editor.lintDelay'));
} }
} }
}
function initHooks() { function initHooks() {
document.querySelectorAll('#header .style-contributor').forEach(node => { document.querySelectorAll('#header .style-contributor').forEach(node => {
@ -1365,8 +1368,14 @@ function validate() {
return null; return null;
} }
function updateLintReportIfEnabled(cm, time) {
if (CodeMirror.lint) {
updateLintReport(cm, time);
}
}
function save() { function save() {
updateLintReport(null, 0); updateLintReportIfEnabled(null, 0);
// save the contents of the CodeMirror editors back into the textareas // save the contents of the CodeMirror editors back into the textareas
for (let i = 0; i < editors.length; i++) { for (let i = 0; i < editors.length; i++) {

View File

@ -1,5 +1,5 @@
/* global CodeMirror CSSLint editors makeSectionVisible showHelp showCodeMirrorPopup */ /* global CodeMirror CSSLint editors makeSectionVisible showHelp showCodeMirrorPopup */
/* global stylelintDefaultConfig onDOMscripted */ /* global stylelintDefaultConfig onDOMscripted injectCSS require */
'use strict'; 'use strict';
function initLint() { function initLint() {
@ -23,19 +23,29 @@ function setStylelintRules(rules = {}) {
} }
function getLinterConfigForCodeMirror(name) { function getLinterConfigForCodeMirror(name) {
return { return CodeMirror.lint && CodeMirror.lint[name] ? {
getAnnotations: CodeMirror.lint[name], getAnnotations: CodeMirror.lint[name],
delay: prefs.get('editor.lintDelay') delay: prefs.get('editor.lintDelay')
}; } : false;
} }
function updateLinter(name = 'csslint') { function updateLinter(name) {
function updateEditors() {
const options = getLinterConfigForCodeMirror(name);
CodeMirror.defaults.lint = options === 'null' ? false : options;
editors.forEach(cm => {
// set lint to "null" to disable
cm.setOption('lint', options);
cm.refresh(); // enabling/disabling linting changes the gutter width
updateLintReport(cm, 200);
});
}
if (prefs.get('editor.linter') !== name) { if (prefs.get('editor.linter') !== name) {
prefs.set('editor.linter', name); prefs.set('editor.linter', name);
} }
editors.forEach(cm => { // load scripts
cm.setOption('lint', getLinterConfigForCodeMirror(name)); loadSelectedLinter(name).then(() => {
updateLintReport(cm, 200); updateEditors();
}); });
$('#stylelint-settings').style.display = name === 'stylelint' ? $('#stylelint-settings').style.display = name === 'stylelint' ?
'inline-block' : 'none'; 'inline-block' : 'none';
@ -228,7 +238,7 @@ function setupStylelintSettingsEvents(popup) {
}, 3000); }, 3000);
} }
}); });
popup.querySelector('reset').addEventListener('click', event => { popup.querySelector('.reset').addEventListener('click', event => {
event.preventDefault(); event.preventDefault();
setStylelintRules(); setStylelintRules();
popup.codebox.setValue(JSON.stringify({rules: stylelintDefaultConfig.rules}, null, 2)); popup.codebox.setValue(JSON.stringify({rules: stylelintDefaultConfig.rules}, null, 2));
@ -254,6 +264,7 @@ function setupStylelintPopup(rules) {
} }
function setJSONMode(cm) { function setJSONMode(cm) {
cm.setOption('mode', 'application/json'); cm.setOption('mode', 'application/json');
cm.setOption('lint', 'json');
} }
const popup = showCodeMirrorPopup(t('setStylelintRules'), $element({ const popup = showCodeMirrorPopup(t('setStylelintRules'), $element({
className: 'contents', className: 'contents',
@ -278,18 +289,32 @@ function setupStylelintPopup(rules) {
] ]
})); }));
const contents = popup.querySelector('.contents'); const contents = popup.querySelector('.contents');
const loadJSON = window.jsonlint ? [] : ['vendor/codemirror/addon/lint/json-lint.js'];
contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild); contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild);
popup.codebox.focus(); popup.codebox.focus();
popup.codebox.setValue(rules); popup.codebox.setValue(rules);
if (!$('script[src*="json-lint.js"]')) { onDOMscripted(loadJSON, () => { setJSONMode(popup.codebox); });
onDOMscripted(
['vendor/codemirror/addon/lint/json-lint.js'],
() => {
setJSONMode(popup.codebox);
}
);
} else {
setJSONMode(popup.codebox);
}
setupStylelintSettingsEvents(popup); setupStylelintSettingsEvents(popup);
} }
function loadSelectedLinter(name) {
let scripts = [];
if (name !== 'null' && !$('script[src*="css-lint.js"]')) {
// inject css
injectCSS('vendor/codemirror/addon/lint/lint.css');
// load CodeMirror lint code
scripts = scripts.concat([
'vendor/codemirror/addon/lint/lint.js',
'vendor-overwrites/codemirror/addon/lint/css-lint.js'
]);
}
if (name === 'csslint' && !window.CSSLint) {
scripts.push('vendor/csslint/csslint-worker.js');
} else if (name === 'stylelint' && !window.stylelint) {
scripts = scripts.concat([
'vendor-overwrites/stylelint/stylelint-bundle.min.js',
'vendor-overwrites/codemirror/addon/lint/stylelint-config.js'
]);
}
return onDOMscripted(scripts);
}

View File

@ -64,8 +64,8 @@ CodeMirror.registerHelper("lint", "csslint", function(text) {
CodeMirror.registerHelper("lint", "stylelint", function(text) { CodeMirror.registerHelper("lint", "stylelint", function(text) {
let found = []; let found = [];
const stylelint = require('stylelint').lint; window.stylelint = require('stylelint').lint;
if (stylelint) { if (window.stylelint) {
return BG.chromeLocal.getValue('editorStylelintRules').then((rules = stylelintDefaultConfig.rules) => { return BG.chromeLocal.getValue('editorStylelintRules').then((rules = stylelintDefaultConfig.rules) => {
// stylelintDefaultConfig stored in stylelint-config.js & loaded by edit.html // stylelintDefaultConfig stored in stylelint-config.js & loaded by edit.html
if (Object.keys(rules).length === 0) { if (Object.keys(rules).length === 0) {

View File

@ -1,4 +1,4 @@
const stylelintDefaultConfig = (defaultSeverity => ({ window.stylelintDefaultConfig = (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',

File diff suppressed because one or more lines are too long

View File

@ -21,3 +21,4 @@ Stylelint bundle file created by:
This prevents a js error when stylelint attempts to access a local file. The This prevents a js error when stylelint attempts to access a local file. The
other `fs.readFile` entries are not accessed because we're using stylelint's other `fs.readFile` entries are not accessed because we're using stylelint's
standalone method. standalone method.
5. The script was then "minified" by manually running it through Google's [Closure Compiler](http://closure-compiler.appspot.com/home) set to "Whitespace only".