| 'use strict'; |
| |
| const keywords = new Map(); |
| const properties = new Map(); |
| const HYPHENMINUS = 45; // '-'.charCodeAt() |
| |
| const keyword = getKeywordDescriptor; |
| const property = getPropertyDescriptor; |
| const vendorPrefix = getVendorPrefix; |
| function isCustomProperty(str, offset) { |
| offset = offset || 0; |
| |
| return str.length - offset >= 2 && |
| str.charCodeAt(offset) === HYPHENMINUS && |
| str.charCodeAt(offset + 1) === HYPHENMINUS; |
| } |
| |
| function getVendorPrefix(str, offset) { |
| offset = offset || 0; |
| |
| // verdor prefix should be at least 3 chars length |
| if (str.length - offset >= 3) { |
| // vendor prefix starts with hyper minus following non-hyper minus |
| if (str.charCodeAt(offset) === HYPHENMINUS && |
| str.charCodeAt(offset + 1) !== HYPHENMINUS) { |
| // vendor prefix should contain a hyper minus at the ending |
| const secondDashIndex = str.indexOf('-', offset + 2); |
| |
| if (secondDashIndex !== -1) { |
| return str.substring(offset, secondDashIndex + 1); |
| } |
| } |
| } |
| |
| return ''; |
| } |
| |
| function getKeywordDescriptor(keyword) { |
| if (keywords.has(keyword)) { |
| return keywords.get(keyword); |
| } |
| |
| const name = keyword.toLowerCase(); |
| let descriptor = keywords.get(name); |
| |
| if (descriptor === undefined) { |
| const custom = isCustomProperty(name, 0); |
| const vendor = !custom ? getVendorPrefix(name, 0) : ''; |
| descriptor = Object.freeze({ |
| basename: name.substr(vendor.length), |
| name, |
| prefix: vendor, |
| vendor, |
| custom |
| }); |
| } |
| |
| keywords.set(keyword, descriptor); |
| |
| return descriptor; |
| } |
| |
| function getPropertyDescriptor(property) { |
| if (properties.has(property)) { |
| return properties.get(property); |
| } |
| |
| let name = property; |
| let hack = property[0]; |
| |
| if (hack === '/') { |
| hack = property[1] === '/' ? '//' : '/'; |
| } else if (hack !== '_' && |
| hack !== '*' && |
| hack !== '$' && |
| hack !== '#' && |
| hack !== '+' && |
| hack !== '&') { |
| hack = ''; |
| } |
| |
| const custom = isCustomProperty(name, hack.length); |
| |
| // re-use result when possible (the same as for lower case) |
| if (!custom) { |
| name = name.toLowerCase(); |
| if (properties.has(name)) { |
| const descriptor = properties.get(name); |
| properties.set(property, descriptor); |
| return descriptor; |
| } |
| } |
| |
| const vendor = !custom ? getVendorPrefix(name, hack.length) : ''; |
| const prefix = name.substr(0, hack.length + vendor.length); |
| const descriptor = Object.freeze({ |
| basename: name.substr(prefix.length), |
| name: name.substr(hack.length), |
| hack, |
| vendor, |
| prefix, |
| custom |
| }); |
| |
| properties.set(property, descriptor); |
| |
| return descriptor; |
| } |
| |
| exports.isCustomProperty = isCustomProperty; |
| exports.keyword = keyword; |
| exports.property = property; |
| exports.vendorPrefix = vendorPrefix; |