Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ your tailwind.config.js.
- [variantChar: `[string]`](#variantchar-string)
- [separatorChar: `[string]`](#separatorchar-string)
- [expandOpenChar: `[string]` and expandCloseChar: `[string]`](#expandopenchar-string-and-expandclosechar-string)
- [compressWhitespaces: `[boolean]`](#compresswhitespaces-boolean)
- [Issues](#issues)
- [🐛 Bugs](#-bugs)
- [💡 Feature Requests](#-feature-requests)
Expand Down Expand Up @@ -244,6 +245,51 @@ export default function Hero({children}) {
}
```

### compressWhitespaces: `[boolean]`

- compressWhitespaces: _Default: `false`_

This allows users to allow compressing the whitespaces in their files. This is
added as a paramter so it doesn't break any existing user setups.

Change the call to `createTransformer` in your `tailwind.config.js`.

```javascript
// tailwind.config.js
const createTransformer = require('tailwind-group-variant')
module.exports = {
content: {
files: ['./app/**/*.{ts,tsx,jsx,js,mdx}'],
transform: createTransformer({ compressWhitespaces: true }),
},
...
}
```

The whitespaces in your components:

```tsx
export default function Hero({children}) {
return (
<div className=" relative z-10 pb-8 sm:pb-16 md:pb-20 lg:( max-w-2xl,w-full ) xl:pb-32 ">
{children}
</div>
)
}
```

will be transformed to:

```tsx
export default function Hero({children}) {
return (
<div className="relative z-10 pb-8 sm:pb-16 md:pb-20 lg:max-w-2xl lg:w-full xl:pb-32">
{children}
</div>
)
}
```

## Issues

_Looking to contribute? Look for the [Good First Issue][good-first-issue]
Expand Down
109 changes: 109 additions & 0 deletions src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,115 @@ describe.each(Object.entries(tests))(
},
)

const testsWithoutWhitespace: Record<string, TestCase> = {
'bad char after variant': {
input: `test dark: (p-2,m-3 lg:(p-3,m-4) )`,
output: `test dark: (p-2,m-3 lg:p-3 lg:m-4)`,
},
'bad char after stack opens': {
input: `test dark:( p-2, lg:(p-3,m-4) )`,
output: `test dark:(p-2, lg:p-3 lg:m-4)`,
},
'extra spacing inside variants': {
input: `test dark:( p-2,m-3 ) a`,
output: `test dark:p-2 dark:m-3 a`,
},
'extra spacing outside variants': {
input: ` test dark:(p-2,m-3) `,
output: `test dark:p-2 dark:m-3`,
},
}

describe.each(Object.entries(testsWithoutWhitespace))(
'group variants without whitespace',
(title, {input, output, only = false, skip = false, options}) => {
options = options ?? {}
options.compressWhitespaces = true

const testFn = () =>
expect(createTransformer(options)(input)).toEqual(output)

if (only) {
test.only(title, testFn)
} else if (skip) {
test.skip(title, testFn)
} else {
test(title, testFn)
}
},
)

const badCharTests: Record<string, TestCase> = {
'normal variant': {
input: `test lg:p-2 lg:m-3`,
output: `test lg:p-2 lg:m-3`,
},
'expand variant': {
input: `test lg:(p-2 m-3)`,
output: `test lg:p-2 lg:m-3`,
},
'expand nested variant': {
input: `test dark:(p-2 m-3 lg:(p-3 m-4))`,
output: `test dark:p-2 dark:m-3 dark:lg:p-3 dark:lg:m-4`,
},
'only use nested variant when outer has error': {
input: `test dark:(p-2 m-3 lg:(p-3 m-4))`,
output: `test dark:p-2 dark:m-3 dark:lg:p-3 dark:lg:m-4`,
},
'bad char after variant': {
input: `test dark: (p-2 m-3 lg:(p-3 m-4) )`,
output: `test dark: (p-2 m-3 lg:p-3 lg:m-4)`,
},
'close after open': {
input: `test dark:() p-2 m-3 lg:(p-3 m-4)`,
output: `test dark:() p-2 m-3 lg:p-3 lg:m-4`,
},
'nested normal variant': {
input: `test dark:(p-2 m-3 hover:text-blue)`,
output: `test dark:p-2 dark:m-3 dark:hover:text-blue`,
},
'nested group in middle of group': {
input: `test dark:(p-2 m-3 hover:(text-blue bg-red) text-red)`,
output: `test dark:p-2 dark:m-3 dark:text-red dark:hover:text-blue dark:hover:bg-red`,
},
'random char after stack close': {
input: `test dark:(p-2 m-3)a`,
output: `test dark:p-2 dark:m-3a`,
},
'random char after nested stack close': {
input: `test dark:(p-2 m-3 lg:(p-3 m-4)a)`,
output: `test dark:(p-2 m-3 lg:p-3 lg:m-4a)`,
},
'extra spacing inside variants': {
input: `test dark:( p-2 m-3 ) a`,
output: `test dark:p-2 dark:m-3 a`,
},
'extra spacing outside variants': {
input: ` test dark:(p-2 m-3) `,
output: `test dark:p-2 dark:m-3`,
},
}

describe.each(Object.entries(badCharTests))(
'group variants with bad char separator',
(title, {input, output, only = false, skip = false, options}) => {
options = options ?? {}
options.separatorChar = ' '
options.compressWhitespaces = true

const testFn = () =>
expect(createTransformer(options)(input)).toEqual(output)

if (only) {
test.only(title, testFn)
} else if (skip) {
test.skip(title, testFn)
} else {
test(title, testFn)
}
},
)

/*
eslint
jest/valid-title: "off",
Expand Down
21 changes: 20 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type TransformOptions = {
expandCloseChar?: string
separatorChar?: string
variantChar?: string
compressWhitespaces?: boolean
}

function stackClose(
Expand Down Expand Up @@ -158,6 +159,8 @@ const transformMachine: TransformMachine = {
if (char === machineState.settings.variantChar) {
machineState.context.variantEndIdx = idx
machineState.state = State.variant
} else if (char === machineState.settings.separatorChar) {
machineState.context.variantStartIdx = idx + 1
} else if (machineState.settings.badChars.includes(char)) {
machineState.state = State.init
}
Expand Down Expand Up @@ -221,7 +224,23 @@ const transformMachine: TransformMachine = {
},
}

function compressWhitespaces(content: string) {
return content
.replace(/\s+/g, ' ')
.replace(/\(\s+/g, '(')
.replace(/\s+\)/g, ')')
.trim()
}

function transform(content: string, options?: TransformOptions) {
if (options?.compressWhitespaces) {
content = compressWhitespaces(content)
}

let localBadChars = [...badChars, ...whitespaceChars].filter(
char => char !== options?.separatorChar,
)

const machineState: TransformMachineState = {
context: {
matches: [],
Expand All @@ -232,7 +251,7 @@ function transform(content: string, options?: TransformOptions) {
},
state: State.init,
settings: {
badChars: [...badChars, ...whitespaceChars],
badChars: localBadChars,
expandClose: options?.expandCloseChar ?? ')',
expandOpen: options?.expandOpenChar ?? '(',
separatorChar: options?.separatorChar ?? ',',
Expand Down