530 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			530 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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;
 | 
