Skip to content

Instantly share code, notes, and snippets.

@joelcardinal
Last active May 23, 2019 09:55
Show Gist options
  • Save joelcardinal/040745aefcf368d39a97911080eb2913 to your computer and use it in GitHub Desktop.
Save joelcardinal/040745aefcf368d39a97911080eb2913 to your computer and use it in GitHub Desktop.
Lists pages stylesheet/inline CSS. Also reports CSS selectors used on page from stylesheet/inline and inline JS.
/*
TODO: add check for used Font Family, refactor
*/
(function getStyleSheetsCssData(){
var styleSheets = document.styleSheets,
data = {
cssData : {
allUsedSelectorText : []
},
jsData : []
},
cssData = data.cssData,
jsData = data.jsData,
debug = false,
debugCount = 0,
debugMaxCount = 2000,
errorCount = 0,
maxErrorCount = 50;
// adding inline scripts
var scripts = document.querySelectorAll('script');
if(scripts.length){
jsData
for(var i=0,len = scripts.length;i<len;i++){
var script = document.querySelectorAll('script')[i];
if( !script.getAttribute('src')){
jsData.push(script.outerHTML);
}
}
}
// iterate over all stylesheets
for(var ii = 0, lenn = styleSheets.length; ii < lenn; ii++){
var cssFileName;
if(!styleSheets[ii].href){
cssFileName = "inline";
}else{
cssFileName = styleSheets[ii].href.split('/').pop();
}
if(!styleSheets[ii].rules){
var msg = "Skipping "+cssFileName+", no CSS rules found. Likely the file is over-optimized and missing the last semi-colon of every rule which breaks styleguide API preventing the ability to parse.";
console.warn(msg);
continue
}
if(debug){
console.log("Found Stylesheet");
console.log(styleSheets[ii]);
console.log("-------");
}
if(!cssData[cssFileName]){
cssData[cssFileName] = {
styles : {
usedSelectorText : [],
classes : [],
cssText : [],
selectorText : [],
selectorsToRules : {},
errors : []
},
media : {
conditionText : [],
usedSelectorText : [],
cssText : []
},
fontface : {
cssText : [],
fontFamily : []
},
keyframes : {
cssText : [],
name : []
},
supports : {
conditionText : [],
usedSelectorText : [],
cssText : []
},
unknown : []
};
}
// iterate over array of stylesheet rules
for(var iii = 0, lennn = styleSheets[ii].rules.length;iii<lennn;iii++){
if(debug){
console.log(styleSheets[ii].rules[iii]);
}
try{
var styleType = Object.getPrototypeOf(styleSheets[ii].rules[iii]).toString();
if( /Style/.test(styleType) ){
// typical rule
var cssText = styleSheets[ii].rules[iii].cssText,
selectorText = styleSheets[ii].rules[iii].selectorText,
rules = styleSheets[ii].rules[iii].style.cssText;
// dirty checking for class, starts with "."
// could add to other styleTypes but probably not very useful, leaving for now
// TODO: evaluate if useful
var selectorArray = selectorText.split(',');
for(var iiii = 0, lennnn = selectorArray.length;iiii<lennnn;iiii++){
var individualSelectorArray = selectorArray[iiii].split(' ');
for(var iiiii = 0, lennnnn = individualSelectorArray.length;iiiii<lennnnn;iiiii++){
var individualSelector = individualSelectorArray[iiiii];
if(/^\./.test(individualSelector) && cssData[cssFileName].styles.classes.indexOf(individualSelector) === -1){
cssData[cssFileName].styles.classes.push(individualSelector);
}
}
}
if(document.querySelectorAll(selectorText).length && cssData[cssFileName].styles.usedSelectorText.indexOf(selectorText) === -1){
cssData[cssFileName].styles.usedSelectorText.push(selectorText);
if(cssData.allUsedSelectorText.indexOf(selectorText) === -1){
cssData.allUsedSelectorText.push(selectorText);
}
}
cssData[cssFileName].styles.cssText.push(cssText);
cssData[cssFileName].styles.selectorText.push(selectorText);
// TODO: evaluate if useful, if so, add selectorsToRules to other styleTypes?
cssData[cssFileName].styles.selectorsToRules[selectorText] = rules;
}else if( /Media/.test(styleType) ){
// media query
var conditionText = styleSheets[ii].rules[iii].conditionText,
cssText = styleSheets[ii].rules[iii].cssText;
cssData[cssFileName].media.conditionText.push(conditionText);
cssData[cssFileName].media.cssText.push(cssText);
for(var x = 0, xlen = styleSheets[ii].rules[iii].cssRules.length; x < xlen; x++){
var selectorText = styleSheets[ii].rules[iii].cssRules[x].selectorText;
if(document.querySelectorAll(selectorText).length && cssData[cssFileName].media.usedSelectorText.indexOf(selectorText) === -1){
cssData[cssFileName].media.usedSelectorText.push(selectorText);
if(cssData.allUsedSelectorText.indexOf(selectorText) === -1){
cssData.allUsedSelectorText.push(selectorText);
}
}
}
}else if( /FontFace/.test(styleType) ){
// font face
var cssText = styleSheets[ii].rules[iii].cssText,
fontFamily = styleSheets[ii].rules[iii].style.fontFamily;
cssData[cssFileName].fontface.cssText.push(cssText);
cssData[cssFileName].fontface.fontFamily.push(fontFamily);
}else if( /Keyframes/.test(styleType) ){
// keyframe
var cssText = styleSheets[ii].rules[iii].cssText,
keyName = styleSheets[ii].rules[iii].name;
cssData[cssFileName].keyframes.cssText.push(cssText);
cssData[cssFileName].keyframes.name.push(keyName);
}else if( /Supports/.test(styleType) ){
// supports
var conditionText = styleSheets[ii].rules[iii].conditionText,
cssText = styleSheets[ii].rules[iii].cssText;
cssData[cssFileName].supports.conditionText.push(conditionText);
cssData[cssFileName].supports.cssText.push(cssText);
for(var xx = 0, xxlen = styleSheets[ii].rules[iii].cssRules.length; xx < xxlen; xx++){
var selectorText = styleSheets[ii].rules[iii].cssRules[xx].selectorText;
if(document.querySelectorAll(selectorText).length && cssData[cssFileName].supports.usedSelectorText.indexOf(selectorText) === -1){
cssData[cssFileName].supports.usedSelectorText.push(selectorText);
if(cssData.allUsedSelectorText.indexOf(selectorText) === -1){
cssData.allUsedSelectorText.push(selectorText);
}
}
}
}else{
if(debug){
console.log('UNKNOWN STYLETYPE');
console.log(styleType);
console.log(styleSheets[ii].rules[iii]);
cssData[cssFileName].unknown.push(styleSheets[ii].rules[iii]);
}
}
}catch(e){
if(debug){
console.log('ERROR');
console.log(e);
console.log(styleSheets[ii].rules[iii]);
}
errorCount ++
if(errorCount === maxErrorCount){
// There could be a lot of errors, so we'll exit early
console.log("MAX ERROR COUNT REACHED");
return
}
}
debugCount ++
if(debug && debugCount === debugMaxCount){return}
}
}
console.log("DATA:");
//console.log(Data);
return data;
}());
/*
function getAllPageCss(){
// dirty checking for class starts with "." in it
// TODO: evaluate if useful
var allElements = document.querySelectorAll('*'),
classes = [];
for(var i = 0, len = allElements.length;i<len;i++){
var element = allElements[i];
if(element.classList && element.classList.value){
var classListArray = element.classList.value.split(' ');
for(var ii = 0, lenn = classListArray.length;ii<lenn;ii++){
classes.push(classListArray[ii]);
}
}
}
console.log("getAllPageCss - classes");
console.log(classes);
return classes;
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment