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/codemirror-default.js"></script>
|
||||||
|
|
||||||
<script src="edit/linter.js"></script>
|
<script src="edit/linter.js"></script>
|
||||||
<script src="edit/linter-csslint.js"></script>
|
<script src="edit/linter-defaults.js"></script>
|
||||||
<script src="edit/linter-stylelint.js"></script>
|
<script src="edit/linter-engines.js"></script>
|
||||||
<script src="edit/linter-meta.js"></script>
|
<script src="edit/linter-meta.js"></script>
|
||||||
<script src="edit/linter-help-dialog.js"></script>
|
<script src="edit/linter-help-dialog.js"></script>
|
||||||
<script src="edit/linter-report.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';
|
'use strict';
|
||||||
|
|
||||||
// eslint-disable-next-line no-var
|
// eslint-disable-next-line no-var
|
||||||
var stylelint = (() => {
|
var LINTER_DEFAULTS = (() => {
|
||||||
const DEFAULT_SEVERITY = {severity: 'warning'};
|
const SEVERITY = {severity: 'warning'};
|
||||||
const DEFAULT = {
|
const STYLELINT = {
|
||||||
// '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',
|
||||||
// ** recommended rules **
|
// ** recommended rules **
|
||||||
// ref: https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
|
// ref: https://github.com/stylelint/stylelint-config-recommended/blob/master/index.js
|
||||||
rules: {
|
rules: {
|
||||||
'at-rule-no-unknown': [true, DEFAULT_SEVERITY],
|
'at-rule-no-unknown': [true, SEVERITY],
|
||||||
'block-no-empty': [true, DEFAULT_SEVERITY],
|
'block-no-empty': [true, SEVERITY],
|
||||||
'color-no-invalid-hex': [true, DEFAULT_SEVERITY],
|
'color-no-invalid-hex': [true, SEVERITY],
|
||||||
'declaration-block-no-duplicate-properties': [true, {
|
'declaration-block-no-duplicate-properties': [true, {
|
||||||
'ignore': ['consecutive-duplicates-with-different-values'],
|
'ignore': ['consecutive-duplicates-with-different-values'],
|
||||||
'severity': 'warning'
|
'severity': 'warning'
|
||||||
}],
|
}],
|
||||||
'declaration-block-no-shorthand-property-overrides': [true, DEFAULT_SEVERITY],
|
'declaration-block-no-shorthand-property-overrides': [true, SEVERITY],
|
||||||
'font-family-no-duplicate-names': [true, DEFAULT_SEVERITY],
|
'font-family-no-duplicate-names': [true, SEVERITY],
|
||||||
'function-calc-no-unspaced-operator': [true, DEFAULT_SEVERITY],
|
'function-calc-no-unspaced-operator': [true, SEVERITY],
|
||||||
'function-linear-gradient-no-nonstandard-direction': [true, DEFAULT_SEVERITY],
|
'function-linear-gradient-no-nonstandard-direction': [true, SEVERITY],
|
||||||
'keyframe-declaration-no-important': [true, DEFAULT_SEVERITY],
|
'keyframe-declaration-no-important': [true, SEVERITY],
|
||||||
'media-feature-name-no-unknown': [true, DEFAULT_SEVERITY],
|
'media-feature-name-no-unknown': [true, SEVERITY],
|
||||||
/* recommended true */
|
/* recommended true */
|
||||||
'no-empty-source': false,
|
'no-empty-source': false,
|
||||||
'no-extra-semicolons': [true, DEFAULT_SEVERITY],
|
'no-extra-semicolons': [true, SEVERITY],
|
||||||
'no-invalid-double-slash-comments': [true, DEFAULT_SEVERITY],
|
'no-invalid-double-slash-comments': [true, SEVERITY],
|
||||||
'property-no-unknown': [true, DEFAULT_SEVERITY],
|
'property-no-unknown': [true, SEVERITY],
|
||||||
'selector-pseudo-class-no-unknown': [true, DEFAULT_SEVERITY],
|
'selector-pseudo-class-no-unknown': [true, SEVERITY],
|
||||||
'selector-pseudo-element-no-unknown': [true, DEFAULT_SEVERITY],
|
'selector-pseudo-element-no-unknown': [true, SEVERITY],
|
||||||
'selector-type-no-unknown': false, // for scss/less/stylus-lang
|
'selector-type-no-unknown': false, // for scss/less/stylus-lang
|
||||||
'string-no-newline': [true, DEFAULT_SEVERITY],
|
'string-no-newline': [true, SEVERITY],
|
||||||
'unit-no-unknown': [true, DEFAULT_SEVERITY],
|
'unit-no-unknown': [true, SEVERITY],
|
||||||
|
|
||||||
// ** non-essential rules
|
// ** non-essential rules
|
||||||
'comment-no-empty': false,
|
'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(() => {
|
// Default disabled
|
||||||
chrome.storage.onChanged.addListener((changes, area) => {
|
'adjoining-classes': 0,
|
||||||
if (area !== 'sync' || !changes.hasOwnProperty('editorStylelintConfig')) {
|
'box-model': 0,
|
||||||
return;
|
'box-sizing': 0,
|
||||||
}
|
'bulletproof-font-face': 0,
|
||||||
getNewValue().then(linter.run);
|
'compatible-vendor-prefixes': 0,
|
||||||
});
|
'duplicate-background-images': 0,
|
||||||
return getNewValue();
|
'fallback-colors': 0,
|
||||||
|
'floats': 0,
|
||||||
function getNewValue() {
|
'font-faces': 0,
|
||||||
return chromeSync.getLZValue('editorStylelintConfig')
|
'font-sizes': 0,
|
||||||
.then(newConfig => {
|
'gradients': 0,
|
||||||
const output = {};
|
'ids': 0,
|
||||||
output.rules = Object.assign({}, DEFAULT.rules, newConfig && newConfig.rules);
|
'import': 0,
|
||||||
output.syntax = 'sugarss';
|
'import-ie-limit': 0,
|
||||||
config = output;
|
'important': 0,
|
||||||
});
|
'order-alphabetical': 0,
|
||||||
}
|
'outline-none': 0,
|
||||||
});
|
'overqualified-elements': 0,
|
||||||
|
'qualified-headings': 0,
|
||||||
linter.register((text, options, cm) => {
|
'regex-selectors': 0,
|
||||||
if (
|
'rules-count': 0,
|
||||||
!prefs.get('editor.linter') ||
|
'selector-max': 0,
|
||||||
cm.getOption('mode') === 'css' && prefs.get('editor.linter') !== 'stylelint'
|
'selector-max-approaching': 0,
|
||||||
) {
|
'selector-newline': 0,
|
||||||
return;
|
'shorthand': 0,
|
||||||
}
|
'star-property-hack': 0,
|
||||||
return prepareConfig()
|
'text-indent': 0,
|
||||||
.then(() => editorWorker.stylelint(text, config))
|
'underscore-property-hack': 0,
|
||||||
.then(({results}) => {
|
'unique-headings': 0,
|
||||||
if (!results[0]) {
|
'universal-selector': 0,
|
||||||
return [];
|
'unqualified-attributes': 0,
|
||||||
}
|
'vendor-prefix': 0,
|
||||||
const output = results[0].warnings.map(({line, column: ch, text, severity}) =>
|
'zero-units': 0
|
||||||
({
|
};
|
||||||
from: {line: line - 1, ch: ch - 1},
|
return {STYLELINT, CSSLINT, SEVERITY};
|
||||||
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};
|
|
||||||
})();
|
})();
|
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