Skip to content

Commit

Permalink
fix: issue of group-modifier converting to sass
Browse files Browse the repository at this point in the history
Sass does not support the custom tailwind group-modifier approach. Now converting as a sub query.
  • Loading branch information
relliv committed Mar 18, 2022
1 parent f3bfa36 commit 955b0cd
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@egoistdeveloper/twcss-to-sass",
"version": "2.1.6",
"version": "2.1.7",
"description": "HTML template to SASS converter for TailwindCSS",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ npm i @egoistdeveloper/twcss-to-sass
- [x] ~~Fix self-closing tags like `link`, `base`, `area`, `br` etc~~
- [x] ~~Fix url conflict with class name in comment line~~
- [ ] Add option for duplicated classes
- [ ] Fix `group` and `peer` utility classes issue on SASS
- [ ] ~~Fix `group`~~ and `peer` utility classes issue on SASS
- [ ] Filter non tailwind classes
- [ ] Order classes
- [ ] Group classes
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/group-modifier-pair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface IGroupModifierPair {
modifier: string
utility: string
className: string
}

export default IGroupModifierPair
137 changes: 132 additions & 5 deletions src/twcss-to-sass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
IHtmlNodeAttribute,
} from './interfaces/html-node'
import { IConverterResult } from './interfaces/converter-result'
import { IGroupModifierPair } from './interfaces/group-modifier-pair'

/**
* Default js-beautify css formatter options
Expand Down Expand Up @@ -214,15 +215,117 @@ function getCssTree(cssTree: IHtmlNode[]): string {

if (styles.length > 0) {
cssTree.forEach((style: IHtmlNode, index) => {
css += `// #region Style Group ${index + 1}\n\n`
css += `/* #region Style Group ${index + 1} */\n\n`
css += `${style.content}\n`
css += `// #endregion\n\n`
css += `/* #endregion */\n\n`
})
}

return css
}

let groupModifierList: IGroupModifierPair[] = []

/**
* Convert group-* modifiers to sub-selectors
*
* @param nodeTree IHtmlNode[]
* @param deepth number
* @param isChildNodes boolean
*
* @returns string
*/
function groupUtilityToSass(
nodeTree: IHtmlNode[],
deepth: number,
isChildNodes = false
): string {
if (!isChildNodes) {
groupModifierList = []
}

let groupSass = ''

const groupPattern = / group-([a-z0-9]+):([a-z0-9-:\/]+)/gm

nodeTree.forEach((node: IHtmlNode) => {
if (node.filterAttributes) {
if (
node.filterAttributes.class &&
node.filterAttributes.class?.match(groupPattern)
) {
node.filterAttributes.class?.match(groupPattern)?.forEach((item) => {
const matches = new RegExp(groupPattern).exec(item)

const groupModifierPair = <IGroupModifierPair>{
modifier: matches?.[1],
utility: matches?.[2],
className: getClassName(node, deepth),
}

groupModifierList.push(groupModifierPair)
})

if (node.filterAttributes.class.match(/(group)(?!-)/gm)) {
return groupSass
} else if (node.children.length) {
groupUtilityToSass(node.children, ++deepth, true)
}
}
}
})

if (!isChildNodes) {
if (groupModifierList.length > 0) {
const modifierGroups = groupModifierList.reduce((prev, next) => {
prev[next.modifier] = prev[next.modifier] || []
prev[next.modifier].push(next)

return prev
}, Object.create(null))

Object.entries(modifierGroups)?.forEach(([modifier, utilityList]) => {
const _utilityList = <IGroupModifierPair[]>utilityList

const classGroups = _utilityList.reduce((prev, next) => {
prev[next.className] = prev[next.className] || []
prev[next.className].push(next)

return prev
}, Object.create(null))

groupSass += `&:${modifier} {\n`

Object.entries(classGroups)?.forEach(([className, utilityList]) => {
const _utilityList = <IGroupModifierPair[]>utilityList

const classList = _utilityList
.map((x: IGroupModifierPair) => x.utility)
.join(' ')

groupSass += `\t${className} {\n`
groupSass += `\t\t@apply ${classList};\n`
groupSass += `\t}\n`
})

groupSass += `}\n\n`

// const classList = _utilityList
// .map((x: IGroupModifierPair) => x.utility)
// .join(' ')

// groupSass += `&:${modifier} {\n`
// groupSass += `\t@apply ${classList};\n`
// groupSass += `}\n`
})
}

return groupSass
}

return ''
}

/**
* Extract SASS tree from HTML JSON tree
*
Expand All @@ -246,9 +349,14 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {
if (node.filterAttributes) {
// print tailwind class names
if (node.filterAttributes.class) {
treeString += node.filterAttributes.class
let tailwindClassList = node.filterAttributes.class
? `@apply ${node.filterAttributes.class};`
: ''

// remove group class
tailwindClassList = tailwindClassList.replace(/(group)(?!-)/gm, ' ')

treeString += tailwindClassList
}

// inline style printing
Expand All @@ -259,7 +367,7 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {
)

treeString += node.filterAttributes.style
? `\n${node.filterAttributes.style}\n`
? `\n\n${node.filterAttributes.style}`
: ''
}
}
Expand All @@ -273,7 +381,26 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {

const className = getClassName(node, deepth)

return `${classComment}${className}{${treeString}${subTreeString}}`
let groupUtilityTree = ''

if (node.filterAttributes?.class?.match(/(group)(?!-)/gm)) {
groupUtilityTree = groupUtilityToSass(node.children, deepth)

if (groupUtilityTree !== '') {
treeString += groupUtilityTree

// clear group modifier classes from @apply
subTreeString = subTreeString.replace(
/ group-([a-z0-9]+):([a-z0-9-:\/]+)/gm,
''
)
}
}

return `${classComment}
${className} {
${treeString} ${subTreeString}
}`
}

return null
Expand Down
1 change: 1 addition & 0 deletions test/twcss-to-sass.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ test('convert to sass with inline css', () => {
const sassOutput = `/* div -> 1 */
.class-div-1 {
@apply w-72 h-40 bg-green-400 transform transition-all;
border: 1px solid white;
padding: 30px;
font-weight: 50px;
Expand Down

0 comments on commit 955b0cd

Please sign in to comment.