Skip to content

Commit

Permalink
1.6.4
Browse files Browse the repository at this point in the history
  • Loading branch information
WezomDev committed Aug 1, 2020
1 parent 76f6cf0 commit 7447155
Show file tree
Hide file tree
Showing 7 changed files with 1,030 additions and 2 deletions.
184 changes: 184 additions & 0 deletions bin/cmd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/usr/bin/env node

// ----------------------------------------
// Imports
// ----------------------------------------

const path = require('path');
const chalk = require('chalk');
const program = require('commander');
const pkg = require('../package.json');
const nodeW3CValidator = require('../lib/validator');

// ----------------------------------------
// Private
// ----------------------------------------

// setup
program
.version(pkg.version)
.usage('[options] <pattern>')
.option(
'-i, --input [path]',
'Validate input path'
)
.option(
'--exclude [path]',
'Exclude from input path'
)
.option(
'-a, --asciiquotes',
'Specifies whether ASCII quotation marks are substituted for Unicode smart quotation marks in messages.'
)
.option(
'-e, --errors-only',
'Specifies that only error-level messages and non-document-error messages are reported (so that warnings and info messages are not reported)'
)
.option(
'-q, --exit-zero-always',
'Makes the checker exit zero even if errors are reported for any documents')
.option(
'--filterfile [filename]',
'Specifies a filename. Each line of the file contains either a regular expression or starts with "#" to indicate the line is a comment. Any error message or warning message that matches a regular expression in the file is filtered out (dropped/suppressed)'
)
.option(
'--filterpattern [pattern]',
'Specifies a regular-expression pattern. Any error message or warning message that matches the pattern is filtered out (dropped/suppressed)'
)
.option(
'-f, --format [gnu|xml|json|text|html|lint]',
'Specifies the output format for reporting the results'
)
.option(
'-s, --skip-non-html',
'Skip documents that don’t have *.html, *.htm, *.xhtml, or *.xht extensions.'
)
.option(
'-H, --html',
'Forces any *.xhtml or *.xht documents to be parsed using the HTML parser'
)
.option(
'--no-langdetect',
'Disables language detection, so that documents are not checked for missing or mislabeled html[lang] attributes.'
)
.option(
'--no-stream',
'Forces all documents to be be parsed in buffered mode instead of streaming mode (causes some parse errors to be treated as non-fatal document errors instead of as fatal document errors)'
)
.option(
'-v, --verbose',
'Specifies "verbose" output (currently this just means that the names of files being checked are written to stdout)'
)
.option(
'-o, --output [path]',
'Write reporting result to the path'
)
.option(
'-b, --buffersize <size>',
'1024 * <size> Increase maxBuffer size for child_process.exec, if result output truncated'
)
.parse(process.argv);

/**
* Properties list for auto detecting
* @const {Array.<string>}
* @private
* @sourceCode
*/
const cliProps = [
'asciiquotes',
'errorsOnly',
'exitZeroAlways',
'format',
'skipNonHtml',
'html',
'stream',
'verbose',
'buffersize'
];

/**
* Detect user's specified properties
* @returns {Object}
* @private
* @sourceCode
*/
function detectUserOptions () {
let outputPath = program.output;
let userOptions = {
output: false,
exec: {},
filterfile: program.filterfile,
filterpattern: program.filterpattern
};

cliProps.forEach((prop) => {
let value = program[prop];

if ((prop === 'stream' || prop === 'langdetect') && value) {
return;
}
if (value !== undefined) {
userOptions[prop] = value;

if (prop === 'buffersize') {
userOptions.exec.maxBuffer = 1024 * value;
}
}
});
if (typeof outputPath === 'string' && outputPath.length) {
userOptions.output = outputPath;
}
return userOptions;
}

/**
* Detect input path where testing files lies
* @returns {*}
*/
function detectUserInput () {
let validatePath = program.input;

if (typeof validatePath !== 'string') {
validatePath = process.cwd();
} else {
if (!/^(http(s)?:)?\/\//i.test(validatePath)) {
if (/^\//.test(validatePath)) {
validatePath = path.resolve(validatePath);
}
}
}
return validatePath;
}

const userOptions = detectUserOptions();
const validatePath = detectUserInput();
if (program.exclude) {
userOptions.exclude = program.exclude;
}

// ----------------------------------------
// Initialize
// ----------------------------------------

nodeW3CValidator(validatePath, userOptions, function (err, output) {
if (err === null) {
process.exit(0);
}
console.log(chalk.red('FOUND ERRORS'));
let outputPath = userOptions.output;
if (outputPath) {
outputPath = path.resolve(outputPath);
let message = [
chalk.red('Resulting report will be written in path:'),
chalk.blue(outputPath.split(path.sep).join('/'))
].join('\n');
console.log(message);
nodeW3CValidator.writeFile(outputPath, output);
} else {
console.log(chalk.red('Resulting report:'));
console.log(output);
}
console.log(' ');
process.exit(1);
});
192 changes: 192 additions & 0 deletions lib/html/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Validation results - Nu Html Checker</title>
<style>button,hr,input{overflow:visible}audio,canvas,progress,video{display:inline-block}progress,sub,sup{vertical-align:baseline}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0;min-width:980px}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects;color:#00f}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}textarea{overflow:auto}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none}.message__type,.tab,.view__path span{display:inline-block}html{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol",sans-serif}a:hover{color:red}.wrapper{margin:1.5rem 3%}.header{margin-bottom:1.5rem}.header__title{background-color:#365d95;color:#fdfdfd;font-size:1.6rem;padding:.43em;border-radius:6px;margin:0;font-weight:400}.header__title a{color:#ccc}.header__title a:hover{color:red}.disclaimer{color:#747474}.navs{margin-bottom:1.5rem;padding-bottom:.5rem;border:1px solid #ccc;border-left-width:0;border-right-width:0}.navs__title{font-size:1.25rem}.navs__list li{margin-bottom:.25rem}.view{overflow:hidden;padding-bottom:1.5rem;margin-bottom:1.5rem;border-bottom:1px solid #ccc}.view__title{font-size:1.5rem}.view__path span{font-size:80%;font-family:monospace,monospace;vertical-align:top;padding:5px;border-radius:4px;background-color:#eee}.messages{padding:1.5rem 2.5rem;background-color:#efefef;border-radius:4px}.message{border:1px solid #ccc;margin-bottom:8px;padding:0 1rem 1rem;border-radius:4px;background-color:#fff}.message__head{font-size:1.25rem;font-weight:600}.message__head code{border:1px dashed #999;font-family:monospace,monospace;padding-left:5px;padding-right:5px;font-weight:400;font-size:1rem;background-color:#fafafa;margin-left:2px;margin-right:2px}.message__type{vertical-align:middle;padding:1px 6px;border-radius:6px;border:1px solid #ccc;font:caption;font-weight:700;text-transform:capitalize}.message__type--error{background-color:#fcc}.message__type--warning{background-color:#ffc}.message__type--fatal{background-color:#fd6f6f}.message__type--info{background-color:#cce8ff}.message__extract{overflow:auto;padding:1rem;background:#fafafa;border:1px dashed #999}.invisible{opacity:.3}.tab{text-align:center;width:2.5rem;border-left:1px dotted rgba(0,0,0,.5)}table{border-collapse:collapse;border-color:#ccc}td,th{padding: .5rem}select{box-sizing:border-box;width:100%;height:2rem;padding.5rem 1rem;border-radius:4px;margin:4px 0 8px;}.is-hidden{visibility:hidden;height:0;overflow:hidden;margin:0;padding:0;border:0}</style>
</head>
<body>
<div class="wrapper">
<header class="header">
<h1 class="header__title">Validation results - <a href="https://validator.w3.org/nu/" title="https://validator.w3.org/nu/" target="_blank">Nu Html Checker</a></h1>
</header>
<p class="disclaimer"><strong>Disclaimer.</strong> This tool is an ongoing experiment in better HTML checking, and its behavior remains subject to change</p>
<% if (Object.keys(views).length > 1) { %>
<nav id="navs" class="navs">
<h2 class="navs__title">Table of contents</h2>
<ul class="navs__list">
<% for (var key in views) { %>
<% var data = views[key]; %>
<li><a href="#<%- data.anchor %>" title="Go to the &quot;<%- data.name %>&quot; block"><%- data.name %></a></li>
<% } %>
</ul>
<h2 class="navs__title">Totals</h2>
<table width="100%" border="1">
<tr align="center">
<th width="36%">total groups</th>
<th width="64%">total messages</th>
</tr>
<tr valign="top">
<td>
<ul class="navs__list">
<% for (var key in counts.groups) { %>
<li><%- key %> - (<%- counts.groups[key] %>)</li>
<% } %>
</ul>
</td>
<td>
<ul class="navs__list">
<% for (var key in counts.msgGroups) { %>
<% var msgGroup = counts.msgGroups[key]; %>
<li>
<%= key.replace(/^(.+:)/, (str, grp) => `<strong>${grp}</strong>`) %> - (<%- msgGroup.count %>)
<% if (Object.keys(msgGroup.urls).length) { %>
<ul>
<% for (var url in msgGroup.urls) { %>
<%
let viewName = url.replace(/\\/, '/').split('/').pop();
let viewAnchor = viewName.replace(/\/|\.|[а-я]|\s/gi, '-');
%>
<li><small><a href="#<%- viewAnchor %>"><%- url %></a></small></li>
<% } %>
</ul>
<br>
<% } %>
</li>
<% } %>
</ul>
</td>
</tr>
</table>
<br>
<br>
</nav>
<% } %>
<main class="results">
<% for (var key in views) { %>
<% var data = views[key]; %>
<div id="<%- data.anchor %>" class="view js-view">
<h3 class="view__title">
<% if (Object.keys(views).length > 1) { %>
<a href="#navs" title="Back to top">&uArr;</a>
<a href="#<%- data.anchor %>" title="Set anchor for block">#</a>
<% } %>
<span><%- data.name %></span>
</h3>
<p class="view__path">
<span><%- data.path %></span>
</p>
<table width="100%" border="1">
<tr align="center">
<th width="36%">groups</th>
<th width="64%">messages</th>
</tr>
<tr valign="top">
<td>
<ul>
<% for (var k in data.errorCounts) { %>
<li style="margin-bottom: 3px;"><%- k %> - (<%- data.errorCounts[k] %>)</li>
<% } %>
</ul>
<small>filter:</small>
<select id="<%- data.anchor + '-select-type' %>" class="js-filter" data-reset="<%- data.anchor + '-select-group' %>">
<option value="group">all groups</option>
<% for (var k in data.errorCounts) { %>
<option value="group--<%- k %>"><%- k %></option>
<% } %>
</select>
</td>
<td>
<ul>
<% for (var k in data.errorGroups) { %>
<li style="margin-bottom: 3px;"><%= k.replace(/^(.+:)/, (str, grp) => `<strong>${grp}</strong>`) %> - (<%- data.errorGroups[k].count %>)</li>
<% } %>
</ul>
<small>filter:</small>
<select id="<%- data.anchor + '-select-group' %>" class="js-filter" data-reset="<%- data.anchor + '-select-type' %>">
<option value="message">all messages</option>
<% for (var k in data.errorGroups) { %>
<option value="message--<%- data.errorGroups[k].key %>"><%- k %></option>
<% } %>
</select>
</td>
</tr>
</table>
<div class="view__list">
<ol class="messages">
<% data.list.forEach(function(item, i) { %>
<% var liAnchor = data.anchor + '-' + (i + 1); %>
<li id="<%- liAnchor %>" class="group message group--<%- item.processType %> message--<%- item.processGroup %> js-filter-item">
<p class="message__head">
<a href="#<%- data.anchor %>" title="Back to block">&uarr;</a>
<a href="#<%- liAnchor %>" title="Set anchor for message">#</a>
<strong class="message__type message__type--<%- item.badge %>"><%- item.badge %></strong>
<span class="message__description"><%= item.message %></span>
</p>
<p class="message__location">
From line <span class="first-line"><%- item.firstLine %></span>, column <span class="first-col"><%- item.firstColumn %></span>; to line <span class="last-line"><%- item.lastLine %></span>, column <span class="last-col"><%- item.lastColumn %></span>
</p>
<pre class="message__extract"><%= item.extract %></pre>
</li>
<% }); %>
</ol>
</div>
</div>
<% } %>
</main>
<footer>
<p>
<small>Date of the audit - <em><%- new Date() %></em></small>
<br>
<small>Validation tool - <em><a href="https://github.com/dutchenkoOleg/node-w3c-validator" target="_blank">node-w3c-validator</a></em></small>
</p>
</footer>
</div>

<script>
(function (window, document) {
function setViewHandlers ($view) {
var $items = $view.getElementsByClassName('js-filter-item');

$view.onchange = function(event) {
var $el = event.target;

if ($el.dataset.reset) {
changeFilter($el, $items);
}
}
}

function changeFilter ($filter, $items) {
var $reset = document.getElementById($filter.dataset.reset);
var filterClass = $filter.value;
var length = $items.length;

for (var i = 0; i < length; i++) {
var $item = $items[i];
var filtered = $item.classList.contains(filterClass);

if (filtered) {
$item.classList.remove('is-hidden');
} else {
$item.classList.add('is-hidden');
}
}

$reset.outerHTML = $reset.outerHTML;
}

window.onload = function () {
var $views = document.getElementsByClassName('js-view');
var length = $views.length;

for (var i = 0; i < length; i++) {
setViewHandlers($views[i]);
}
};
})(window, document);
</script>
</body>
</html>
Loading

0 comments on commit 7447155

Please sign in to comment.