Use local svgo.cmd wrapper binary

Switch SVG optimizer resolution from bin/svgo-cli.exe to bin/svgo.cmd.

Update unit tests to validate the new local binary path behavior.

Co-Authored-By: Abacus.AI CLI <agent@abacus.ai>
This commit is contained in:
2026-06-08 14:50:19 +02:00
parent 75059f829a
commit 6c5a5256c7
1054 changed files with 152359 additions and 7 deletions
+12
View File
@@ -0,0 +1,12 @@
import type { CompiledQuery, InternalOptions } from "../types.js";
/**
* Some selectors such as `:contains` and (non-relative) `:has` will only be
* able to match elements if their parents match the selector (as they contain
* a subset of the elements that the parent contains).
*
* This function wraps the given `matches` function in a function that caches
* the results of the parent elements, so that the `matches` function only
* needs to be called once for each subtree.
*/
export declare function cacheParentResults<Node, ElementNode extends Node>(next: CompiledQuery<ElementNode>, { adapter, cacheResults }: InternalOptions<Node, ElementNode>, matches: (elem: ElementNode) => boolean): CompiledQuery<ElementNode>;
//# sourceMappingURL=cache.d.ts.map
+45
View File
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cacheParentResults = cacheParentResults;
var querying_js_1 = require("./querying.js");
/**
* Some selectors such as `:contains` and (non-relative) `:has` will only be
* able to match elements if their parents match the selector (as they contain
* a subset of the elements that the parent contains).
*
* This function wraps the given `matches` function in a function that caches
* the results of the parent elements, so that the `matches` function only
* needs to be called once for each subtree.
*/
function cacheParentResults(next, _a, matches) {
var adapter = _a.adapter, cacheResults = _a.cacheResults;
if (cacheResults === false || typeof WeakMap === "undefined") {
return function (elem) { return next(elem) && matches(elem); };
}
// Use a cache to avoid re-checking children of an element.
// @ts-expect-error `Node` is not extending object
var resultCache = new WeakMap();
function addResultToCache(elem) {
var result = matches(elem);
resultCache.set(elem, result);
return result;
}
return function cachedMatcher(elem) {
if (!next(elem))
return false;
if (resultCache.has(elem)) {
return resultCache.get(elem);
}
// Check all of the element's parents.
var node = elem;
do {
var parent = (0, querying_js_1.getElementParent)(node, adapter);
if (parent === null) {
return addResultToCache(elem);
}
node = parent;
} while (!resultCache.has(node));
return resultCache.get(node) && addResultToCache(elem);
};
}
//# sourceMappingURL=cache.js.map
+24
View File
@@ -0,0 +1,24 @@
import type { InternalOptions, Predicate, Adapter } from "../types.js";
/**
* Find all elements matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
*
* @param query - Function that returns true if the element matches the query.
* @param elems - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns All matching elements.
*/
export declare function findAll<Node, ElementNode extends Node>(query: Predicate<ElementNode>, elems: Node[], options: InternalOptions<Node, ElementNode>): ElementNode[];
/**
* Find the first element matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
*
* @param query - Function that returns true if the element matches the query.
* @param elems - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns The first matching element, or null if there was no match.
*/
export declare function findOne<Node, ElementNode extends Node>(query: Predicate<ElementNode>, elems: Node[], options: InternalOptions<Node, ElementNode>): ElementNode | null;
export declare function getNextSiblings<Node, ElementNode extends Node>(elem: Node, adapter: Adapter<Node, ElementNode>): ElementNode[];
export declare function getElementParent<Node, ElementNode extends Node>(node: ElementNode, adapter: Adapter<Node, ElementNode>): ElementNode | null;
//# sourceMappingURL=querying.d.ts.map
+111
View File
@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findAll = findAll;
exports.findOne = findOne;
exports.getNextSiblings = getNextSiblings;
exports.getElementParent = getElementParent;
/**
* Find all elements matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
*
* @param query - Function that returns true if the element matches the query.
* @param elems - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns All matching elements.
*/
function findAll(query, elems, options) {
var adapter = options.adapter, _a = options.xmlMode, xmlMode = _a === void 0 ? false : _a;
var result = [];
/** Stack of the arrays we are looking at. */
var nodeStack = [elems];
/** Stack of the indices within the arrays. */
var indexStack = [0];
for (;;) {
// First, check if the current array has any more elements to look at.
if (indexStack[0] >= nodeStack[0].length) {
// If we have no more arrays to look at, we are done.
if (nodeStack.length === 1) {
return result;
}
nodeStack.shift();
indexStack.shift();
// Loop back to the start to continue with the next array.
continue;
}
var elem = nodeStack[0][indexStack[0]++];
if (!adapter.isTag(elem))
continue;
if (query(elem))
result.push(elem);
if (xmlMode || adapter.getName(elem) !== "template") {
/*
* Add the children to the stack. We are depth-first, so this is
* the next array we look at.
*/
var children = adapter.getChildren(elem);
if (children.length > 0) {
nodeStack.unshift(children);
indexStack.unshift(0);
}
}
}
}
/**
* Find the first element matching the query. If not in XML mode, the query will ignore
* the contents of `<template>` elements.
*
* @param query - Function that returns true if the element matches the query.
* @param elems - Nodes to query. If a node is an element, its children will be queried.
* @param options - Options for querying the document.
* @returns The first matching element, or null if there was no match.
*/
function findOne(query, elems, options) {
var adapter = options.adapter, _a = options.xmlMode, xmlMode = _a === void 0 ? false : _a;
/** Stack of the arrays we are looking at. */
var nodeStack = [elems];
/** Stack of the indices within the arrays. */
var indexStack = [0];
for (;;) {
// First, check if the current array has any more elements to look at.
if (indexStack[0] >= nodeStack[0].length) {
// If we have no more arrays to look at, we are done.
if (nodeStack.length === 1) {
return null;
}
nodeStack.shift();
indexStack.shift();
// Loop back to the start to continue with the next array.
continue;
}
var elem = nodeStack[0][indexStack[0]++];
if (!adapter.isTag(elem))
continue;
if (query(elem))
return elem;
if (xmlMode || adapter.getName(elem) !== "template") {
/*
* Add the children to the stack. We are depth-first, so this is
* the next array we look at.
*/
var children = adapter.getChildren(elem);
if (children.length > 0) {
nodeStack.unshift(children);
indexStack.unshift(0);
}
}
}
}
function getNextSiblings(elem, adapter) {
var siblings = adapter.getSiblings(elem);
if (siblings.length <= 1)
return [];
var elemIndex = siblings.indexOf(elem);
if (elemIndex < 0 || elemIndex === siblings.length - 1)
return [];
return siblings.slice(elemIndex + 1).filter(adapter.isTag);
}
function getElementParent(node, adapter) {
var parent = adapter.getParent(node);
return parent != null && adapter.isTag(parent) ? parent : null;
}
//# sourceMappingURL=querying.js.map
+20
View File
@@ -0,0 +1,20 @@
import type { InternalSelector } from "../types.js";
import { type Traversal } from "css-what";
export declare function isTraversal(token: InternalSelector): token is Traversal;
/**
* Sort the parts of the passed selector, as there is potential for
* optimization (some types of selectors are faster than others).
*
* @param arr Selector to sort
*/
export declare function sortRules(arr: InternalSelector[]): void;
/**
* Determine the quality of the passed token. The higher the number, the
* faster the token is to execute.
*
* @param token Token to get the quality of.
* @returns The token's quality.
*/
export declare function getQuality(token: InternalSelector): number;
export declare function includesScopePseudo(t: InternalSelector): boolean;
//# sourceMappingURL=selectors.d.ts.map
+111
View File
@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTraversal = isTraversal;
exports.sortRules = sortRules;
exports.getQuality = getQuality;
exports.includesScopePseudo = includesScopePseudo;
var css_what_1 = require("css-what");
function isTraversal(token) {
return token.type === "_flexibleDescendant" || (0, css_what_1.isTraversal)(token);
}
/**
* Sort the parts of the passed selector, as there is potential for
* optimization (some types of selectors are faster than others).
*
* @param arr Selector to sort
*/
function sortRules(arr) {
var ratings = arr.map(getQuality);
for (var i = 1; i < arr.length; i++) {
var procNew = ratings[i];
if (procNew < 0)
continue;
// Use insertion sort to move the token to the correct position.
for (var j = i; j > 0 && procNew < ratings[j - 1]; j--) {
var token = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = token;
ratings[j] = ratings[j - 1];
ratings[j - 1] = procNew;
}
}
}
function getAttributeQuality(token) {
switch (token.action) {
case css_what_1.AttributeAction.Exists: {
return 10;
}
case css_what_1.AttributeAction.Equals: {
// Prefer ID selectors (eg. #ID)
return token.name === "id" ? 9 : 8;
}
case css_what_1.AttributeAction.Not: {
return 7;
}
case css_what_1.AttributeAction.Start: {
return 6;
}
case css_what_1.AttributeAction.End: {
return 6;
}
case css_what_1.AttributeAction.Any: {
return 5;
}
case css_what_1.AttributeAction.Hyphen: {
return 4;
}
case css_what_1.AttributeAction.Element: {
return 3;
}
}
}
/**
* Determine the quality of the passed token. The higher the number, the
* faster the token is to execute.
*
* @param token Token to get the quality of.
* @returns The token's quality.
*/
function getQuality(token) {
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (token.type) {
case css_what_1.SelectorType.Universal: {
return 50;
}
case css_what_1.SelectorType.Tag: {
return 30;
}
case css_what_1.SelectorType.Attribute: {
return Math.floor(getAttributeQuality(token) /
// `ignoreCase` adds some overhead, half the result if applicable.
(token.ignoreCase ? 2 : 1));
}
case css_what_1.SelectorType.Pseudo: {
return !token.data
? 3
: token.name === "has" ||
token.name === "contains" ||
token.name === "icontains"
? // Expensive in any case — run as late as possible.
0
: Array.isArray(token.data)
? // Eg. `:is`, `:not`
Math.max(
// If we have traversals, try to avoid executing this selector
0, Math.min.apply(Math, token.data.map(function (d) {
return Math.min.apply(Math, d.map(getQuality));
})))
: 2;
}
default: {
return -1;
}
}
}
function includesScopePseudo(t) {
return (t.type === css_what_1.SelectorType.Pseudo &&
(t.name === "scope" ||
(Array.isArray(t.data) &&
t.data.some(function (data) { return data.some(includesScopePseudo); }))));
}
//# sourceMappingURL=selectors.js.map