123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- "use strict";
- const htmlparser = require("htmlparser2");
- const buildSyntaxResolver = require("../syntax/build-syntax-resolver");
- const buildTemplateSyntax = require("../template/syntax");
- const SvelteTokenizer = require("./svelte-tokenizer");
- function iterateCode(source, { onStyleTag, onStyleAttribute, svelte }) {
- const openTag = {};
- let disable, ignore, style;
- const parser = new htmlparser.Parser(
- {
- oncomment: (data) => {
- ignore = false;
- const match = /(?:^|\s+)postcss-(\w+)(?:\s+|$)/i.exec(data);
- if (!match) {
- return;
- }
- const directive = match[1].toLowerCase();
- if (directive === "enable") {
- disable = false;
- } else if (directive === "disable") {
- disable = true;
- } else if (directive === "ignore") {
- ignore = true;
- }
- },
- onopentag(name, attribute) {
- openTag[name] = true;
- const currIgnore = ignore;
- ignore = false;
- if (currIgnore) {
- // ignore
- return;
- }
- // 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;
- ignore = 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 || ignore || 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,
- });
- },
- },
- {
- Tokenizer: svelte ? SvelteTokenizer : undefined,
- }
- );
- parser.parseComplete(source);
- }
- function getSubString(str, regexp) {
- const subStr = str && regexp.exec(str);
- if (subStr) {
- return subStr[1].toLowerCase();
- }
- return undefined;
- }
- function getLang(attribute) {
- return (
- getSubString(attribute.type, /^\w+\/(?:x-)?(\w+)$/i) ||
- getSubString(attribute.lang, /^(\w+)(?:\?.+)?$/) ||
- "css"
- );
- }
- function extractStyles(source, opts) {
- const styles = [];
- const resolveSyntax = buildSyntaxResolver(opts.config);
- 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);
- style.syntax = resolveSyntax(style.lang);
- if (style.syntax) styles.push(style);
- }
- function onStyleAttribute(style) {
- if (/\{[\s\S]*?\}/.test(style.content)) {
- style.syntax = buildTemplateSyntax(resolveSyntax());
- style.lang = "custom-template";
- } else {
- style.syntax = resolveSyntax();
- style.lang = "css";
- }
- styles.push(style);
- }
- iterateCode(source, {
- onStyleTag,
- onStyleAttribute,
- svelte: opts.from && /\.svelte$/i.test(opts.from),
- });
- return styles;
- }
- module.exports = extractStyles;
|