forked from lix-project/lix-website
123 lines
2.9 KiB
JavaScript
123 lines
2.9 KiB
JavaScript
|
"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;
|