Specialized diffing for CSS content with CSS-aware tokenization. Optimizes diff results for CSS syntax by treating CSS structural elements (selectors, properties, values, and punctuation) as meaningful tokens.
Performs CSS-aware diff between two CSS strings with specialized tokenization.
/**
* Compare two CSS strings with CSS-aware tokenization
* @param oldStr - Original CSS content
* @param newStr - New CSS content to compare against
* @param options - Configuration options
* @returns Array of change objects representing the diff
*/
function diffCss(oldStr, newStr, options);Usage Examples:
import { diffCss } from "diff";
// Basic CSS comparison
const result = diffCss(
".class { color: red; }",
".class { color: blue; }"
);
console.log(result);
// Shows structured diff with CSS tokens
// Complex CSS comparison
const complexResult = diffCss(`
.header {
background-color: #ffffff;
padding: 20px;
margin: 0;
}
.footer {
background-color: #000000;
}
`, `
.header {
background-color: #f0f0f0;
padding: 20px;
margin: 10px;
}
.sidebar {
width: 300px;
}
.footer {
background-color: #000000;
}
`);Pre-configured Diff instance for CSS comparisons with CSS-specific tokenization.
/**
* Pre-configured CSS diff instance
* Uses CSS-aware tokenization for structural elements
*/
const cssDiff: Diff;The CSS diff tokenizes content based on CSS syntax elements:
.class, #id, element, [attribute]{ and }color, red, 20px:, ;, ,import { cssDiff } from "diff";
// Understanding tokenization
const tokens = cssDiff.tokenize(".class { color: red; }");
console.log("CSS tokens:", tokens);
// [".class", " ", "{", " ", "color", ":", " ", "red", ";", " ", "}"]import { diffCss } from "diff";
function compareStyleRules(oldCss, newCss) {
const changes = diffCss(oldCss, newCss);
const analysis = {
selectorsChanged: 0,
propertiesChanged: 0,
valuesChanged: 0,
rulesAdded: 0,
rulesRemoved: 0
};
changes.forEach(change => {
if (change.added || change.removed) {
const content = change.value;
if (content.includes('{')) analysis.rulesAdded += change.added ? 1 : 0;
if (content.includes('{')) analysis.rulesRemoved += change.removed ? 1 : 0;
if (content.includes(':')) analysis.propertiesChanged++;
}
});
return analysis;
}
// Usage
const oldStyles = `
.button {
background: blue;
padding: 10px;
}`;
const newStyles = `
.button {
background: green;
padding: 15px;
border: 1px solid;
}`;
const styleAnalysis = compareStyleRules(oldStyles, newStyles);import { diffCss } from "diff";
function detectCssChanges(originalCss, refactoredCss) {
const diff = diffCss(originalCss, refactoredCss);
const changeTypes = {
colorChanges: [],
sizingChanges: [],
layoutChanges: [],
newRules: [],
removedRules: []
};
diff.forEach(change => {
if (change.added || change.removed) {
const value = change.value.toLowerCase();
if (value.includes('color') || value.includes('#') ||
value.includes('rgb') || value.includes('rgba')) {
changeTypes.colorChanges.push(change);
}
if (value.includes('px') || value.includes('em') ||
value.includes('rem') || value.includes('%')) {
changeTypes.sizingChanges.push(change);
}
if (value.includes('position') || value.includes('display') ||
value.includes('flex') || value.includes('grid')) {
changeTypes.layoutChanges.push(change);
}
}
});
return changeTypes;
}import { diffCss } from "diff";
function generateMigrationReport(oldStylesheet, newStylesheet) {
const changes = diffCss(oldStylesheet, newStylesheet);
const report = {
timestamp: new Date().toISOString(),
totalChanges: changes.filter(c => c.added || c.removed).length,
additions: changes.filter(c => c.added).map(c => c.value.trim()),
removals: changes.filter(c => c.removed).map(c => c.value.trim()),
affectedSelectors: new Set()
};
// Extract selectors from changes
changes.forEach(change => {
if (change.added || change.removed) {
const selectorMatch = change.value.match(/([.#]?[\w-]+)\s*{/);
if (selectorMatch) {
report.affectedSelectors.add(selectorMatch[1]);
}
}
});
report.affectedSelectors = Array.from(report.affectedSelectors);
return report;
}import { diffCss } from "diff";
function validateCssChanges(oldCss, newCss) {
const changes = diffCss(oldCss, newCss);
const warnings = [];
changes.forEach(change => {
if (change.added) {
const value = change.value;
// Check for potential issues
if (value.includes('!important')) {
warnings.push({
type: 'important_usage',
content: value.trim(),
message: 'New !important declaration added'
});
}
if (value.match(/color:\s*#[\da-f]{3,6}/i)) {
const colorMatch = value.match(/#[\da-f]{3,6}/i);
if (colorMatch) {
warnings.push({
type: 'color_change',
content: colorMatch[0],
message: 'New color value introduced'
});
}
}
}
if (change.removed) {
// Check for potentially breaking removals
if (change.value.includes('display') || change.value.includes('position')) {
warnings.push({
type: 'layout_removal',
content: change.value.trim(),
message: 'Layout-affecting property removed'
});
}
}
});
return warnings;
}import { diffCss } from "diff";
function diffLargeStylesheets(css1, css2, callback) {
// Process large CSS files asynchronously
diffCss(css1, css2, {
callback: callback,
maxEditLength: 20000, // Suitable for large CSS files
timeout: 30000 // 30 second timeout
});
}
// Usage
diffLargeStylesheets(largeStylesheet1, largeStylesheet2, (result) => {
if (result) {
const significantChanges = result.filter(change =>
(change.added || change.removed) &&
change.value.trim().length > 0
);
console.log(`Found ${significantChanges.length} significant CSS changes`);
} else {
console.log("Stylesheets too different to compute diff efficiently");
}
});import { cssDiff } from "diff";
// Using the pre-configured instance
const directResult = cssDiff.diff(
".old { color: red; }",
".new { color: blue; }"
);
// Access tokenization directly
const tokens = cssDiff.tokenize("body { margin: 0; padding: 0; }");
console.log("CSS structure:", tokens);
// Custom processing with the instance
const customResult = cssDiff.diff(oldCss, newCss);
const onlyMeaningfulChanges = customResult.filter(change => {
// Filter out pure whitespace changes
return !(change.value.trim() === '' || /^\s+$/.test(change.value));
});import { diffCss } from "diff";
function migrateTheme(lightTheme, darkTheme) {
const themeDiff = diffCss(lightTheme, darkTheme);
return themeDiff
.filter(change => change.added)
.map(change => change.value)
.join('')
.replace(/\s+/g, ' ')
.trim();
}import { diffCss } from "diff";
function cssChangeDetection(beforeBuild, afterBuild) {
const changes = diffCss(beforeBuild, afterBuild);
const hasSignificantChanges = changes.some(change =>
(change.added || change.removed) &&
!change.value.match(/^\s*$/) // Not just whitespace
);
return {
hasChanges: hasSignificantChanges,
changeCount: changes.filter(c => c.added || c.removed).length,
diff: changes
};
}