Skip to content

Commit e0f9bd5

Browse files
authored
Tidy whitespace and remove duplicates (#70)
* Remove duplicate classes * Trim whitespace from class lists * Don't tidy whitespace in multi-line class lists * Update tests * `trim` -> `tidy` * Formatting * Update tests * Formatting
1 parent f03d66c commit e0f9bd5

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

src/index.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@ function getClassOrderPolyfill(classes, { env }) {
6565

6666
function sortClasses(
6767
classStr,
68-
{ env, ignoreFirst = false, ignoreLast = false }
68+
{
69+
env,
70+
ignoreFirst = false,
71+
ignoreLast = false,
72+
tidyWhitespace = { start: true, end: true },
73+
}
6974
) {
7075
if (typeof classStr !== 'string' || classStr === '') {
7176
return classStr
@@ -77,6 +82,10 @@ function sortClasses(
7782
return classStr
7883
}
7984

85+
if (classStr.includes('\n')) {
86+
tidyWhitespace = false
87+
}
88+
8089
let result = ''
8190
let parts = classStr.split(/(\s+)/)
8291
let classes = parts.filter((_, i) => i % 2 === 0)
@@ -86,6 +95,10 @@ function sortClasses(
8695
classes.pop()
8796
}
8897

98+
if (tidyWhitespace) {
99+
whitespace = whitespace.map(() => ' ')
100+
}
101+
89102
let prefix = ''
90103
if (ignoreFirst) {
91104
prefix = `${classes.shift() ?? ''}${whitespace.shift() ?? ''}`
@@ -96,6 +109,15 @@ function sortClasses(
96109
suffix = `${whitespace.pop() ?? ''}${classes.pop() ?? ''}`
97110
}
98111

112+
// Remove duplicates
113+
classes = classes.filter((cls, index, arr) => {
114+
if (arr.indexOf(cls) === index) {
115+
return true
116+
}
117+
whitespace.splice(index - 1, 1)
118+
return false
119+
})
120+
99121
let classNamesWithOrder = env.context.getClassOrder
100122
? env.context.getClassOrder(classes)
101123
: getClassOrderPolyfill(classes, { env })
@@ -115,6 +137,12 @@ function sortClasses(
115137
result += `${classes[i]}${whitespace[i] ?? ''}`
116138
}
117139

140+
if (tidyWhitespace) {
141+
result = result
142+
.replace(/^\s+/, tidyWhitespace.start ? '' : ' ')
143+
.replace(/\s+$/, tidyWhitespace.end ? '' : ' ')
144+
}
145+
118146
return prefix + result + suffix
119147
}
120148

@@ -287,6 +315,10 @@ function sortTemplateLiteral(node, { env }) {
287315
env,
288316
ignoreFirst: i > 0 && !/^\s/.test(quasi.value.raw),
289317
ignoreLast: i < node.expressions.length && !/\s$/.test(quasi.value.raw),
318+
tidyWhitespace: {
319+
start: i === 0,
320+
end: i >= node.expressions.length,
321+
},
290322
})
291323

292324
quasi.value.cooked = same
@@ -296,6 +328,10 @@ function sortTemplateLiteral(node, { env }) {
296328
ignoreFirst: i > 0 && !/^\s/.test(quasi.value.cooked),
297329
ignoreLast:
298330
i < node.expressions.length && !/\s$/.test(quasi.value.cooked),
331+
tidyWhitespace: {
332+
start: i === 0,
333+
end: i >= node.expressions.length,
334+
},
299335
})
300336

301337
if (
@@ -444,6 +480,10 @@ function transformSvelte(ast, { env, changes }) {
444480
env,
445481
ignoreFirst: i > 0 && !/^\s/.test(value.raw),
446482
ignoreLast: i < attr.value.length - 1 && !/\s$/.test(value.raw),
483+
tidyWhitespace: {
484+
start: i === 0,
485+
end: i >= attr.value.length - 1,
486+
},
447487
})
448488
value.data = same
449489
? value.raw
@@ -452,6 +492,10 @@ function transformSvelte(ast, { env, changes }) {
452492
ignoreFirst: i > 0 && !/^\s/.test(value.data),
453493
ignoreLast:
454494
i < attr.value.length - 1 && !/\s$/.test(value.data),
495+
tidyWhitespace: {
496+
start: i === 0,
497+
end: i >= attr.value.length - 1,
498+
},
455499
})
456500
} else if (value.type === 'MustacheTag') {
457501
visit(value.expression, {

tests/test.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ let html = [
5959
['<div class=" sm:p-0 p-0 "></div>', '<div class="p-0 sm:p-0"></div>'],
6060
t`<div class></div>`,
6161
t`<div class=""></div>`,
62+
['<div class="sm:p-0 p-0 p-0"></div>', '<div class="p-0 sm:p-0"></div>'],
6263
]
6364

6465
let css = [
@@ -95,6 +96,24 @@ let javascript = [
9596
`;<div class={\`sm:p-0 p-0 \${someVar}sm:block md:inline flex\`} />`,
9697
`;<div class={\`p-0 sm:p-0 \${someVar}sm:block flex md:inline\`} />`,
9798
],
99+
[
100+
';<div class=" m-0 sm:p-0 p-0 " />',
101+
';<div class="m-0 p-0 sm:p-0" />',
102+
],
103+
[
104+
";<div class={' m-0 sm:p-0 p-0 '} />",
105+
";<div class={'m-0 p-0 sm:p-0'} />",
106+
],
107+
[
108+
';<div class={` sm:p-0\n p-0 `} />',
109+
';<div\n class={` p-0\n sm:p-0 `}\n/>',
110+
],
111+
[';<div class="flex flex" />', ';<div class="flex" />'],
112+
[';<div class={` flex flex `} />', ';<div class={`flex`} />'],
113+
[
114+
';<div class={` flex flex flex${someVar}block block`} />',
115+
';<div class={`flex flex${someVar}block block`} />',
116+
],
98117
]
99118
javascript = javascript.concat(
100119
javascript.map((test) => test.map((t) => t.replace(/class/g, 'className')))
@@ -128,6 +147,8 @@ let vue = [
128147
`<div :class="\`sm:p-0 p-0 \${someVar}sm:block md:inline flex\`"></div>`,
129148
`<div :class="\`p-0 sm:p-0 \${someVar}sm:block flex md:inline\`"></div>`,
130149
],
150+
[`<div :class="' flex flex '"></div>`, `<div :class="'flex'"></div>`],
151+
[`<div :class="\` flex flex \`"></div>`, `<div :class="\`flex\`"></div>`],
131152
]
132153

133154
let tests = {
@@ -180,7 +201,6 @@ let tests = {
180201
`<div class="sm:p-0 p-0 {someVar}sm:block md:inline flex" />`,
181202
`<div class="p-0 sm:p-0 {someVar}sm:block flex md:inline" />`,
182203
],
183-
['<div class={`sm:p-0\np-0`} />', '<div\n class={`p-0\nsm:p-0`}\n/>'],
184204
],
185205
}
186206

0 commit comments

Comments
 (0)