mirror of
https://github.com/kemko/liquid.git
synced 2026-01-12 21:15:45 +03:00
Fixing up Grunt file to watch for directories Exclude node modules folder from Jekyll built site
527 lines
11 KiB
JavaScript
527 lines
11 KiB
JavaScript
'use strict';
|
|
|
|
var csswring;
|
|
|
|
var list = require('postcss/lib/list');
|
|
var onecolor = require('onecolor');
|
|
var postcss = require('postcss');
|
|
var re = require('./regexp');
|
|
var shortColors = require('./color_keywords').short;
|
|
|
|
// Set quotation mark
|
|
var setQuote = function (quote) {
|
|
if (!quote) {
|
|
quote = '"';
|
|
}
|
|
|
|
return quote;
|
|
};
|
|
|
|
// Check string can unquote or not
|
|
var canUnquote = function (str) {
|
|
var firstChar = str.slice(0, 1);
|
|
var secondChar;
|
|
|
|
if (re.number.test(firstChar)) {
|
|
return false;
|
|
}
|
|
|
|
secondChar = str.slice(1, 2);
|
|
|
|
if (
|
|
firstChar === '-' &&
|
|
(secondChar === '-' || re.number.test(secondChar))
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
if (/^[\w-]+$/.test(str)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// Unquote font family name if possible
|
|
var unquoteFontFamily = function (family) {
|
|
var quote;
|
|
family = family.replace(re.quotedString, '$2');
|
|
quote = setQuote(RegExp.$1);
|
|
|
|
if (!list.space(family).every(canUnquote)) {
|
|
family = quote + family + quote;
|
|
}
|
|
|
|
return family;
|
|
};
|
|
|
|
// Convert colors to HEX or `rgba()` notation
|
|
var toRGBColor = function (m, leading, color) {
|
|
color = onecolor(color);
|
|
|
|
/* istanbul ignore if */
|
|
// Return unmodified value when `one.color` failed to parse `color`
|
|
if (!color) {
|
|
return m;
|
|
}
|
|
|
|
if (color.alpha() < 1) {
|
|
return leading + color.cssa();
|
|
}
|
|
|
|
return leading + color.hex() + ' ';
|
|
};
|
|
|
|
// Convert to shortest color
|
|
var toShortestColor = function (m, leading, r1, r2, g1, g2, b1, b2) {
|
|
var color = '#' + r1 + r2 + g1 + g2 + b1 + b2;
|
|
|
|
if (r1 === r2 && g1 === g2 && b1 === b2) {
|
|
color = '#' + r1 + g1 + b1;
|
|
}
|
|
|
|
if (shortColors.hasOwnProperty(color)) {
|
|
color = shortColors[color];
|
|
}
|
|
|
|
return leading + color.toLowerCase();
|
|
};
|
|
|
|
// Unquote inside `url()` notation if possible
|
|
var unquoteURL = function (m, leading, url) {
|
|
var quote;
|
|
url = url.replace(re.quotedString, '$2');
|
|
quote = setQuote(RegExp.$1);
|
|
|
|
if (re.urlNeedQuote.test(url)) {
|
|
url = quote + url + quote;
|
|
}
|
|
|
|
return leading + 'url(' + url + ')';
|
|
};
|
|
|
|
// Remove white spaces inside `calc()` notation
|
|
var removeCalcWhiteSpaces = function (m, leading, calc) {
|
|
calc = calc.replace(/\s([*/])\s/g, '$1');
|
|
|
|
return leading + 'calc(' + calc + ')';
|
|
};
|
|
|
|
// Wring value of declaration
|
|
var wringValue = function (value) {
|
|
value = value.replace(re.colorFunction, toRGBColor);
|
|
value = value.replace(re.colorHex, toShortestColor);
|
|
value = value.replace(re.colorTransparent, '$1transparent ');
|
|
value = value.trim();
|
|
value = value.replace(re.whiteSpaces, ' ');
|
|
value = value.replace(/([(,])\s/g, '$1');
|
|
value = value.replace(/\s([),])/g, '$1');
|
|
value = value.replace(re.numberLeadingZeros, '$1$2');
|
|
value = value.replace(re.zeroValueUnit, '$1$2');
|
|
value = value.replace(re.decimalWithZeros, '$1$2$3.$4');
|
|
value = value.replace(re.urlFunction, unquoteURL);
|
|
value = value.replace(re.calcFunction, removeCalcWhiteSpaces);
|
|
|
|
return value;
|
|
};
|
|
|
|
// Unquote attribute selector if possible
|
|
var unquoteAttributeSelector = function (m, att, con, val) {
|
|
var quote;
|
|
|
|
if (!con || !val) {
|
|
return '[' + att + ']';
|
|
}
|
|
|
|
val = val.trim();
|
|
val = val.replace(re.quotedString, '$2');
|
|
quote = setQuote(RegExp.$1);
|
|
|
|
if (!canUnquote(val)) {
|
|
val = quote + val + quote;
|
|
}
|
|
|
|
return '[' + att + con + val + ']';
|
|
};
|
|
|
|
// Remove white spaces from string
|
|
var removeWhiteSpaces = function (string) {
|
|
return string.replace(re.whiteSpaces, '');
|
|
};
|
|
|
|
// Remove white spaces from both ends of `:not()`
|
|
var trimNegationFunction = function (m, not) {
|
|
return ':not(' + not.trim() + ')';
|
|
};
|
|
|
|
// Wring selector of ruleset
|
|
var wringSelector = function (selector) {
|
|
selector = selector.replace(re.whiteSpaces, ' ');
|
|
selector = selector.replace(re.selectorAtt, unquoteAttributeSelector);
|
|
selector = selector.replace(re.selectorFunctions, removeWhiteSpaces);
|
|
selector = selector.replace(re.selectorNegationFunction, trimNegationFunction);
|
|
selector = selector.replace(re.selectorCombinators, '$1');
|
|
|
|
return selector;
|
|
};
|
|
|
|
// Check keyframe is valid or not
|
|
var isValidKeyframe = function (keyframe) {
|
|
if (keyframe === 'from' || keyframe === 'to') {
|
|
return true;
|
|
}
|
|
|
|
keyframe = parseFloat(keyframe);
|
|
|
|
if (!isNaN(keyframe) && keyframe >= 0 && keyframe <= 100) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// Unique array element
|
|
var uniqueArray = function (array) {
|
|
var i;
|
|
var l;
|
|
var result = [];
|
|
var value;
|
|
|
|
for (i = 0, l = array.length; i < l; i++) {
|
|
value = array[i];
|
|
|
|
if (result.indexOf(value) < 0) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
// Remove duplicate declaration
|
|
var removeDuplicateDeclaration = function (decl, index) {
|
|
var d = decl.before + decl.prop + decl.between + decl.value;
|
|
|
|
if (this.hasOwnProperty(d)) {
|
|
decl.parent.remove(this[d]);
|
|
}
|
|
|
|
this[d] = index;
|
|
};
|
|
|
|
// Check required `@font-face` descriptor or not
|
|
var isRequiredFontFaceDescriptor = function (decl) {
|
|
var prop = decl.prop;
|
|
|
|
return (prop === 'src') || (prop === 'font-family');
|
|
};
|
|
|
|
// Remove `@font-face` descriptor with default value
|
|
var removeDefaultFontFaceDescriptor = function (decl, index) {
|
|
var prop = decl.prop;
|
|
var value = decl.value;
|
|
|
|
if (
|
|
(re.descriptorFontFace.test(prop) && value === 'normal') ||
|
|
(prop === 'unicode-range' && re.unicodeRangeDefault.test(value)) ||
|
|
prop + value === 'font-weight400'
|
|
) {
|
|
decl.parent.remove(index);
|
|
}
|
|
};
|
|
|
|
// Quote `@import` URL
|
|
var quoteImportURL = function (m, quote, url) {
|
|
quote = setQuote(quote);
|
|
|
|
return quote + url + quote;
|
|
};
|
|
|
|
// Quote `@namespace` URL
|
|
var quoteNamespaceURL = function (param, index, p) {
|
|
var quote;
|
|
|
|
if (param === p[p.length - 1]) {
|
|
param = param.replace(re.quotedString, '$2');
|
|
quote = setQuote(RegExp.$1);
|
|
param = quote + param + quote;
|
|
}
|
|
|
|
return param;
|
|
};
|
|
|
|
// Wring comment
|
|
var wringComment = function (removeAllComments, comment) {
|
|
if (
|
|
(removeAllComments || comment.text.indexOf('!') !== 0) &&
|
|
comment.text.indexOf('#') !== 0
|
|
) {
|
|
comment.removeSelf();
|
|
|
|
return;
|
|
}
|
|
|
|
comment.before = '';
|
|
};
|
|
|
|
// Wring declaration
|
|
var wringDecl = function (preserveHacks, decl) {
|
|
var prop = decl.prop;
|
|
var value = decl.value;
|
|
var values;
|
|
delete decl._value;
|
|
|
|
if (preserveHacks && decl.before) {
|
|
decl.before = decl.before.replace(/[;\s]/g, '');
|
|
} else {
|
|
decl.before = '';
|
|
}
|
|
|
|
if (preserveHacks && decl.between) {
|
|
decl.between = decl.between.replace(re.whiteSpaces, '');
|
|
} else {
|
|
decl.between = ':';
|
|
}
|
|
|
|
if (decl.important) {
|
|
decl._important = '!important';
|
|
}
|
|
|
|
if (prop === 'content') {
|
|
return;
|
|
}
|
|
|
|
if (prop === 'font-family') {
|
|
decl.value = list.comma(value).map(unquoteFontFamily).join(',');
|
|
|
|
return;
|
|
}
|
|
|
|
values = list.comma(value);
|
|
value = values.map(wringValue).join(',');
|
|
|
|
if (re.propertyMultipleValues.test(prop)) {
|
|
values = list.space(value);
|
|
|
|
if (values.length === 4 && values[1] === values[3]) {
|
|
values.splice(3, 1);
|
|
}
|
|
|
|
if (values.length === 3 && values[0] === values[2]) {
|
|
values.splice(2, 1);
|
|
}
|
|
|
|
if (values.length === 2 && values[0] === values[1]) {
|
|
values.splice(1, 1);
|
|
}
|
|
|
|
value = values.join(' ');
|
|
}
|
|
|
|
if (prop === 'font-weight') {
|
|
if (value === 'normal') {
|
|
value = '400';
|
|
} else if (value === 'bold') {
|
|
value = '700';
|
|
}
|
|
}
|
|
|
|
decl.value = value;
|
|
};
|
|
|
|
// Wring declaration like string
|
|
var wringDeclLike = function (m, prop, value) {
|
|
var decl = postcss.decl({
|
|
prop: prop,
|
|
value: value
|
|
});
|
|
wringDecl.call(null, false, decl);
|
|
|
|
return '(' + decl.toString() + ')';
|
|
};
|
|
|
|
// Wring ruleset
|
|
var wringRule = function (rule) {
|
|
var decls;
|
|
var parent;
|
|
var selectors;
|
|
delete rule._selector;
|
|
rule.before = '';
|
|
rule.between = '';
|
|
rule.semicolon = false;
|
|
rule.after = '';
|
|
|
|
if (rule.nodes.length === 0 || rule.selector === '') {
|
|
rule.removeSelf();
|
|
|
|
return;
|
|
}
|
|
|
|
parent = rule.parent;
|
|
selectors = rule.selectors.map(wringSelector);
|
|
|
|
if (parent.type === 'atrule' && parent.name === 'keyframes') {
|
|
selectors = selectors.filter(isValidKeyframe);
|
|
|
|
if (selectors.length === 0) {
|
|
rule.removeSelf();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
rule.selector = uniqueArray(selectors).join(',');
|
|
decls = {};
|
|
rule.each(removeDuplicateDeclaration.bind(decls));
|
|
};
|
|
|
|
// Filter at-rule
|
|
var filterAtRule = function (rule) {
|
|
var name = rule.name;
|
|
var type = rule.type;
|
|
|
|
if (type === 'comment') {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
type !== 'atrule' ||
|
|
(name !== 'charset' && name !== 'import')
|
|
) {
|
|
this.filter = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (name === 'charset' && !this.charset) {
|
|
this.charset = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (this.filter || (name === 'charset' && this.charset)) {
|
|
rule.removeSelf();
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Wring at-rule
|
|
var wringAtRule = function (atRule) {
|
|
var params;
|
|
delete atRule._params;
|
|
atRule.before = '';
|
|
atRule.afterName = ' ';
|
|
atRule.between = '';
|
|
atRule.semicolon = false;
|
|
atRule.after = '';
|
|
|
|
if (!atRule.params) {
|
|
atRule.params = '';
|
|
}
|
|
|
|
if (atRule.name === 'charset') {
|
|
return;
|
|
}
|
|
|
|
if (atRule.name === 'font-face') {
|
|
if (atRule.nodes.filter(isRequiredFontFaceDescriptor).length < 2) {
|
|
atRule.removeSelf();
|
|
|
|
return;
|
|
}
|
|
|
|
atRule.each(removeDefaultFontFaceDescriptor);
|
|
}
|
|
|
|
if (atRule.nodes && atRule.nodes.length === 0) {
|
|
atRule.removeSelf();
|
|
|
|
return;
|
|
}
|
|
|
|
params = atRule.params;
|
|
params = params.replace(re.whiteSpaces, ' ');
|
|
params = params.replace(/([(),:])\s/g, '$1');
|
|
params = params.replace(/\s([),:])/g, '$1');
|
|
|
|
if (atRule.name === 'import') {
|
|
params = params.replace(re.urlFunction, '$1$2');
|
|
params = params.replace(re.quotedString, quoteImportURL);
|
|
}
|
|
|
|
if (atRule.name === 'namespace') {
|
|
params = params.replace(re.urlFunction, '$1$2');
|
|
params = list.space(params).map(quoteNamespaceURL).join('');
|
|
}
|
|
|
|
if (atRule.name === 'keyframes') {
|
|
params = params.replace(re.quotedString, '$2');
|
|
}
|
|
|
|
if (atRule.name === 'supports') {
|
|
params = params.replace(re.declInParentheses, wringDeclLike);
|
|
params = params.replace(re.supportsConjunctions, ') $1');
|
|
}
|
|
|
|
atRule.params = params;
|
|
|
|
if (
|
|
atRule.params === '' ||
|
|
params.indexOf('(') === 0 ||
|
|
params.indexOf('"') === 0 ||
|
|
params.indexOf('\'') === 0
|
|
) {
|
|
atRule.afterName = '';
|
|
}
|
|
};
|
|
|
|
// CSSWring object
|
|
var CSSWring = function (opts) {
|
|
var preserveHacks = false;
|
|
var removeAllComments = false;
|
|
|
|
if (opts && opts.preserveHacks) {
|
|
preserveHacks = opts.preserveHacks;
|
|
}
|
|
|
|
if (opts && opts.removeAllComments) {
|
|
removeAllComments = opts.removeAllComments;
|
|
}
|
|
|
|
this.postcss = this.postcss.bind(null, preserveHacks, removeAllComments);
|
|
};
|
|
|
|
CSSWring.prototype.postcss = function (preserveHacks, removeAllComments, css) {
|
|
css.semicolon = false;
|
|
css.after = '';
|
|
css.eachComment(wringComment.bind(null, removeAllComments));
|
|
css.eachDecl(wringDecl.bind(null, preserveHacks));
|
|
css.eachRule(wringRule);
|
|
css.each(filterAtRule.bind({}));
|
|
css.eachAtRule(wringAtRule);
|
|
|
|
return css;
|
|
};
|
|
|
|
CSSWring.prototype.wring = function (css, opts) {
|
|
return postcss().use(this.postcss).process(css, opts);
|
|
};
|
|
|
|
// CSSWring instance
|
|
csswring = function (opts) {
|
|
return new CSSWring(opts);
|
|
};
|
|
|
|
csswring.postcss = function (css) {
|
|
return csswring().postcss(css);
|
|
};
|
|
|
|
csswring.wring = function (css, opts) {
|
|
return csswring(opts).wring(css, opts);
|
|
};
|
|
|
|
module.exports = csswring;
|
|
|
|
/*eslint no-underscore-dangle:0*/
|