Created
          April 29, 2021 22:43 
        
      - 
      
- 
        Save LionsAd/b794e5f9d115bc985916bcf7fa944f46 to your computer and use it in GitHub Desktop. 
    Tailwind.css-to-JSON
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | const fs = require("fs") | |
| const postcss = require("postcss") | |
| const selectorParser = require("postcss-selector-parser") | |
| const { | |
| promisify | |
| } = require("util") | |
| const { | |
| createHash, | |
| } = require('crypto') | |
|  | |
| const asyncFs = { | |
| access: promisify(fs.access), | |
| readFile: promisify(fs.readFile), | |
| }; | |
|  | |
| const ALWAYS = 'keep:always'; | |
|  | |
| function isInPseudoClass(selector) { | |
| return ( | |
| (selector.parent && | |
| selector.parent.type === "pseudo" && | |
| selector.parent.value.startsWith(":")) || | |
| false | |
| ); | |
| } | |
|  | |
| function findSelectors(selector) { | |
| // ignore the selector if it is inside a pseudo class | |
| if (isInPseudoClass(selector)) { | |
| return []; | |
| } | |
|  | |
| let matches = []; | |
|  | |
| for (const selectorNode of selector.nodes) { | |
| switch (selectorNode.type) { | |
| case "attribute": | |
| break; | |
| case "class": | |
| case "id": | |
| case "tag": | |
| matches.push(selectorNode.toString()) | |
| break; | |
| default: | |
| continue; | |
| } | |
| } | |
|  | |
| return matches; | |
| } | |
|  | |
| async function process() { | |
| let rules = {}; | |
| let selectors = {}; | |
|  | |
| let content = await asyncFs.readFile("css/utils.css", "utf-8") | |
| let root = postcss.parse(content) | |
| let atrule = ''; | |
|  | |
| root.walk((node) => { | |
| // Store atrule for later use. | |
| if (node.type == 'atrule') { | |
| let nodes = node.nodes; | |
| node.nodes = []; | |
| atrule = node.toString(); | |
| node.nodes = nodes; | |
| } | |
|  | |
| // exit if it is not a rule | |
| if (node.type != "rule" || !node.selector) { | |
| return; | |
| } | |
|  | |
| let rule = node.toString(); | |
| let ruleHash = createHash('sha1').update(rule).digest('hex'); | |
|  | |
| let item = {}; | |
| item['rule'] = rule; | |
|  | |
| // Check again that this has an atrule. | |
| if (node.parent && node.parent.type == 'atrule') { | |
| item['atrule'] = atrule; | |
| } | |
|  | |
| rules[ruleHash] = item; | |
|  | |
| selectorParser((selectorsParsed) => { | |
| selectorsParsed.walk((selector) => { | |
| if (selector.type !== "selector") { | |
| return; | |
| } | |
|  | |
| if (selector.toString() == '[hidden]') { | |
| return; | |
| } | |
|  | |
| // Find selector matches | |
| let matches = findSelectors(selector); | |
| if (matches.length == 0) { | |
| matches.push(ALWAYS); | |
| } | |
|  | |
| delete item['and']; | |
|  | |
| if (matches.length > 1) { | |
| item['and'] = matches; | |
| matches = [matches[0]]; | |
| } | |
|  | |
| for (key in matches) { | |
| let match = matches[key] | |
|  | |
| if (!(match in selectors)) { | |
| selectors[match] = []; | |
| } | |
|  | |
| selectors[match].push(item); | |
| } | |
| }); | |
| }).processSync(node.selector); | |
| }); | |
|  | |
| console.log(JSON.stringify(selectors)); | |
| } | |
|  | |
| process(); | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment