Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
scss-to-css
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张俊
scss-to-css
Commits
8e4d2c53
Commit
8e4d2c53
authored
Mar 04, 2023
by
张俊
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[feat]更新转化文件
parent
7062b53f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
395 additions
and
28 deletions
+395
-28
htmv.js
htmv.js
+395
-28
No files found.
htmv.js
View file @
8e4d2c53
...
...
@@ -22,44 +22,411 @@ function dealVueStyleNode(dirPath, partten) {
files
.
forEach
(
file
=>
dealVueStyleNodeSingleFile
(
path
.
resolve
(
dirPath
,
file
)));
}
const
rewriter
=
vueStyleRewriter
();
function
dealVueStyleNodeSingleFile
(
file
)
{
const
html
=
fs
.
readFileSync
(
file
,
'
utf-8
'
);
// 使用 cheerio 加载 HTML 文档
// 第三个参数表示不加载到document中
const
$
=
cheerio
.
load
(
html
,
{
lowerCaseTags
:
false
,
xmlMode
:
true
,
normalizeWhitespace
:
false
,
decodeEntities
:
false
,
},
false
);
let
styleIndex
=
0
;
const
rewritedHtml
=
rewriter
(
html
,
(
style
)
=>
{
// 使用 cheerio 加载 HTML 文档
// 第三个参数表示不加载到document中
const
$
=
cheerio
.
load
(
style
,
{
lowerCaseTags
:
false
,
xmlMode
:
true
,
normalizeWhitespace
:
false
,
decodeEntities
:
false
,
},
false
);
// 修改 HTML 文档中的内容
$
(
'
style
'
).
each
((
index
,
styleEl
)
=>
{
styleEl
=
$
(
styleEl
);
const
lang
=
styleEl
.
attr
(
'
lang
'
);
if
(
!
lang
||
lang
==
'
scss
'
)
{
const
scssString
=
styleEl
.
text
();
try
{
const
result
=
parseScss
(
scssString
,
file
);
styleEl
.
text
(
result
.
css
);
console
.
log
(
`file:
${
file
}
style-node:
${
index
}
deal style success.`
);
}
catch
(
e
)
{
console
.
warn
(
`file:
${
file
}
style-node:
${
index
}
deal style error.`
,
e
);
$
(
'
style
'
).
each
((
index
,
styleEl
)
=>
{
styleEl
=
$
(
styleEl
);
const
lang
=
styleEl
.
attr
(
'
lang
'
);
if
(
!
lang
||
lang
.
indexOf
(
'
scss
'
)
==
0
)
{
const
scssString
=
styleEl
.
text
();
try
{
const
result
=
parseScss
(
scssString
,
file
);
styleEl
.
text
(
`
${
result
.
css
}
`
);
console
.
log
(
`file:
${
file
}
style-node:
${
styleIndex
}
deal style success.`
);
}
catch
(
e
)
{
console
.
warn
(
`file:
${
file
}
style-node:
${
styleIndex
}
deal style error.`
,
e
);
}
if
(
lang
&&
lang
.
indexOf
(
'
scoped
'
)
>=
0
)
{
styleEl
.
attr
(
'
scoped
'
,
true
);
}
styleEl
.
attr
(
'
lang
'
,
'
css
'
);
}
styleEl
.
attr
(
'
lang
'
,
'
css
'
);
}
})
if
(
$
(
'
style
'
).
length
)
{
fs
.
writeFileSync
(
file
,
$
.
html
());
});
styleIndex
++
;
return
$
.
html
();
});
if
(
styleIndex
>
0
)
{
// // 将修改后的 HTML 文档写入文件
fs
.
writeFileSync
(
file
,
rewritedHtml
);
}
// // 将修改后的 HTML 文档写入文件
// fs.writeFileSync('index.html', $.html());
}
function
parseScss
(
scssString
,
file
)
{
const
result
=
sass
.
compileString
(
scssString
,
{
url
:
file
});
const
replaceTagSelector
=
'
tag::replace
'
;
const
result
=
sass
.
compileString
(
`
${
replaceTagSelector
}
{
${
scssString
}
}`
,
{
url
:
file
});
result
.
css
=
result
.
css
// + "\n\t" + result.css
.
replace
(
/tag::replace
([\.
:
\[])
/g
,
'
&$1
'
)
.
replace
(
/tag::replace
[\s]
*
[\{]
/g
,
'
& {
'
)
.
replace
(
/tag::replace
[\s]
*/g
,
''
);
return
result
;
}
dealVueStyleNode
(
dirPath
,
partten
);
function
vueStyleRewriter
()
{
// 从 node_modules\vue-template-compiler\build.js 中 复用解析代码
/**
* Always return false.
*/
const
no
=
(
a
,
b
,
c
)
=>
false
;
// HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
const
isNonPhrasingTag
=
makeMap
(
'
address,article,aside,base,blockquote,body,caption,col,colgroup,dd,
'
+
'
details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,
'
+
'
h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,
'
+
'
optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,
'
+
'
title,tr,track
'
);
/**
* Make a map and return a function for checking if a key
* is in that map.
*/
function
makeMap
(
str
,
expectsLowerCase
)
{
const
map
=
Object
.
create
(
null
);
const
list
=
str
.
split
(
'
,
'
);
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
map
[
list
[
i
]]
=
true
;
}
return
expectsLowerCase
?
val
=>
map
[
val
.
toLowerCase
()]
:
val
=>
map
[
val
];
}
const
unicodeRegExp
=
/a-zA-Z
\u
00B7
\u
00C0-
\u
00D6
\u
00D8-
\u
00F6
\u
00F8-
\u
037D
\u
037F-
\u
1FFF
\u
200C-
\u
200D
\u
203F-
\u
2040
\u
2070-
\u
218F
\u
2C00-
\u
2FEF
\u
3001-
\u
D7FF
\u
F900-
\u
FDCF
\u
FDF0-
\u
FFFD/
;
/**
* Not type-checking this file because it's mostly vendor code.
*/
// Regular Expressions for parsing tags and attributes
const
attribute
=
/^
\s
*
([^\s
"'<>
\/
=
]
+
)(?:\s
*
(
=
)\s
*
(?:
"
([^
"
]
*
)
"+|'
([^
'
]
*
)
'+|
([^\s
"'=<>`
]
+
)))?
/
;
const
dynamicArgAttribute
=
/^
\s
*
((?:
v-
[\w
-
]
+:|@|:|#
)\[[^
=
]
+
?\][^\s
"'<>
\/
=
]
*
)(?:\s
*
(
=
)\s
*
(?:
"
([^
"
]
*
)
"+|'
([^
'
]
*
)
'+|
([^\s
"'=<>`
]
+
)))?
/
;
const
ncname
=
`[a-zA-Z_][\\-\\.0-9_a-zA-Z
${
unicodeRegExp
.
source
}
]*`
;
const
qnameCapture
=
`((?:
${
ncname
}
\\:)?
${
ncname
}
)`
;
const
startTagOpen
=
new
RegExp
(
`^<
${
qnameCapture
}
`
);
const
startTagClose
=
/^
\s
*
(\/?)
>/
;
const
endTag
=
new
RegExp
(
`^<\\/
${
qnameCapture
}
[^>]*>`
);
const
doctype
=
/^<!DOCTYPE
[^
>
]
+>/i
;
// #7298: escape - to avoid being passed as HTML comment when inlined in page
const
comment
=
/^<!
\-
-/
;
const
conditionalComment
=
/^<!
\[
/
;
// Special Elements (can contain anything)
const
isPlainTextElement
=
makeMap
(
'
script,style
'
,
true
);
const
reCache
=
{};
const
decodingMap
=
{
'
<
'
:
'
<
'
,
'
>
'
:
'
>
'
,
'
"
'
:
'
"
'
,
'
&
'
:
'
&
'
,
'
'
:
'
\n
'
,
'
	
'
:
'
\t
'
,
'
'
'
:
"
'
"
};
const
encodedAttr
=
/&
(?:
lt|gt|quot|amp|#39
)
;/g
;
const
encodedAttrWithNewLines
=
/&
(?:
lt|gt|quot|amp|#39|#10|#9
)
;/g
;
// #5992
const
isIgnoreNewlineTag
=
makeMap
(
'
pre,textarea
'
,
true
);
const
shouldIgnoreFirstNewline
=
(
tag
,
html
)
=>
tag
&&
isIgnoreNewlineTag
(
tag
)
&&
html
[
0
]
===
'
\n
'
;
function
decodeAttr
(
value
,
shouldDecodeNewlines
)
{
const
re
=
shouldDecodeNewlines
?
encodedAttrWithNewLines
:
encodedAttr
;
return
value
.
replace
(
re
,
match
=>
decodingMap
[
match
]);
}
function
parseHTML
(
html
,
options
)
{
const
stack
=
[];
const
expectHTML
=
options
.
expectHTML
;
const
isUnaryTag
=
options
.
isUnaryTag
||
no
;
const
canBeLeftOpenTag
=
options
.
canBeLeftOpenTag
||
no
;
let
index
=
0
;
let
last
,
lastTag
;
while
(
html
)
{
last
=
html
;
// Make sure we're not in a plaintext content element like script/style
if
(
!
lastTag
||
!
isPlainTextElement
(
lastTag
))
{
let
textEnd
=
html
.
indexOf
(
'
<
'
);
if
(
textEnd
===
0
)
{
// Comment:
if
(
comment
.
test
(
html
))
{
const
commentEnd
=
html
.
indexOf
(
'
-->
'
);
if
(
commentEnd
>=
0
)
{
if
(
options
.
shouldKeepComment
&&
options
.
comment
)
{
options
.
comment
(
html
.
substring
(
4
,
commentEnd
),
index
,
index
+
commentEnd
+
3
);
}
advance
(
commentEnd
+
3
);
continue
;
}
}
// http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
if
(
conditionalComment
.
test
(
html
))
{
const
conditionalEnd
=
html
.
indexOf
(
'
]>
'
);
if
(
conditionalEnd
>=
0
)
{
advance
(
conditionalEnd
+
2
);
continue
;
}
}
// Doctype:
const
doctypeMatch
=
html
.
match
(
doctype
);
if
(
doctypeMatch
)
{
advance
(
doctypeMatch
[
0
].
length
);
continue
;
}
// End tag:
const
endTagMatch
=
html
.
match
(
endTag
);
if
(
endTagMatch
)
{
const
curIndex
=
index
;
advance
(
endTagMatch
[
0
].
length
);
parseEndTag
(
endTagMatch
[
1
],
curIndex
,
index
);
continue
;
}
// Start tag:
const
startTagMatch
=
parseStartTag
();
if
(
startTagMatch
)
{
handleStartTag
(
startTagMatch
);
if
(
shouldIgnoreFirstNewline
(
startTagMatch
.
tagName
,
html
))
{
advance
(
1
);
}
continue
;
}
}
let
text
,
rest
,
next
;
if
(
textEnd
>=
0
)
{
rest
=
html
.
slice
(
textEnd
);
while
(
!
endTag
.
test
(
rest
)
&&
!
startTagOpen
.
test
(
rest
)
&&
!
comment
.
test
(
rest
)
&&
!
conditionalComment
.
test
(
rest
))
{
// < in plain text, be forgiving and treat it as text
next
=
rest
.
indexOf
(
'
<
'
,
1
);
if
(
next
<
0
)
break
;
textEnd
+=
next
;
rest
=
html
.
slice
(
textEnd
);
}
text
=
html
.
substring
(
0
,
textEnd
);
}
if
(
textEnd
<
0
)
{
text
=
html
;
}
if
(
text
)
{
advance
(
text
.
length
);
}
if
(
options
.
chars
&&
text
)
{
options
.
chars
(
text
,
index
-
text
.
length
,
index
);
}
}
else
{
let
endTagLength
=
0
;
const
stackedTag
=
lastTag
.
toLowerCase
();
const
reStackedTag
=
reCache
[
stackedTag
]
||
(
reCache
[
stackedTag
]
=
new
RegExp
(
'
([
\\
s
\\
S]*?)(</
'
+
stackedTag
+
'
[^>]*>)
'
,
'
i
'
));
const
rest
=
html
.
replace
(
reStackedTag
,
function
(
all
,
text
,
endTag
)
{
endTagLength
=
endTag
.
length
;
if
(
!
isPlainTextElement
(
stackedTag
)
&&
stackedTag
!==
'
noscript
'
)
{
text
=
text
.
replace
(
/<!
\-
-
([\s\S]
*
?)
-->/g
,
'
$1
'
)
// #7298
.
replace
(
/<!
\[
CDATA
\[([\s\S]
*
?)
]]>/g
,
'
$1
'
);
}
if
(
shouldIgnoreFirstNewline
(
stackedTag
,
text
))
{
text
=
text
.
slice
(
1
);
}
if
(
options
.
chars
)
{
options
.
chars
(
text
);
}
return
''
;
});
index
+=
html
.
length
-
rest
.
length
;
html
=
rest
;
parseEndTag
(
stackedTag
,
index
-
endTagLength
,
index
);
}
if
(
html
===
last
)
{
options
.
chars
&&
options
.
chars
(
html
);
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
&&
!
stack
.
length
&&
options
.
warn
)
{
options
.
warn
(
`Mal-formatted tag at end of template: "
${
html
}
"`
,
{
start
:
index
+
html
.
length
});
}
break
;
}
}
// Clean up any remaining tags
parseEndTag
();
function
advance
(
n
)
{
index
+=
n
;
html
=
html
.
substring
(
n
);
}
function
parseStartTag
()
{
const
start
=
html
.
match
(
startTagOpen
);
if
(
start
)
{
const
match
=
{
tagName
:
start
[
1
],
attrs
:
[],
start
:
index
};
advance
(
start
[
0
].
length
);
let
end
,
attr
;
while
(
!
(
end
=
html
.
match
(
startTagClose
))
&&
(
attr
=
html
.
match
(
dynamicArgAttribute
)
||
html
.
match
(
attribute
)))
{
attr
.
start
=
index
;
advance
(
attr
[
0
].
length
);
attr
.
end
=
index
;
match
.
attrs
.
push
(
attr
);
}
if
(
end
)
{
match
.
unarySlash
=
end
[
1
];
advance
(
end
[
0
].
length
);
match
.
end
=
index
;
return
match
;
}
}
}
function
handleStartTag
(
match
)
{
const
tagName
=
match
.
tagName
;
const
unarySlash
=
match
.
unarySlash
;
if
(
expectHTML
)
{
if
(
lastTag
===
'
p
'
&&
isNonPhrasingTag
(
tagName
))
{
parseEndTag
(
lastTag
);
}
if
(
canBeLeftOpenTag
(
tagName
)
&&
lastTag
===
tagName
)
{
parseEndTag
(
tagName
);
}
}
const
unary
=
isUnaryTag
(
tagName
)
||
!!
unarySlash
;
const
l
=
match
.
attrs
.
length
;
const
attrs
=
new
Array
(
l
);
for
(
let
i
=
0
;
i
<
l
;
i
++
)
{
const
args
=
match
.
attrs
[
i
];
const
value
=
args
[
3
]
||
args
[
4
]
||
args
[
5
]
||
''
;
const
shouldDecodeNewlines
=
tagName
===
'
a
'
&&
args
[
1
]
===
'
href
'
?
options
.
shouldDecodeNewlinesForHref
:
options
.
shouldDecodeNewlines
;
attrs
[
i
]
=
{
name
:
args
[
1
],
value
:
decodeAttr
(
value
,
shouldDecodeNewlines
)
};
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
&&
options
.
outputSourceRange
)
{
attrs
[
i
].
start
=
args
.
start
+
args
[
0
].
match
(
/^
\s
*/
).
length
;
attrs
[
i
].
end
=
args
.
end
;
}
}
if
(
!
unary
)
{
stack
.
push
({
tag
:
tagName
,
lowerCasedTag
:
tagName
.
toLowerCase
(),
attrs
:
attrs
,
start
:
match
.
start
,
end
:
match
.
end
});
lastTag
=
tagName
;
}
if
(
options
.
start
)
{
options
.
start
(
tagName
,
attrs
,
unary
,
match
.
start
,
match
.
end
);
}
}
function
parseEndTag
(
tagName
,
start
,
end
)
{
let
pos
,
lowerCasedTagName
;
if
(
start
==
null
)
start
=
index
;
if
(
end
==
null
)
end
=
index
;
// Find the closest opened tag of the same type
if
(
tagName
)
{
lowerCasedTagName
=
tagName
.
toLowerCase
();
for
(
pos
=
stack
.
length
-
1
;
pos
>=
0
;
pos
--
)
{
if
(
stack
[
pos
].
lowerCasedTag
===
lowerCasedTagName
)
{
break
;
}
}
}
else
{
// If no tag name is provided, clean shop
pos
=
0
;
}
if
(
pos
>=
0
)
{
// Close all the open elements, up the stack
for
(
let
i
=
stack
.
length
-
1
;
i
>=
pos
;
i
--
)
{
if
(
process
.
env
.
NODE_ENV
!==
'
production
'
&&
(
i
>
pos
||
!
tagName
)
&&
options
.
warn
)
{
options
.
warn
(
`tag <
${
stack
[
i
].
tag
}
> has no matching end tag.`
,
{
start
:
stack
[
i
].
start
,
end
:
stack
[
i
].
end
});
}
if
(
options
.
end
)
{
options
.
end
(
stack
[
i
].
tag
,
start
,
end
);
}
}
// Remove the open elements from the stack
stack
.
length
=
pos
;
lastTag
=
pos
&&
stack
[
pos
-
1
].
tag
;
}
else
if
(
lowerCasedTagName
===
'
br
'
)
{
if
(
options
.
start
)
{
options
.
start
(
tagName
,
[],
true
,
start
,
end
);
}
}
else
if
(
lowerCasedTagName
===
'
p
'
)
{
if
(
options
.
start
)
{
options
.
start
(
tagName
,
[],
false
,
start
,
end
);
}
if
(
options
.
end
)
{
options
.
end
(
tagName
,
start
,
end
);
}
}
}
}
return
function
parseVUE
(
vueString
,
replaceStyle
)
{
const
items
=
[];
let
currentParent
;
parseHTML
(
vueString
,
{
shouldKeepComment
:
true
,
start
(
tag
,
attrs
,
unary
,
start
,
end
)
{
if
(
!
unary
)
{
currentParent
=
{
tag
,
attrs
,
unary
,
start
,
end
};
}
else
{
currentParent
=
null
;
}
if
(
currentParent
!=
null
&&
currentParent
.
tag
==
'
style
'
)
{
}
else
{
items
.
push
(
vueString
.
substring
(
start
,
end
));
}
},
end
(
tag
,
start
,
end
)
{
if
(
currentParent
!=
null
&&
currentParent
.
tag
==
'
style
'
)
{
const
tagStr
=
vueString
.
substring
(
currentParent
.
start
,
end
);
items
.
push
(
replaceStyle
(
tagStr
));
}
else
{
items
.
push
(
vueString
.
substring
(
start
,
end
));
}
currentParent
=
null
;
},
chars
(
text
,
start
,
end
)
{
if
(
currentParent
!=
null
&&
currentParent
.
tag
==
'
style
'
)
{
}
else
{
items
.
push
(
text
);
}
},
comment
(
text
,
start
,
end
)
{
// adding anything as a sibling to the root node is forbidden
// comments should still be allowed, but ignored
items
.
push
(
vueString
.
substring
(
start
,
end
));
}
})
return
items
.
join
(
""
)
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment