unclosed-tag-finder
Advanced tools
Comparing version 0.0.10 to 0.0.11
@@ -25,19 +25,6 @@ #!/usr/bin/env node | ||
if (unclosedTags.length == 0) { | ||
console.info('Congratulations! No unclosed tags.'); | ||
process.exit(0); | ||
} else { | ||
if (unclosedTags.length == 1) { | ||
console.info('The following tag doesn\'t seem to be closed'); | ||
} else { | ||
console.info('The following tags don\'t seem to be closed'); | ||
} | ||
var returnValue = finder.printUnclosedTags(unclosedTags); | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
console.info('line ' + unclosedTags[i].line + ': ' + unclosedTags[i].full); | ||
} | ||
process.exit(1); | ||
} | ||
process.exit(returnValue); | ||
}); | ||
193
index.js
@@ -24,4 +24,6 @@ /** | ||
'link', | ||
'menuitem', | ||
'meta', | ||
'param', | ||
'script', | ||
'source', | ||
@@ -32,8 +34,3 @@ 'track', | ||
/** | ||
* Finds unclosed tag and returns them (validation). | ||
* | ||
* @param {String} html The html string to validate. | ||
*/ | ||
exports.builder.prototype.getUnclosedTags = function(html) { | ||
exports.builder.prototype.getUnclosedTags = function(html, filename) { | ||
@@ -44,44 +41,146 @@ var unclosedTags = []; | ||
/* saves all tags that where found at the html variable */ | ||
var tags = []; | ||
/* scan each line */ | ||
for (var i = 0; i < lines.length; i++) { | ||
var matchedTags = lines[i].match(/<(\/{1})?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)>/g); | ||
if (matchedTags) { | ||
for (var j = 0; j < matchedTags.length; j++) { | ||
/* remove already closed tags from unclosedTags */ | ||
if (matchedTags[j].indexOf('</') >= 0) { | ||
var closeTagName = matchedTags[j].substr(2, matchedTags[j].length - 3); | ||
closeTagName = closeTagName.replace(/ /g, ''); | ||
/* find opening and closing html tags */ | ||
var matchedTags = lines[i].match(/<[^>]*[^/]>/g) || []; | ||
for (var k = unclosedTags.length - 1; k >= 0; k--) { | ||
if (unclosedTags[k].element === closeTagName) { | ||
/* remove tag */ | ||
unclosedTags.splice(k, 1); | ||
for (var j = 0; j < matchedTags.length; j++) { | ||
if (closeTagName !== 'html') { | ||
break; | ||
} | ||
} | ||
} | ||
var matchedTag = matchedTags[j]; | ||
/* add open tags to unclosedTags */ | ||
} else { | ||
var unclosedTag = {}; | ||
var matches = matchedTag.match(/<\/?([a-z0-9]+)/i); | ||
unclosedTag.full = matchedTags[j]; | ||
unclosedTag.line = i + 1; | ||
if (matches) { | ||
tags.push({ | ||
tag: matchedTag, | ||
name: matches[1], | ||
line: i + 1, | ||
closing: matchedTag[1] === '/' | ||
}); | ||
} | ||
}; | ||
}; | ||
if (unclosedTag.full.indexOf(' ') > 0) { | ||
unclosedTag.element = unclosedTag.full.substr(1, unclosedTag.full.indexOf(' ') - 1); | ||
} else { | ||
unclosedTag.element = unclosedTag.full.substr(1, unclosedTag.full.length - 2); | ||
/* no html tags found */ | ||
if (tags.length == 0) { | ||
return unclosedTags; | ||
} | ||
var openTags = []; | ||
for (var i = 0; i < tags.length; i++) { | ||
var tag = tags[i]; | ||
/* we do have a closing tag element */ | ||
if (tag.closing) { | ||
var closingTag = tag; | ||
/* do not check this tag */ | ||
if (this.isSelfClosing(closingTag.name)) { | ||
continue; | ||
} | ||
/* noOpenTagFound: no open tags found */ | ||
if (openTags.length == 0) { | ||
unclosedTags.push({ | ||
tag: closingTag.tag, | ||
name: closingTag.name, | ||
filename: filename ? filename : null, | ||
line: closingTag.line, | ||
hasNoCloseTag: false, | ||
hasNoOpenTag: true | ||
}); | ||
continue; | ||
} | ||
var openTag = openTags[openTags.length - 1]; | ||
/* noOpenTagFound: close tag does not match with the last open tag */ | ||
if (closingTag.name !== openTag.name) { | ||
var foundOpeningTag = false; | ||
for (var j = openTags.length - 1; j >= 0; j--) { | ||
var currentOpenTag = openTags[j]; | ||
/* we found the open tag that matches with the closing tag element */ | ||
if (closingTag.name === currentOpenTag.name) { | ||
foundOpeningTag = true; | ||
openTags.pop(); | ||
break; | ||
} | ||
if (this.isSelfClosing(unclosedTag.element) === false) { | ||
unclosedTags.push(unclosedTag); | ||
} | ||
/* until we havn't found the opening element, all following tags are specified as unclosed */ | ||
unclosedTags.push({ | ||
tag: currentOpenTag.tag, | ||
name: currentOpenTag.name, | ||
filename: filename ? filename : null, | ||
line: currentOpenTag.line, | ||
hasNoCloseTag: true, | ||
hasNoOpenTag: false | ||
}); | ||
openTags.pop(); | ||
} | ||
if (!foundOpeningTag) { | ||
unclosedTags.push({ | ||
tag: closingTag.tag, | ||
name: closingTag.name, | ||
filename: filename ? filename : null, | ||
line: closingTag.line, | ||
hasNoCloseTag: false, | ||
hasNoOpenTag: true | ||
}); | ||
} | ||
continue; | ||
/* openTagFound: remove last open tag */ | ||
} else { | ||
openTags.pop(); | ||
} | ||
/* we do have an opening tag element */ | ||
} else { | ||
var openingTag = tag; | ||
/* do not check this tag */ | ||
if (this.isSelfClosing(openingTag.name)) { | ||
continue; | ||
} | ||
/* add opening tag to our openTags list */ | ||
openTags.push(openingTag); | ||
} | ||
} | ||
/* we do have some open tags over */ | ||
if (openTags.length > 0) { | ||
for (var i = 0; i < openTags.length; i++) { | ||
var tag = openTags[i]; | ||
unclosedTags.push({ | ||
tag: tag.tag, | ||
name: tag.name, | ||
filename: filename ? filename : null, | ||
line: tag.line, | ||
hasNoCloseTag: true, | ||
hasNoOpenTag: false | ||
}); | ||
} | ||
} | ||
/* sort unclosedTags list */ | ||
unclosedTags.sort( | ||
function(a, b) { | ||
return (a.line > b.line) ? 1 : ((b.line > a.line) ? -1 : 0); | ||
} | ||
); | ||
return unclosedTags; | ||
@@ -113,14 +212,24 @@ }; | ||
if (unclosedTags.length == 0) { | ||
console.info('Congratulations! No unclosed tags.'); | ||
} else { | ||
if (unclosedTags.length == 1) { | ||
console.info('The following tag doesn\'t seem to be closed'); | ||
} else { | ||
console.info('The following tags don\'t seem to be closed'); | ||
return 0; | ||
} | ||
/* prints out missing close tag issues */ | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
if (unclosedTags[i].hasNoCloseTag) { | ||
console.info(unclosedTags[i].filename + ':' + unclosedTags[i].line + ' (missing close tag: <' + unclosedTags[i].name + '/>)'); | ||
console.info(unclosedTags[i].tag); | ||
console.info(''); | ||
} | ||
} | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
console.info('line ' + unclosedTags[i].line + ': ' + unclosedTags[i].full); | ||
/* prints out missing open tag issues */ | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
if (unclosedTags[i].hasNoOpenTag) { | ||
console.info(unclosedTags[i].filename + ':' + unclosedTags[i].line + ' (missing open tag: <' + unclosedTags[i].name + '>)'); | ||
console.info(unclosedTags[i].tag); | ||
console.info(''); | ||
} | ||
} | ||
return 1; | ||
}; |
{ | ||
"name": "unclosed-tag-finder", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "A library to find unclosed html5 tags, that are normally optional.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -71,6 +71,10 @@ # Unclosed Tag Finder | ||
user$ unclosed-tag-finder w3cValid.html | ||
The following tags don't seem to be closed | ||
line 7: <p> | ||
line 8: <p> | ||
line 10: <li> | ||
codequality/valid-utf8-unclosed.html:7 (missing close tag: <p/>) | ||
<p> | ||
codequality/valid-utf8-unclosed.html:8 (missing close tag: <p/>) | ||
<p> | ||
codequality/valid-utf8-unclosed.html:10 (missing close tag: <li/>) | ||
<li> | ||
``` | ||
@@ -105,17 +109,25 @@ | ||
var unclosedTags = finder.getUnclosedTags(html); | ||
var unclosedTags = finder.getUnclosedTags(html, process.argv[2]); | ||
if (unclosedTags.length == 0) { | ||
console.info('Congratulations! No unclosed tags.'); | ||
} else { | ||
if (unclosedTags.length == 1) { | ||
console.info('The following tag doesn\'t seem to be closed'); | ||
} else { | ||
console.info('The following tags don\'t seem to be closed'); | ||
} | ||
return; | ||
} | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
console.info('line ' + unclosedTags[i].line + ': ' + unclosedTags[i].full); | ||
} | ||
/* prints out missing close tag issues */ | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
if (unclosedTags[i].hasNoCloseTag) { | ||
console.info(unclosedTags[i].filename + ':' + unclosedTags[i].line + ' (missing close tag: <' + unclosedTags[i].name + '/>)'); | ||
console.info(unclosedTags[i].tag); | ||
console.info(''); | ||
} | ||
} | ||
/* prints out missing open tag issues */ | ||
for (var i = 0; i < unclosedTags.length; i++) { | ||
if (unclosedTags[i].hasNoOpenTag) { | ||
console.info(unclosedTags[i].filename + ':' + unclosedTags[i].line + ' (missing open tag: <' + unclosedTags[i].name + '>)'); | ||
console.info(unclosedTags[i].tag); | ||
console.info(''); | ||
} | ||
} | ||
}); | ||
@@ -132,6 +144,10 @@ ``` | ||
user$ ./listUnclosedTags.js w3cValid.html | ||
The following tags don't seem to be closed | ||
line 7: <p> | ||
line 8: <p> | ||
line 10: <li> | ||
codequality/valid-utf8-unclosed.html:7 (missing close tag: <p/>) | ||
<p> | ||
codequality/valid-utf8-unclosed.html:8 (missing close tag: <p/>) | ||
<p> | ||
codequality/valid-utf8-unclosed.html:10 (missing close tag: <li/>) | ||
<li> | ||
``` | ||
@@ -141,3 +157,3 @@ | ||
More informations and the source code you will find at [GitHub](https://github.com/bjoern-hempel/node-unclosed-tag-finder) | ||
You will find more informations and the source code at [GitHub](https://github.com/bjoern-hempel/node-unclosed-tag-finder) | ||
@@ -144,0 +160,0 @@ ## License |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12493
209
160