-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Expand file tree
/
Copy pathcss.ts
More file actions
74 lines (71 loc) · 2.26 KB
/
Copy pathcss.ts
File metadata and controls
74 lines (71 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import postcss, { type ChildNode, type Node } from 'postcss'
import type { Definition } from '#design-diff/types'
function context(node: ChildNode): string[] {
const result: string[] = []
let parent: Node | undefined = node.parent
while (parent && parent.type !== 'root' && parent.type !== 'document') {
result.unshift(
'selector' in parent
? String(parent.selector)
: 'name' in parent && 'params' in parent
? `@${parent.name} ${parent.params}`
: parent.type
)
parent = parent.parent
}
return result
}
export function extractCss(source: string, file: string): Definition[] {
const result: Definition[] = []
const root = postcss.parse(source, { from: file })
let order = 0
root.walk((node) => {
if (node.type === 'comment') return
const chain = context(node)
const selector = chain.join(' > ')
const base = {
location: {
file,
line: node.source?.start?.line ?? 1,
column: node.source?.start?.column ?? 1,
},
symbol: selector || 'stylesheet',
conditions: chain,
dependencies: [file],
unresolved: [],
}
if (node.type === 'decl') {
result.push({
...base,
key: `css:${selector}:${node.prop}:${order}`,
kind: 'css',
property: node.prop,
value: { value: node.value, important: node.important, order: order++ },
})
} else if (node.type === 'atrule' && !node.nodes) {
result.push({
...base,
key: `at:${order}`,
kind: ['import', 'plugin', 'config', 'apply', 'source'].includes(node.name)
? 'review'
: 'css',
property: `@${node.name}`,
value: { params: node.params, order: order++ },
})
}
})
return result
}
/** Stable CSS representation, retaining selector, conditional and cascade order. */
export function cssValue(source: string): string {
const root = postcss.parse(source)
root.walkComments((comment) => {
comment.remove()
})
const value: unknown[] = []
root.walk((node) => {
if (node.type === 'decl') value.push([context(node), node.prop, node.value, node.important])
if (node.type === 'atrule' && !node.nodes) value.push([context(node), node.name, node.params])
})
return JSON.stringify(value)
}