mirror of https://github.com/thangisme/notes.git
122 lines
3.5 KiB
JavaScript
122 lines
3.5 KiB
JavaScript
var assign = require('object-assign');
|
|
var colorDiff = require('color-diff');
|
|
var formatter = require('./formatter');
|
|
var postcss = require('postcss');
|
|
var pipetteur = require('pipetteur');
|
|
var reporter = require('postcss-reporter');
|
|
|
|
function convertToLab (clr) {
|
|
clr = clr.rgb();
|
|
|
|
try {
|
|
return colorDiff.rgb_to_lab({
|
|
R: Math.round(clr.red() * 255),
|
|
G: Math.round(clr.green() * 255),
|
|
B: Math.round(clr.blue() * 255)
|
|
});
|
|
} catch (e) {
|
|
throw new Error('Error converting color ' + clr.hex() + ' to lab format.');
|
|
}
|
|
}
|
|
|
|
// returns correct column number of the color declaration
|
|
// pipetteur finds the position from the beginning of value declaration,
|
|
// we need line position instead
|
|
function getColumnPositionRelativeToLine (position) {
|
|
var decl = position.declaration;
|
|
return decl.source.start.column + position.column + decl.prop.length;
|
|
}
|
|
|
|
function getWhitelistHashKey (pair) {
|
|
pair = pair.sort();
|
|
return pair[0] + '-' + pair[1];
|
|
}
|
|
|
|
function getDiff (a, b) {
|
|
return Math.min(colorDiff.diff(convertToLab(a), convertToLab(b)), 100);
|
|
}
|
|
|
|
var stripUrl = /url\(['|"]?.*?['|"]?\)/;
|
|
|
|
var colorguard = postcss.plugin('css-colorguard', function (opts) {
|
|
opts = assign({
|
|
ignore: [],
|
|
threshold: 3
|
|
}, opts);
|
|
|
|
var whitelistHash = {};
|
|
if (opts.whitelist) {
|
|
opts.whitelist.forEach(function (pair) {
|
|
if (!Array.isArray(pair)) {
|
|
throw new Error('The whitelist option takes an array of array pairs. ' +
|
|
'You probably sent an array of strings.');
|
|
}
|
|
whitelistHash[getWhitelistHashKey(pair)] = true;
|
|
});
|
|
}
|
|
|
|
return function (css, result) {
|
|
var colors = {};
|
|
|
|
css.walkDecls(function (decl) {
|
|
var cleanValue = decl.value.replace(stripUrl, '');
|
|
var matches = pipetteur(cleanValue);
|
|
matches.forEach(function (match) {
|
|
// FIXME: This discards alpha channel
|
|
var name = match.color.hex();
|
|
// Just bail if we want to ignore the color
|
|
if (opts.ignore.indexOf(name) > -1) {
|
|
return;
|
|
}
|
|
|
|
match.declaration = decl;
|
|
|
|
if (!(name in colors)) {
|
|
colors[name] = colors[name] || [];
|
|
colors[name].push(match);
|
|
}
|
|
|
|
Object.keys(colors).forEach(function (color) {
|
|
var cached = colors[color];
|
|
if (cached[0] === match || cached[0].match === match.match) {
|
|
return;
|
|
}
|
|
var diffAmount = getDiff(cached[0].color, match.color);
|
|
|
|
// If colors are the same (no diff) but have a different representation
|
|
// (e.g. #000 and #000000 and black), do not complain
|
|
if (opts.allowEquivalentNotation && diffAmount === 0) {
|
|
return;
|
|
}
|
|
|
|
var whitelisted = getWhitelistHashKey([color, name]);
|
|
if (diffAmount < opts.threshold && !whitelistHash[whitelisted]) {
|
|
var message = (
|
|
match.match +
|
|
' collides with ' +
|
|
cached[0].match +
|
|
' (' +
|
|
cached[0].declaration.source.start.line +
|
|
':' +
|
|
getColumnPositionRelativeToLine(cached[0]) +
|
|
')'
|
|
);
|
|
decl.warn(result, message, {
|
|
secondColor: match.match,
|
|
firstColor: cached[0].match
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
};
|
|
});
|
|
|
|
colorguard.process = function (css, opts) {
|
|
opts = opts || {};
|
|
var processor = postcss([ colorguard(opts), reporter({formatter: formatter}) ]);
|
|
return processor.process(css, opts);
|
|
};
|
|
|
|
module.exports = colorguard;
|