summaryrefslogtreecommitdiff
path: root/node_modules/svgo/lib/style.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/svgo/lib/style.js')
-rw-r--r--node_modules/svgo/lib/style.js95
1 files changed, 72 insertions, 23 deletions
diff --git a/node_modules/svgo/lib/style.js b/node_modules/svgo/lib/style.js
index eb8d93d8..29e4a538 100644
--- a/node_modules/svgo/lib/style.js
+++ b/node_modules/svgo/lib/style.js
@@ -14,8 +14,9 @@
*/
const csstree = require('css-tree');
+const csswhat = require('css-what');
const {
- // @ts-ignore not defined in @types/csso
+ // @ts-ignore internal api
syntax: { specificity },
} = require('csso');
const { visit, matches } = require('./xast.js');
@@ -47,9 +48,7 @@ const parseRule = (ruleNode, dynamic) => {
}
});
- /**
- * @type {StylesheetRule[]}
- */
+ /** @type {StylesheetRule[]} */
const rules = [];
csstree.walk(ruleNode.prelude, (node) => {
if (node.type === 'Selector') {
@@ -78,9 +77,7 @@ const parseRule = (ruleNode, dynamic) => {
* @type {(css: string, dynamic: boolean) => Array<StylesheetRule>}
*/
const parseStylesheet = (css, dynamic) => {
- /**
- * @type {Array<StylesheetRule>}
- */
+ /** @type {Array<StylesheetRule>} */
const rules = [];
const ast = csstree.parse(css, {
parseValue: false,
@@ -92,7 +89,10 @@ const parseStylesheet = (css, dynamic) => {
return csstreeWalkSkip;
}
if (cssNode.type === 'Atrule') {
- if (cssNode.name === 'keyframes') {
+ if (
+ cssNode.name === 'keyframes' ||
+ cssNode.name === '-webkit-keyframes'
+ ) {
return csstreeWalkSkip;
}
csstree.walk(cssNode, (ruleNode) => {
@@ -111,9 +111,7 @@ const parseStylesheet = (css, dynamic) => {
* @type {(css: string) => Array<StylesheetDeclaration>}
*/
const parseStyleDeclarations = (css) => {
- /**
- * @type {Array<StylesheetDeclaration>}
- */
+ /** @type {Array<StylesheetDeclaration>} */
const declarations = [];
const ast = csstree.parse(css, {
context: 'declarationList',
@@ -135,9 +133,7 @@ const parseStyleDeclarations = (css) => {
* @type {(stylesheet: Stylesheet, node: XastElement) => ComputedStyles}
*/
const computeOwnStyle = (stylesheet, node) => {
- /**
- * @type {ComputedStyles}
- */
+ /** @type {ComputedStyles} */
const computedStyle = {};
const importantStyles = new Map();
@@ -197,10 +193,12 @@ const computeOwnStyle = (stylesheet, node) => {
};
/**
- * Compares two selector specificities.
- * extracted from https://github.com/keeganstreet/specificity/blob/main/specificity.js#L211
+ * Compares selector specificities.
+ * Derived from https://github.com/keeganstreet/specificity/blob/8757133ddd2ed0163f120900047ff0f92760b536/specificity.js#L207
*
- * @type {(a: Specificity, b: Specificity) => number}
+ * @param {Specificity} a
+ * @param {Specificity} b
+ * @returns {number}
*/
const compareSpecificity = (a, b) => {
for (let i = 0; i < 4; i += 1) {
@@ -213,18 +211,15 @@ const compareSpecificity = (a, b) => {
return 0;
};
+exports.compareSpecificity = compareSpecificity;
/**
* @type {(root: XastRoot) => Stylesheet}
*/
const collectStylesheet = (root) => {
- /**
- * @type {Array<StylesheetRule>}
- */
+ /** @type {Array<StylesheetRule>} */
const rules = [];
- /**
- * @type {Map<XastElement, XastParent>}
- */
+ /** @type {Map<XastElement, XastParent>} */
const parents = new Map();
visit(root, {
element: {
@@ -282,3 +277,57 @@ const computeStyle = (stylesheet, node) => {
return computedStyles;
};
exports.computeStyle = computeStyle;
+
+/**
+ * Determines if the CSS selector includes or traverses the given attribute.
+ *
+ * Classes and IDs are generated as attribute selectors, so you can check for
+ * if a `.class` or `#id` is included by passing `name=class` or `name=id`
+ * respectively.
+ *
+ * @param {csstree.ListItem<csstree.CssNode>|string} selector
+ * @param {string} name
+ * @param {?string} value
+ * @param {boolean} traversed
+ * @returns {boolean}
+ */
+const includesAttrSelector = (
+ selector,
+ name,
+ value = null,
+ traversed = false
+) => {
+ const selectors =
+ typeof selector === 'string'
+ ? csswhat.parse(selector)
+ : csswhat.parse(csstree.generate(selector.data));
+
+ for (const subselector of selectors) {
+ const hasAttrSelector = subselector.some((segment, index) => {
+ if (traversed) {
+ if (index === subselector.length - 1) {
+ return false;
+ }
+
+ const isNextTraversal = csswhat.isTraversal(subselector[index + 1]);
+
+ if (!isNextTraversal) {
+ return false;
+ }
+ }
+
+ if (segment.type !== 'attribute' || segment.name !== name) {
+ return false;
+ }
+
+ return value == null ? true : segment.value === value;
+ });
+
+ if (hasAttrSelector) {
+ return true;
+ }
+ }
+
+ return false;
+};
+exports.includesAttrSelector = includesAttrSelector;