Refactor: replace linter modules with linter-defaults and linter-engines
This commit is contained in:
parent
2efc2d8dd2
commit
e68abad922
|
@ -89,8 +89,8 @@
|
|||
<script src="edit/codemirror-default.js"></script>
|
||||
|
||||
<script src="edit/linter.js"></script>
|
||||
<script src="edit/linter-csslint.js"></script>
|
||||
<script src="edit/linter-stylelint.js"></script>
|
||||
<script src="edit/linter-defaults.js"></script>
|
||||
<script src="edit/linter-engines.js"></script>
|
||||
<script src="edit/linter-meta.js"></script>
|
||||
<script src="edit/linter-help-dialog.js"></script>
|
||||
<script src="edit/linter-report.js"></script>
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/* global linter editorWorker memoize */
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var csslint = (() => {
|
||||
const DEFAULT = {
|
||||
// Default warnings
|
||||
'display-property-grouping': 1,
|
||||
'duplicate-properties': 1,
|
||||
'empty-rules': 1,
|
||||
'errors': 1,
|
||||
'warnings': 1,
|
||||
'known-properties': 1,
|
||||
|
||||
// Default disabled
|
||||
'adjoining-classes': 0,
|
||||
'box-model': 0,
|
||||
'box-sizing': 0,
|
||||
'bulletproof-font-face': 0,
|
||||
'compatible-vendor-prefixes': 0,
|
||||
'duplicate-background-images': 0,
|
||||
'fallback-colors': 0,
|
||||
'floats': 0,
|
||||
'font-faces': 0,
|
||||
'font-sizes': 0,
|
||||
'gradients': 0,
|
||||
'ids': 0,
|
||||
'import': 0,
|
||||
'import-ie-limit': 0,
|
||||
'important': 0,
|
||||
'order-alphabetical': 0,
|
||||
'outline-none': 0,
|
||||
'overqualified-elements': 0,
|
||||
'qualified-headings': 0,
|
||||
'regex-selectors': 0,
|
||||
'rules-count': 0,
|
||||
'selector-max': 0,
|
||||
'selector-max-approaching': 0,
|
||||
'selector-newline': 0,
|
||||
'shorthand': 0,
|
||||
'star-property-hack': 0,
|
||||
'text-indent': 0,
|
||||
'underscore-property-hack': 0,
|
||||
'unique-headings': 0,
|
||||
'universal-selector': 0,
|
||||
'unqualified-attributes': 0,
|
||||
'vendor-prefix': 0,
|
||||
'zero-units': 0
|
||||
};
|
||||
let config;
|
||||
|
||||
const prepareConfig = memoize(() => {
|
||||
chrome.storage.onChanged.addListener((changes, area) => {
|
||||
if (area !== 'sync' || !changes.hasOwnProperty('editorCSSLintConfig')) {
|
||||
return;
|
||||
}
|
||||
getNewValue().then(linter.refresh);
|
||||
});
|
||||
return getNewValue();
|
||||
|
||||
function getNewValue() {
|
||||
return chromeSync.getLZValue('editorCSSLintConfig')
|
||||
.then(newConfig => {
|
||||
config = Object.assign({}, DEFAULT, newConfig);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
linter.register((text, options, cm) => {
|
||||
if (prefs.get('editor.linter') !== 'csslint' || cm.getOption('mode') !== 'css') {
|
||||
return;
|
||||
}
|
||||
return prepareConfig()
|
||||
.then(() => editorWorker.csslint(text, config))
|
||||
.then(results =>
|
||||
results
|
||||
.map(({line, col: ch, message, rule, type: severity}) => line && {
|
||||
message,
|
||||
from: {line: line - 1, ch: ch - 1},
|
||||
to: {line: line - 1, ch},
|
||||
rule: rule.id,
|
||||
severity,
|
||||
})
|
||||
.filter(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
return {DEFAULT};
|
||||
})();
|
|
@ -1,39 +1,38 @@
|
|||
/* global linter editorWorker memoize */
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var stylelint = (() => {
|
||||
const DEFAULT_SEVERITY = {severity: 'warning'};
|
||||
const DEFAULT = {
|
||||
var LINTER_DEFAULTS = (() => {
|
||||
const SEVERITY = {severity: 'warning'};
|
||||
const STYLELINT = {
|
||||
// 'sugarss' is a indent-based syntax like Sass or Stylus
|
||||
// ref: https://github.com/postcss/postcss#syntaxes
|
||||
// syntax: 'sugarss',
|
||||
// ** recommended rules **
|
||||
// ref: https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
|
||||
rules: {
|
||||
'at-rule-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'block-no-empty': [true, DEFAULT_SEVERITY],
|
||||
'color-no-invalid-hex': [true, DEFAULT_SEVERITY],
|
||||
'at-rule-no-unknown': [true, SEVERITY],
|
||||
'block-no-empty': [true, SEVERITY],
|
||||
'color-no-invalid-hex': [true, SEVERITY],
|
||||
'declaration-block-no-duplicate-properties': [true, {
|
||||
'ignore': ['consecutive-duplicates-with-different-values'],
|
||||
'severity': 'warning'
|
||||
}],
|
||||
'declaration-block-no-shorthand-property-overrides': [true, DEFAULT_SEVERITY],
|
||||
'font-family-no-duplicate-names': [true, DEFAULT_SEVERITY],
|
||||
'function-calc-no-unspaced-operator': [true, DEFAULT_SEVERITY],
|
||||
'function-linear-gradient-no-nonstandard-direction': [true, DEFAULT_SEVERITY],
|
||||
'keyframe-declaration-no-important': [true, DEFAULT_SEVERITY],
|
||||
'media-feature-name-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'declaration-block-no-shorthand-property-overrides': [true, SEVERITY],
|
||||
'font-family-no-duplicate-names': [true, SEVERITY],
|
||||
'function-calc-no-unspaced-operator': [true, SEVERITY],
|
||||
'function-linear-gradient-no-nonstandard-direction': [true, SEVERITY],
|
||||
'keyframe-declaration-no-important': [true, SEVERITY],
|
||||
'media-feature-name-no-unknown': [true, SEVERITY],
|
||||
/* recommended true */
|
||||
'no-empty-source': false,
|
||||
'no-extra-semicolons': [true, DEFAULT_SEVERITY],
|
||||
'no-invalid-double-slash-comments': [true, DEFAULT_SEVERITY],
|
||||
'property-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'selector-pseudo-class-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'selector-pseudo-element-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'no-extra-semicolons': [true, SEVERITY],
|
||||
'no-invalid-double-slash-comments': [true, SEVERITY],
|
||||
'property-no-unknown': [true, SEVERITY],
|
||||
'selector-pseudo-class-no-unknown': [true, SEVERITY],
|
||||
'selector-pseudo-element-no-unknown': [true, SEVERITY],
|
||||
'selector-type-no-unknown': false, // for scss/less/stylus-lang
|
||||
'string-no-newline': [true, DEFAULT_SEVERITY],
|
||||
'unit-no-unknown': [true, DEFAULT_SEVERITY],
|
||||
'string-no-newline': [true, SEVERITY],
|
||||
'unit-no-unknown': [true, SEVERITY],
|
||||
|
||||
// ** non-essential rules
|
||||
'comment-no-empty': false,
|
||||
|
@ -172,59 +171,49 @@ var stylelint = (() => {
|
|||
*/
|
||||
}
|
||||
};
|
||||
let config;
|
||||
const CSSLINT = {
|
||||
// Default warnings
|
||||
'display-property-grouping': 1,
|
||||
'duplicate-properties': 1,
|
||||
'empty-rules': 1,
|
||||
'errors': 1,
|
||||
'warnings': 1,
|
||||
'known-properties': 1,
|
||||
|
||||
const prepareConfig = memoize(() => {
|
||||
chrome.storage.onChanged.addListener((changes, area) => {
|
||||
if (area !== 'sync' || !changes.hasOwnProperty('editorStylelintConfig')) {
|
||||
return;
|
||||
}
|
||||
getNewValue().then(linter.run);
|
||||
});
|
||||
return getNewValue();
|
||||
|
||||
function getNewValue() {
|
||||
return chromeSync.getLZValue('editorStylelintConfig')
|
||||
.then(newConfig => {
|
||||
const output = {};
|
||||
output.rules = Object.assign({}, DEFAULT.rules, newConfig && newConfig.rules);
|
||||
output.syntax = 'sugarss';
|
||||
config = output;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
linter.register((text, options, cm) => {
|
||||
if (
|
||||
!prefs.get('editor.linter') ||
|
||||
cm.getOption('mode') === 'css' && prefs.get('editor.linter') !== 'stylelint'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return prepareConfig()
|
||||
.then(() => editorWorker.stylelint(text, config))
|
||||
.then(({results}) => {
|
||||
if (!results[0]) {
|
||||
return [];
|
||||
}
|
||||
const output = results[0].warnings.map(({line, column: ch, text, severity}) =>
|
||||
({
|
||||
from: {line: line - 1, ch: ch - 1},
|
||||
to: {line: line - 1, ch},
|
||||
message: text
|
||||
.replace('Unexpected ', '')
|
||||
.replace(/^./, firstLetter => firstLetter.toUpperCase())
|
||||
.replace(/\s*\([^(]+\)$/, ''), // strip the rule,
|
||||
rule: text.replace(/^.*?\s*\(([^(]+)\)$/, '$1'),
|
||||
severity,
|
||||
})
|
||||
);
|
||||
return cm.doc.mode.name !== 'stylus' ?
|
||||
output :
|
||||
output.filter(({message}) =>
|
||||
!message.includes('"@css"') || !message.includes('(at-rule-no-unknown)'));
|
||||
});
|
||||
});
|
||||
|
||||
return {DEFAULT};
|
||||
// Default disabled
|
||||
'adjoining-classes': 0,
|
||||
'box-model': 0,
|
||||
'box-sizing': 0,
|
||||
'bulletproof-font-face': 0,
|
||||
'compatible-vendor-prefixes': 0,
|
||||
'duplicate-background-images': 0,
|
||||
'fallback-colors': 0,
|
||||
'floats': 0,
|
||||
'font-faces': 0,
|
||||
'font-sizes': 0,
|
||||
'gradients': 0,
|
||||
'ids': 0,
|
||||
'import': 0,
|
||||
'import-ie-limit': 0,
|
||||
'important': 0,
|
||||
'order-alphabetical': 0,
|
||||
'outline-none': 0,
|
||||
'overqualified-elements': 0,
|
||||
'qualified-headings': 0,
|
||||
'regex-selectors': 0,
|
||||
'rules-count': 0,
|
||||
'selector-max': 0,
|
||||
'selector-max-approaching': 0,
|
||||
'selector-newline': 0,
|
||||
'shorthand': 0,
|
||||
'star-property-hack': 0,
|
||||
'text-indent': 0,
|
||||
'underscore-property-hack': 0,
|
||||
'unique-headings': 0,
|
||||
'universal-selector': 0,
|
||||
'unqualified-attributes': 0,
|
||||
'vendor-prefix': 0,
|
||||
'zero-units': 0
|
||||
};
|
||||
return {STYLELINT, CSSLINT, SEVERITY};
|
||||
})();
|
105
edit/linter-engines.js
Normal file
105
edit/linter-engines.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* global LINTER_DEFAULTS linter editorWorker */
|
||||
'use strict';
|
||||
|
||||
(() => {
|
||||
registerLinters({
|
||||
csslint: {
|
||||
storageName: 'editorCSSLintConfig',
|
||||
lint: csslint,
|
||||
validMode: mode => mode === 'css',
|
||||
getConfig: config => Object.assign({}, LINTER_DEFAULTS.CSSLINT, config)
|
||||
},
|
||||
stylelint: {
|
||||
storageName: 'editorStylelintConfig',
|
||||
lint: stylelint,
|
||||
validMode: () => true,
|
||||
getConfig: config => ({
|
||||
syntax: 'sugarss',
|
||||
rules: Object.assign({}, LINTER_DEFAULTS.STYLELINT.rules, config && config.rules)
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
function stylelint(text, config, mode) {
|
||||
return editorWorker.stylelint(text, config)
|
||||
.then(({results}) => {
|
||||
if (!results[0]) {
|
||||
return [];
|
||||
}
|
||||
const output = results[0].warnings.map(({line, column: ch, text, severity}) =>
|
||||
({
|
||||
from: {line: line - 1, ch: ch - 1},
|
||||
to: {line: line - 1, ch},
|
||||
message: text
|
||||
.replace('Unexpected ', '')
|
||||
.replace(/^./, firstLetter => firstLetter.toUpperCase())
|
||||
.replace(/\s*\([^(]+\)$/, ''), // strip the rule,
|
||||
rule: text.replace(/^.*?\s*\(([^(]+)\)$/, '$1'),
|
||||
severity,
|
||||
})
|
||||
);
|
||||
return mode !== 'stylus' ?
|
||||
output :
|
||||
output.filter(({message}) =>
|
||||
!message.includes('"@css"') || !message.includes('(at-rule-no-unknown)'));
|
||||
});
|
||||
}
|
||||
|
||||
function csslint(text, config) {
|
||||
return editorWorker.csslint(text, config)
|
||||
.then(results =>
|
||||
results
|
||||
.map(({line, col: ch, message, rule, type: severity}) => line && {
|
||||
message,
|
||||
from: {line: line - 1, ch: ch - 1},
|
||||
to: {line: line - 1, ch},
|
||||
rule: rule.id,
|
||||
severity,
|
||||
})
|
||||
.filter(Boolean)
|
||||
);
|
||||
}
|
||||
|
||||
function registerLinters(engines) {
|
||||
const configs = new Map();
|
||||
|
||||
chrome.storage.onChanged.addListener((changes, area) => {
|
||||
if (area !== 'sync' || !changes.hasOwnProperty('editorStylelintConfig')) {
|
||||
return;
|
||||
}
|
||||
for (const [name, engine] of Object.entries(engines)) {
|
||||
if (changes.hasOwnProperty(engine.storageName)) {
|
||||
chromeSync.getLZValue(engine.storageName)
|
||||
.then(config => {
|
||||
configs.set(name, engine.getConfig(config));
|
||||
linter.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
linter.register((text, options, cm) => {
|
||||
const selectedLinter = prefs.get('editor.linter');
|
||||
if (!selectedLinter) {
|
||||
return;
|
||||
}
|
||||
const mode = cm.getOption('mode');
|
||||
for (const [name, engine] of Object.entries(engines)) {
|
||||
if (name === selectedLinter && engine.validMode(mode)) {
|
||||
return getConfig(name).then(config => engine.lint(text, config, mode));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function getConfig(name) {
|
||||
if (configs.has(name)) {
|
||||
return Promise.resolve(configs.get(name));
|
||||
}
|
||||
return chromeSync.getLZValue(engines[name].storageName)
|
||||
.then(config => {
|
||||
configs.set(name, engines[name].getConfig(config));
|
||||
return configs.get(name);
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
Loading…
Reference in New Issue
Block a user