@@ -12,6 +12,7 @@ import {
1212 IHtmlNodeAttribute ,
1313} from './interfaces/html-node'
1414import { IConverterResult } from './interfaces/converter-result'
15+ import { IGroupModifierPair } from './interfaces/group-modifier-pair'
1516
1617/**
1718 * Default js-beautify css formatter options
@@ -214,15 +215,117 @@ function getCssTree(cssTree: IHtmlNode[]): string {
214215
215216 if ( styles . length > 0 ) {
216217 cssTree . forEach ( ( style : IHtmlNode , index ) => {
217- css += `// #region Style Group ${ index + 1 } \n\n`
218+ css += `/* #region Style Group ${ index + 1 } */ \n\n`
218219 css += `${ style . content } \n`
219- css += `// #endregion\n\n`
220+ css += `/* #endregion */ \n\n`
220221 } )
221222 }
222223
223224 return css
224225}
225226
227+ let groupModifierList : IGroupModifierPair [ ] = [ ]
228+
229+ /**
230+ * Convert group-* modifiers to sub-selectors
231+ *
232+ * @param nodeTree IHtmlNode[]
233+ * @param deepth number
234+ * @param isChildNodes boolean
235+ *
236+ * @returns string
237+ */
238+ function groupUtilityToSass (
239+ nodeTree : IHtmlNode [ ] ,
240+ deepth : number ,
241+ isChildNodes = false
242+ ) : string {
243+ if ( ! isChildNodes ) {
244+ groupModifierList = [ ]
245+ }
246+
247+ let groupSass = ''
248+
249+ const groupPattern = / g r o u p - ( [ a - z 0 - 9 ] + ) : ( [ a - z 0 - 9 -:\/ ] + ) / gm
250+
251+ nodeTree . forEach ( ( node : IHtmlNode ) => {
252+ if ( node . filterAttributes ) {
253+ if (
254+ node . filterAttributes . class &&
255+ node . filterAttributes . class ?. match ( groupPattern )
256+ ) {
257+ node . filterAttributes . class ?. match ( groupPattern ) ?. forEach ( ( item ) => {
258+ const matches = new RegExp ( groupPattern ) . exec ( item )
259+
260+ const groupModifierPair = < IGroupModifierPair > {
261+ modifier : matches ?. [ 1 ] ,
262+ utility : matches ?. [ 2 ] ,
263+ className : getClassName ( node , deepth ) ,
264+ }
265+
266+ groupModifierList . push ( groupModifierPair )
267+ } )
268+
269+ if ( node . filterAttributes . class . match ( / ( g r o u p ) (? ! - ) / gm) ) {
270+ return groupSass
271+ } else if ( node . children . length ) {
272+ groupUtilityToSass ( node . children , ++ deepth , true )
273+ }
274+ }
275+ }
276+ } )
277+
278+ if ( ! isChildNodes ) {
279+ if ( groupModifierList . length > 0 ) {
280+ const modifierGroups = groupModifierList . reduce ( ( prev , next ) => {
281+ prev [ next . modifier ] = prev [ next . modifier ] || [ ]
282+ prev [ next . modifier ] . push ( next )
283+
284+ return prev
285+ } , Object . create ( null ) )
286+
287+ Object . entries ( modifierGroups ) ?. forEach ( ( [ modifier , utilityList ] ) => {
288+ const _utilityList = < IGroupModifierPair [ ] > utilityList
289+
290+ const classGroups = _utilityList . reduce ( ( prev , next ) => {
291+ prev [ next . className ] = prev [ next . className ] || [ ]
292+ prev [ next . className ] . push ( next )
293+
294+ return prev
295+ } , Object . create ( null ) )
296+
297+ groupSass += `&:${ modifier } {\n`
298+
299+ Object . entries ( classGroups ) ?. forEach ( ( [ className , utilityList ] ) => {
300+ const _utilityList = < IGroupModifierPair [ ] > utilityList
301+
302+ const classList = _utilityList
303+ . map ( ( x : IGroupModifierPair ) => x . utility )
304+ . join ( ' ' )
305+
306+ groupSass += `\t${ className } {\n`
307+ groupSass += `\t\t@apply ${ classList } ;\n`
308+ groupSass += `\t}\n`
309+ } )
310+
311+ groupSass += `}\n\n`
312+
313+ // const classList = _utilityList
314+ // .map((x: IGroupModifierPair) => x.utility)
315+ // .join(' ')
316+
317+ // groupSass += `&:${modifier} {\n`
318+ // groupSass += `\t@apply ${classList};\n`
319+ // groupSass += ` }\n`
320+ } )
321+ }
322+
323+ return groupSass
324+ }
325+
326+ return ''
327+ }
328+
226329/**
227330 * Extract SASS tree from HTML JSON tree
228331 *
@@ -246,9 +349,14 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {
246349 if ( node . filterAttributes ) {
247350 // print tailwind class names
248351 if ( node . filterAttributes . class ) {
249- treeString + = node . filterAttributes . class
352+ let tailwindClassList = node . filterAttributes . class
250353 ? `@apply ${ node . filterAttributes . class } ;`
251354 : ''
355+
356+ // remove group class
357+ tailwindClassList = tailwindClassList . replace ( / ( g r o u p ) (? ! - ) / gm, ' ' )
358+
359+ treeString += tailwindClassList
252360 }
253361
254362 // inline style printing
@@ -259,7 +367,7 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {
259367 )
260368
261369 treeString += node . filterAttributes . style
262- ? `\n${ node . filterAttributes . style } \n `
370+ ? `\n\n ${ node . filterAttributes . style } `
263371 : ''
264372 }
265373 }
@@ -273,7 +381,26 @@ function getSassTree(nodeTree: IHtmlNode[], deepth = 0) {
273381
274382 const className = getClassName ( node , deepth )
275383
276- return `${ classComment } ${ className } {${ treeString } ${ subTreeString } }`
384+ let groupUtilityTree = ''
385+
386+ if ( node . filterAttributes ?. class ?. match ( / ( g r o u p ) (? ! - ) / gm) ) {
387+ groupUtilityTree = groupUtilityToSass ( node . children , deepth )
388+
389+ if ( groupUtilityTree !== '' ) {
390+ treeString += groupUtilityTree
391+
392+ // clear group modifier classes from @apply
393+ subTreeString = subTreeString . replace (
394+ / g r o u p - ( [ a - z 0 - 9 ] + ) : ( [ a - z 0 - 9 -:\/ ] + ) / gm,
395+ ''
396+ )
397+ }
398+ }
399+
400+ return `${ classComment }
401+ ${ className } {
402+ ${ treeString } ${ subTreeString }
403+ }`
277404 }
278405
279406 return null
0 commit comments