Track locations when printing
This commit is contained in:
parent
fcd4e2d2bc
commit
6febfd966a
3 changed files with 168 additions and 2 deletions
28
packages/tailwindcss/src/ast.bench.ts
Normal file
28
packages/tailwindcss/src/ast.bench.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { bench } from 'vitest'
|
||||
import { toCss } from './ast'
|
||||
import * as CSS from './css-parser'
|
||||
|
||||
const css = String.raw
|
||||
const input = css`
|
||||
@theme {
|
||||
--color-primary: #333;
|
||||
}
|
||||
@tailwind utilities;
|
||||
.foo {
|
||||
color: red;
|
||||
/* comment */
|
||||
&:hover {
|
||||
color: blue;
|
||||
@apply font-bold;
|
||||
}
|
||||
}
|
||||
`
|
||||
const ast = CSS.parse(input)
|
||||
|
||||
bench('toCss', () => {
|
||||
toCss(ast)
|
||||
})
|
||||
|
||||
bench('toCss with source maps', () => {
|
||||
toCss(ast, true)
|
||||
})
|
||||
|
|
@ -714,7 +714,14 @@ export function optimizeAst(
|
|||
return newAst
|
||||
}
|
||||
|
||||
export function toCss(ast: AstNode[]) {
|
||||
export function toCss(ast: AstNode[], track?: boolean) {
|
||||
let pos = 0
|
||||
|
||||
let source: Source = {
|
||||
file: null,
|
||||
code: '',
|
||||
}
|
||||
|
||||
function stringify(node: AstNode, depth = 0): string {
|
||||
let css = ''
|
||||
let indent = ' '.repeat(depth)
|
||||
|
|
@ -722,15 +729,70 @@ export function toCss(ast: AstNode[]) {
|
|||
// Declaration
|
||||
if (node.kind === 'declaration') {
|
||||
css += `${indent}${node.property}: ${node.value}${node.important ? ' !important' : ''};\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// node.property
|
||||
let start = pos
|
||||
pos += node.property.length
|
||||
|
||||
// `: `
|
||||
pos += 2
|
||||
|
||||
// node.value
|
||||
pos += node.value?.length ?? 0
|
||||
|
||||
// !important
|
||||
if (node.important) {
|
||||
pos += 11
|
||||
}
|
||||
|
||||
let end = pos
|
||||
|
||||
// `;\n`
|
||||
pos += 2
|
||||
|
||||
node.dst = [source, start, end]
|
||||
}
|
||||
}
|
||||
|
||||
// Rule
|
||||
else if (node.kind === 'rule') {
|
||||
css += `${indent}${node.selector} {\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// node.selector
|
||||
let start = pos
|
||||
pos += node.selector.length
|
||||
|
||||
// ` `
|
||||
pos += 1
|
||||
|
||||
let end = pos
|
||||
node.dst = [source, start, end]
|
||||
|
||||
// `{\n`
|
||||
pos += 2
|
||||
}
|
||||
|
||||
for (let child of node.nodes) {
|
||||
css += stringify(child, depth + 1)
|
||||
}
|
||||
|
||||
css += `${indent}}\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// `}\n`
|
||||
pos += 2
|
||||
}
|
||||
}
|
||||
|
||||
// AtRule
|
||||
|
|
@ -744,19 +806,93 @@ export function toCss(ast: AstNode[]) {
|
|||
// ```
|
||||
if (node.nodes.length === 0) {
|
||||
let css = `${indent}${node.name} ${node.params};\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// node.name
|
||||
let start = pos
|
||||
pos += node.name.length
|
||||
|
||||
// ` `
|
||||
pos += 1
|
||||
|
||||
// node.params
|
||||
pos += node.params.length
|
||||
let end = pos
|
||||
|
||||
// `;\n`
|
||||
pos += 2
|
||||
|
||||
node.dst = [source, start, end]
|
||||
}
|
||||
|
||||
return css
|
||||
}
|
||||
|
||||
css += `${indent}${node.name}${node.params ? ` ${node.params} ` : ' '}{\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// node.name
|
||||
let start = pos
|
||||
pos += node.name.length
|
||||
|
||||
if (node.params) {
|
||||
// ` `
|
||||
pos += 1
|
||||
|
||||
// node.params
|
||||
pos += node.params.length
|
||||
}
|
||||
|
||||
// ` `
|
||||
pos += 1
|
||||
|
||||
let end = pos
|
||||
node.dst = [source, start, end]
|
||||
|
||||
// `{\n`
|
||||
pos += 2
|
||||
}
|
||||
|
||||
for (let child of node.nodes) {
|
||||
css += stringify(child, depth + 1)
|
||||
}
|
||||
|
||||
css += `${indent}}\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// `}\n`
|
||||
pos += 2
|
||||
}
|
||||
}
|
||||
|
||||
// Comment
|
||||
else if (node.kind === 'comment') {
|
||||
css += `${indent}/*${node.value}*/\n`
|
||||
|
||||
if (track) {
|
||||
// indent
|
||||
pos += indent.length
|
||||
|
||||
// The comment itself. We do this instead of just the inside because
|
||||
// it seems more useful to have the entire comment span tracked.
|
||||
let start = pos
|
||||
pos += 2 + node.value.length + 2
|
||||
let end = pos
|
||||
|
||||
node.dst = [source, start, end]
|
||||
|
||||
// `\n`
|
||||
pos += 1
|
||||
}
|
||||
}
|
||||
|
||||
// These should've been handled already by `optimizeAst` which
|
||||
|
|
@ -780,6 +916,8 @@ export function toCss(ast: AstNode[]) {
|
|||
css += stringify(node, 0)
|
||||
}
|
||||
|
||||
source.code = css
|
||||
|
||||
return css
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -814,7 +814,7 @@ export async function compile(
|
|||
return compiledCss
|
||||
}
|
||||
|
||||
compiledCss = toCss(newAst)
|
||||
compiledCss = toCss(newAst, !!opts.from)
|
||||
compiledAst = newAst
|
||||
|
||||
return compiledCss
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue