Skip to content

Commit

Permalink
Merge pull request #450 from XantreDev/main
Browse files Browse the repository at this point in the history
refactor(perf): reduce allocations overhead from mergeClassList
  • Loading branch information
dcastil authored Jul 29, 2024
2 parents 38db48d + 80e6af4 commit 1d82a24
Showing 1 changed file with 62 additions and 84 deletions.
146 changes: 62 additions & 84 deletions src/lib/merge-classlist.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { ConfigUtils } from './config-utils'
import { IMPORTANT_MODIFIER, sortModifiers } from './parse-class-name'

const SPLIT_CLASSES_REGEX = /\s+/

export const mergeClassList = (classList: string, configUtils: ConfigUtils) => {
const { parseClassName, getClassGroupId, getConflictingClassGroupIds } = configUtils

Expand All @@ -13,86 +11,66 @@ export const mergeClassList = (classList: string, configUtils: ConfigUtils) => {
* @example 'hover:focus:bg-color'
* @example 'md:!pr'
*/
const classGroupsInConflict = new Set<string>()

return (
classList
.trim()
.split(SPLIT_CLASSES_REGEX)
.map((originalClassName) => {
const {
modifiers,
hasImportantModifier,
baseClassName,
maybePostfixModifierPosition,
} = parseClassName(originalClassName)

let hasPostfixModifier = Boolean(maybePostfixModifierPosition)
let classGroupId = getClassGroupId(
hasPostfixModifier
? baseClassName.substring(0, maybePostfixModifierPosition)
: baseClassName,
)

if (!classGroupId) {
if (!hasPostfixModifier) {
return {
isTailwindClass: false as const,
originalClassName,
}
}

classGroupId = getClassGroupId(baseClassName)

if (!classGroupId) {
return {
isTailwindClass: false as const,
originalClassName,
}
}

hasPostfixModifier = false
}

const variantModifier = sortModifiers(modifiers).join(':')

const modifierId = hasImportantModifier
? variantModifier + IMPORTANT_MODIFIER
: variantModifier

return {
isTailwindClass: true as const,
modifierId,
classGroupId,
originalClassName,
hasPostfixModifier,
}
})
.reverse()
// Last class in conflict wins, so we need to filter conflicting classes in reverse order.
.filter((parsed) => {
if (!parsed.isTailwindClass) {
return true
}

const { modifierId, classGroupId, hasPostfixModifier } = parsed

const classId = modifierId + classGroupId

if (classGroupsInConflict.has(classId)) {
return false
}

classGroupsInConflict.add(classId)

getConflictingClassGroupIds(classGroupId, hasPostfixModifier).forEach((group) =>
classGroupsInConflict.add(modifierId + group),
)

return true
})
.reverse()
.map((parsed) => parsed.originalClassName)
.join(' ')
)
const classGroupsInConflict: string[] = []

let result = ''

for (let i = classList.length - 1; i >= 0; ) {
while (classList[i] === ' ') {
--i
}
const nextI = classList.lastIndexOf(' ', i)
const originalClassName = classList.slice(nextI === -1 ? 0 : nextI + 1, i + 1)
i = nextI

const { modifiers, hasImportantModifier, baseClassName, maybePostfixModifierPosition } =
parseClassName(originalClassName)

let hasPostfixModifier = Boolean(maybePostfixModifierPosition)
let classGroupId = getClassGroupId(
hasPostfixModifier
? baseClassName.substring(0, maybePostfixModifierPosition)
: baseClassName,
)

if (!classGroupId) {
if (!hasPostfixModifier) {
result = originalClassName + (result.length > 0 ? ' ' + result : result)
continue
}

classGroupId = getClassGroupId(baseClassName)

if (!classGroupId) {
result = originalClassName + (result.length > 0 ? ' ' + result : result)
continue
}

hasPostfixModifier = false
}

const variantModifier = sortModifiers(modifiers).join(':')

const modifierId = hasImportantModifier
? variantModifier + IMPORTANT_MODIFIER
: variantModifier

const classId = modifierId + classGroupId

if (classGroupsInConflict.includes(classId)) {
continue
}

classGroupsInConflict.push(classId)

const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier)
for (let i = 0; i < conflictGroups.length; ++i) {
const group = conflictGroups[i]!
classGroupsInConflict.push(modifierId + group)
}

result = originalClassName + (result.length > 0 ? ' ' + result : result)
}

return result
}

0 comments on commit 1d82a24

Please sign in to comment.