Skip to content

Instantly share code, notes, and snippets.

@raininglemons
Last active September 5, 2016 11:26
Show Gist options
  • Save raininglemons/89fbfe32ffcd30d9c8536ef890269694 to your computer and use it in GitHub Desktop.
Save raininglemons/89fbfe32ffcd30d9c8536ef890269694 to your computer and use it in GitHub Desktop.
(() => {
class CSSReader {
constructor(input) {
const rules = input.split('\n') //.match(/((#|\.)?[\[\]\(\)a-zA-Z0-9_\-:]+,?\s*)+{.+}/g);
this.rules = rules.map((rule, i) => {
// console.log(`Processing ${i} of ${rules.length}`);
if (rule.substr(0, 1) === '@') {
// Strip out media queries...
rule = rule.substr(rule.indexOf('{'));
}
try {
return new Rule(rule);
} catch (e) {
// console.error(e);
return null;
}
}).filter(rule => rule !== null);
this.hashes = this.rules.reduce((hashes, rule) => {
if (!hashes[rule.hash]) {
hashes[rule.hash] = [];
}
hashes[rule.hash].push(rule);
return hashes;
}, {});
this.duplicates = Object.keys(this.hashes).filter(hash => this.hashes[hash].length > 1)
.reduce((duplicates, hash) => {
duplicates[hash] = this.hashes[hash];
return duplicates;
}, {})
}
}
const regex = {
selector: /((#|\.?[\[\]\(\)a-zA-Z0-9_\-:\,\s]+)\s*)+/,
rules: /([a-zA-Z\-]+):([^;]+)/g,
split: /^(.+?):(.+)$/,
}
class Rule {
constructor(rule) {
this.selector = rule.match(regex.selector)[0];
const rules = rule.match(/{(.+)}/)[1];
const parsedRules = rules.match(regex.rules);
this.rules = parsedRules.map(rule => rule.match(regex.split))
.sort((a, b) => {
const la = a[1].toLowerCase();
const lb = b[1].toLowerCase();
if (la < lb) {
return -1;
} else if (la > lb) {
return 1;
} else {
return 0;
}
})
.reduce((obj, rule) => {
obj[rule[1]] = rule[2];
return obj;
}, {});
this.hash = this.hash(JSON.stringify({ selector: this.selector, rules: this.rules }));
}
hash(val) {
var hash = 0, i, chr, len;
if (val.length === 0) return hash;
for (i = 0, len = val.length; i < len; i++) {
chr = val.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
toString() {
return this.selector + '{' +
Object.keys(this.rules)
.map(rule => rule + ':' + this.rules[rule])
.join(';')
+ '}';
}
}
const rules = new CSSReader(document.body.innerText);
Object.keys(rules.duplicates).sort((a, b) => rules.duplicates[b].length - rules.duplicates[a].length).forEach(hash => console.log(`${rules.duplicates[hash].length} occurences for \`${rules.duplicates[hash][0]}\``));
window.rules = rules;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment