Skip to content

Commit

Permalink
removeUnknownsAndDefaults: remove from style attribute properties as …
Browse files Browse the repository at this point in the history
…well as individual attributes (#29)
  • Loading branch information
johnkenny54 authored Oct 2, 2024
1 parent 18d0925 commit e2c6e0e
Show file tree
Hide file tree
Showing 20 changed files with 393 additions and 141 deletions.
6 changes: 5 additions & 1 deletion lib/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ export class CSSRule {
switch (simpleSelectors[0].type) {
case 'ClassSelector':
return (element) =>
element.attributes.class === simpleSelectors[0].name;
element.attributes.class
? element.attributes.class
.split(/\s/)
.includes(simpleSelectors[0].name)
: false;
case 'IdSelector':
return (element) => element.attributes.id === simpleSelectors[0].name;
case 'TypeSelector':
Expand Down
65 changes: 39 additions & 26 deletions lib/docdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { getStyleDeclarations } from './css-tools.js';
* @typedef {import('../lib/types.js').CSSFeatures} CSSFeatures
* @typedef {import('./css.js').CSSRule} CSSRule
* @typedef {import('./css.js').CSSRuleSet} CSSRuleSet
* @typedef {import('../lib/types.js').CSSDeclarationMap} CSSDeclarationMap
*/

const VAR_REGEXP = /([^\w]var|^var)\(/;
Expand Down Expand Up @@ -80,19 +81,20 @@ export class StyleData {
}

/**
* @param {XastParent} node
* @param {XastParent} element
* @param {CSSDeclarationMap} [declarations]
* @returns {Map<string,string|null>}
*/
computeOwnStyle(node) {
computeOwnStyle(element, declarations) {
/** @type {Map<string,string|null>} */
const computedStyles = new Map();

if (node.type === 'root') {
if (element.type === 'root') {
return computedStyles;
}

// Collect attributes.
for (const [name, value] of Object.entries(node.attributes)) {
for (const [name, value] of Object.entries(element.attributes)) {
if (attrsGroups.presentation.has(name)) {
computedStyles.set(name, value);
}
Expand All @@ -101,7 +103,7 @@ export class StyleData {
// Override with style element rules.
const importantProperties = new Set();
for (const rule of this.#sortedRules) {
if (rule.matches(node)) {
if (rule.matches(element)) {
const isDynamic = rule.isInMediaQuery() || rule.hasPseudos();
rule.getDeclarations().forEach((value, name) => {
if (isDynamic) {
Expand All @@ -122,7 +124,9 @@ export class StyleData {
}

// Override with inline styles.
const declarations = getStyleDeclarations(node);
if (!declarations) {
declarations = getStyleDeclarations(element);
}
if (declarations) {
declarations.forEach((value, name) => {
if (value.important || !importantProperties.has(name)) {
Expand All @@ -135,21 +139,20 @@ export class StyleData {
}

/**
* @param {XastElement} node
* @param {{element:XastParent,styles?:Map<string,string|null>}[]} parents
* @param {{element:XastParent,styles?:Map<string,string|null>}[]} parentInfo
* @returns {Map<string,string|null>}
*/
computeStyle(node, parents) {
computeParentStyle(parentInfo) {
/**
* @param {StyleData} styleData
* @param {number} index
*/
function getParentStyles(styleData, index) {
const parent = parents[index];
const parent = parentInfo[index];
if (!parent.styles) {
parent.styles = styleData.computeOwnStyle(parent.element);
if (index > 0) {
mergeMissingProperties(
StyleData.#mergeMissingProperties(
parent.styles,
getParentStyles(styleData, index - 1),
);
Expand All @@ -158,29 +161,39 @@ export class StyleData {
return parent.styles;
}

/**
* @param {Map<string,string|null>} currentStyles
* @param {Map<string,string|null>} parentStyles
*/
function mergeMissingProperties(currentStyles, parentStyles) {
parentStyles.forEach((value, name) => {
if (inheritableAttrs.has(name) && !currentStyles.has(name)) {
currentStyles.set(name, value);
}
});
}
return getParentStyles(this, parentInfo.length - 1);
}

const computedStyles = this.computeOwnStyle(node);
/**
* @param {XastElement} element
* @param {{element:XastParent,styles?:Map<string,string|null>}[]} parentInfo
* @param {CSSDeclarationMap} [declarations]
* @returns {Map<string,string|null>}
*/
computeStyle(element, parentInfo, declarations) {
const computedStyles = this.computeOwnStyle(element, declarations);

// Fill in any missing properties from the parent.
if (parents.length) {
const parentStyles = getParentStyles(this, parents.length - 1);
mergeMissingProperties(computedStyles, parentStyles);
if (parentInfo.length) {
const parentStyles = this.computeParentStyle(parentInfo);
StyleData.#mergeMissingProperties(computedStyles, parentStyles);
}

return computedStyles;
}

/**
* @param {Map<string,string|null>} currentStyles
* @param {Map<string,string|null>} parentStyles
*/
static #mergeMissingProperties(currentStyles, parentStyles) {
parentStyles.forEach((value, name) => {
if (inheritableAttrs.has(name) && !currentStyles.has(name)) {
currentStyles.set(name, value);
}
});
}

/** @param {Set<CSSRule>} rules */
deleteRules(rules) {
if (rules.size === 0) {
Expand Down
6 changes: 5 additions & 1 deletion lib/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,13 @@ type CSSFeatures =

export class StyleData {
computeOwnStyle(node: XastElement): Map<string, string | null>;
computeParentStyle(
parentInfo: { element: XastParent; styles?: Map<string, string | null> }[],
): Map<string, string | null>;
computeStyle(
node: XastElement,
parents: { element: XastParent; styles?: Map<string, string | null> }[],
parentInfo: { element: XastParent; styles?: Map<string, string | null> }[],
declarations?: CSSDeclarationMap,
): Map<string, string | null>;
deleteRules(rules: Set<CSSRule>): void;
getFeatures(): Set<CSSFeatures>;
Expand Down
11 changes: 7 additions & 4 deletions plugins/_collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -1392,10 +1392,13 @@ export const elems = {
'y2',
]),
defaults: {
x1: '0',
y1: '0',
x2: '100%',
y2: '0',
// TODO: Figure out why these can't always be used. See test removeUnknownsAndDefaults.19.svg.txt - removing x1="0" changes
// appearance. Is there a similar issue with radialGradient? Seems like behavior of coordinates depends on setting of
// gradientUnits.
// x1: '0',
// y1: '0',
// x2: '100%',
// y2: '0',
spreadMethod: 'pad',
},
contentGroups: new Set(['descriptive']),
Expand Down
9 changes: 6 additions & 3 deletions plugins/removeDimensions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { visitSkip } from '../lib/xast.js';

export const name = 'removeDimensions';
export const description =
'removes width and height in presence of viewBox (opposite to removeViewBox)';
Expand All @@ -19,12 +21,12 @@ export const fn = () => {
element: {
enter: (node) => {
if (node.name === 'svg') {
if (node.attributes.viewBox != null) {
if (node.attributes.viewBox) {
delete node.attributes.width;
delete node.attributes.height;
} else if (
node.attributes.width != null &&
node.attributes.height != null &&
node.attributes.width &&
node.attributes.height &&
Number.isNaN(Number(node.attributes.width)) === false &&
Number.isNaN(Number(node.attributes.height)) === false
) {
Expand All @@ -35,6 +37,7 @@ export const fn = () => {
delete node.attributes.height;
}
}
return visitSkip;
},
},
};
Expand Down
Loading

0 comments on commit e2c6e0e

Please sign in to comment.