1
1
import postcss , {
2
+ Input ,
2
3
type ChildNode as PostCssChildNode ,
3
4
type Container as PostCssContainerNode ,
4
5
type Root as PostCssRoot ,
5
6
type Source as PostcssSource ,
6
7
} from 'postcss'
7
8
import { 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'
8
12
9
13
const EXCLAMATION_MARK = 0x21
10
14
11
15
export 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
+
12
25
let root = postcss . root ( )
13
26
root . source = source
14
27
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
+
35
+ return {
36
+ input : inputMap . get ( loc [ 0 ] ) ,
37
+ start : {
38
+ ...table . find ( loc [ 1 ] ) ,
39
+ offset : loc [ 1 ] ,
40
+ } ,
41
+ end : {
42
+ ...table . find ( loc [ 2 ] ) ,
43
+ offset : loc [ 2 ] ,
44
+ } ,
45
+ }
46
+ }
47
+
15
48
function transform ( node : AstNode , parent : PostCssContainerNode ) {
16
49
// Declaration
17
50
if ( node . kind === 'declaration' ) {
@@ -20,14 +53,14 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
20
53
value : node . value ?? '' ,
21
54
important : node . important ,
22
55
} )
23
- astNode . source = source
56
+ astNode . source = toSource ( node . src )
24
57
parent . append ( astNode )
25
58
}
26
59
27
60
// Rule
28
61
else if ( node . kind === 'rule' ) {
29
62
let astNode = postcss . rule ( { selector : node . selector } )
30
- astNode . source = source
63
+ astNode . source = toSource ( node . src )
31
64
astNode . raws . semicolon = true
32
65
parent . append ( astNode )
33
66
for ( let child of node . nodes ) {
@@ -38,7 +71,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
38
71
// AtRule
39
72
else if ( node . kind === 'at-rule' ) {
40
73
let astNode = postcss . atRule ( { name : node . name . slice ( 1 ) , params : node . params } )
41
- astNode . source = source
74
+ astNode . source = toSource ( node . src )
42
75
astNode . raws . semicolon = true
43
76
parent . append ( astNode )
44
77
for ( let child of node . nodes ) {
@@ -53,7 +86,7 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
53
86
// spaces.
54
87
astNode . raws . left = ''
55
88
astNode . raws . right = ''
56
- astNode . source = source
89
+ astNode . source = toSource ( node . src )
57
90
parent . append ( astNode )
58
91
}
59
92
@@ -75,33 +108,56 @@ export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undef
75
108
}
76
109
77
110
export function postCssAstToCssAst ( root : PostCssRoot ) : AstNode [ ] {
111
+ let inputMap = new DefaultMap < Input , Source > ( ( input ) => ( {
112
+ file : input . file ?? input . id ?? null ,
113
+ code : input . css ,
114
+ } ) )
115
+
116
+ function toSource ( node : PostCssChildNode ) : SourceLocation | undefined {
117
+ let source = node . source
118
+ if ( ! source ) return
119
+
120
+ let input = source . input
121
+ if ( ! input ) return
122
+ if ( source . start === undefined ) return
123
+ if ( source . end === undefined ) return
124
+
125
+ return [ inputMap . get ( input ) , source . start . offset , source . end . offset ]
126
+ }
127
+
78
128
function transform (
79
129
node : PostCssChildNode ,
80
130
parent : Extract < AstNode , { nodes : AstNode [ ] } > [ 'nodes' ] ,
81
131
) {
82
132
// Declaration
83
133
if ( node . type === 'decl' ) {
84
- parent . push ( decl ( node . prop , node . value , node . important ) )
134
+ let astNode = decl ( node . prop , node . value , node . important )
135
+ astNode . src = toSource ( node )
136
+ parent . push ( astNode )
85
137
}
86
138
87
139
// Rule
88
140
else if ( node . type === 'rule' ) {
89
141
let astNode = rule ( node . selector )
142
+ astNode . src = toSource ( node )
90
143
node . each ( ( child ) => transform ( child , astNode . nodes ) )
91
144
parent . push ( astNode )
92
145
}
93
146
94
147
// AtRule
95
148
else if ( node . type === 'atrule' ) {
96
149
let astNode = atRule ( `@${ node . name } ` , node . params )
150
+ astNode . src = toSource ( node )
97
151
node . each ( ( child ) => transform ( child , astNode . nodes ) )
98
152
parent . push ( astNode )
99
153
}
100
154
101
155
// Comment
102
156
else if ( node . type === 'comment' ) {
103
157
if ( node . text . charCodeAt ( 0 ) !== EXCLAMATION_MARK ) return
104
- parent . push ( comment ( node . text ) )
158
+ let astNode = comment ( node . text )
159
+ astNode . src = toSource ( node )
160
+ parent . push ( astNode )
105
161
}
106
162
107
163
// Unknown
0 commit comments