seo/seoChecker.js
// ------------------------- dependency -------------------------
var Horseman = require('node-horseman'),
horseman = new Horseman(),
fs = require('fs-extra'),
isUrl = require('is-url'),
jsonPretty = require('json-pretty'),
program = require('commander');
// --------------------------- get url ---------------------------
program
.version('0.0.1')
.option('-u, --url [url]', 'Input URL')
.option('-d, --destination [path]', 'Input Path to Store The Output')
.option('--title', 'Include Title Tag Checker')
.option('--header', 'Include Header Tag Checker')
.option('--footer', 'Include Footer Tag Checker')
.option('--favicon', 'Include Favicon Checker')
.option('--aria', 'Include ARIA Landmark Checker')
.option('--noalt', 'Include No Alternate Text on Image Tag Checker')
.option('--i18n', 'Include Internationalization (i18n) Checker')
.option('--meta', 'Include Necessary Meta Tag Checker')
.option('--heading', 'Include Heading Tag Checker')
.parse(process.argv);
var url = program.url;
var dest;
if ( !isUrl(url) ) {
console.log('ERROR: this is not an url');
horseman.close();
process.exit(1);
}
// ---------------------- initialization ----------------------
var resultSEO = {
name : 'SEO Checker',
url : url,
checking: []
};
var error = 'Error',
warning = 'Warning',
errDesc,
counter = 0;
var openUrl = horseman.open(url);
fs.exists(program.destination, function (exists) {
if ( !exists ) {
fs.mkdirsSync( program.destination );
}
dest = './' + program.destination;
// ----------------------- Title tag checking -----------------------
if ( program.title ) {
var countTitle = horseman.count( 'title' );
if ( countTitle === 0 ) {
errDesc = 'Title Tag is not found. Please add Title Tag to keep the standarization.';
pushErrMsg(errDesc);
} else if ( countTitle > 1 ) {
errDesc = 'We have found ' + countTitle + ' Title Tags. Title Tag should only be one.';
pushErrMsg(errDesc);
}
counter++;
}
// ----------------------- header tag checking -----------------------
if ( program.header ) {
var countHeader = horseman.count( 'header' );
if ( countHeader === 0 ) {
errDesc = 'Header Tag is not found. Please add Header Tag to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
}
// ---------------------- footer tag checking ----------------------
if ( program.footer ) {
var countFooter = horseman.count( 'footer' );
if ( countFooter === 0 ) {
errDesc = 'Footer Tag is not found. Please add Footer Tag to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
}
// ----------------------------- favicon -----------------------------
if ( program.favicon ) {
var countFavicon = horseman.count('link[rel*="icon"]');
if ( countFavicon === 0 ) {
errDesc = 'Favicon is not found. Please add <link rel="icon" type="image/png" href="path/to/your/file"></link> to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
}
// -------------------------- ARIA Landmark --------------------------
if ( program.aria ) {
var arr_role = ['banner', 'main', 'contentinfo', 'navigation', 'search'];
for (var i = 0; i < arr_role.length; i++) {
var _current = '[role="' + arr_role[i] + '"]';
var isExist = horseman.exists(_current);
if ( !isExist ) {
errDesc = 'This Aria Landmark : '+ arr_role[i] +' is not found. Please add ' + _current + ' to this page to keep the standarization.';
pushWarnMsg(errDesc);
}
counter++;
}
}
// --------------------------- image no alt ---------------------------
if ( program.noalt ) {
var imgCount = horseman
.count('img');
var noAltTextCount = horseman
.count('img[alt=""]');
if ( noAltTextCount > 0 ) {
var noAltTextCode = horseman
.evaluate(function (selector) {
var selectorNoAlt = document.querySelectorAll('img[alt=""]');
var tempp = [];
for (var i = 0; i < selectorNoAlt.length; i++) {
tempp.push(selectorNoAlt[i].outerHTML);
}
return tempp;
}, 'img');
for (var j = 0; j < noAltTextCode.length; j++) {
errDesc = 'This Image Tag ' + noAltTextCode[j] + ' has no Alternate Text. Please add the alternate text to keep the standarization.';
pushErrMsg(errDesc);
}
}
counter = counter + imgCount;
}
// ------------------------------ i18n ------------------------------
if ( program.i18n ) {
var isLang = horseman.exists('html[lang]');
if ( isLang ) {
var getLang = horseman.attribute('html','lang');
if ( getLang === "" ) {
errDesc = 'Please fill the Lang attribute to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
} else {
errDesc = 'Language attribute is not found. Please add <html lang=""> to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
var isHttpEquiv = horseman.exists('meta[http-equiv]');
var isCharset = horseman.exists('meta[charset]');
var getHttpEquiv = getLowerCase( horseman.attribute('meta[http-equiv]','http-equiv') );
var getCharset = getLowerCase( horseman.attribute('meta[charset]','charset') );
if ( !isHttpEquiv && !isCharset ) {
errDesc = 'Please add character encoding meta tag element (<meta charset="utf-8"/> or <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>)';
pushErrMsg(errDesc);
} else {
if ( getHttpEquiv === "content-type" && getCharset === "utf-8" ) {
errDesc = 'Please do not declare both of character encoding element (<meta charset="utf-8"/> and <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>).';
pushErrMsg(errDesc);
} else {
if ( isCharset ) {
if ( getCharset === "" || getCharset === null ) {
errDesc = 'Please fill the charset attribute on meta tag.';
pushErrMsg(errDesc);
} else if ( getCharset !== "utf-8" ) {
errDesc = 'Please only use "utf-8" for charset attribute on meta tag.';
pushErrMsg(errDesc);
}
counter++;
} else if ( isHttpEquiv ) {
if ( getHttpEquiv === "" || getHttpEquiv === null ) {
errDesc = 'Please fill the http-equiv attribute on meta tag.';
pushErrMsg(errDesc);
} else if ( getHttpEquiv !== "content-type" ) {
errDesc = 'Http-equiv attribute on meta tag is wrong. Please change it to <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
}
counter++;
}
counter++;
}
counter++;
}
// ------------------------ meta tag checking ------------------------
if ( program.meta ) {
var metaDesc = 'meta[name="description"]',
metaVp = 'meta[name="viewport"]';
var isMetaDesc = horseman.exists(metaDesc);
if ( isMetaDesc ) {
var getMetaDesc = horseman.attribute('meta[name="description"]', 'content');
if ( getMetaDesc === "" ) {
errDesc = "Meta Description tag must be filled.";
pushErrMsg(errDesc);
}
counter++;
} else {
errDesc = "Please add Meta Description tag to keep the standarization.";
}
counter++;
var isMetaVp = horseman.exists(metaVp);
if ( isMetaVp ) {
var getMetaVp = horseman.attribute('meta[name="viewport"]', 'content');
if ( getMetaVp === "" ) {
errDesc = "Meta Viewport tag must be filled";
pushErrMsg(errDesc);
}
counter++;
} else {
errDesc = "Please add Meta Viewport tag to keep the standarization.";
pushErrMsg(errDesc);
}
counter++;
}
// ----------------------------- heading -----------------------------
if ( program.heading ) {
var isMainHeading = horseman.exists('h1');
if ( isMainHeading ) {
var countMainHeading = horseman.count('h1');
if ( countMainHeading > 1 ) {
errDesc = 'Tag <h1> should only be one.';
pushWarnMsg(errDesc);
}
} else {
errDesc = 'Tag <h1> is not found. Please add tag <h1></hi> to keep the standarization.';
pushErrMsg(errDesc);
}
counter++;
}
// ------------------------ save to json file ------------------------
resultSEO.counter = counter;
var toJson = jsonPretty(resultSEO);
function saveReport() {
fs.writeFile(dest + 'resultSEO.json', toJson, function (err) {
if (err) throw err;
console.log("resultSEO.json has saved!");
});
}
saveReport();
// ---------------------------- function ----------------------------
function pushErrMsg(message) {
resultSEO.checking.push({
error : error,
desc : message
});
}
function pushWarnMsg(message) {
resultSEO.checking.push({
error : warning,
desc : message
});
}
horseman.close();
});
function getLowerCase (message) {
if ( message === "" || message === null ) {
return message;
} else {
return message.toLowerCase();
}
}