Skip to content

Commit e96909a

Browse files
authored
Add tailwindcss canonicalize sub-command (#19783)
This PR adds a new `tailwindcss canonicalize` sub-command.
1 parent d5717f2 commit e96909a

8 files changed

Lines changed: 503 additions & 65 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import path from 'node:path'
2+
import { fileURLToPath } from 'node:url'
3+
import { describe, expect, test } from 'vitest'
4+
import { runCommandLine } from '.'
5+
import { normalizeWindowsSeparators } from '../../utils/test-helpers'
6+
7+
let css = normalizeWindowsSeparators(
8+
path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'fixtures/input.css'),
9+
)
10+
11+
describe('runCommandLine', () => {
12+
test('canonicalizes, collapses, and sorts candidate groups from positional arguments', async () => {
13+
let result = await runCommandLine({
14+
argv: ['--css', css, 'py-3 p-1 px-3'],
15+
stdinIsTTY: true,
16+
stdoutIsTTY: false,
17+
})
18+
19+
expect(result).toEqual({
20+
exitCode: 0,
21+
stdout: 'p-3',
22+
stderr: '',
23+
})
24+
})
25+
26+
test('falls back to the default tailwind import when --css is omitted', async () => {
27+
let result = await runCommandLine({
28+
argv: ['py-3 p-1 px-3'],
29+
cwd: path.dirname(css),
30+
stdinIsTTY: true,
31+
stdoutIsTTY: false,
32+
})
33+
34+
expect(result).toEqual({
35+
exitCode: 0,
36+
stdout: 'p-3',
37+
stderr: '',
38+
})
39+
})
40+
41+
test('canonicalizes, collapses, and sorts multiple groups from stdin lines', async () => {
42+
let result = await runCommandLine({
43+
argv: ['--css', css],
44+
stdin: '[display:_flex_] py-3 p-1 px-3\nmt-2 mr-2 mb-2 ml-2 focus:hover:p-3 hover:p-1 py-3\n',
45+
stdinIsTTY: false,
46+
stdoutIsTTY: false,
47+
})
48+
49+
expect(result).toEqual({
50+
exitCode: 0,
51+
stdout: 'flex p-3\nm-2 py-3 hover:p-1 focus:hover:p-3',
52+
stderr: '',
53+
})
54+
})
55+
56+
test('collapses equivalent candidates', async () => {
57+
let result = await runCommandLine({
58+
argv: ['--css', css, 'mt-2 mr-2 mb-2 ml-2'],
59+
stdinIsTTY: true,
60+
stdoutIsTTY: false,
61+
})
62+
63+
expect(result).toEqual({
64+
exitCode: 0,
65+
stdout: 'm-2',
66+
stderr: '',
67+
})
68+
})
69+
70+
test('renders json output for processed candidate groups', async () => {
71+
let result = await runCommandLine({
72+
argv: ['--css', css, '--format', 'json', 'py-3 p-1 px-3'],
73+
stdinIsTTY: true,
74+
stdoutIsTTY: false,
75+
})
76+
77+
expect(result.exitCode).toBe(0)
78+
expect(JSON.parse(result.stdout)).toEqual([
79+
{
80+
input: 'py-3 p-1 px-3',
81+
output: 'p-3',
82+
changed: true,
83+
},
84+
])
85+
expect(result.stderr).toBe('')
86+
})
87+
88+
test('splits candidate lists with segment-aware spacing', async () => {
89+
let result = await runCommandLine({
90+
argv: ['--css', css, '--format', 'json', "content-['hello world'] p-1"],
91+
stdinIsTTY: true,
92+
stdoutIsTTY: false,
93+
})
94+
95+
expect(result.exitCode).toBe(0)
96+
expect(JSON.parse(result.stdout)).toEqual([
97+
{
98+
input: "content-['hello world'] p-1",
99+
output: "p-1 content-['hello_world']",
100+
changed: true,
101+
},
102+
])
103+
expect(result.stderr).toBe('')
104+
})
105+
106+
test('shows a usage error when no candidate groups are provided', async () => {
107+
let result = await runCommandLine({
108+
argv: ['--css', css],
109+
stdinIsTTY: true,
110+
stdoutIsTTY: false,
111+
})
112+
113+
expect(result.exitCode).toBe(1)
114+
expect(result.stderr).toBe('No candidate groups provided')
115+
expect(result.stdout).toContain('Usage:')
116+
})
117+
118+
test('renders text help output', async () => {
119+
let result = await runCommandLine({
120+
argv: ['--help'],
121+
stdinIsTTY: true,
122+
stdoutIsTTY: false,
123+
})
124+
125+
expect(result).toEqual({
126+
exitCode: 0,
127+
stdout: expect.stringContaining('Usage:'),
128+
stderr: '',
129+
})
130+
expect(result.stdout).toContain('tailwindcss canonicalize [classes...]')
131+
expect(result.stdout).toContain('Options:')
132+
expect(result.stdout).not.toContain('markdown output')
133+
})
134+
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'tailwindcss';

0 commit comments

Comments
 (0)