mirror of
https://github.com/svg/svgo.git
synced 2025-07-31 07:44:22 +03:00
Add descendants test and universal selector support
This commit is contained in:
26
lib/xast.js
26
lib/xast.js
@ -30,7 +30,7 @@ const trimQuotes = (string) => {
|
|||||||
*/
|
*/
|
||||||
const elementMatches = (csstreeNode, xastElement) => {
|
const elementMatches = (csstreeNode, xastElement) => {
|
||||||
if (csstreeNode.type === 'TypeSelector') {
|
if (csstreeNode.type === 'TypeSelector') {
|
||||||
return csstreeNode.name === xastElement.name;
|
return csstreeNode.name === '*' || csstreeNode.name === xastElement.name;
|
||||||
}
|
}
|
||||||
if (csstreeNode.type === 'IdSelector') {
|
if (csstreeNode.type === 'IdSelector') {
|
||||||
return csstreeNode.name === xastElement.attributes.id;
|
return csstreeNode.name === xastElement.attributes.id;
|
||||||
@ -90,7 +90,7 @@ const elementMatches = (csstreeNode, xastElement) => {
|
|||||||
/**
|
/**
|
||||||
* @type {(
|
* @type {(
|
||||||
* startNode: XastParent,
|
* startNode: XastParent,
|
||||||
* descendants: Array<XastElement>,
|
* descendants: Set<XastElement>,
|
||||||
* parents: WeakMap<XastElement, XastParent>
|
* parents: WeakMap<XastElement, XastParent>
|
||||||
* ) => void}
|
* ) => void}
|
||||||
*/
|
*/
|
||||||
@ -98,7 +98,7 @@ const collectDescendantElements = (startNode, descendants, parents) => {
|
|||||||
for (const childNode of startNode.children) {
|
for (const childNode of startNode.children) {
|
||||||
if (childNode.type === 'element') {
|
if (childNode.type === 'element') {
|
||||||
parents.set(childNode, startNode);
|
parents.set(childNode, startNode);
|
||||||
descendants.push(childNode);
|
descendants.add(childNode);
|
||||||
collectDescendantElements(childNode, descendants, parents);
|
collectDescendantElements(childNode, descendants, parents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ const collectDescendantElements = (startNode, descendants, parents) => {
|
|||||||
/**
|
/**
|
||||||
* @type {(
|
* @type {(
|
||||||
* startNodes: Array<XastElement>,
|
* startNodes: Array<XastElement>,
|
||||||
* children: Array<XastElement>,
|
* children: Set<XastElement>,
|
||||||
* parents: WeakMap<XastElement, XastParent>
|
* parents: WeakMap<XastElement, XastParent>
|
||||||
* ) => void}
|
* ) => void}
|
||||||
*/
|
*/
|
||||||
@ -116,7 +116,7 @@ const collectChildrenElements = (startNodes, children, parents) => {
|
|||||||
for (const child of startNode.children) {
|
for (const child of startNode.children) {
|
||||||
if (child.type === 'element') {
|
if (child.type === 'element') {
|
||||||
parents.set(child, startNode);
|
parents.set(child, startNode);
|
||||||
children.push(child);
|
children.add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ const collectChildrenElements = (startNodes, children, parents) => {
|
|||||||
/**
|
/**
|
||||||
* @type {(
|
* @type {(
|
||||||
* startNodes: Array<XastElement>,
|
* startNodes: Array<XastElement>,
|
||||||
* siblings: Array<XastElement>,
|
* siblings: Set<XastElement>,
|
||||||
* parents: WeakMap<XastElement, XastParent>
|
* parents: WeakMap<XastElement, XastParent>
|
||||||
* ) => void}
|
* ) => void}
|
||||||
*/
|
*/
|
||||||
@ -139,7 +139,7 @@ const collectAdjacentSiblings = (startNodes, siblings, parents) => {
|
|||||||
for (const adjacentSibling of adjacentSiblings) {
|
for (const adjacentSibling of adjacentSiblings) {
|
||||||
if (adjacentSibling.type === 'element') {
|
if (adjacentSibling.type === 'element') {
|
||||||
parents.set(adjacentSibling, parentNode);
|
parents.set(adjacentSibling, parentNode);
|
||||||
siblings.push(adjacentSibling);
|
siblings.add(adjacentSibling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ const collectAdjacentSiblings = (startNodes, siblings, parents) => {
|
|||||||
/**
|
/**
|
||||||
* @type {(
|
* @type {(
|
||||||
* startNodes: Array<XastElement>,
|
* startNodes: Array<XastElement>,
|
||||||
* siblings: Array<XastElement>,
|
* siblings: Set<XastElement>,
|
||||||
* parents: WeakMap<XastElement, XastParent>
|
* parents: WeakMap<XastElement, XastParent>
|
||||||
* ) => void}
|
* ) => void}
|
||||||
*/
|
*/
|
||||||
@ -163,7 +163,7 @@ const collectGeneralSiblings = (startNodes, siblings, parents) => {
|
|||||||
for (const generalSibling of generalSiblings) {
|
for (const generalSibling of generalSiblings) {
|
||||||
if (generalSibling.type === 'element') {
|
if (generalSibling.type === 'element') {
|
||||||
parents.set(generalSibling, parentNode);
|
parents.set(generalSibling, parentNode);
|
||||||
siblings.push(generalSibling);
|
siblings.add(generalSibling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,9 +175,9 @@ const collectGeneralSiblings = (startNodes, siblings, parents) => {
|
|||||||
*/
|
*/
|
||||||
const combination = (csstreeNodes, xastNode) => {
|
const combination = (csstreeNodes, xastNode) => {
|
||||||
/**
|
/**
|
||||||
* @type {Array<XastElement>}
|
* @type {Set<XastElement>}
|
||||||
*/
|
*/
|
||||||
let candidateNodes = [];
|
let candidateNodes = new Set();
|
||||||
/**
|
/**
|
||||||
* @type {WeakMap<XastElement, XastParent>}
|
* @type {WeakMap<XastElement, XastParent>}
|
||||||
*/
|
*/
|
||||||
@ -189,12 +189,12 @@ const combination = (csstreeNodes, xastNode) => {
|
|||||||
let lastMatchedNodes = [];
|
let lastMatchedNodes = [];
|
||||||
for (const csstreeChild of csstreeNodes) {
|
for (const csstreeChild of csstreeNodes) {
|
||||||
if (csstreeChild.type === 'WhiteSpace') {
|
if (csstreeChild.type === 'WhiteSpace') {
|
||||||
|
candidateNodes = new Set();
|
||||||
for (const node of lastMatchedNodes) {
|
for (const node of lastMatchedNodes) {
|
||||||
candidateNodes = [];
|
|
||||||
collectDescendantElements(node, candidateNodes, candidateParents);
|
collectDescendantElements(node, candidateNodes, candidateParents);
|
||||||
}
|
}
|
||||||
} else if (csstreeChild.type === 'Combinator') {
|
} else if (csstreeChild.type === 'Combinator') {
|
||||||
candidateNodes = [];
|
candidateNodes = new Set();
|
||||||
if (csstreeChild.name === '>') {
|
if (csstreeChild.name === '>') {
|
||||||
collectChildrenElements(
|
collectChildrenElements(
|
||||||
lastMatchedNodes,
|
lastMatchedNodes,
|
||||||
|
@ -74,6 +74,15 @@ test('visit skips entering children if node is detached', () => {
|
|||||||
expect(entered).toEqual(['g', 'ellipse']);
|
expect(entered).toEqual(['g', 'ellipse']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('select by universal selector', () => {
|
||||||
|
const ast = root([x('g', null, [x('rect'), x('circle')])]);
|
||||||
|
expect(selectAll('*', ast)).toEqual([
|
||||||
|
x('g', null, [x('rect'), x('circle')]),
|
||||||
|
x('rect'),
|
||||||
|
x('circle'),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test('select elements by tag', () => {
|
test('select elements by tag', () => {
|
||||||
const ast = root([x('g', null, [x('rect')]), x('rect')]);
|
const ast = root([x('g', null, [x('rect')]), x('rect')]);
|
||||||
expect(selectAll('rect', ast)).toEqual([x('rect'), x('rect')]);
|
expect(selectAll('rect', ast)).toEqual([x('rect'), x('rect')]);
|
||||||
@ -172,6 +181,20 @@ test('select sibling and child elements', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('select descendants elements', () => {
|
||||||
|
const ast = root([
|
||||||
|
x('g', null, [
|
||||||
|
x('rect', { class: 'inside-g' }),
|
||||||
|
x('g', null, [x('rect', { class: 'inside-deeper-g' })]),
|
||||||
|
]),
|
||||||
|
x('rect', { class: 'inside-root' }),
|
||||||
|
]);
|
||||||
|
expect(selectAll('g rect', ast)).toEqual([
|
||||||
|
x('rect', { class: 'inside-g' }),
|
||||||
|
x('rect', { class: 'inside-deeper-g' }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test('select sibling and child elements', () => {
|
test('select sibling and child elements', () => {
|
||||||
const ast = root([
|
const ast = root([
|
||||||
x('g', null, [
|
x('g', null, [
|
||||||
|
Reference in New Issue
Block a user