Last active
May 22, 2025 13:28
-
-
Save ryantxr/a88122815c4fb8d6edd31ef923072227 to your computer and use it in GitHub Desktop.
Converts pre-v4 style safelist from tailwind.config.js to css @source inline(...)
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
| #!/usr/bin/env node | |
| /** | |
| * Script: generate-safelist.js | |
| * | |
| * Reads the `safelist` array from tailwind.config.js and | |
| * generates a `resources/css/safelist.css` file containing | |
| * @source inline(...) directives for each entry. | |
| * | |
| * Usage: `node scripts/generate-safelist.js` | |
| */ | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| /** | |
| * Convert a regex like "^border-(red|green|blue)(-(50|100|200))?$" | |
| * into the Tailwind safelist string: | |
| * border-{red,green,blue}{,-{50,100,200}} | |
| */ | |
| function regexToInline(regex) { | |
| // Strip anchors | |
| let pattern = regex.replace(/^\^/, '').replace(/\$$/, ''); | |
| // Recursive transformer | |
| function transform(str) { | |
| let out = ''; | |
| for (let i = 0; i < str.length;) { | |
| if (str[i] === '(') { | |
| // find matching ')' | |
| let depth = 1, j = i + 1, isNonCapt = false; | |
| if (str[j] === '?' && str[j + 1] === ':') { | |
| isNonCapt = true; | |
| j += 2; | |
| } | |
| const start = j; | |
| while (j < str.length && depth > 0) { | |
| if (str[j] === '(') depth++; | |
| else if (str[j] === ')') depth--; | |
| j++; | |
| } | |
| let content = str.slice(start, j - 1); | |
| // check for trailing "?" (optional) | |
| let optional = false; | |
| if (str[j] === '?') { | |
| optional = true; | |
| j++; | |
| } | |
| // recurse into the group | |
| let inner = transform(content) | |
| .split('|') | |
| // compress pure-number lists to a range if contiguous | |
| .reduce((acc, token) => { | |
| acc.items.push(token); | |
| return acc; | |
| }, { items: [] }) | |
| .items | |
| .map(x => x); // no automatic numeric compression here | |
| // build brace block | |
| let brace = `{${inner.join(',')}}`; | |
| if (optional) { | |
| brace = `{,${brace}}`; | |
| } | |
| out += brace; | |
| i = j; | |
| } else { | |
| out += str[i++]; | |
| } | |
| } | |
| return out; | |
| } | |
| return transform(pattern); | |
| } | |
| // Adjust paths if needed | |
| const projectRoot = path.resolve(__dirname, '..'); | |
| const configPath = path.join(projectRoot, 'tailwind.config.js'); | |
| const outputPath = path.join(projectRoot, 'resources', 'css', 'safelist-dev.css'); | |
| // Load tailwind.config.js | |
| let config; | |
| try { | |
| config = require(configPath); | |
| } catch (err) { | |
| console.error(`Failed to load Tailwind config at ${configPath}:`, err); | |
| process.exit(1); | |
| } | |
| const safelist = config.safelist; | |
| if (!Array.isArray(safelist) || safelist.length === 0) { | |
| console.error('No safelist array found in tailwind.config.js.'); | |
| process.exit(1); | |
| } | |
| // Generate @source inline directives | |
| const lines = safelist.map(entry => { | |
| if (typeof entry === 'string') { | |
| // plain class name | |
| return `@source inline("${entry}");`; | |
| } | |
| if (entry.pattern) { | |
| // pattern can be RegExp or string | |
| let ret = ''; | |
| if(entry.pattern instanceof RegExp){ | |
| const pattern = regexToInline(entry.pattern.source); | |
| ret = ret + '/* ' + entry.pattern.source + " */\n"; | |
| ret = ret + `@source inline("${pattern}");`; | |
| } else { | |
| ret = `@source inline("${entry.pattern}");`; | |
| } | |
| return ret; | |
| } | |
| return null; | |
| }).filter(Boolean); | |
| if (lines.length === 0) { | |
| console.error('No valid safelist entries to generate.'); | |
| process.exit(1); | |
| } | |
| // Write output file | |
| const header = `/* AUTO-GENERATED safelist.css - do not edit directly. */`; | |
| const header2 = `/* Instead: add safelist to tailwind.config.css */`; | |
| const content = [header, header2, ...lines].join('\n') + '\n'; | |
| fs.writeFileSync(outputPath, content, 'utf8'); | |
| console.log(`Generated safelist directives in ${outputPath}`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment