import { __unstable__loadDesignSystem } from '@tailwindcss/node'
import { expect, test, vi } from 'vitest'
import type { UserConfig } from '../../../../tailwindcss/src/compat/config/types'
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
import * as versions from '../../utils/version'
import { migrateArbitraryVariants } from './migrate-arbitrary-variants'
import { migrateEmptyArbitraryValues } from './migrate-handle-empty-arbitrary-values'
import { migrateModernizeArbitraryValues } from './migrate-modernize-arbitrary-values'
import { migratePrefix } from './migrate-prefix'
vi.spyOn(versions, 'isMajor').mockReturnValue(true)
function migrate(designSystem: DesignSystem, userConfig: UserConfig | null, rawCandidate: string) {
for (let migration of [
migrateEmptyArbitraryValues,
migratePrefix,
migrateModernizeArbitraryValues,
migrateArbitraryVariants,
]) {
rawCandidate = migration(designSystem, userConfig, rawCandidate)
}
return rawCandidate
}
test.each([
['[[data-visible]]:flex', 'data-visible:flex'],
['[&[data-visible]]:flex', 'data-visible:flex'],
['[[data-visible]&]:flex', 'data-visible:flex'],
['[&>[data-visible]]:flex', '*:data-visible:flex'],
['[&_>_[data-visible]]:flex', '*:data-visible:flex'],
['[&>*]:flex', '*:flex'],
['[&_>_*]:flex', '*:flex'],
['[&_[data-visible]]:flex', '**:data-visible:flex'],
['[&_*]:flex', '**:flex'],
['[&:first-child]:flex', 'first:flex'],
['[&:not(:first-child)]:flex', 'not-first:flex'],
['[p_&]:flex', 'in-[p]:flex'],
['[.foo_&]:flex', 'in-[.foo]:flex'],
['[[data-visible]_&]:flex', 'in-data-visible:flex'],
['[[data-foo][data-bar]_&]:flex', '[[data-foo][data-bar]_&]:flex'],
['[figure>&]:my-0', '[figure>&]:my-0'],
['group-[]:flex', 'in-[.group]:flex'],
['group-[]/name:flex', 'in-[.group\\/name]:flex'],
['peer-[]:flex', 'peer-[&]:flex'],
['peer-[]/name:flex', 'peer-[&]/name:flex'],
['has-group-[]:flex', 'has-in-[.group]:flex'],
['has-group-[]/name:flex', 'has-in-[.group\\/name]:flex'],
['not-group-[]:flex', 'not-in-[.group]:flex'],
['not-group-[]/name:flex', 'not-in-[.group\\/name]:flex'],
['[&:nth-child(2)]:flex', 'nth-2:flex'],
['[&:not(:nth-child(2))]:flex', 'not-nth-2:flex'],
['[&:nth-child(-n+3)]:flex', 'nth-[-n+3]:flex'],
['[&:not(:nth-child(-n+3))]:flex', 'not-nth-[-n+3]:flex'],
['[&:nth-child(-n_+_3)]:flex', 'nth-[-n+3]:flex'],
['[&:not(:nth-child(-n_+_3))]:flex', 'not-nth-[-n+3]:flex'],
['[&:nth-last-child(2)]:flex', 'nth-last-2:flex'],
['[&:not(:nth-last-child(2))]:flex', 'not-nth-last-2:flex'],
['[&:nth-last-child(-n+3)]:flex', 'nth-last-[-n+3]:flex'],
['[&:not(:nth-last-child(-n+3))]:flex', 'not-nth-last-[-n+3]:flex'],
['[&:nth-last-child(-n_+_3)]:flex', 'nth-last-[-n+3]:flex'],
['[&:not(:nth-last-child(-n_+_3))]:flex', 'not-nth-last-[-n+3]:flex'],
['[&:nth-child(odd)]:flex', 'odd:flex'],
['[&:not(:nth-child(odd))]:flex', 'even:flex'],
['[&:nth-child(even)]:flex', 'even:flex'],
['[&:not(:nth-child(even))]:flex', 'odd:flex'],
['[[data-visible][data-dark]]:flex', '[[data-visible][data-dark]]:flex'],
['[:where([data-visible])]:flex', '[:where([data-visible])]:flex'],
['[[data-url*="example"]]:flex', 'data-[url*="example"]:flex'],
['[[data-url$=".com"_i]]:flex', 'data-[url$=".com"_i]:flex'],
['[[data-url$=.com_i]]:flex', 'data-[url$=.com_i]:flex'],
['[&:is([data-visible])]:flex', 'data-visible:flex'],
['[@media(pointer:fine)]:flex', 'pointer-fine:flex'],
['[@media_(pointer_:_fine)]:flex', 'pointer-fine:flex'],
['[@media_not_(pointer_:_fine)]:flex', 'not-pointer-fine:flex'],
['[@media_print]:flex', 'print:flex'],
['[@media_not_print]:flex', 'not-print:flex'],
['[@media_not_(prefers-color-scheme:dark)]:flex', 'not-dark:flex'],
[
'[@media_not_(prefers-color-scheme:unknown)]:flex',
'not-[@media_(prefers-color-scheme:unknown)]:flex',
],
['has-[[data-visible]]:flex', 'has-data-visible:flex'],
['has-[&:is([data-visible])]:flex', 'has-data-visible:flex'],
['has-[&>[data-visible]]:flex', 'has-[&>[data-visible]]:flex'],
['has-[[data-slot=description]]:flex', 'has-data-[slot=description]:flex'],
['has-[&:is([data-slot=description])]:flex', 'has-data-[slot=description]:flex'],
['has-[[aria-visible="true"]]:flex', 'has-aria-visible:flex'],
['has-[[aria-visible]]:flex', 'has-aria-[visible]:flex'],
['has-[&:not(:nth-child(even))]:flex', 'has-odd:flex'],
])('%s => %s (%#)', async (candidate, result) => {
let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', {
base: __dirname,
})
expect(migrate(designSystem, {}, candidate)).toEqual(result)
})
test.each([
['[.foo_&]:tw-flex', 'tw:in-[.foo]:flex'],
['group-[]:tw-flex', 'tw:in-[.tw\\:group]:flex'],
['group-[]/name:tw-flex', 'tw:in-[.tw\\:group\\/name]:flex'],
['peer-[]:tw-flex', 'tw:peer-[&]:flex'],
['peer-[]/name:tw-flex', 'tw:peer-[&]/name:flex'],
['[.group_&]:tw-flex', 'tw:in-[.group]:flex'],
['has-group-[]:tw-flex', 'tw:has-in-[.tw\\:group]:flex'],
['has-group-[]/name:tw-flex', 'tw:has-in-[.tw\\:group\\/name]:flex'],
['not-group-[]:tw-flex', 'tw:not-in-[.tw\\:group]:flex'],
['not-group-[]/name:tw-flex', 'tw:not-in-[.tw\\:group\\/name]:flex'],
])('%s => %s (%#)', async (candidate, result) => {
let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss" prefix(tw);', {
base: __dirname,
})
expect(migrate(designSystem, { prefix: 'tw-' }, candidate)).toEqual(result)
})