import postcss, { type ChildNode, type Plugin, type Root } from 'postcss'
import { format, type Options } from 'prettier'
import { walk } from '../../utils/walk'
const FORMAT_OPTIONS: Options = {
parser: 'css',
semi: true,
singleQuote: true,
}
export function formatNodes(): Plugin {
async function migrate(root: Root) {
let nodesToFormat: ChildNode[] = []
walk(root, (child, _idx, parent) => {
if (child.type === 'atrule') {
child.raws.semicolon = true
}
if (child.type === 'atrule' && child.name === 'tw-bucket') {
nodesToFormat.push(child)
} else if (child.raws.tailwind_pretty) {
child.parent ??= parent
nodesToFormat.unshift(child)
}
})
let output: string[] = []
for (let node of nodesToFormat) {
let contents = (() => {
if (node.type === 'atrule' && node.name === 'tw-bucket') {
return node
.toString()
.trim()
.replace(/@tw-bucket(.*?){([\s\S]*)}/, '$2')
}
return node.toString()
})()
if (node.type === 'atrule' && node.name === 'tw-bucket' && node.params === 'user') {
output.push(contents)
continue
}
if (node.type === 'atrule' && node.name === 'tw-bucket') {
output.push(await format(contents, FORMAT_OPTIONS))
continue
}
node.replaceWith(
postcss.parse(
`${node.raws.before ?? ''}${(await format(contents, FORMAT_OPTIONS)).trim()}`,
),
)
}
root.removeAll()
root.append(
postcss.parse(
output
.map((bucket) => bucket.trim())
.filter(Boolean)
.join('\n\n'),
),
)
}
return {
postcssPlugin: '@tailwindcss/upgrade/format-nodes',
OnceExit: migrate,
}
}