Skip to content

Commit

Permalink
Refactors validator into a set of functions.
Browse files Browse the repository at this point in the history
Why:

* There's no need to keep it as an object, since configuration
  can also be passed in.
  • Loading branch information
jakubpawlowicz committed Jan 14, 2017
1 parent bb1e8ff commit d4825a7
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 121 deletions.
4 changes: 2 additions & 2 deletions lib/clean.js
Expand Up @@ -15,7 +15,7 @@ var optimizationLevelFrom = require('./options/optimization-level').optimization
var level0Optimize = require('./optimizer/level-0/optimize');
var level1Optimize = require('./optimizer/level-1/optimize');
var level2Optimize = require('./optimizer/level-2/optimize');
var Validator = require('./optimizer/level-2/compacting/validator');
var validator = require('./optimizer/validator');

var inputSourceMapTracker = require('./reader/input-source-map-tracker');
var readSources = require('./reader/read-sources');
Expand Down Expand Up @@ -89,7 +89,7 @@ CleanCSS.prototype.minify = function (input, callback) {
options: this.options,
source: null,
sourcesContent: {},
validator: new Validator(this.options.compatibility),
validator: validator(this.options.compatibility),
warnings: []
};

Expand Down
Expand Up @@ -30,159 +30,191 @@ var styleKeywords = ['auto', 'inherit', 'hidden', 'none', 'dotted', 'dashed', 's
var listStyleTypeKeywords = ['armenian', 'circle', 'cjk-ideographic', 'decimal', 'decimal-leading-zero', 'disc', 'georgian', 'hebrew', 'hiragana', 'hiragana-iroha', 'inherit', 'katakana', 'katakana-iroha', 'lower-alpha', 'lower-greek', 'lower-latin', 'lower-roman', 'none', 'square', 'upper-alpha', 'upper-latin', 'upper-roman'];
var listStylePositionKeywords = ['inside', 'outside', 'inherit'];

function Validator(compatibility) {
var validUnits = allUnits.slice(0).filter(function (value) {
return !(value in compatibility.units) || compatibility.units[value] === true;
});

var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)';
this.compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i');
this.compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i');

this.colorOpacity = compatibility.colors.opacity;
}

Validator.prototype.isValidHexColor = function (s) {
function isValidHexColor(s) {
return (s.length === 4 || s.length === 7) && s[0] === '#';
};
}

Validator.prototype.isValidRgbaColor = function (s) {
function isValidRgbaColor(s) {
s = s.split(' ').join('');
return s.length > 0 && s.indexOf('rgba(') === 0 && s.indexOf(')') === s.length - 1;
};
}

Validator.prototype.isValidHslaColor = function (s) {
function isValidHslaColor(s) {
s = s.split(' ').join('');
return s.length > 0 && s.indexOf('hsla(') === 0 && s.indexOf(')') === s.length - 1;
};
}

Validator.prototype.isValidNamedColor = function (s) {
function isValidNamedColor(s) {
// We don't really check if it's a valid color value, but allow any letters in it
return s !== 'auto' && (s === 'transparent' || s === 'inherit' || /^[a-zA-Z]+$/.test(s));
};
}

Validator.prototype.isValidVariable = function (s) {
function isValidVariable(s) {
return cssVariableRegex.test(s);
};

Validator.prototype.isValidColor = function (s) {
return this.isValidNamedColor(s) ||
this.isValidColorValue(s) ||
this.isValidVariable(s) ||
this.isValidVendorPrefixedValue(s);
};

Validator.prototype.isValidColorValue = function (s) {
return this.isValidHexColor(s) ||
this.isValidRgbaColor(s) ||
this.isValidHslaColor(s);
};

Validator.prototype.isValidUrl = function (s) {
}

function isValidColor(s) {
return isValidNamedColor(s) ||
isValidColorValue(s) ||
isValidVariable(s) ||
isValidVendorPrefixedValue(s);
}

function isValidColorValue(s) {
return isValidHexColor(s) ||
isValidRgbaColor(s) ||
isValidHslaColor(s);
}

function isValidUrl(s) {
return urlRegex.test(s);
};
}

Validator.prototype.isValidUnit = function (s) {
function isValidUnit(s) {
return cssUnitAnyRegex.test(s);
};
}

Validator.prototype.isValidUnitWithoutFunction = function (s) {
function isValidUnitWithoutFunction(s) {
return cssUnitRegex.test(s);
};
}

Validator.prototype.isValidAndCompatibleUnit = function (s) {
return this.compatibleCssUnitAnyRegex.test(s);
};
function isValidAndCompatibleUnit(compatibleCssUnitAnyRegex, s) {
return compatibleCssUnitAnyRegex.test(s);
}

Validator.prototype.isValidAndCompatibleUnitWithoutFunction = function (s) {
return this.compatibleCssUnitRegex.test(s);
};
function isValidAndCompatibleUnitWithoutFunction(compatibleCssUnitRegex, s) {
return compatibleCssUnitRegex.test(s);
}

Validator.prototype.isValidFunctionWithoutVendorPrefix = function (s) {
function isValidFunctionWithoutVendorPrefix(s) {
return !urlRegex.test(s) && cssFunctionNoVendorRegex.test(s);
};
}

Validator.prototype.isValidFunctionWithVendorPrefix = function (s) {
function isValidFunctionWithVendorPrefix(s) {
return !urlRegex.test(s) && cssFunctionVendorRegex.test(s);
};
}

Validator.prototype.isValidFunction = function (s) {
function isValidFunction(s) {
return !urlRegex.test(s) && cssFunctionAnyRegex.test(s);
};
}

Validator.prototype.isValidBackgroundRepeat = function (s) {
return backgroundRepeatKeywords.indexOf(s) >= 0 || this.isValidVariable(s);
};
function isValidBackgroundRepeat(s) {
return backgroundRepeatKeywords.indexOf(s) >= 0 || isValidVariable(s);
}

Validator.prototype.isValidBackgroundAttachment = function (s) {
return backgroundAttachmentKeywords.indexOf(s) >= 0 || this.isValidVariable(s);
};
function isValidBackgroundAttachment(s) {
return backgroundAttachmentKeywords.indexOf(s) >= 0 || isValidVariable(s);
}

Validator.prototype.isValidBackgroundBox = function (s) {
return backgroundBoxKeywords.indexOf(s) >= 0 || this.isValidVariable(s);
};
function isValidBackgroundBox(s) {
return backgroundBoxKeywords.indexOf(s) >= 0 || isValidVariable(s);
}

Validator.prototype.isValidBackgroundPositionPart = function (s) {
return backgroundPositionKeywords.indexOf(s) >= 0 || cssUnitOrCalcRegex.test(s) || this.isValidVariable(s);
};
function isValidBackgroundPositionPart(s) {
return backgroundPositionKeywords.indexOf(s) >= 0 || cssUnitOrCalcRegex.test(s) || isValidVariable(s);
}

Validator.prototype.isValidBackgroundPosition = function (s) {
function isValidBackgroundPosition(s) {
if (s === 'inherit')
return true;

var parts = s.split(' ');
for (var i = 0, l = parts.length; i < l; i++) {
if (parts[i] === '')
continue;
if (this.isValidBackgroundPositionPart(parts[i]) || this.isValidVariable(parts[i]))
if (isValidBackgroundPositionPart(parts[i]) || isValidVariable(parts[i]))
continue;

return false;
}

return true;
};
}

Validator.prototype.isValidBackgroundSizePart = function (s) {
return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || this.isValidVariable(s);
};
function isValidBackgroundSizePart(s) {
return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || isValidVariable(s);
}

Validator.prototype.isValidListStyleType = function (s) {
return listStyleTypeKeywords.indexOf(s) >= 0 || this.isValidVariable(s);
};
function isValidListStyleType(s) {
return listStyleTypeKeywords.indexOf(s) >= 0 || isValidVariable(s);
}

Validator.prototype.isValidListStylePosition = function (s) {
return listStylePositionKeywords.indexOf(s) >= 0 || this.isValidVariable(s);
};
function isValidListStylePosition(s) {
return listStylePositionKeywords.indexOf(s) >= 0 || isValidVariable(s);
}

Validator.prototype.isValidStyle = function (s) {
return this.isValidStyleKeyword(s) || this.isValidVariable(s);
};
function isValidStyle(s) {
return isValidStyleKeyword(s) || isValidVariable(s);
}

Validator.prototype.isValidStyleKeyword = function (s) {
function isValidStyleKeyword(s) {
return styleKeywords.indexOf(s) >= 0;
};
}

Validator.prototype.isValidWidth = function (s) {
return this.isValidUnit(s) || this.isValidWidthKeyword(s) || this.isValidVariable(s);
};
function isValidWidth(s) {
return isValidUnit(s) || isValidWidthKeyword(s) || isValidVariable(s);
}

Validator.prototype.isValidWidthKeyword = function (s) {
function isValidWidthKeyword(s) {
return widthKeywords.indexOf(s) >= 0;
};
}

Validator.prototype.isValidVendorPrefixedValue = function (s) {
function isValidVendorPrefixedValue(s) {
return /^-([A-Za-z0-9]|-)*$/gi.test(s);
};
}

Validator.prototype.areSameFunction = function (a, b) {
if (!this.isValidFunction(a) || !this.isValidFunction(b))
function areSameFunction(a, b) {
if (!isValidFunction(a) || !isValidFunction(b))
return false;

var f1name = a.substring(0, a.indexOf('('));
var f2name = b.substring(0, b.indexOf('('));

return f1name === f2name;
};
}

function validator(compatibility) {
var validUnits = allUnits.slice(0).filter(function (value) {
return !(value in compatibility.units) || compatibility.units[value] === true;
});

var compatibleCssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + validUnits.join('|') + '|)|auto|inherit)';
var compatibleCssUnitRegex = new RegExp('^' + compatibleCssUnitRegexStr + '$', 'i');
var compatibleCssUnitAnyRegex = new RegExp('^(none|' + widthKeywords.join('|') + '|' + compatibleCssUnitRegexStr + '|' + cssVariableRegexStr + '|' + cssFunctionNoVendorRegexStr + '|' + cssFunctionVendorRegexStr + ')$', 'i');
var colorOpacity = compatibility.colors.opacity;

return {
colorOpacity: colorOpacity,
isValidHexColor: isValidHexColor,
isValidRgbaColor: isValidRgbaColor,
isValidHslaColor: isValidHslaColor,
isValidNamedColor: isValidNamedColor,
isValidVariable: isValidVariable,
isValidColor: isValidColor,
isValidColorValue: isValidColorValue,
isValidUrl: isValidUrl,
isValidUnit: isValidUnit,
isValidUnitWithoutFunction: isValidUnitWithoutFunction,
isValidAndCompatibleUnit: isValidAndCompatibleUnit.bind(null, compatibleCssUnitAnyRegex),
isValidAndCompatibleUnitWithoutFunction: isValidAndCompatibleUnitWithoutFunction.bind(null, compatibleCssUnitRegex),
isValidFunctionWithoutVendorPrefix: isValidFunctionWithoutVendorPrefix,
isValidFunctionWithVendorPrefix: isValidFunctionWithVendorPrefix,
isValidFunction: isValidFunction,
isValidBackgroundRepeat: isValidBackgroundRepeat,
isValidBackgroundAttachment: isValidBackgroundAttachment,
isValidBackgroundBox: isValidBackgroundBox,
isValidBackgroundPositionPart: isValidBackgroundPositionPart,
isValidBackgroundPosition: isValidBackgroundPosition,
isValidBackgroundSizePart: isValidBackgroundSizePart,
isValidListStyleType: isValidListStyleType,
isValidListStylePosition: isValidListStylePosition,
isValidStyle: isValidStyle,
isValidStyleKeyword: isValidStyleKeyword,
isValidWidth: isValidWidth,
isValidWidthKeyword: isValidWidthKeyword,
isValidVendorPrefixedValue: isValidVendorPrefixedValue,
areSameFunction: areSameFunction
};
}

module.exports = Validator;
module.exports = validator;
5 changes: 2 additions & 3 deletions test/optimizer/level-2/break-up-test.js
Expand Up @@ -3,15 +3,14 @@ var vows = require('vows');

var wrapForOptimizing = require('../../../lib/optimizer/wrap-for-optimizing').all;
var populateComponents = require('../../../lib/optimizer/level-2/compacting/populate-components');
var Validator = require('../../../lib/optimizer/level-2/compacting/validator');
var validator = require('../../../lib/optimizer/validator');
var compatibility = require('../../../lib/utils/compatibility');

var breakUp = require('../../../lib/optimizer/level-2/break-up');

function _breakUp(properties) {
var validator = new Validator(compatibility());
var wrapped = wrapForOptimizing(properties);
populateComponents(wrapped, validator, []);
populateComponents(wrapped, validator(compatibility()), []);

return wrapped[0].components;
}
Expand Down
5 changes: 2 additions & 3 deletions test/optimizer/level-2/compacting/longhand-overriding-test.js
Expand Up @@ -6,7 +6,7 @@ var optimize = require('../../../../lib/optimizer/level-2/compacting/optimize');
var tokenize = require('../../../../lib/tokenizer/tokenize');
var inputSourceMapTracker = require('../../../../lib/reader/input-source-map-tracker');
var compatibility = require('../../../../lib/utils/compatibility');
var Validator = require('../../../../lib/optimizer/level-2/compacting/validator');
var validator = require('../../../../lib/optimizer/validator');

function _optimize(source) {
var tokens = tokenize(source, {
Expand All @@ -28,8 +28,7 @@ function _optimize(source) {
}
}
};
var validator = new Validator(compat);
optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator });
optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator(compat) });

return tokens[0][2];
}
Expand Down
5 changes: 2 additions & 3 deletions test/optimizer/level-2/compacting/optimize-test.js
Expand Up @@ -6,7 +6,7 @@ var optimize = require('../../../../lib/optimizer/level-2/compacting/optimize');
var tokenize = require('../../../../lib/tokenizer/tokenize');
var inputSourceMapTracker = require('../../../../lib/reader/input-source-map-tracker');
var compatibility = require('../../../../lib/utils/compatibility');
var Validator = require('../../../../lib/optimizer/level-2/compacting/validator');
var validator = require('../../../../lib/optimizer/validator');

function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOptions) {
var compat = compatibility(compatibilityOptions);
Expand All @@ -22,14 +22,13 @@ function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOption
}
}
};
var validator = new Validator(compat);
var tokens = tokenize(source, {
inputSourceMapTracker: inputSourceMapTracker(),
options: {},
warnings: []
});

optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { options: options, validator: validator });
optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { options: options, validator: validator(compat) });

return tokens[0][2];
}
Expand Down
5 changes: 2 additions & 3 deletions test/optimizer/level-2/compacting/override-compacting-test.js
Expand Up @@ -6,7 +6,7 @@ var optimize = require('../../../../lib/optimizer/level-2/compacting/optimize');
var tokenize = require('../../../../lib/tokenizer/tokenize');
var inputSourceMapTracker = require('../../../../lib/reader/input-source-map-tracker');
var compatibility = require('../../../../lib/utils/compatibility');
var Validator = require('../../../../lib/optimizer/level-2/compacting/validator');
var validator = require('../../../../lib/optimizer/validator');

function _optimize(source, compat, aggressiveMerging) {
var tokens = tokenize(source, {
Expand All @@ -16,7 +16,6 @@ function _optimize(source, compat, aggressiveMerging) {
});
compat = compatibility(compat);

var validator = new Validator(compat);
var options = {
aggressiveMerging: undefined === aggressiveMerging ? true : aggressiveMerging,
compatibility: compat,
Expand All @@ -26,7 +25,7 @@ function _optimize(source, compat, aggressiveMerging) {
}
}
};
optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator });
optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator(compat) });

return tokens[0][2];
}
Expand Down

0 comments on commit d4825a7

Please sign in to comment.