Array-like collection management for media queries and document matchers with automatic deduplication and proper serialization.
Manages collections of media types and media queries with array-like behavior and automatic deduplication.
/**
* Collection of media types and queries for @media rules and @import conditions
*/
class MediaList {
constructor();
/** Number of media items in the list */
length: number;
/** Comma-separated string representation of all media items */
mediaText: string;
/**
* Add a media type/query if not already present
* @param {string} medium - Media type or query to add
*/
appendMedium(medium): void;
/**
* Remove a media type/query if present
* @param {string} medium - Media type or query to remove
*/
deleteMedium(medium): void;
// Array-like indexed access: [0], [1], etc.
}Usage Examples:
const { MediaList, parse } = require("cssom");
// Create new media list
const mediaList = new MediaList();
// Add media types
mediaList.appendMedium("screen");
mediaList.appendMedium("print");
mediaList.appendMedium("(max-width: 768px)");
console.log(mediaList.length); // 3
console.log(mediaList.mediaText); // "screen, print, (max-width: 768px)"
// Array-like access
console.log(mediaList[0]); // "screen"
console.log(mediaList[1]); // "print"
console.log(mediaList[2]); // "(max-width: 768px)"
// Remove media type
mediaList.deleteMedium("print");
console.log(mediaList.length); // 2
console.log(mediaList.mediaText); // "screen, (max-width: 768px)"
// Access from parsed CSS
const sheet = parse(`
@media screen and (max-width: 768px), print {
body { font-size: 14px; }
}
`);
const mediaRule = sheet.cssRules[0];
console.log(mediaRule.media.length); // 2
console.log(mediaRule.media.mediaText); // "screen and (max-width: 768px), print"MediaList integration with CSS @import rules:
const { parse } = require("cssom");
const sheet = parse(`
@import "base.css";
@import "responsive.css" screen and (min-width: 768px);
@import url("print.css") print;
`);
// Access media list from import rules
const importRule1 = sheet.cssRules[0];
const importRule2 = sheet.cssRules[1];
const importRule3 = sheet.cssRules[2];
console.log(importRule1.media.length); // 0 (no media specified)
console.log(importRule2.media.mediaText); // "screen and (min-width: 768px)"
console.log(importRule3.media.mediaText); // "print"Manages collections of document matchers for @-moz-document rules with similar array-like behavior.
/**
* Collection of document matchers for @-moz-document rules
*/
class MatcherList {
constructor();
/** Number of matcher items in the list */
length: number;
/** Comma-separated string representation of all matchers */
matcherText: string;
/**
* Add a document matcher if not already present
* @param {string} matcher - Document matcher to add
*/
appendMatcher(matcher): void;
/**
* Remove a document matcher if present
* @param {string} matcher - Document matcher to remove
*/
deleteMatcher(matcher): void;
// Array-like indexed access: [0], [1], etc.
}Usage Examples:
const { MatcherList, parse } = require("cssom");
// Create new matcher list
const matcherList = new MatcherList();
// Add document matchers
matcherList.appendMatcher("url(http://example.com/)");
matcherList.appendMatcher("url-prefix(https://secure.example.com/)");
matcherList.appendMatcher("domain(example.org)");
console.log(matcherList.length); // 3
console.log(matcherList.matcherText);
// "url(http://example.com/), url-prefix(https://secure.example.com/), domain(example.org)"
// Array-like access
console.log(matcherList[0]); // "url(http://example.com/)"
console.log(matcherList[1]); // "url-prefix(https://secure.example.com/)"
// Remove matcher
matcherList.deleteMatcher("domain(example.org)");
console.log(matcherList.length); // 2
// Access from parsed CSS (Firefox-specific)
const sheet = parse(`
@-moz-document url-prefix(http://example.com/), domain(example.org) {
body { background: red; }
}
`);
const docRule = sheet.cssRules[0];
console.log(docRule.matcher.length); // 2
console.log(docRule.matcher.matcherText); // "url-prefix(http://example.com/), domain(example.org)"Complex operations and manipulations with media and matcher lists:
const { MediaList, MatcherList } = require("cssom");
// Media list manipulation
const media = new MediaList();
// Bulk operations
const mediaTypes = ["screen", "print", "(max-width: 768px)", "handheld"];
mediaTypes.forEach(type => media.appendMedium(type));
console.log(media.mediaText);
// Conditional modifications
if (media.length > 2) {
media.deleteMedium("handheld"); // Remove outdated media type
}
// Check for specific media types
for (let i = 0; i < media.length; i++) {
if (media[i].includes("max-width")) {
console.log("Found responsive media query:", media[i]);
}
}
// Matcher list manipulation
const matchers = new MatcherList();
// Common document matcher patterns
const patterns = [
"url(http://example.com/)",
"url-prefix(https://secure.)",
"domain(trusted.example.org)",
"regexp(\"https://.*\\.example\\.com/.*\")"
];
patterns.forEach(pattern => matchers.appendMatcher(pattern));
console.log(matchers.matcherText);Both MediaList and MatcherList automatically handle duplicates:
const { MediaList } = require("cssom");
const media = new MediaList();
// Add same media type multiple times
media.appendMedium("screen");
media.appendMedium("print");
media.appendMedium("screen"); // Duplicate - won't be added again
console.log(media.length); // 2 (not 3)
console.log(media.mediaText); // "screen, print"
// Verify deduplication
console.log(media[0]); // "screen"
console.log(media[1]); // "print"
console.log(media[2]); // undefinedHow lists serialize to and parse from CSS text:
const { parse, MediaList } = require("cssom");
// Parse complex media queries
const complexCSS = `
@media screen and (min-width: 768px) and (max-width: 1024px),
print and (orientation: landscape),
(prefers-color-scheme: dark) {
.content { padding: 20px; }
}
`;
const sheet = parse(complexCSS);
const mediaRule = sheet.cssRules[0];
console.log("Parsed media count:", mediaRule.media.length);
console.log("Full media text:", mediaRule.media.mediaText);
// Individual media queries
for (let i = 0; i < mediaRule.media.length; i++) {
console.log(`Media ${i + 1}:`, mediaRule.media[i]);
}
// Modify and re-serialize
mediaRule.media.appendMedium("(min-resolution: 2dppx)");
console.log("Updated media text:", mediaRule.media.mediaText);Important considerations when working with lists:
const { MatcherList } = require("cssom");
// Current limitation: URLs with commas may not parse correctly
const matchers = new MatcherList();
// This works fine
matchers.appendMatcher("url(http://example.com/path)");
// This might have issues if the URL contains commas
// matchers.appendMatcher("url(http://example.com/path?param=a,b,c)");
// Workaround: Use URL encoding or avoid commas in matcher URLs
console.log("Matcher count:", matchers.length);
console.log("Matcher text:", matchers.matcherText);
// MediaList handles complex queries better
const media = new MediaList();
media.appendMedium("screen and (min-width: 768px)");
media.appendMedium("print and (color)");
console.log("Media handling is more robust:", media.mediaText);Utility patterns for working with CSS collections:
const { parse } = require("cssom");
// Helper function to extract all media queries from a stylesheet
function extractMediaQueries(stylesheet) {
const mediaQueries = [];
for (let i = 0; i < stylesheet.cssRules.length; i++) {
const rule = stylesheet.cssRules[i];
if (rule.type === 4) { // MEDIA_RULE
for (let j = 0; j < rule.media.length; j++) {
mediaQueries.push(rule.media[j]);
}
}
if (rule.type === 3) { // IMPORT_RULE
for (let j = 0; j < rule.media.length; j++) {
mediaQueries.push(rule.media[j]);
}
}
}
return mediaQueries;
}
// Usage
const sheet = parse(`
@import "base.css" screen;
@media (max-width: 768px) { body { font-size: 14px; } }
@media print { body { color: black; } }
`);
const allMediaQueries = extractMediaQueries(sheet);
console.log("All media queries found:", allMediaQueries);