11import postcss , {
2+ Input ,
23 type ChildNode as PostCssChildNode ,
34 type Container as PostCssContainerNode ,
45 type Root as PostCssRoot ,
56 type Source as PostcssSource ,
67} from 'postcss'
78import { atRule , comment , decl , rule , type AstNode } from '../../tailwindcss/src/ast'
9+ import { createLineTable , type LineTable } from '../../tailwindcss/src/source-maps/line-table'
10+ import type { Source , SourceLocation } from '../../tailwindcss/src/source-maps/source'
11+ import { DefaultMap } from '../../tailwindcss/src/utils/default-map'
812
913const EXCLAMATION_MARK = 0x21
1014
1115export function cssAstToPostCssAst ( ast : AstNode [ ] , source : PostcssSource | undefined ) : PostCssRoot {
16+ let inputMap = new DefaultMap < Source , Input > ( ( src ) => {
17+ return new Input ( src . code , {
18+ map : source ?. input . map ,
19+ from : src . file ?? undefined ,
20+ } )
21+ } )
22+
23+ let lineTables = new DefaultMap < Source , LineTable > ( ( src ) => createLineTable ( src . code ) )
24+
1225 let root = postcss . root ( )
1326 root . source = source
1427
28+ function toSource ( loc : SourceLocation | undefined ) : PostcssSource | undefined {
29+ // Use the fallback if this node has no location info in the AST
30+ if ( ! loc ) return source
31+ if ( ! loc [ 0 ] ) return source
32+
33+ let table = lineTables . get ( loc [ 0 ] )
34+ let start = table . find ( loc [ 1 ] )
35+ let end = table . find ( loc [ 2 ] )
36+
37+ return {
38+ input : inputMap . get ( loc [ 0 ] ) ,
39+ start : {
40+ line : start . line ,
41+ column : start . column + 1 ,
42+ offset : loc [ 1 ] ,
43+ } ,
44+ end : {
45+ line : end . line ,
46+ column : end . column + 1 ,
47+ offset : loc [ 2 ] ,
48+ } ,
49+ }
50+ }
51+
1552 function transform ( node : AstNode , parent : PostCssContainerNode ) {
1653 // Declaration
1754 if ( node . kind === 'declaration' ) {
@@ -20,14 +57,14 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
2057 value : node . value ?? '' ,
2158 important : node . important ,
2259 } )
23- astNode . source = source
60+ astNode . source = toSource ( node . src )
2461 parent . append ( astNode )
2562 }
2663
2764 // Rule
2865 else if ( node . kind === 'rule' ) {
2966 let astNode = postcss . rule ( { selector : node . selector } )
30- astNode . source = source
67+ astNode . source = toSource ( node . src )
3168 astNode . raws . semicolon = true
3269 parent . append ( astNode )
3370 for ( let child of node . nodes ) {
@@ -38,7 +75,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
3875 // AtRule
3976 else if ( node . kind === 'at-rule' ) {
4077 let astNode = postcss . atRule ( { name : node . name . slice ( 1 ) , params : node . params } )
41- astNode . source = source
78+ astNode . source = toSource ( node . src )
4279 astNode . raws . semicolon = true
4380 parent . append ( astNode )
4481 for ( let child of node . nodes ) {
@@ -53,7 +90,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
5390 // spaces.
5491 astNode . raws . left = ''
5592 astNode . raws . right = ''
56- astNode . source = source
93+ astNode . source = toSource ( node . src )
5794 parent . append ( astNode )
5895 }
5996
@@ -75,33 +112,56 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
75112}
76113
77114export function postCssAstToCssAst ( root : PostCssRoot ) : AstNode [ ] {
115+ let inputMap = new DefaultMap < Input , Source > ( ( input ) => ( {
116+ file : input . file ?? input . id ?? null ,
117+ code : input . css ,
118+ } ) )
119+
120+ function toSource ( node : PostCssChildNode ) : SourceLocation | undefined {
121+ let source = node . source
122+ if ( ! source ) return
123+
124+ let input = source . input
125+ if ( ! input ) return
126+ if ( source . start === undefined ) return
127+ if ( source . end === undefined ) return
128+
129+ return [ inputMap . get ( input ) , source . start . offset , source . end . offset ]
130+ }
131+
78132 function transform (
79133 node : PostCssChildNode ,
80134 parent : Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
81135 ) {
82136 // Declaration
83137 if ( node . type === 'decl' ) {
84- parent . push ( decl ( node . prop , node . value , node . important ) )
138+ let astNode = decl ( node . prop , node . value , node . important )
139+ astNode . src = toSource ( node )
140+ parent . push ( astNode )
85141 }
86142
87143 // Rule
88144 else if ( node . type === 'rule' ) {
89145 let astNode = rule ( node . selector )
146+ astNode . src = toSource ( node )
90147 node . each ( ( child ) => transform ( child , astNode . nodes ) )
91148 parent . push ( astNode )
92149 }
93150
94151 // AtRule
95152 else if ( node . type === 'atrule' ) {
96153 let astNode = atRule ( `@${ node . name } ` , node . params )
154+ astNode . src = toSource ( node )
97155 node . each ( ( child ) => transform ( child , astNode . nodes ) )
98156 parent . push ( astNode )
99157 }
100158
101159 // Comment
102160 else if ( node . type === 'comment' ) {
103161 if ( node . text . charCodeAt ( 0 ) !== EXCLAMATION_MARK ) return
104- parent . push ( comment ( node . text ) )
162+ let astNode = comment ( node . text )
163+ astNode . src = toSource ( node )
164+ parent . push ( astNode )
105165 }
106166
107167 // Unknown
0 commit comments