| 'use strict'; | 
|   | 
| const postcss = require('postcss'); | 
| const selectorParser = require('postcss-selector-parser'); | 
|   | 
| const hasOwnProperty = Object.prototype.hasOwnProperty; | 
|   | 
| function getSingleLocalNamesForComposes(root) { | 
|   return root.nodes.map(node => { | 
|     if (node.type !== 'selector' || node.nodes.length !== 1) { | 
|       throw new Error( | 
|         `composition is only allowed when selector is single :local class name not in "${root}"` | 
|       ); | 
|     } | 
|   | 
|     node = node.nodes[0]; | 
|   | 
|     if ( | 
|       node.type !== 'pseudo' || | 
|       node.value !== ':local' || | 
|       node.nodes.length !== 1 | 
|     ) { | 
|       throw new Error( | 
|         'composition is only allowed when selector is single :local class name not in "' + | 
|           root + | 
|           '", "' + | 
|           node + | 
|           '" is weird' | 
|       ); | 
|     } | 
|   | 
|     node = node.first; | 
|   | 
|     if (node.type !== 'selector' || node.length !== 1) { | 
|       throw new Error( | 
|         'composition is only allowed when selector is single :local class name not in "' + | 
|           root + | 
|           '", "' + | 
|           node + | 
|           '" is weird' | 
|       ); | 
|     } | 
|   | 
|     node = node.first; | 
|   | 
|     if (node.type !== 'class') { | 
|       // 'id' is not possible, because you can't compose ids | 
|       throw new Error( | 
|         'composition is only allowed when selector is single :local class name not in "' + | 
|           root + | 
|           '", "' + | 
|           node + | 
|           '" is weird' | 
|       ); | 
|     } | 
|   | 
|     return node.value; | 
|   }); | 
| } | 
|   | 
| const whitespace = '[\\x20\\t\\r\\n\\f]'; | 
| const unescapeRegExp = new RegExp( | 
|   '\\\\([\\da-f]{1,6}' + whitespace + '?|(' + whitespace + ')|.)', | 
|   'ig' | 
| ); | 
|   | 
| function unescape(str) { | 
|   return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => { | 
|     const high = '0x' + escaped - 0x10000; | 
|   | 
|     // NaN means non-codepoint | 
|     // Workaround erroneous numeric interpretation of +"0x" | 
|     return high !== high || escapedWhitespace | 
|       ? escaped | 
|       : high < 0 | 
|         ? // BMP codepoint | 
|           String.fromCharCode(high + 0x10000) | 
|         : // Supplemental Plane codepoint (surrogate pair) | 
|           String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00); | 
|   }); | 
| } | 
|   | 
| const processor = postcss.plugin('postcss-modules-scope', function(options) { | 
|   return css => { | 
|     const generateScopedName = | 
|       (options && options.generateScopedName) || processor.generateScopedName; | 
|     const generateExportEntry = | 
|       (options && options.generateExportEntry) || processor.generateExportEntry; | 
|     const exportGlobals = options && options.exportGlobals; | 
|   | 
|     const exports = Object.create(null); | 
|   | 
|     function exportScopedName(name, rawName) { | 
|       const scopedName = generateScopedName( | 
|         rawName ? rawName : name, | 
|         css.source.input.from, | 
|         css.source.input.css | 
|       ); | 
|       const exportEntry = generateExportEntry( | 
|         rawName ? rawName : name, | 
|         scopedName, | 
|         css.source.input.from, | 
|         css.source.input.css | 
|       ); | 
|       const { key, value } = exportEntry; | 
|   | 
|       exports[key] = exports[key] || []; | 
|   | 
|       if (exports[key].indexOf(value) < 0) { | 
|         exports[key].push(value); | 
|       } | 
|   | 
|       return scopedName; | 
|     } | 
|   | 
|     function localizeNode(node) { | 
|       switch (node.type) { | 
|         case 'selector': | 
|           node.nodes = node.map(localizeNode); | 
|           return node; | 
|         case 'class': | 
|           return selectorParser.className({ | 
|             value: exportScopedName( | 
|               node.value, | 
|               node.raws && node.raws.value ? node.raws.value : null | 
|             ), | 
|           }); | 
|         case 'id': { | 
|           return selectorParser.id({ | 
|             value: exportScopedName( | 
|               node.value, | 
|               node.raws && node.raws.value ? node.raws.value : null | 
|             ), | 
|           }); | 
|         } | 
|       } | 
|   | 
|       throw new Error( | 
|         `${node.type} ("${node}") is not allowed in a :local block` | 
|       ); | 
|     } | 
|   | 
|     function traverseNode(node) { | 
|       switch (node.type) { | 
|         case 'pseudo': | 
|           if (node.value === ':local') { | 
|             if (node.nodes.length !== 1) { | 
|               throw new Error('Unexpected comma (",") in :local block'); | 
|             } | 
|   | 
|             const selector = localizeNode(node.first, node.spaces); | 
|             // move the spaces that were around the psuedo selector to the first | 
|             // non-container node | 
|             selector.first.spaces = node.spaces; | 
|   | 
|             const nextNode = node.next(); | 
|   | 
|             if ( | 
|               nextNode && | 
|               nextNode.type === 'combinator' && | 
|               nextNode.value === ' ' && | 
|               /\\[A-F0-9]{1,6}$/.test(selector.last.value) | 
|             ) { | 
|               selector.last.spaces.after = ' '; | 
|             } | 
|   | 
|             node.replaceWith(selector); | 
|   | 
|             return; | 
|           } | 
|         /* falls through */ | 
|         case 'root': | 
|         case 'selector': { | 
|           node.each(traverseNode); | 
|           break; | 
|         } | 
|         case 'id': | 
|         case 'class':  | 
|           if (exportGlobals) { | 
|             exports[node.value] = [node.value]; | 
|           } | 
|           break; | 
|       } | 
|       return node; | 
|     } | 
|   | 
|     // Find any :import and remember imported names | 
|     const importedNames = {}; | 
|   | 
|     css.walkRules(rule => { | 
|       if (/^:import\(.+\)$/.test(rule.selector)) { | 
|         rule.walkDecls(decl => { | 
|           importedNames[decl.prop] = true; | 
|         }); | 
|       } | 
|     }); | 
|   | 
|     // Find any :local classes | 
|     css.walkRules(rule => { | 
|       if ( | 
|         rule.nodes && | 
|         rule.selector.slice(0, 2) === '--' && | 
|         rule.selector.slice(-1) === ':' | 
|       ) { | 
|         // ignore custom property set | 
|         return; | 
|       } | 
|   | 
|       let parsedSelector = selectorParser().astSync(rule); | 
|   | 
|       rule.selector = traverseNode(parsedSelector.clone()).toString(); | 
|   | 
|       rule.walkDecls(/composes|compose-with/, decl => { | 
|         const localNames = getSingleLocalNamesForComposes(parsedSelector); | 
|         const classes = decl.value.split(/\s+/); | 
|   | 
|         classes.forEach(className => { | 
|           const global = /^global\(([^\)]+)\)$/.exec(className); | 
|   | 
|           if (global) { | 
|             localNames.forEach(exportedName => { | 
|               exports[exportedName].push(global[1]); | 
|             }); | 
|           } else if (hasOwnProperty.call(importedNames, className)) { | 
|             localNames.forEach(exportedName => { | 
|               exports[exportedName].push(className); | 
|             }); | 
|           } else if (hasOwnProperty.call(exports, className)) { | 
|             localNames.forEach(exportedName => { | 
|               exports[className].forEach(item => { | 
|                 exports[exportedName].push(item); | 
|               }); | 
|             }); | 
|           } else { | 
|             throw decl.error( | 
|               `referenced class name "${className}" in ${decl.prop} not found` | 
|             ); | 
|           } | 
|         }); | 
|   | 
|         decl.remove(); | 
|       }); | 
|   | 
|       rule.walkDecls(decl => { | 
|         let tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/); | 
|   | 
|         tokens = tokens.map((token, idx) => { | 
|           if (idx === 0 || tokens[idx - 1] === ',') { | 
|             const localMatch = /^(\s*):local\s*\((.+?)\)/.exec(token); | 
|   | 
|             if (localMatch) { | 
|               return ( | 
|                 localMatch[1] + | 
|                 exportScopedName(localMatch[2]) + | 
|                 token.substr(localMatch[0].length) | 
|               ); | 
|             } else { | 
|               return token; | 
|             } | 
|           } else { | 
|             return token; | 
|           } | 
|         }); | 
|   | 
|         decl.value = tokens.join(''); | 
|       }); | 
|     }); | 
|   | 
|     // Find any :local keyframes | 
|     css.walkAtRules(atrule => { | 
|       if (/keyframes$/i.test(atrule.name)) { | 
|         const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atrule.params); | 
|   | 
|         if (localMatch) { | 
|           atrule.params = exportScopedName(localMatch[1]); | 
|         } | 
|       } | 
|     }); | 
|   | 
|     // If we found any :locals, insert an :export rule | 
|     const exportedNames = Object.keys(exports); | 
|   | 
|     if (exportedNames.length > 0) { | 
|       const exportRule = postcss.rule({ selector: ':export' }); | 
|   | 
|       exportedNames.forEach(exportedName => | 
|         exportRule.append({ | 
|           prop: exportedName, | 
|           value: exports[exportedName].join(' '), | 
|           raws: { before: '\n  ' }, | 
|         }) | 
|       ); | 
|   | 
|       css.append(exportRule); | 
|     } | 
|   }; | 
| }); | 
|   | 
| processor.generateScopedName = function(name, path) { | 
|   const sanitisedPath = path | 
|     .replace(/\.[^\.\/\\]+$/, '') | 
|     .replace(/[\W_]+/g, '_') | 
|     .replace(/^_|_$/g, ''); | 
|   | 
|   return `_${sanitisedPath}__${name}`.trim(); | 
| }; | 
|   | 
| processor.generateExportEntry = function(name, scopedName) { | 
|   return { | 
|     key: unescape(name), | 
|     value: unescape(scopedName), | 
|   }; | 
| }; | 
|   | 
| module.exports = processor; |