blob: 2364084daec5af3c1095094f3637e7b6a7877e62 [file] [log] [blame]
"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;