🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

css-dedup

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-dedup - npm Package Compare versions

Comparing version
1.3.2
to
1.3.3
+2
-2
package.json

@@ -64,3 +64,3 @@ {

"types": "src/index.d.ts",
"version": "1.3.2"
}
"version": "1.3.3"
}
import postcss from 'postcss';
import { normalizeProp, declarationKey } from './normalization.js';
import { isIgnoredSelector, resolveIgnorePatterns } from './hacks.js';
import { splitSelectors, selectorsAreMutuallyExclusive, selectorsLikelyDisjoint, resetSubjectIdentities } from './selectors.js';
import { splitSelectors, hasSpacedTopLevelComma, selectorsAreMutuallyExclusive, selectorsLikelyDisjoint, resetSubjectIdentities } from './selectors.js';
import { propertiesOverlap } from './shorthands.js';

@@ -362,4 +362,38 @@

function joinSelectors(selectors, rule, multiline) {
if (!multiline) return selectors.join(', ');
// Detects whether this style sheet’s existing multi-selector rules put a
// space after the (inline) comma (`.a, .b {}`) or not (`.a,.b{}`, as a
// minifier writes it)—by majority vote among their first top-level commas,
// same “majority vote” approach as `typicalSeparator()` above. Only rules
// already written inline count—a rule using the multiline convention says
// nothing about inline comma spacing.
function usesSpacedCommas(root) {
let spaced = 0;
let tight = 0;
root.walkRules(rule => {
if (RE_MULTILINE_SELECTOR_SEPARATOR.test(rule.selector)) return;
const spacedComma = hasSpacedTopLevelComma(rule.selector);
if (spacedComma === null) return;
if (spacedComma) spaced++; else tight++;
});
if (spaced || tight) return spaced >= tight;
// No existing multi-selector rule to learn the comma convention from
// (the merge about to run may be creating the file’s first one)—fall back
// to whether rules already omit the space before their opening brace
// (`.a{}` vs `.a {}`), which a minifier strips just as consistently as
// the space after a comma
return usesSpacedBraces(root);
}
function usesSpacedBraces(root) {
let spaced = 0;
let tight = 0;
root.walkRules(rule => {
if ((rule.raws.between ?? ' ') === '') tight++; else spaced++;
});
return spaced >= tight;
}
function joinSelectors(selectors, rule, multiline, spacedCommas) {
if (!multiline) return selectors.join(spacedCommas ? ', ' : ',');
const indent = (rule.raws.before ?? '').match(RE_TRAILING_INDENT)[0];

@@ -438,2 +472,3 @@ return selectors.join(`,\n${indent}`);

const multilineSelectors = usesMultilineSelectors(root);
const spacedCommas = usesSpacedCommas(root);
const applied = [];

@@ -685,3 +720,3 @@ const skipped = [];

const targetOriginalSelector = target.selector;
target.selector = joinSelectors(mergedSelectors, target, multilineSelectors);
target.selector = joinSelectors(mergedSelectors, target, multilineSelectors, spacedCommas);

@@ -845,3 +880,3 @@ // All occurrences share a normalized key, so they’re equivalent by our

}
target.selector = joinSelectors(mergedSelectors, target, multilineSelectors);
target.selector = joinSelectors(mergedSelectors, target, multilineSelectors, spacedCommas);

@@ -930,3 +965,3 @@ for (const decl of target.nodes) {

const mergedRule = lastRule.clone({ nodes: [] });
mergedRule.selector = joinSelectors(mergedSelectors, lastRule, multilineSelectors);
mergedRule.selector = joinSelectors(mergedSelectors, lastRule, multilineSelectors, spacedCommas);
const lastDecl = runOccurrences.find(occ => occ.rule === lastRule).decl;

@@ -1092,3 +1127,3 @@ lastDecl.remove();

const anchorRule = hub.clone({ nodes: [] });
anchorRule.selector = joinSelectors(mergedSelectors, hub, multilineSelectors);
anchorRule.selector = joinSelectors(mergedSelectors, hub, multilineSelectors, spacedCommas);
sharedDecl.remove();

@@ -1095,0 +1130,0 @@ anchorRule.append(sharedDecl);

@@ -56,2 +56,30 @@ // Splits a selector list on top-level commas only, respecting commas nested

// Whether a selector list’s top-level commas are followed by whitespace
// (`.a, .b`) or not (`.a,.b`, as a minifier writes it)—checked against the
// first top-level comma only, on the assumption that one selector list
// doesn’t mix conventions. “null” when there’s no top-level comma to judge
// by. Reuses the same depth/quote/escape-aware scan as `splitSelectors()`
// above, so a comma nested inside `:is(a,b)`/`[attr="a,b"]` is never
// mistaken for the list’s own separator.
export function hasSpacedTopLevelComma(selectorList) {
let depth = 0;
let quote = null;
let escaped = false;
for (let i = 0; i < selectorList.length; i++) {
const char = selectorList[i];
if (escaped) { escaped = false; continue; }
if (char === '\\') { escaped = true; continue; }
if (quote) { if (char === quote) quote = null; continue; }
if (char === '"' || char === '\'') { quote = char; continue; }
if (char === '(' || char === '[') depth++;
if (char === ')' || char === ']') depth = Math.max(0, depth - 1);
if (char === ',' && depth === 0) return /\s/.test(selectorList[i + 1] ?? '');
}
return null;
}
// Matches one `[attr]`, `[attr=value]`, `[attr~=value]`, `[attr|=value]`,

@@ -58,0 +86,0 @@ // `[attr^=value]`, `[attr$=value]`, or `[attr*=value]`, quoted or not, with