Commit 5b05d2b9 authored by Tim Zallmann's avatar Tim Zallmann Committed by Kushal Pandya

First iteration of GitLab own Stylelints

DRYed the code

Changed new rules to warnings

Manual prettified and added stylelint rules
parent b4de23a6
{ {
"plugins":[ "plugins":[
"stylelint-scss" "./scripts/frontend/stylelint/stylelint-duplicate-selectors.js",
"./scripts/frontend/stylelint/stylelint-utility-classes.js",
"stylelint-scss",
], ],
"rules":{ "rules":{
"at-rule-blacklist":[ "at-rule-blacklist":[
...@@ -95,13 +97,15 @@ ...@@ -95,13 +97,15 @@
}, },
], ],
"selector-list-comma-newline-after":"always", "selector-list-comma-newline-after":"always",
"selector-max-compound-selectors":[5, { "severity": "warning" }], "selector-max-compound-selectors":[3, { "severity": "warning" }],
"selector-max-id":1, "selector-max-id":1,
"selector-no-vendor-prefix":true, "selector-no-vendor-prefix":true,
"selector-pseudo-element-colon-notation":"double", "selector-pseudo-element-colon-notation":"double",
"selector-pseudo-element-no-unknown":true, "selector-pseudo-element-no-unknown":true,
"shorthand-property-no-redundant-values":true, "shorthand-property-no-redundant-values":true,
"string-quotes":"single", "string-quotes":"single",
"value-no-vendor-prefix":[true, { ignoreValues: ["sticky"] }] "value-no-vendor-prefix":[true, { ignoreValues: ["sticky"] }],
"stylelint-gitlab/duplicate-selectors":[true,{ "severity": "warning" }],
"stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }],
} }
} }
@import "framework/variables"; @import 'framework/variables';
img { img {
max-width: 100%; max-width: 100%;
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
"prettier-all": "node ./scripts/frontend/prettier.js check-all", "prettier-all": "node ./scripts/frontend/prettier.js check-all",
"prettier-all-save": "node ./scripts/frontend/prettier.js save-all", "prettier-all-save": "node ./scripts/frontend/prettier.js save-all",
"stylelint": "node node_modules/stylelint/bin/stylelint.js app/assets/stylesheets/**/*.* --custom-formatter node_modules/stylelint-error-string-formatter", "stylelint": "node node_modules/stylelint/bin/stylelint.js app/assets/stylesheets/**/*.* --custom-formatter node_modules/stylelint-error-string-formatter",
"stylelint-file": "node node_modules/stylelint/bin/stylelint.js",
"stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js",
"test": "yarn jest && yarn karma", "test": "yarn jest && yarn karma",
"webpack": "webpack --config config/webpack.config.js", "webpack": "webpack --config config/webpack.config.js",
"webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js" "webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js"
...@@ -169,13 +171,15 @@ ...@@ -169,13 +171,15 @@
"karma-mocha-reporter": "^2.2.5", "karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-beta.0", "karma-webpack": "^4.0.0-beta.0",
"md5": "^2.2.1",
"node-sass": "^4.11.0",
"nodemon": "^1.18.9", "nodemon": "^1.18.9",
"pixelmatch": "^4.0.2", "pixelmatch": "^4.0.2",
"postcss": "^7.0.14", "postcss": "^7.0.14",
"prettier": "1.16.4", "prettier": "1.16.4",
"stylelint": "^9.10.1", "stylelint": "^9.10.1",
"stylelint-config-recommended": "^2.1.0", "stylelint-config-recommended": "^2.1.0",
"stylelint-scss": "^3.5.3", "stylelint-scss": "^3.5.4",
"vue-jest": "^4.0.0-beta.2", "vue-jest": "^4.0.0-beta.2",
"webpack-dev-server": "^3.1.14", "webpack-dev-server": "^3.1.14",
"yarn-deduplicate": "^1.1.1" "yarn-deduplicate": "^1.1.1"
......
const stylelint = require('stylelint');
const utils = require('./stylelint-utils');
const ruleName = 'stylelint-gitlab/duplicate-selectors';
const messages = stylelint.utils.ruleMessages(ruleName, {
expected: (selector1, selector2) => {
return `"${selector1}" and "${selector2}" have the same properties.`;
},
});
module.exports = stylelint.createPlugin(ruleName, function(enabled) {
if (!enabled) {
return;
}
return function(root, result) {
const selectorGroups = {};
utils.createPropertiesHashmap(root, result, ruleName, messages, selectorGroups, true);
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;
const stylelint = require('stylelint');
const utils = require('./stylelint-utils');
const utilityClasses = require('./utility-classes-map.js');
const ruleName = 'stylelint-gitlab/utility-classes';
const messages = stylelint.utils.ruleMessages(ruleName, {
expected: (selector1, selector2) => {
return `"${selector1}" has the same properties as our BS4 utility class "${selector2}" so please use that instead.`;
},
});
module.exports = stylelint.createPlugin(ruleName, function(enabled) {
if (!enabled) {
return;
}
return function(root, result) {
utils.createPropertiesHashmap(root, result, ruleName, messages, utilityClasses, false);
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;
const sass = require('node-sass');
const postcss = require('postcss');
const fs = require('fs');
const path = require('path');
const prettier = require('prettier');
const utils = require('./stylelint-utils');
const ROOT_PATH = path.resolve(__dirname, '../../..');
const hashMapPath = path.resolve(__dirname, './utility-classes-map.js');
//
// This creates a JS based hash map (saved in utility-classes-map.js) of the different values in the utility classes
//
sass.render(
{
data: `
@import './functions';
@import './variables';
@import './mixins';
@import './utilities';
`,
includePaths: [path.resolve(ROOT_PATH, 'node_modules/bootstrap/scss')],
},
(err, result) => {
if (err) console.error('Error ', err);
const cssResult = result.css.toString();
// We just use postcss to create a CSS tree
postcss([])
.process(cssResult, {
// This supresses a postcss warning
from: undefined,
})
.then(result => {
const selectorGroups = {};
utils.createPropertiesHashmap(result.root, result, null, null, selectorGroups, true);
const prettierOptions = prettier.resolveConfig.sync(hashMapPath);
const prettyHashmap = prettier.format(
`module.exports = ${JSON.stringify(selectorGroups)};`,
prettierOptions,
);
fs.writeFile(hashMapPath, prettyHashmap, function(err) {
if (err) {
return console.log(err);
}
console.log('The file was saved!');
});
});
},
);
const stylelint = require('stylelint');
const md5 = require('md5');
module.exports.createPropertiesHashmap = (
ruleRoot,
result,
ruleName,
messages,
selectorGroups,
addSelectors,
) => {
ruleRoot.walkRules(rule => {
const selector = rule.selector.replace(/(?:\r\n|\r|\n)/g, ' ');
if (
rule &&
rule.parent &&
rule.parent.type != 'atrule' &&
!(
selector.includes('-webkit-') ||
selector.includes('-moz-') ||
selector.includes('-o-') ||
selector.includes('-ms-') ||
selector.includes(':')
)
) {
let cssArray = [];
rule.nodes.forEach(function(property) {
const { prop, value } = property;
if (property && value) {
const propval = `${prop}${value}${property.important ? '!important' : ''}`;
cssArray.push(propval);
}
});
cssArray = cssArray.sort();
const cssContent = cssArray.toString();
if (cssContent) {
const hashValue = md5(cssContent);
const selObj = selectorGroups[hashValue];
const selectorLine = `${selector} (${
rule.source.input.file ? rule.source.input.file + ' -' : ''
}${rule.source.start.line}:${rule.source.start.column})`;
if (selObj) {
if (selectorGroups[hashValue].selectors.indexOf(selector) == -1) {
let lastSelector =
selectorGroups[hashValue].selectors[selectorGroups[hashValue].selectors.length - 1];
// So we have nicer formatting if it is the same file, we remove the filename
lastSelector = lastSelector.replace(`${rule.source.input.file} - `, '');
if (messages) {
stylelint.utils.report({
result,
ruleName,
message: messages.expected(selector, lastSelector),
node: rule,
word: rule.node,
});
}
if (addSelectors) {
selectorGroups[hashValue].selectors.push(selectorLine);
}
}
} else if (addSelectors) {
selectorGroups[hashValue] = {
selectors: [selectorLine],
};
}
}
}
});
};
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment