| var isCustomProperty = require('../../utils/names').isCustomProperty; | 
| var TYPE = require('../../tokenizer').TYPE; | 
| var rawMode = require('./Raw').mode; | 
|   | 
| var IDENT = TYPE.Ident; | 
| var HASH = TYPE.Hash; | 
| var COLON = TYPE.Colon; | 
| var SEMICOLON = TYPE.Semicolon; | 
| var DELIM = TYPE.Delim; | 
| var WHITESPACE = TYPE.WhiteSpace; | 
| var EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!) | 
| var NUMBERSIGN = 0x0023;      // U+0023 NUMBER SIGN (#) | 
| var DOLLARSIGN = 0x0024;      // U+0024 DOLLAR SIGN ($) | 
| var AMPERSAND = 0x0026;       // U+0026 ANPERSAND (&) | 
| var ASTERISK = 0x002A;        // U+002A ASTERISK (*) | 
| var PLUSSIGN = 0x002B;        // U+002B PLUS SIGN (+) | 
| var SOLIDUS = 0x002F;         // U+002F SOLIDUS (/) | 
|   | 
| function consumeValueRaw(startToken) { | 
|     return this.Raw(startToken, rawMode.exclamationMarkOrSemicolon, true); | 
| } | 
|   | 
| function consumeCustomPropertyRaw(startToken) { | 
|     return this.Raw(startToken, rawMode.exclamationMarkOrSemicolon, false); | 
| } | 
|   | 
| function consumeValue() { | 
|     var startValueToken = this.scanner.tokenIndex; | 
|     var value = this.Value(); | 
|   | 
|     if (value.type !== 'Raw' && | 
|         this.scanner.eof === false && | 
|         this.scanner.tokenType !== SEMICOLON && | 
|         this.scanner.isDelim(EXCLAMATIONMARK) === false && | 
|         this.scanner.isBalanceEdge(startValueToken) === false) { | 
|         this.error(); | 
|     } | 
|   | 
|     return value; | 
| } | 
|   | 
| module.exports = { | 
|     name: 'Declaration', | 
|     structure: { | 
|         important: [Boolean, String], | 
|         property: String, | 
|         value: ['Value', 'Raw'] | 
|     }, | 
|     parse: function() { | 
|         var start = this.scanner.tokenStart; | 
|         var startToken = this.scanner.tokenIndex; | 
|         var property = readProperty.call(this); | 
|         var customProperty = isCustomProperty(property); | 
|         var parseValue = customProperty ? this.parseCustomProperty : this.parseValue; | 
|         var consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw; | 
|         var important = false; | 
|         var value; | 
|   | 
|         this.scanner.skipSC(); | 
|         this.eat(COLON); | 
|   | 
|         const valueStart = this.scanner.tokenIndex; | 
|   | 
|         if (!customProperty) { | 
|             this.scanner.skipSC(); | 
|         } | 
|   | 
|         if (parseValue) { | 
|             value = this.parseWithFallback(consumeValue, consumeRaw); | 
|         } else { | 
|             value = consumeRaw.call(this, this.scanner.tokenIndex); | 
|         } | 
|   | 
|         if (customProperty && value.type === 'Value' && value.children.isEmpty()) { | 
|             for (let offset = valueStart - this.scanner.tokenIndex; offset <= 0; offset++) { | 
|                 if (this.scanner.lookupType(offset) === WHITESPACE) { | 
|                     value.children.appendData({ | 
|                         type: 'WhiteSpace', | 
|                         loc: null, | 
|                         value: ' ' | 
|                     }); | 
|                     break; | 
|                 } | 
|             } | 
|         } | 
|   | 
|         if (this.scanner.isDelim(EXCLAMATIONMARK)) { | 
|             important = getImportant.call(this); | 
|             this.scanner.skipSC(); | 
|         } | 
|   | 
|         // Do not include semicolon to range per spec | 
|         // https://drafts.csswg.org/css-syntax/#declaration-diagram | 
|   | 
|         if (this.scanner.eof === false && | 
|             this.scanner.tokenType !== SEMICOLON && | 
|             this.scanner.isBalanceEdge(startToken) === false) { | 
|             this.error(); | 
|         } | 
|   | 
|         return { | 
|             type: 'Declaration', | 
|             loc: this.getLocation(start, this.scanner.tokenStart), | 
|             important: important, | 
|             property: property, | 
|             value: value | 
|         }; | 
|     }, | 
|     generate: function(node) { | 
|         this.chunk(node.property); | 
|         this.chunk(':'); | 
|         this.node(node.value); | 
|   | 
|         if (node.important) { | 
|             this.chunk(node.important === true ? '!important' : '!' + node.important); | 
|         } | 
|     }, | 
|     walkContext: 'declaration' | 
| }; | 
|   | 
| function readProperty() { | 
|     var start = this.scanner.tokenStart; | 
|     var prefix = 0; | 
|   | 
|     // hacks | 
|     if (this.scanner.tokenType === DELIM) { | 
|         switch (this.scanner.source.charCodeAt(this.scanner.tokenStart)) { | 
|             case ASTERISK: | 
|             case DOLLARSIGN: | 
|             case PLUSSIGN: | 
|             case NUMBERSIGN: | 
|             case AMPERSAND: | 
|                 this.scanner.next(); | 
|                 break; | 
|   | 
|             // TODO: not sure we should support this hack | 
|             case SOLIDUS: | 
|                 this.scanner.next(); | 
|                 if (this.scanner.isDelim(SOLIDUS)) { | 
|                     this.scanner.next(); | 
|                 } | 
|                 break; | 
|         } | 
|     } | 
|   | 
|     if (prefix) { | 
|         this.scanner.skip(prefix); | 
|     } | 
|   | 
|     if (this.scanner.tokenType === HASH) { | 
|         this.eat(HASH); | 
|     } else { | 
|         this.eat(IDENT); | 
|     } | 
|   | 
|     return this.scanner.substrToCursor(start); | 
| } | 
|   | 
| // ! ws* important | 
| function getImportant() { | 
|     this.eat(DELIM); | 
|     this.scanner.skipSC(); | 
|   | 
|     var important = this.consume(IDENT); | 
|   | 
|     // store original value in case it differ from `important` | 
|     // for better original source restoring and hacks like `!ie` support | 
|     return important === 'important' ? true : important; | 
| } |