'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;