You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
2.9 KiB
122 lines
2.9 KiB
"use strict"; |
|
|
|
const htmlparser = require("htmlparser2"); |
|
const loadSyntax = require("postcss-syntax/load-syntax"); |
|
|
|
function iterateCode (source, onStyleTag, onStyleAttribute) { |
|
const openTag = {}; |
|
let disable; |
|
let style; |
|
|
|
const parser = new htmlparser.Parser({ |
|
oncomment: (data) => { |
|
if (!/(?:^|\s+)postcss-(\w+)(?:\s+|$)/i.test(data)) { |
|
return; |
|
} |
|
data = RegExp.$1.toLowerCase(); |
|
if (data === "enable") { |
|
disable = false; |
|
} else if (data === "disable") { |
|
disable = true; |
|
} |
|
}, |
|
onopentag (name, attribute) { |
|
openTag[name] = true; |
|
|
|
// Test if current tag is a valid <style> tag. |
|
if (!/^style$/i.test(name)) { |
|
return; |
|
} |
|
|
|
style = { |
|
inXsls: openTag["xsl:stylesheet"], |
|
inXslt: openTag["xsl:template"], |
|
inHtml: openTag.html, |
|
tagName: name, |
|
attribute, |
|
startIndex: parser.endIndex + 1, |
|
}; |
|
}, |
|
|
|
onclosetag (name) { |
|
openTag[name] = false; |
|
if (disable || !style || name !== style.tagName) { |
|
return; |
|
} |
|
|
|
let content = source.slice(style.startIndex, parser.startIndex); |
|
|
|
const firstNewLine = /^[ \t]*\r?\n/.exec(content); |
|
if (firstNewLine) { |
|
const offset = firstNewLine[0].length; |
|
style.startIndex += offset; |
|
content = content.slice(offset); |
|
} |
|
style.content = content.replace(/[ \t]*$/, ""); |
|
|
|
onStyleTag(style); |
|
style = null; |
|
}, |
|
|
|
onattribute (name, content) { |
|
if (disable || name !== "style") { |
|
return; |
|
} |
|
const endIndex = parser._tokenizer._index; |
|
const startIndex = endIndex - content.length; |
|
if (source[startIndex - 1] !== source[endIndex] || !/\S/.test(source[endIndex])) { |
|
return; |
|
} |
|
onStyleAttribute({ |
|
content, |
|
startIndex, |
|
inline: true, |
|
inTemplate: openTag.template, |
|
}); |
|
}, |
|
}); |
|
|
|
parser.parseComplete(source); |
|
} |
|
|
|
function getSubString (str, regexp) { |
|
const subStr = str && regexp.exec(str); |
|
if (subStr) { |
|
return subStr[1].toLowerCase(); |
|
} |
|
} |
|
|
|
function getLang (attribute) { |
|
return getSubString(attribute.type, /^\w+\/(?:x-)?(\w+)$/i) || getSubString(attribute.lang, /^(\w+)(?:\?.+)?$/) || "css"; |
|
} |
|
|
|
function htmlParser (source, opts, styles) { |
|
styles = styles || []; |
|
|
|
const standard = opts.from && /\.(?:\w*html?|xht|xslt?|jsp|aspx?|ejs|php\d*|twig|liquid|m(?:ark)?d(?:ow)?n|mk?d)$/i.test(opts.from); |
|
|
|
function onStyleTag (style) { |
|
if (!(style.inHtml || style.inXsls || style.inXslt || standard) && (style.attribute.src || style.attribute.href) && !style.content.trim()) { |
|
return; |
|
} |
|
style.lang = getLang(style.attribute); |
|
styles.push(style); |
|
} |
|
|
|
function onStyleAttribute (style) { |
|
if (/{[\s\S]*?}/g.test(style.content)) { |
|
style.syntax = loadSyntax(opts, __dirname); |
|
style.lang = "custom-template"; |
|
} else { |
|
// style.ignoreErrors = opts.from && /\.(?:jsp|aspx?|ejs|php\d*|twig)$/i.test(opts.from); |
|
style.lang = "css"; |
|
} |
|
styles.push(style); |
|
} |
|
|
|
iterateCode(source, onStyleTag, onStyleAttribute); |
|
|
|
return styles; |
|
} |
|
|
|
module.exports = htmlParser;
|
|
|