1
0
mirror of https://github.com/svg/svgo.git synced 2025-07-31 07:44:22 +03:00

Drop node.style usages (#1534)

Parsing inline styles with csstree in place is easier.
Caching does not add much value here.
This commit is contained in:
Bogdan Chadkin
2021-08-22 16:18:55 +03:00
committed by GitHub
parent 98c023bdb0
commit 6cb2f7034f
2 changed files with 66 additions and 18 deletions

View File

@ -78,7 +78,10 @@ const parseStylesheet = (css, dynamic) => {
* @type {Array<StylesheetRule>}
*/
const rules = [];
const ast = csstree.parse(css);
const ast = csstree.parse(css, {
parseValue: false,
parseAtrulePrelude: false,
});
csstree.walk(ast, (cssNode) => {
if (cssNode.type === 'Rule') {
rules.push(parseRule(cssNode, dynamic || false));
@ -100,6 +103,30 @@ const parseStylesheet = (css, dynamic) => {
return rules;
};
/**
* @type {(css: string) => Array<StylesheetDeclaration>}
*/
const parseStyleDeclarations = (css) => {
/**
* @type {Array<StylesheetDeclaration>}
*/
const declarations = [];
const ast = csstree.parse(css, {
context: 'declarationList',
parseValue: false,
});
csstree.walk(ast, (cssNode) => {
if (cssNode.type === 'Declaration') {
declarations.push({
name: cssNode.property,
value: csstree.generate(cssNode.value),
important: cssNode.important === true,
});
}
});
return declarations;
};
/**
* @type {(stylesheet: Array<StylesheetRule>, node: XastElement) => ComputedStyles}
*/
@ -143,10 +170,12 @@ const computeOwnStyle = (stylesheet, node) => {
}
// collect inline styles
// @ts-ignore node.style is hidden from pubilc usage
for (const [name, { value, priority }] of node.style.properties) {
const styleDeclarations =
node.attributes.style == null
? []
: parseStyleDeclarations(node.attributes.style);
for (const { name, value, important } of styleDeclarations) {
const computed = computedStyle[name];
const important = priority === 'important';
if (computed && computed.type === 'dynamic') {
continue;
}

View File

@ -148,32 +148,51 @@ exports.fn = function (root, opts) {
if (selector.rule === null) {
continue;
}
const styleDeclarationList = csstree.parse(
selectedEl.attributes.style == null ? '' : selectedEl.attributes.style,
{
context: 'declarationList',
parseValue: false,
}
);
const styleDeclarationItems = new Map();
csstree.walk(styleDeclarationList, {
visit: 'Declaration',
enter(node, item) {
styleDeclarationItems.set(node.property, item);
},
});
// merge declarations
csstree.walk(selector.rule, {
visit: 'Declaration',
enter: function (styleCsstreeDeclaration) {
enter(ruleDeclaration) {
// existing inline styles have higher priority
// no inline styles, external styles, external styles used
// inline styles, external styles same priority as inline styles, inline styles used
// inline styles, external styles higher priority than inline styles, external styles used
var styleDeclaration = cssTools.csstreeToStyleDeclaration(
styleCsstreeDeclaration
const matchedItem = styleDeclarationItems.get(
ruleDeclaration.property
);
if (
selectedEl.style.getPropertyValue(styleDeclaration.name) !== null &&
selectedEl.style.getPropertyPriority(styleDeclaration.name) >=
styleDeclaration.priority
const ruleDeclarationItem =
styleDeclarationList.children.createItem(ruleDeclaration);
if (matchedItem == null) {
styleDeclarationList.children.append(ruleDeclarationItem);
} else if (
matchedItem.data.important !== true &&
ruleDeclaration.important === true
) {
return;
styleDeclarationList.children.replace(
matchedItem,
ruleDeclarationItem
);
styleDeclarationItems.set(
ruleDeclaration.property,
ruleDeclarationItem
);
}
selectedEl.style.setProperty(
styleDeclaration.name,
styleDeclaration.value,
styleDeclaration.priority
);
},
});
selectedEl.attributes.style = csstree.generate(styleDeclarationList);
}
if (