Skip to content

Commit 36d2871

Browse files
committed
feat: auto class name from comment block
1 parent 02c6d67 commit 36d2871

File tree

8 files changed

+2052
-645
lines changed

8 files changed

+2052
-645
lines changed

docs/index.html

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100

101101
<!-- twcss-to-sass -->
102102
<script src="https://unpkg.com/@egoistdeveloper/twcss-to-sass@latest/dist/umd/index.js"></script>
103+
<!-- <script src="../dist/umd/index.js"></script> -->
103104

104105
<!-- Monaco Editor -->
105106
<script>
@@ -143,15 +144,27 @@
143144

144145
const {
145146
convertToSass
146-
} = TwCssToSass,
147-
theme = this.getCurrentTheme(),
147+
} = TwCssToSass;
148+
149+
const theme = this.getCurrentTheme(),
148150
commonEditorConfig = {
149151
theme: `vs-${theme}`,
150152
minimap: {
151153
enabled: false
152154
}
153155
};
154156

157+
const converterConfigs = {
158+
useCommentBlocksAsClassName: true,
159+
printComments: true,
160+
classNameOptions: {
161+
lowercase: true,
162+
replaceWith: '-',
163+
prefix: '',
164+
suffix: ''
165+
}
166+
};
167+
155168
htmlMonacoEditor = monaco.editor.create(document.getElementById('htmlContainer'), Object
156169
.assign(commonEditorConfig, {
157170
value: defaultTemplate,
@@ -163,10 +176,10 @@
163176
language: 'scss',
164177
}));
165178

166-
sassMonacoEditor.getModel().setValue(convertToSass(defaultTemplate));
179+
sassMonacoEditor.getModel().setValue(convertToSass(defaultTemplate, converterConfigs));
167180

168181
htmlMonacoEditor.onDidChangeModelContent(function (e) {
169-
let sassOutput = convertToSass(htmlMonacoEditor.getValue());
182+
let sassOutput = convertToSass(htmlMonacoEditor.getValue(), converterConfigs);
170183

171184
if (!sassOutput || !sassOutput.length) {
172185
sassOutput = 'Invalid HTML content.';

package-lock.json

Lines changed: 1939 additions & 575 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@egoistdeveloper/twcss-to-sass",
3-
"version": "2.0.1",
3+
"version": "2.0.2",
44
"description": "HTML template to SASS converter for TailwindCSS",
55
"main": "dist/cjs/index.js",
66
"module": "dist/esm/index.js",
@@ -49,20 +49,22 @@
4949
"dependencies": {
5050
"@egoistdeveloper/twcss-to-sass": "file:egoistdeveloper-twcss-to-sass-2.0.1.tgz",
5151
"himalaya": "^1.1.0",
52-
"js-beautify": "^1.14.0"
52+
"js-beautify": "^1.14.0",
53+
"slug": "^5.3.0"
5354
},
5455
"devDependencies": {
5556
"@commitlint/cli": "^13.1.0",
5657
"@commitlint/config-conventional": "^13.1.0",
5758
"@types/jest": "^27.0.1",
5859
"@types/js-beautify": "^1.13.3",
60+
"@types/slug": "^5.0.3",
5961
"@typescript-eslint/eslint-plugin": "^4.31.1",
6062
"@typescript-eslint/parser": "^4.31.1",
6163
"eslint": "^7.32.0",
6264
"eslint-config-prettier": "^8.3.0",
6365
"eslint-plugin-prettier": "^4.0.0",
6466
"husky": "^7.0.2",
65-
"jest": "^27.2.0",
67+
"jest": "^27.5.1",
6668
"pinst": "^2.1.6",
6769
"prettier": "^2.4.0",
6870
"ts-jest": "^27.0.5",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface IClassNameOptions {
2+
lowercase: boolean
3+
replaceWith: string
4+
prefix: string
5+
suffix: string
6+
}

src/interfaces/formatter-options.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import { IFormatterOptions } from './formatter-options'
1+
import { CSSBeautifyOptions } from 'js-beautify'
2+
import { IClassNameOptions } from './classname-options'
23

34
export interface ITwToSassOptions {
45
formatOutput: boolean
5-
fomatterOptions: IFormatterOptions | null
6+
formatterOptions: CSSBeautifyOptions
7+
printComments: boolean
8+
useCommentBlocksAsClassName: boolean
9+
maxClassNameLength: number
10+
classNameOptions: IClassNameOptions
611
}

src/twcss-to-sass.ts

Lines changed: 74 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,45 @@
11
import { parse } from 'himalaya'
2-
import beautifyCss from 'js-beautify'
2+
import beautifyCss, { CSSBeautifyOptions } from 'js-beautify'
3+
import slug from 'slug'
34

45
import Utils from './utils/utils'
56
import { ITwToSassOptions } from './interfaces/tw-to-sass-options'
6-
import { IFormatterOptions } from './interfaces/formatter-options'
77
import {
88
IAttribute,
99
IHtmlNode,
1010
IHtmlNodeAttribute,
1111
} from './interfaces/html-node'
1212

13-
/**
14-
* Default options
15-
*/
16-
const defaultOptions: ITwToSassOptions = {
17-
formatOutput: true,
18-
fomatterOptions: null,
19-
}
20-
2113
/**
2214
* Default js-beautify css formatter options
2315
*/
24-
const formatterOptions: IFormatterOptions = {
25-
indent_size: '4',
16+
const formatterOptions: CSSBeautifyOptions = {
17+
indent_size: 4,
2618
indent_char: ' ',
2719
max_preserve_newlines: 5,
2820
preserve_newlines: true,
29-
keep_array_indentation: false,
30-
break_chained_methods: false,
31-
indent_scripts: 'normal',
32-
brace_style: 'collapse',
33-
space_before_conditional: true,
34-
unescape_strings: false,
35-
jslint_happy: false,
3621
end_with_newline: false,
37-
wrap_line_length: '0',
38-
indent_inner_html: false,
39-
comma_first: false,
40-
e4x: false,
22+
wrap_line_length: 0,
4123
indent_empty_lines: false,
4224
}
4325

26+
/**
27+
* Default options
28+
*/
29+
let defaultOptions: ITwToSassOptions = {
30+
formatOutput: true,
31+
useCommentBlocksAsClassName: false,
32+
maxClassNameLength: 50,
33+
printComments: true,
34+
formatterOptions: formatterOptions,
35+
classNameOptions: {
36+
lowercase: true,
37+
replaceWith: '-',
38+
prefix: '',
39+
suffix: '',
40+
},
41+
}
42+
4443
/**
4544
* Get style and class attributes
4645
*
@@ -157,7 +156,6 @@ const filterHtmlData = function (
157156
.reverse()
158157
.join(', ')
159158

160-
node.comment = node.comment ? node.comment : node.tagName
161159
node.order = nestedOrder
162160

163161
const children: IHtmlNode[] | null = filterHtmlData(
@@ -192,6 +190,46 @@ const filterHtmlData = function (
192190
return null
193191
}
194192

193+
/**
194+
* Get CSS class name from node details
195+
*
196+
* @param node IHtmlNode
197+
* @param deepth number
198+
*
199+
* @returns string
200+
*/
201+
const getClassName = function (node: IHtmlNode, deepth: number): string {
202+
let className = ''
203+
204+
const classComment = defaultOptions.printComments
205+
? `/* ${node.comment ? node.comment : node.tagName} -> ${node.order} */`
206+
: ''
207+
208+
if (node.comment && defaultOptions.useCommentBlocksAsClassName) {
209+
let classSlug = defaultOptions.classNameOptions.prefix
210+
211+
classSlug += slug(node.comment, {
212+
lower: !!defaultOptions.classNameOptions.lowercase,
213+
replacement: defaultOptions.classNameOptions.replaceWith,
214+
})
215+
216+
classSlug =
217+
classSlug.length > defaultOptions.maxClassNameLength
218+
? classSlug.substring(0, defaultOptions.maxClassNameLength)
219+
: classSlug
220+
221+
classSlug += defaultOptions.classNameOptions.suffix
222+
223+
className += `.${classSlug}`
224+
} else if (node.tagName != 'div') {
225+
className += `${node.tagName}`
226+
} else {
227+
className += `.class-${node.tagName}-${deepth}`
228+
}
229+
230+
return classComment + className
231+
}
232+
195233
/**
196234
* Extract SASS tree from HTML JSON tree
197235
*
@@ -251,8 +289,8 @@ const getSassTree = function (nodeTree: IHtmlNode[] | IHtmlNode, deepth = 0) {
251289
}
252290

253291
if (treeSTring.length || subTreeSTring.length) {
254-
let result = `/* ${node.comment} -> ${node.order} */`
255-
result += `.class-${deepth}-${node.tagName}`
292+
let result = getClassName(node, deepth)
293+
256294
result += `{${treeSTring}${subTreeSTring}}`
257295

258296
return result
@@ -277,9 +315,16 @@ const getSassTree = function (nodeTree: IHtmlNode[] | IHtmlNode, deepth = 0) {
277315
*/
278316
export const convertToSass = function (
279317
html: string,
280-
options: ITwToSassOptions = defaultOptions
318+
options: ITwToSassOptions | null = null
281319
): null | string {
282320
if (html && html.length) {
321+
if (options) {
322+
defaultOptions = {
323+
...defaultOptions,
324+
...options,
325+
}
326+
}
327+
283328
html = Utils.cleanText(html)
284329

285330
const htmlJson: IHtmlNode[] | IHtmlNode = parse(html)
@@ -290,19 +335,10 @@ export const convertToSass = function (
290335
const sassTreeResult = getSassTree(filteredHtmlData)
291336

292337
// export with formatted output
293-
if (options && options.formatOutput === true) {
294-
let _formatterOptions = {}
295-
296-
if (options && options.fomatterOptions) {
297-
_formatterOptions = Object.assign(
298-
formatterOptions,
299-
options.fomatterOptions
300-
)
301-
}
302-
338+
if (defaultOptions.formatOutput === true) {
303339
const formattedResult = beautifyCss.css(
304340
sassTreeResult,
305-
_formatterOptions
341+
defaultOptions.formatterOptions
306342
)
307343

308344
return Utils.fixFomatterApplyIssue(formattedResult)

test/twcss-to-sass.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test('convert to sass', () => {
44
const htmlCotnent =
55
'<div class="w-72 h-40 bg-green-400 transform transition-all">My Text 1</div>',
66
sassOutput = `/* div -> 1 */
7-
.class-1-div {
7+
.class-div-1 {
88
@apply w-72 h-40 bg-green-400 transform transition-all;
99
}`
1010

@@ -15,7 +15,7 @@ test('convert to sass with inline css', () => {
1515
const htmlCotnent =
1616
'<div class="w-72 h-40 bg-green-400 transform transition-all" style="border: 1px solid white; padding: 30px; font-weight: 50px;">My Text 1</div>',
1717
sassOutput = `/* div -> 1 */
18-
.class-1-div {
18+
.class-div-1 {
1919
@apply w-72 h-40 bg-green-400 transform transition-all;
2020
border: 1px solid white;
2121
padding: 30px;
@@ -36,11 +36,11 @@ test('convert to sass with comments', () => {
3636
</div>
3737
<!-- Container End-->`,
3838
sassOutput = `/* Container Start, Container Any -> 1 */
39-
.class-1-div {
39+
.class-div-1 {
4040
@apply bg-white;
4141
4242
/* Some Div -> 2 */
43-
.class-2-div {
43+
.class-div-2 {
4444
@apply flex justify-center items-center min-h-screen min-w-full;
4545
}
4646
}`

0 commit comments

Comments
 (0)