193 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| var Hack = require('./hack');
 | |
| 
 | |
| var Marker = require('../tokenizer/marker');
 | |
| var Token = require('../tokenizer/token');
 | |
| 
 | |
| var Match = {
 | |
|   ASTERISK: '*',
 | |
|   BACKSLASH: '\\',
 | |
|   BANG: '!',
 | |
|   BANG_SUFFIX_PATTERN: /!\w+$/,
 | |
|   IMPORTANT_TOKEN: '!important',
 | |
|   IMPORTANT_TOKEN_PATTERN: new RegExp('!important$', 'i'),
 | |
|   IMPORTANT_WORD: 'important',
 | |
|   IMPORTANT_WORD_PATTERN: new RegExp('important$', 'i'),
 | |
|   SUFFIX_BANG_PATTERN: /!$/,
 | |
|   UNDERSCORE: '_',
 | |
|   VARIABLE_REFERENCE_PATTERN: /var\(--.+\)$/
 | |
| };
 | |
| 
 | |
| function wrapAll(properties, skipProperties) {
 | |
|   var wrapped = [];
 | |
|   var single;
 | |
|   var property;
 | |
|   var i;
 | |
| 
 | |
|   for (i = properties.length - 1; i >= 0; i--) {
 | |
|     property = properties[i];
 | |
| 
 | |
|     if (property[0] != Token.PROPERTY) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (skipProperties && skipProperties.indexOf(property[1][1]) > -1) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     single = wrapSingle(property);
 | |
|     single.all = properties;
 | |
|     single.position = i;
 | |
|     wrapped.unshift(single);
 | |
|   }
 | |
| 
 | |
|   return wrapped;
 | |
| }
 | |
| 
 | |
| function someVariableReferences(property) {
 | |
|   var i, l;
 | |
|   var value;
 | |
| 
 | |
|   // skipping `property` and property name tokens
 | |
|   for (i = 2, l = property.length; i < l; i++) {
 | |
|     value = property[i];
 | |
| 
 | |
|     if (value[0] != Token.PROPERTY_VALUE) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (isVariableReference(value[1])) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function isVariableReference(value) {
 | |
|   return Match.VARIABLE_REFERENCE_PATTERN.test(value);
 | |
| }
 | |
| 
 | |
| function isMultiplex(property) {
 | |
|   var value;
 | |
|   var i, l;
 | |
| 
 | |
|   for (i = 3, l = property.length; i < l; i++) {
 | |
|     value = property[i];
 | |
| 
 | |
|     if (value[0] == Token.PROPERTY_VALUE && (value[1] == Marker.COMMA || value[1] == Marker.FORWARD_SLASH)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function hackFrom(property) {
 | |
|   var match = false;
 | |
|   var name = property[1][1];
 | |
|   var lastValue = property[property.length - 1];
 | |
| 
 | |
|   if (name[0] == Match.UNDERSCORE) {
 | |
|     match = [Hack.UNDERSCORE];
 | |
|   } else if (name[0] == Match.ASTERISK) {
 | |
|     match = [Hack.ASTERISK];
 | |
|   } else if (lastValue[1][0] == Match.BANG && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN)) {
 | |
|     match = [Hack.BANG];
 | |
|   } else if (lastValue[1].indexOf(Match.BANG) > 0
 | |
|     && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN)
 | |
|     && Match.BANG_SUFFIX_PATTERN.test(lastValue[1])) {
 | |
|     match = [Hack.BANG];
 | |
|   } else if (lastValue[1].indexOf(Match.BACKSLASH) > 0
 | |
|     && lastValue[1].indexOf(Match.BACKSLASH) == lastValue[1].length - Match.BACKSLASH.length - 1) {
 | |
|     match = [Hack.BACKSLASH, lastValue[1].substring(lastValue[1].indexOf(Match.BACKSLASH) + 1)];
 | |
|   } else if (lastValue[1].indexOf(Match.BACKSLASH) === 0 && lastValue[1].length == 2) {
 | |
|     match = [Hack.BACKSLASH, lastValue[1].substring(1)];
 | |
|   }
 | |
| 
 | |
|   return match;
 | |
| }
 | |
| 
 | |
| function isImportant(property) {
 | |
|   if (property.length < 3) { return false; }
 | |
| 
 | |
|   var lastValue = property[property.length - 1];
 | |
|   if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) {
 | |
|     return true;
 | |
|   } if (Match.IMPORTANT_WORD_PATTERN.test(lastValue[1])
 | |
|     && Match.SUFFIX_BANG_PATTERN.test(property[property.length - 2][1])) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function stripImportant(property) {
 | |
|   var lastValue = property[property.length - 1];
 | |
|   var oneButLastValue = property[property.length - 2];
 | |
| 
 | |
|   if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) {
 | |
|     lastValue[1] = lastValue[1].replace(Match.IMPORTANT_TOKEN_PATTERN, '');
 | |
|   } else {
 | |
|     lastValue[1] = lastValue[1].replace(Match.IMPORTANT_WORD_PATTERN, '');
 | |
|     oneButLastValue[1] = oneButLastValue[1].replace(Match.SUFFIX_BANG_PATTERN, '');
 | |
|   }
 | |
| 
 | |
|   if (lastValue[1].length === 0) {
 | |
|     property.pop();
 | |
|   }
 | |
| 
 | |
|   if (oneButLastValue[1].length === 0) {
 | |
|     property.pop();
 | |
|   }
 | |
| }
 | |
| 
 | |
| function stripPrefixHack(property) {
 | |
|   property[1][1] = property[1][1].substring(1);
 | |
| }
 | |
| 
 | |
| function stripSuffixHack(property, hackFrom) {
 | |
|   var lastValue = property[property.length - 1];
 | |
|   lastValue[1] = lastValue[1]
 | |
|     .substring(0, lastValue[1].indexOf(hackFrom[0] == Hack.BACKSLASH ? Match.BACKSLASH : Match.BANG))
 | |
|     .trim();
 | |
| 
 | |
|   if (lastValue[1].length === 0) {
 | |
|     property.pop();
 | |
|   }
 | |
| }
 | |
| 
 | |
| function wrapSingle(property) {
 | |
|   var importantProperty = isImportant(property);
 | |
|   if (importantProperty) {
 | |
|     stripImportant(property);
 | |
|   }
 | |
| 
 | |
|   var whichHack = hackFrom(property);
 | |
|   if (whichHack[0] == Hack.ASTERISK || whichHack[0] == Hack.UNDERSCORE) {
 | |
|     stripPrefixHack(property);
 | |
|   } else if (whichHack[0] == Hack.BACKSLASH || whichHack[0] == Hack.BANG) {
 | |
|     stripSuffixHack(property, whichHack);
 | |
|   }
 | |
| 
 | |
|   return {
 | |
|     block: property[2] && property[2][0] == Token.PROPERTY_BLOCK,
 | |
|     components: [],
 | |
|     dirty: false,
 | |
|     dynamic: someVariableReferences(property),
 | |
|     hack: whichHack,
 | |
|     important: importantProperty,
 | |
|     name: property[1][1],
 | |
|     multiplex: property.length > 3 ? isMultiplex(property) : false,
 | |
|     optimizable: true,
 | |
|     position: 0,
 | |
|     shorthand: false,
 | |
|     unused: false,
 | |
|     value: property.slice(2)
 | |
|   };
 | |
| }
 | |
| 
 | |
| module.exports = {
 | |
|   all: wrapAll,
 | |
|   single: wrapSingle
 | |
| };
 |