Skip to content

Commit 3b50a44

Browse files
author
Brad Cornes
committed
refactor class name extraction and stringify
1 parent 9caa94f commit 3b50a44

File tree

7 files changed

+287
-214
lines changed

7 files changed

+287
-214
lines changed

packages/tailwindcss-class-names/src/extractClassNames.mjs

Lines changed: 54 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,6 @@ function getClassNamesFromSelector(selector) {
1818
const { nodes: subSelectors } = selectorParser().astSync(selector)
1919

2020
for (let i = 0; i < subSelectors.length; i++) {
21-
// const final = subSelectors[i].nodes[subSelectors[i].nodes.length - 1]
22-
23-
// if (final.type === 'class') {
24-
// const scope = subSelectors[i].nodes.slice(
25-
// 0,
26-
// subSelectors[i].nodes.length - 1
27-
// )
28-
29-
// classNames.push({
30-
// className: String(final).trim(),
31-
// scope: createSelectorFromNodes(scope)
32-
// })
33-
// }
34-
3521
let scope = []
3622
for (let j = 0; j < subSelectors[i].nodes.length; j++) {
3723
let node = subSelectors[i].nodes[j]
@@ -47,39 +33,28 @@ function getClassNamesFromSelector(selector) {
4733
}
4834

4935
classNames.push({
50-
className: String(node)
51-
.trim()
52-
.substr(1),
36+
className: node.value.trim(),
5337
scope: createSelectorFromNodes(scope),
5438
__rule: j === subSelectors[i].nodes.length - 1,
55-
// __pseudo: createSelectorFromNodes(pseudo)
56-
__pseudo: pseudo.length === 0 ? null : pseudo.map(String)
39+
__pseudo: pseudo.length === 0 ? null : pseudo.map(String),
5740
})
5841
}
5942
scope.push(node, ...pseudo)
6043
}
6144
}
6245

63-
// console.log(classNames)
64-
6546
return classNames
6647
}
6748

68-
// console.log(getClassNamesFromSelector('h1, h2, h3, .foo .bar, .baz'))
69-
70-
// const css = fs.readFileSync(path.resolve(__dirname, 'tailwind.css'), 'utf8')
71-
7249
async function process(ast) {
73-
const start = new Date()
74-
7550
const tree = {}
7651
const commonContext = {}
7752

78-
ast.root.walkRules(rule => {
53+
ast.root.walkRules((rule) => {
7954
const classNames = getClassNamesFromSelector(rule.selector)
8055

81-
const decls = { __decls: true }
82-
rule.walkDecls(decl => {
56+
const decls = {}
57+
rule.walkDecls((decl) => {
8358
decls[decl.prop] = decl.value
8459
})
8560

@@ -96,49 +71,48 @@ async function process(ast) {
9671
const context = keys.concat([])
9772
const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__')
9873
const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
99-
100-
if (classNames[i].scope) {
101-
let index = []
102-
const existing = dlv(tree, baseKeys)
103-
if (typeof existing !== 'undefined') {
104-
if (Array.isArray(existing)) {
105-
const scopeIndex = existing.findIndex(
106-
x => x.__scope === classNames[i].scope
107-
)
108-
if (scopeIndex > -1) {
109-
keys.unshift(scopeIndex)
110-
index.push(scopeIndex)
111-
} else {
112-
keys.unshift(existing.length)
113-
index.push(existing.length)
114-
}
74+
const index = []
75+
76+
const existing = dlv(tree, baseKeys)
77+
if (typeof existing !== 'undefined') {
78+
if (Array.isArray(existing)) {
79+
const scopeIndex = existing.findIndex(
80+
(x) =>
81+
x.__scope === classNames[i].scope &&
82+
arraysEqual(existing.__context, context)
83+
)
84+
if (scopeIndex > -1) {
85+
keys.unshift(scopeIndex)
86+
index.push(scopeIndex)
11587
} else {
116-
if (existing.__scope !== classNames[i].scope) {
117-
dset(tree, baseKeys, [existing])
118-
keys.unshift(1)
119-
index.push(1)
120-
}
88+
keys.unshift(existing.length)
89+
index.push(existing.length)
12190
}
122-
}
123-
if (classNames[i].__rule) {
124-
dset(tree, [...baseKeys, ...index, '__rule'], true)
125-
dsetEach(tree, [...baseKeys, ...keys], decls)
126-
}
127-
if (classNames[i].__pseudo) {
128-
dset(tree, [...baseKeys, ...keys, '__pseudo'], classNames[i].__pseudo)
129-
}
130-
dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
131-
} else {
132-
if (classNames[i].__rule) {
133-
dset(tree, [...baseKeys, '__rule'], true)
134-
dsetEach(tree, [...baseKeys, ...keys], decls)
13591
} else {
136-
dset(tree, [...baseKeys, ...keys], {})
137-
}
138-
if (classNames[i].__pseudo) {
139-
dset(tree, [...baseKeys, ...keys, '__pseudo'], classNames[i].__pseudo)
92+
if (
93+
existing.__scope !== classNames[i].scope ||
94+
!arraysEqual(existing.__context, context)
95+
) {
96+
dset(tree, baseKeys, [existing])
97+
keys.unshift(1)
98+
index.push(1)
99+
}
140100
}
141101
}
102+
if (classNames[i].__rule) {
103+
dset(tree, [...baseKeys, ...index, '__rule'], true)
104+
105+
dsetEach(tree, [...baseKeys, ...index], decls)
106+
}
107+
if (classNames[i].__pseudo) {
108+
dset(tree, [...baseKeys, '__pseudo'], classNames[i].__pseudo)
109+
}
110+
dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
111+
dset(
112+
tree,
113+
[...baseKeys, ...index, '__context'],
114+
context.concat([]).reverse()
115+
)
142116

143117
// common context
144118
if (classNames[i].__pseudo) {
@@ -157,15 +131,12 @@ async function process(ast) {
157131
}
158132
}
159133
})
160-
// console.log(`${new Date() - start}ms`)
161-
// console.log(tree)
162-
// console.log(commonContext)
163134

164135
return { classNames: tree, context: commonContext }
165136
}
166137

167138
function intersection(arr1, arr2) {
168-
return arr1.filter(value => arr2.indexOf(value) !== -1)
139+
return arr1.filter((value) => arr2.indexOf(value) !== -1)
169140
}
170141

171142
function dsetEach(obj, keys, values) {
@@ -175,14 +146,15 @@ function dsetEach(obj, keys, values) {
175146
}
176147
}
177148

178-
export default process
149+
function arraysEqual(a, b) {
150+
if (a === b) return true
151+
if (a == null || b == null) return false
152+
if (a.length !== b.length) return false
179153

180-
// process(`
181-
// .bg-red {
182-
// background-color: red;
183-
// }
184-
// .bg-red {
185-
// color: white;
186-
// }`).then(x => {
187-
// console.log(x)
188-
// })
154+
for (let i = 0; i < a.length; ++i) {
155+
if (a[i] !== b[i]) return false
156+
}
157+
return true
158+
}
159+
160+
export default process

0 commit comments

Comments
 (0)