const parser = require('postcss-selector-parser') function nodeIsInsensitiveAttribute(node) { return node.type === 'attribute' && node.insensitive } function selectorHasInsensitiveAttribute(selector) { return selector.some(nodeIsInsensitiveAttribute) } function transformString(strings, charPos, string) { const char = string.charAt(charPos) if (char === '') { return strings } let newStrings = strings.map(x => x + char) const upperChar = char.toLocaleUpperCase() if (upperChar !== char) { newStrings = newStrings.concat(strings.map(x => x + upperChar)) } return transformString(newStrings, charPos + 1, string) } function createSensitiveAtributes(attribute) { const attributes = transformString([''], 0, attribute.value) return attributes.map(x => { const newAttribute = attribute.clone({ spaces: { after: attribute.spaces.after, before: attribute.spaces.before }, insensitive: false }) newAttribute.setValue(x) return newAttribute }) } function createNewSelectors(selector) { let newSelectors = [parser.selector()] selector.walk(node => { if (!nodeIsInsensitiveAttribute(node)) { newSelectors.forEach(newSelector => { newSelector.append(node.clone()) }) return } const sensitiveAttributes = createSensitiveAtributes(node) const newSelectorsWithSensitiveAttributes = [] sensitiveAttributes.forEach(newNode => { newSelectors.forEach(newSelector => { const newSelectorWithNewNode = newSelector.clone() newSelectorWithNewNode.append(newNode) newSelectorsWithSensitiveAttributes.push(newSelectorWithNewNode) }) }) newSelectors = newSelectorsWithSensitiveAttributes }) return newSelectors } function transform(selectors) { let newSelectors = [] selectors.each(selector => { if (selectorHasInsensitiveAttribute(selector)) { newSelectors = newSelectors.concat(createNewSelectors(selector)) selector.remove() } }) if (newSelectors.length) { newSelectors.forEach(newSelector => selectors.append(newSelector)) } } const caseInsensitiveRegExp = /i(\s*\/\*[\W\w]*?\*\/)*\s*\]/ module.exports = () => { return { postcssPlugin: 'postcss-attribute-case-insensitive', Rule(rule) { if (caseInsensitiveRegExp.test(rule.selector)) { rule.selector = parser(transform).processSync(rule.selector) } } } } module.exports.postcss = true