blob: 7140bed7fde683c5672d132a8d5ba75aa3c4d46e [file] [log] [blame]
var functionNoVendorRegexStr = '[A-Z]+(\\-|[A-Z]|[0-9])+\\(.*?\\)';
var functionVendorRegexStr = '\\-(\\-|[A-Z]|[0-9])+\\(.*?\\)';
var variableRegexStr = 'var\\(\\-\\-[^\\)]+\\)';
var functionAnyRegexStr = '(' + variableRegexStr + '|' + functionNoVendorRegexStr + '|' + functionVendorRegexStr + ')';
var calcRegex = new RegExp('^(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)$', 'i');
var decimalRegex = /[0-9]/;
var functionAnyRegex = new RegExp('^' + functionAnyRegexStr + '$', 'i');
var hslColorRegex = /^hsl\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31}\)|hsla\(\s{0,31}[\-\.]?\d+\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+%\s{0,31},\s{0,31}\.?\d+\s{0,31}\)$/i;
var identifierRegex = /^(\-[a-z0-9_][a-z0-9\-_]*|[a-z][a-z0-9\-_]*)$/i;
var namedEntityRegex = /^[a-z]+$/i;
var prefixRegex = /^-([a-z0-9]|-)*$/i;
var rgbColorRegex = /^rgb\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31}\)|rgba\(\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\d]{1,3}\s{0,31},\s{0,31}[\.\d]+\s{0,31}\)$/i;
var timingFunctionRegex = /^(cubic\-bezier|steps)\([^\)]+\)$/;
var validTimeUnits = ['ms', 's'];
var urlRegex = /^url\([\s\S]+\)$/i;
var variableRegex = new RegExp('^' + variableRegexStr + '$', 'i');
var eightValueColorRegex = /^#[0-9a-f]{8}$/i;
var fourValueColorRegex = /^#[0-9a-f]{4}$/i;
var sixValueColorRegex = /^#[0-9a-f]{6}$/i;
var threeValueColorRegex = /^#[0-9a-f]{3}$/i;
var DECIMAL_DOT = '.';
var MINUS_SIGN = '-';
var PLUS_SIGN = '+';
var Keywords = {
'^': [
'inherit',
'initial',
'unset'
],
'*-style': [
'auto',
'dashed',
'dotted',
'double',
'groove',
'hidden',
'inset',
'none',
'outset',
'ridge',
'solid'
],
'*-timing-function': [
'ease',
'ease-in',
'ease-in-out',
'ease-out',
'linear',
'step-end',
'step-start'
],
'animation-direction': [
'alternate',
'alternate-reverse',
'normal',
'reverse'
],
'animation-fill-mode': [
'backwards',
'both',
'forwards',
'none'
],
'animation-iteration-count': [
'infinite'
],
'animation-name': [
'none'
],
'animation-play-state': [
'paused',
'running'
],
'background-attachment': [
'fixed',
'inherit',
'local',
'scroll'
],
'background-clip': [
'border-box',
'content-box',
'inherit',
'padding-box',
'text'
],
'background-origin': [
'border-box',
'content-box',
'inherit',
'padding-box'
],
'background-position': [
'bottom',
'center',
'left',
'right',
'top'
],
'background-repeat': [
'no-repeat',
'inherit',
'repeat',
'repeat-x',
'repeat-y',
'round',
'space'
],
'background-size': [
'auto',
'cover',
'contain'
],
'border-collapse': [
'collapse',
'inherit',
'separate'
],
'bottom': [
'auto'
],
'clear': [
'both',
'left',
'none',
'right'
],
'color': [
'transparent'
],
'cursor': [
'all-scroll',
'auto',
'col-resize',
'crosshair',
'default',
'e-resize',
'help',
'move',
'n-resize',
'ne-resize',
'no-drop',
'not-allowed',
'nw-resize',
'pointer',
'progress',
'row-resize',
's-resize',
'se-resize',
'sw-resize',
'text',
'vertical-text',
'w-resize',
'wait'
],
'display': [
'block',
'inline',
'inline-block',
'inline-table',
'list-item',
'none',
'table',
'table-caption',
'table-cell',
'table-column',
'table-column-group',
'table-footer-group',
'table-header-group',
'table-row',
'table-row-group'
],
'float': [
'left',
'none',
'right'
],
'left': [
'auto'
],
'font': [
'caption',
'icon',
'menu',
'message-box',
'small-caption',
'status-bar',
'unset'
],
'font-size': [
'large',
'larger',
'medium',
'small',
'smaller',
'x-large',
'x-small',
'xx-large',
'xx-small'
],
'font-stretch': [
'condensed',
'expanded',
'extra-condensed',
'extra-expanded',
'normal',
'semi-condensed',
'semi-expanded',
'ultra-condensed',
'ultra-expanded'
],
'font-style': [
'italic',
'normal',
'oblique'
],
'font-variant': [
'normal',
'small-caps'
],
'font-weight': [
'100',
'200',
'300',
'400',
'500',
'600',
'700',
'800',
'900',
'bold',
'bolder',
'lighter',
'normal'
],
'line-height': [
'normal'
],
'list-style-position': [
'inside',
'outside'
],
'list-style-type': [
'armenian',
'circle',
'decimal',
'decimal-leading-zero',
'disc',
'decimal|disc', // this is the default value of list-style-type, see comment in compactable.js
'georgian',
'lower-alpha',
'lower-greek',
'lower-latin',
'lower-roman',
'none',
'square',
'upper-alpha',
'upper-latin',
'upper-roman'
],
'overflow': [
'auto',
'hidden',
'scroll',
'visible'
],
'position': [
'absolute',
'fixed',
'relative',
'static'
],
'right': [
'auto'
],
'text-align': [
'center',
'justify',
'left',
'left|right', // this is the default value of list-style-type, see comment in compactable.js
'right'
],
'text-decoration': [
'line-through',
'none',
'overline',
'underline'
],
'text-overflow': [
'clip',
'ellipsis'
],
'top': [
'auto'
],
'vertical-align': [
'baseline',
'bottom',
'middle',
'sub',
'super',
'text-bottom',
'text-top',
'top'
],
'visibility': [
'collapse',
'hidden',
'visible'
],
'white-space': [
'normal',
'nowrap',
'pre'
],
'width': [
'inherit',
'initial',
'medium',
'thick',
'thin'
]
};
var Units = [
'%',
'ch',
'cm',
'em',
'ex',
'in',
'mm',
'pc',
'pt',
'px',
'rem',
'vh',
'vm',
'vmax',
'vmin',
'vw'
];
function isColor(value) {
return value != 'auto' &&
(
isKeyword('color')(value) ||
isHexColor(value) ||
isColorFunction(value) ||
isNamedEntity(value)
);
}
function isColorFunction(value) {
return isRgbColor(value) || isHslColor(value);
}
function isDynamicUnit(value) {
return calcRegex.test(value);
}
function isFunction(value) {
return functionAnyRegex.test(value);
}
function isHexColor(value) {
return threeValueColorRegex.test(value) || fourValueColorRegex.test(value) || sixValueColorRegex.test(value) || eightValueColorRegex.test(value);
}
function isHslColor(value) {
return hslColorRegex.test(value);
}
function isIdentifier(value) {
return identifierRegex.test(value);
}
function isImage(value) {
return value == 'none' || value == 'inherit' || isUrl(value);
}
function isKeyword(propertyName) {
return function(value) {
return Keywords[propertyName].indexOf(value) > -1;
};
}
function isNamedEntity(value) {
return namedEntityRegex.test(value);
}
function isNumber(value) {
return scanForNumber(value) == value.length;
}
function isRgbColor(value) {
return rgbColorRegex.test(value);
}
function isPrefixed(value) {
return prefixRegex.test(value);
}
function isPositiveNumber(value) {
return isNumber(value) &&
parseFloat(value) >= 0;
}
function isVariable(value) {
return variableRegex.test(value);
}
function isTime(value) {
var numberUpTo = scanForNumber(value);
return numberUpTo == value.length && parseInt(value) === 0 ||
numberUpTo > -1 && validTimeUnits.indexOf(value.slice(numberUpTo + 1)) > -1;
}
function isTimingFunction() {
var isTimingFunctionKeyword = isKeyword('*-timing-function');
return function (value) {
return isTimingFunctionKeyword(value) || timingFunctionRegex.test(value);
};
}
function isUnit(validUnits, value) {
var numberUpTo = scanForNumber(value);
return numberUpTo == value.length && parseInt(value) === 0 ||
numberUpTo > -1 && validUnits.indexOf(value.slice(numberUpTo + 1)) > -1 ||
value == 'auto' ||
value == 'inherit';
}
function isUrl(value) {
return urlRegex.test(value);
}
function isZIndex(value) {
return value == 'auto' ||
isNumber(value) ||
isKeyword('^')(value);
}
function scanForNumber(value) {
var hasDot = false;
var hasSign = false;
var character;
var i, l;
for (i = 0, l = value.length; i < l; i++) {
character = value[i];
if (i === 0 && (character == PLUS_SIGN || character == MINUS_SIGN)) {
hasSign = true;
} else if (i > 0 && hasSign && (character == PLUS_SIGN || character == MINUS_SIGN)) {
return i - 1;
} else if (character == DECIMAL_DOT && !hasDot) {
hasDot = true;
} else if (character == DECIMAL_DOT && hasDot) {
return i - 1;
} else if (decimalRegex.test(character)) {
continue;
} else {
return i - 1;
}
}
return i;
}
function validator(compatibility) {
var validUnits = Units.slice(0).filter(function (value) {
return !(value in compatibility.units) || compatibility.units[value] === true;
});
return {
colorOpacity: compatibility.colors.opacity,
isAnimationDirectionKeyword: isKeyword('animation-direction'),
isAnimationFillModeKeyword: isKeyword('animation-fill-mode'),
isAnimationIterationCountKeyword: isKeyword('animation-iteration-count'),
isAnimationNameKeyword: isKeyword('animation-name'),
isAnimationPlayStateKeyword: isKeyword('animation-play-state'),
isTimingFunction: isTimingFunction(),
isBackgroundAttachmentKeyword: isKeyword('background-attachment'),
isBackgroundClipKeyword: isKeyword('background-clip'),
isBackgroundOriginKeyword: isKeyword('background-origin'),
isBackgroundPositionKeyword: isKeyword('background-position'),
isBackgroundRepeatKeyword: isKeyword('background-repeat'),
isBackgroundSizeKeyword: isKeyword('background-size'),
isColor: isColor,
isColorFunction: isColorFunction,
isDynamicUnit: isDynamicUnit,
isFontKeyword: isKeyword('font'),
isFontSizeKeyword: isKeyword('font-size'),
isFontStretchKeyword: isKeyword('font-stretch'),
isFontStyleKeyword: isKeyword('font-style'),
isFontVariantKeyword: isKeyword('font-variant'),
isFontWeightKeyword: isKeyword('font-weight'),
isFunction: isFunction,
isGlobal: isKeyword('^'),
isHslColor: isHslColor,
isIdentifier: isIdentifier,
isImage: isImage,
isKeyword: isKeyword,
isLineHeightKeyword: isKeyword('line-height'),
isListStylePositionKeyword: isKeyword('list-style-position'),
isListStyleTypeKeyword: isKeyword('list-style-type'),
isNumber: isNumber,
isPrefixed: isPrefixed,
isPositiveNumber: isPositiveNumber,
isRgbColor: isRgbColor,
isStyleKeyword: isKeyword('*-style'),
isTime: isTime,
isUnit: isUnit.bind(null, validUnits),
isUrl: isUrl,
isVariable: isVariable,
isWidth: isKeyword('width'),
isZIndex: isZIndex
};
}
module.exports = validator;