Skip to content

Instantly share code, notes, and snippets.

@lucamug
Last active November 17, 2016 10:05
Show Gist options
  • Save lucamug/0eb113b62bbf1ff820841d79cead4cfb to your computer and use it in GitHub Desktop.
Save lucamug/0eb113b62bbf1ff820841d79cead4cfb to your computer and use it in GitHub Desktop.
// See https://coding-and-design.blogspot.de/2016/11/are-all-element-tags-closed-testing-it.html for more info
var 凸 = typeof global === 'undefined' ? 凸 : global.tmp;
var 凸 = (function (凸) {
凸.buildGetPageFunction = function buildGetPageFunction() {
if (typeof global === 'undefined') {
// Browser
return function (url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
return callback(xhr.responseText);
}
};
xhr.open('GET', url, true);
xhr.send(null);
};
} else {
// Node
return function (url, callback) {
var request = require("request");
request({ url: url }, function (err, response, responseText) {
if (!err && response.statusCode === 200) {
return callback(responseText);
} else {
throw err;
}
});
};
}
};
return 凸;
}(凸 || {}));
var 凸 = (function (凸) {
function isSelfClosingTag(tagName) {
return tagName.match(/area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr|script/i);
}
function displayLine(line, array) {
return ('Line #' + line + ': ' + array[line - 1]);
}
凸.checkHtml = function checkHtml(p) {
// Based on http://jona.ca/blog/unclosed-tag-finder
var
array1 = p.constructor === Array ? p : p.split('\n'),
tags = [],
tag,
openTags = [],
openTag,
i,
j,
line,
array2,
matches,
closingTag;
for (i = 0; i < array1.length; i++) {
line = array1[i];
array2 = line.match(/<[^>]*[^/]>/g) || [];
for (j = 0; j < array2.length; j++) {
tag = array2[j];
matches = tag.match(/<\/?([a-z0-9]+)/i);
if (matches) {
tags.push({ tag: tag, name: matches[1], line: i + 1, closing: tag[1] === '/' });
}
}
}
if (tags.length === 0) {
return 'No tags found.';
}
for (i = 0; i < tags.length; i++) {
tag = tags[i];
if (tag.closing) {
closingTag = tag;
if (isSelfClosingTag(closingTag.name)) {
continue;
}
if (openTags.length === 0) {
return [
'Closing tag ' + closingTag.tag + ' on line ' + closingTag.line + ' does not have corresponding open tag.',
displayLine(closingTag.line, array1),
].join('\n');
}
openTag = openTags[openTags.length - 1];
if (closingTag.name !== openTag.name) {
return [
'Closing tag ' + closingTag.tag + ' on line ' + closingTag.line + ' does not match open tag ' + openTag.tag + ' on line ' + openTag.line + '.',
displayLine(openTag.line, array1),
displayLine(closingTag.line, array1)
].join('\n');
} else {
openTags.pop();
}
} else {
openTag = tag;
if (isSelfClosingTag(openTag.name)) {
continue;
}
openTags.push(openTag);
}
}
if (openTags.length > 0) {
openTag = openTags[openTags.length - 1];
return [
'Open tag ' + openTag.tag + ' on line ' + openTag.line + ' does not have a corresponding closing tag.',
displayLine(openTag.line, array1),
].join('\n');
}
return 'Success: No unclosed tags found.';
};
return 凸;
}(凸 || {}));
(function () {
var url = (typeof global === 'undefined') ? document.location.href : "http://example.com";
凸.buildGetPageFunction()(url, function (page) {
console.log("### Checking " + url + "\n\n" + 凸.checkHtml(page) + "\n\n");
});
console.log("### Checking <div>\n\n" + 凸.checkHtml("<div>") + "\n\n");
console.log("### Checking ['<div>']\n\n" + 凸.checkHtml(["<div>"]) + "\n\n");
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment