diff --git a/README.md b/README.md index 7bdb345..17b4159 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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 ( +
+ {children} +
+ ) +} +``` + +will be transformed to: + +```tsx +export default function Hero({children}) { + return ( +
+ {children} +
+ ) +} +``` + ## Issues _Looking to contribute? Look for the [Good First Issue][good-first-issue] diff --git a/src/__tests__/index.ts b/src/__tests__/index.ts index 085e6be..57ce056 100644 --- a/src/__tests__/index.ts +++ b/src/__tests__/index.ts @@ -76,6 +76,115 @@ describe.each(Object.entries(tests))( }, ) +const testsWithoutWhitespace: Record = { + '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 = { + '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", diff --git a/src/index.ts b/src/index.ts index c754b76..12fe55a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -54,6 +54,7 @@ type TransformOptions = { expandCloseChar?: string separatorChar?: string variantChar?: string + compressWhitespaces?: boolean } function stackClose( @@ -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 } @@ -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: [], @@ -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 ?? ',',