From 43b44e6df8537d81c4eb9d64a94beb94c2125b5a Mon Sep 17 00:00:00 2001 From: John Kenny Date: Mon, 23 Sep 2024 06:17:41 -0700 Subject: [PATCH] Removed original version of inlineStyles. --- plugins/inlineStyles-orig.js | 377 ----------------------------------- 1 file changed, 377 deletions(-) delete mode 100644 plugins/inlineStyles-orig.js diff --git a/plugins/inlineStyles-orig.js b/plugins/inlineStyles-orig.js deleted file mode 100644 index 3bc69be..0000000 --- a/plugins/inlineStyles-orig.js +++ /dev/null @@ -1,377 +0,0 @@ -import * as csstree from 'css-tree'; -import { syntax } from 'csso'; -import { attrsGroups, pseudoClasses } from './_collections.js'; -import { visitSkip, querySelectorAll, matches } from '../lib/xast.js'; -import { compareSpecificity, includesAttrSelector } from '../lib/style.js'; - -/** - * @typedef {import('../lib/types.js').XastElement} XastElement - * @typedef {import('../lib/types.js').XastParent} XastParent - */ - -export const name = 'inlineStyles'; -export const description = 'inline styles (additional options)'; - -/** - * Some pseudo-classes can only be calculated by clients, like :visited, - * :future, or :hover, but there are other pseudo-classes that we can evaluate - * during optimization. - * - * The list of pseudo-classes that we can evaluate during optimization, and - * shouldn't be toggled conditionally through the `usePseudos` parameter. - * - * @see https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes - */ -const preservedPseudos = [ - ...pseudoClasses.functional, - ...pseudoClasses.treeStructural, -]; - -/** - * @param {import('css-tree').CssNode} node - */ -function getProperties(node) { - const props = new Set(); - csstree.walk(node, { - visit: 'Declaration', - enter(ruleDeclaration) { - props.add(ruleDeclaration.property.toLowerCase()); - }, - }); - return props; -} -/** - * @param {import('css-tree').CssNode} node - */ -function isPseudo(node) { - return ( - (node.type === 'PseudoClassSelector' || - node.type === 'PseudoElementSelector') && - !preservedPseudos.includes(node.name) - ); -} - -/** - * Merges styles from style nodes into inline styles. - * - * @type {import('./plugins-types.js').Plugin<'inlineStyles'>} - */ -export const fn = (root, params, info) => { - const { disableIfAtRulesPresent = true, onlyMatchedOnce = true } = params; - - const styleData = info.docData.getStyles(); - if ( - info.docData.hasScripts() || - styleData === null || - !styleData.hasStyles() || - (disableIfAtRulesPresent && styleData.getFeatures().has('atrules')) - ) { - return; - } - - /** - * @type {{ node: XastElement, parentNode: XastParent, cssAst: csstree.StyleSheet }[]} - */ - const styles = []; - /** - * @type {{ - * node: csstree.Selector, - * item: csstree.ListItem, - * rule: csstree.Rule, - * matchedElements?: XastElement[] - * }[]} - */ - let selectors = []; - /** @type {{selectorStr:string,props:Set}[]} */ - const clientPseudoSelectors = []; - - return { - element: { - enter: (node, parentNode) => { - if (node.name === 'foreignObject') { - return visitSkip; - } - if (node.name !== 'style' || node.children.length === 0) { - return; - } - if ( - node.attributes.type != null && - node.attributes.type !== '' && - node.attributes.type !== 'text/css' - ) { - return; - } - - const cssText = node.children - .filter((child) => child.type === 'text' || child.type === 'cdata') - // @ts-ignore - .map((child) => child.value) - .join(''); - - /** @type {?csstree.CssNode} */ - let cssAst = null; - try { - cssAst = csstree.parse(cssText, { - parseValue: false, - parseCustomProperty: false, - }); - } catch { - return; - } - if (cssAst.type === 'StyleSheet') { - styles.push({ node, parentNode, cssAst }); - } - - // collect selectors - csstree.walk(cssAst, { - visit: 'Rule', - enter(node) { - const atrule = this.atrule; - - // skip media queries not included into useMqs param - if (atrule != null) { - return; - } - - if (node.prelude.type === 'SelectorList') { - node.prelude.children.forEach((childNode, item) => { - if (childNode.type === 'Selector') { - /** - * @type {{ - * item: csstree.ListItem, - * list: csstree.List - * }[]} - */ - const pseudos = []; - childNode.children.forEach( - (grandchildNode, grandchildItem, grandchildList) => { - if (isPseudo(grandchildNode)) { - pseudos.push({ - item: grandchildItem, - list: grandchildList, - }); - } - }, - ); - - let addToSelectors = true; - if (pseudos.length > 0) { - // The selector has pseudo classes that must be evaluated by the client. Don't inline the style. - // Record the selector (without the pseudo classes), so we can ensure we don't inline styles for any element that - // may be targeted by this selector. - - /** - * @param {import('css-tree').Selector} node - * @returns {import('css-tree').CssNode} - */ - function cloneSelectorWithoutPseudos(node) { - return { - type: node.type, - children: node.children - .filter((n) => !isPseudo(n)) - .map(csstree.clone), - }; - } - - addToSelectors = false; - const selectorWithoutPseudos = - cloneSelectorWithoutPseudos(childNode); - clientPseudoSelectors.push({ - selectorStr: csstree.generate(selectorWithoutPseudos), - props: getProperties(node), - }); - } - - if (addToSelectors) { - selectors.push({ node: childNode, rule: node, item: item }); - } - } - }); - } - }, - }); - }, - }, - - root: { - exit: () => { - const sortedSelectors = selectors - .slice() - .sort((a, b) => { - const aSpecificity = syntax.specificity(a.item.data); - const bSpecificity = syntax.specificity(b.item.data); - return compareSpecificity(aSpecificity, bSpecificity); - }) - .reverse(); - - const preservedClassNodes = new Set(); - - for (const selector of sortedSelectors) { - // match selectors - const selectorText = csstree.generate(selector.item.data); - /** @type {XastElement[]} */ - const matchedElements = []; - try { - for (const node of querySelectorAll(root, selectorText)) { - if (node.type === 'element') { - matchedElements.push(node); - } - } - } catch { - continue; - } - // nothing selected - if (matchedElements.length === 0) { - continue; - } - - // apply styles to matched elements - // skip selectors that match more than once if option onlyMatchedOnce is enabled - if (onlyMatchedOnce && matchedElements.length > 1) { - continue; - } - - // apply