validate-website 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba01cfb0d05bb3670aecfb1afcc94bc72dd02088
4
- data.tar.gz: 8f8259c854e992e72c18e48141509475378e3a91
3
+ metadata.gz: 2d3196fa0c3271fa922d6435a995279a40099389
4
+ data.tar.gz: c78180f6adf88588d048082a6431f9061f20f0be
5
5
  SHA512:
6
- metadata.gz: 8585f39f42b34a667c34f760c96b6c1dbeba03ab4d1adefc1bb26aa8a846038e26fba3e48f657007fb1973f10b4173e86e84e16b8b13f7bd20809adbd40e7f2e
7
- data.tar.gz: 620cf747186ef3518b9bec8f248cf8d78d4c73510ff745117fbbecdad66f24816124a26287485b77396043574e48aa5878bcc61c123f8a2c9b0d00502b83761f
6
+ metadata.gz: 415f9b8ce3a4579747b22a9b5fddfd3948f1af9b3136529ddfd33c39afcd87099f065c7e40563235881307453b7802035da57ba07c0e87b8c4423289f57839ed
7
+ data.tar.gz: 15cd19df7a2de8f764685a21e61f77160f52a9573b294639168b9d7844d712d7eab0ab432d579057045143acfb41512c97d2eea3e880d944eac159ede82fec70
data/History.md CHANGED
@@ -1,4 +1,12 @@
1
1
 
2
+ v1.8.0 / 2017-08-24
3
+ ===================
4
+
5
+ * Update manpages
6
+ * Update rubies and jruby on travis
7
+ * Remove encoding and other Style/SymbolArray fixes
8
+ * Add tidy validator for html5
9
+
2
10
  v1.7.0 / 2017-04-08
3
11
  ===================
4
12
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake/testtask'
2
2
  require 'rubocop/rake_task'
3
3
 
4
- task default: [:test, :rubocop]
4
+ task default: %i(test rubocop)
5
5
 
6
6
  # install asciidoc libxml2-utils xmlto docbook-xsl docbook-xml
7
7
  desc 'Update manpage from asciidoc file'
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'paint'
3
2
 
4
3
  module ValidateWebsite
@@ -110,7 +110,7 @@ module ValidateWebsite
110
110
  # @param [Regexp] Errors to ignore
111
111
  #
112
112
  def validate(doc, body, url, ignore = nil)
113
- validator = Validator.new(doc, body, ignore)
113
+ validator = Validator.new(doc, body, ignore: ignore)
114
114
  if validator.valid?
115
115
  print color(:success, '.', options[:color]) # rspec style
116
116
  else
@@ -1,10 +1,9 @@
1
- # encoding: utf-8
2
1
  require 'slop'
3
2
 
4
3
  module ValidateWebsite
5
4
  # Internal class for parse command line args
6
5
  class Parser
7
- VALID_TYPES = [:crawl, :static].freeze
6
+ VALID_TYPES = %i(crawl static).freeze
8
7
 
9
8
  DEFAULT_OPTIONS = {
10
9
  site: 'http://localhost/',
@@ -21,6 +20,7 @@ module ValidateWebsite
21
20
  # regex to ignore certain validation errors
22
21
  ignore: nil,
23
22
  color: true,
23
+ html5_validator: 'tidy',
24
24
  # internal verbose for ValidateWebsite
25
25
  verbose: false
26
26
  }.freeze
@@ -51,8 +51,11 @@ module ValidateWebsite
51
51
  def self.ignore_html5_options(o)
52
52
  o.regexp('-i', '--ignore',
53
53
  'Validation errors to ignore (ex: "valign|autocorrect")')
54
+ o.string('-x', '--html5-validator',
55
+ 'Change default html5 validator engine (ex: tidy or nu)',
56
+ default: DEFAULT_OPTIONS[:html5_validator])
54
57
  o.string('-5', '--html5-validator-service-url',
55
- 'Change default html5 validator service URL')
58
+ 'Change default html5 validator service URL for "nu" engine')
56
59
  end
57
60
 
58
61
  def self.markup_syntax(o)
@@ -1,27 +1,24 @@
1
1
  require 'uri'
2
+
2
3
  require 'nokogiri'
3
4
  require 'w3c_validators'
4
5
 
6
+ require 'validate_website/validator_class_methods'
7
+
5
8
  module ValidateWebsite
6
9
  # Document validation from DTD or XSD (webservice for html5)
7
10
  class Validator
8
- @html5_validator_service_url = 'https://checker.html5.org/'
11
+ extend ValidatorClassMethods
9
12
 
13
+ @html5_validator_service_url = 'https://checker.html5.org/'
10
14
  class << self
11
15
  attr_accessor :html5_validator_service_url
12
-
13
- def validator_uri
14
- @validator_uri ||=
15
- ENV['VALIDATOR_NU_URL'] || @html5_validator_service_url
16
- end
17
16
  end
18
17
 
19
18
  XHTML_PATH = File.expand_path('../../../data/schemas', __FILE__)
20
19
 
21
- @xsd_schemas = {}
22
- class << self
23
- attr_reader :xsd_schemas
24
- end
20
+ @xsd_schemas ||= {}
21
+
25
22
  # `Dir.chdir` is needed by `Nokogiri::XML::Schema` to validate with local
26
23
  # files and cannot use file absolute path.
27
24
  Dir.glob(File.join(XHTML_PATH, '*.xsd')).each do |schema|
@@ -36,19 +33,21 @@ module ValidateWebsite
36
33
  end
37
34
  end
38
35
 
39
- attr_reader :original_doc, :body, :dtd, :doc, :namespace
36
+ attr_reader :original_doc, :body, :dtd, :doc, :namespace, :html5_validator
40
37
 
41
38
  ##
42
39
  # @param [Nokogiri::HTML::Document] original_doc
43
40
  # @param [String] The raw HTTP response body of the page
44
41
  # @param [Regexp] Errors to ignore
45
- #
46
- def initialize(original_doc, body, ignore = nil)
42
+ # @param [Symbol] html5_validator default offline :tidy
43
+ # fallback webservice :nu
44
+ def initialize(original_doc, body, ignore: nil, html5_validator: :tidy)
47
45
  @errors = []
48
46
  @document, @dtd_uri = nil
49
47
  @original_doc = original_doc
50
48
  @body = body
51
49
  @ignore = ignore
50
+ @html5_validator = html5_validator
52
51
  @dtd = @original_doc.internal_subset
53
52
  @namespace = find_namespace(@dtd)
54
53
  end
@@ -93,11 +92,11 @@ module ValidateWebsite
93
92
  end
94
93
 
95
94
  # @return [Array] contain result errors
96
- def validate(xml_doc, document_body)
95
+ def validate(xhtml_doc)
97
96
  if self.class.xsd(@namespace)
98
- self.class.xsd(@namespace).validate(xml_doc)
99
- elsif document_body =~ /^\<!DOCTYPE html\>/i
100
- html5_validate(document_body)
97
+ self.class.xsd(@namespace).validate(xhtml_doc)
98
+ elsif document =~ /^\<!DOCTYPE html\>/i
99
+ html5_validate
101
100
  else
102
101
  # dont have xsd fall back to dtd
103
102
  Dir.chdir(XHTML_PATH) do
@@ -108,20 +107,37 @@ module ValidateWebsite
108
107
 
109
108
  # http://nokogiri.org/tutorials/ensuring_well_formed_markup.html
110
109
  def find_errors
111
- doc = Dir.chdir(XHTML_PATH) do
110
+ xhtml_doc = Dir.chdir(XHTML_PATH) do
112
111
  Nokogiri::XML(document) { |cfg| cfg.noent.dtdload.dtdvalid }
113
112
  end
114
- @errors = validate(doc, document)
113
+ @errors = validate(xhtml_doc)
115
114
  rescue Nokogiri::XML::SyntaxError => e
116
115
  @errors << e
117
116
  end
118
117
 
119
- def html5_validate(document)
118
+ def html5_validate
119
+ if html5_validator.to_sym == :tidy && self.class.tidy
120
+ tidy_validate
121
+ else
122
+ nu_validate
123
+ end
124
+ end
125
+
126
+ def tidy_validate
127
+ results = self.class.tidy.new(document)
128
+ if results.errors
129
+ errors.concat(results.errors.split("\n"))
130
+ else
131
+ []
132
+ end
133
+ end
134
+
135
+ def nu_validate
120
136
  validator = W3CValidators::NuValidator.new(
121
137
  validator_uri: self.class.validator_uri
122
138
  )
123
139
  results = validator.validate_text(document)
124
- errors.concat results.errors
140
+ errors.concat(results.errors)
125
141
  end
126
142
  end
127
143
  end
@@ -0,0 +1,17 @@
1
+ require 'tidy_ffi'
2
+
3
+ # Validator Class Methods
4
+ module ValidatorClassMethods
5
+ def validator_uri
6
+ @validator_uri ||=
7
+ ENV['VALIDATOR_NU_URL'] || @html5_validator_service_url
8
+ end
9
+
10
+ def tidy
11
+ return @tidy if defined?(@tidy)
12
+ @lib_tidy = TidyFFI::LibTidy
13
+ @tidy = TidyFFI::Tidy
14
+ rescue TidyFFI::LibTidyNotInstalled
15
+ @tidy = nil
16
+ end
17
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version file for ValidateWebsite
4
4
  module ValidateWebsite
5
- VERSION = '1.7.0'.freeze
5
+ VERSION = '1.8.0'.freeze
6
6
  end
@@ -2,12 +2,12 @@
2
2
  .\" Title: validate-website-static
3
3
  .\" Author: [see the "AUTHOR" section]
4
4
  .\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
5
- .\" Date: 01/04/2017
5
+ .\" Date: 06/20/2017
6
6
  .\" Manual: \ \&
7
7
  .\" Source: \ \&
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "VALIDATE\-WEBSITE\-S" "1" "01/04/2017" "\ \&" "\ \&"
10
+ .TH "VALIDATE\-WEBSITE\-S" "1" "06/20/2017" "\ \&" "\ \&"
11
11
  .\" -----------------------------------------------------------------
12
12
  .\" * Define some portability stuff
13
13
  .\" -----------------------------------------------------------------
@@ -80,9 +80,14 @@ Log files not on filesystem, pwd considered as root \(Fo / \(Fc (Default: false)
80
80
  Show colored output (Default: true)
81
81
  .RE
82
82
  .PP
83
+ \fB\-x\fR, \fB\-\-html5\-validator\fR \fIVALIDATOR\fR
84
+ .RS 4
85
+ Change default html5 validator engine (ex: tidy or nu)
86
+ .RE
87
+ .PP
83
88
  \fB\-5\fR, \fB\-\-html5\-validator\-service\-url\fR \fIURL\fR
84
89
  .RS 4
85
- Change default html5 validator service URL
90
+ Change default html5 validator service URL for "nu" engine
86
91
  .RE
87
92
  .PP
88
93
  \fB\-v\fR, \fB\-\-verbose\fR
@@ -2,12 +2,12 @@
2
2
  .\" Title: validate-website
3
3
  .\" Author: [see the "AUTHOR" section]
4
4
  .\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
5
- .\" Date: 01/04/2017
5
+ .\" Date: 06/20/2017
6
6
  .\" Manual: \ \&
7
7
  .\" Source: \ \&
8
8
  .\" Language: English
9
9
  .\"
10
- .TH "VALIDATE\-WEBSITE" "1" "01/04/2017" "\ \&" "\ \&"
10
+ .TH "VALIDATE\-WEBSITE" "1" "06/20/2017" "\ \&" "\ \&"
11
11
  .\" -----------------------------------------------------------------
12
12
  .\" * Define some portability stuff
13
13
  .\" -----------------------------------------------------------------
@@ -85,9 +85,14 @@ Log not found url (Default: false)
85
85
  Show colored output (Default: true)
86
86
  .RE
87
87
  .PP
88
+ \fB\-x\fR, \fB\-\-html5\-validator\fR \fIVALIDATOR\fR
89
+ .RS 4
90
+ Change default html5 validator engine (ex: tidy or nu)
91
+ .RE
92
+ .PP
88
93
  \fB\-5\fR, \fB\-\-html5\-validator\-service\-url\fR \fIURL\fR
89
94
  .RS 4
90
- Change default html5 validator service URL
95
+ Change default html5 validator service URL for "nu" engine
91
96
  .RE
92
97
  .PP
93
98
  \fB\-v\fR, \fB\-\-verbose\fR
@@ -0,0 +1,476 @@
1
+ <!DOCTYPE html>
2
+ <!-- Page last generated 2017-04-08 21:20:41 +0000 -->
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <title>The Rust Programming Language</title>
9
+ <meta name="keywords" content="Rust, Rust programming language, rustlang, rust-lang, Mozilla Rust">
10
+ <meta name="description" content="A systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.">
11
+
12
+ <link rel="stylesheet" href="/css/bootstrap.css">
13
+ <link rel="stylesheet" href="/css/style.css">
14
+
15
+ </head>
16
+
17
+ <body class="container">
18
+ <a href="https://github.com/rust-lang/rust">
19
+ <img class="ribbon" style="display: none" src="/logos/forkme.png" alt="Fork me on GitHub" width="298" height="298">
20
+ </a>
21
+
22
+ <header>
23
+ <ul class="row menu">
24
+ <li class="col-xs-12 col-md-2">
25
+ <a href="/en-US/index.html">
26
+ <img class="img-responsive" src="/logos/rust-logo-blk.svg" onerror="this.src='/logos/rust-logo-256x256-blk.png'" height="128" width="128" alt="Rust logo" />
27
+ </a>
28
+ </li>
29
+ <li class="col-xs-12 col-md-10 menu">
30
+ <h2><a href="/en-US/documentation.html">Documentation</a></h2>
31
+ <h2><a href="/en-US/install.html">Install</a></h2>
32
+ <h2><a href="/en-US/community.html">Community</a></h2>
33
+ <h2><a href="/en-US/contribute.html">Contribute</a></h2>
34
+ </li>
35
+ </ul>
36
+ </header>
37
+
38
+ <div class="row pitch-row">
39
+ <div class="col-md-8">
40
+ <p class="pitch">
41
+ <b>Rust</b> is a systems programming language
42
+ that runs blazingly fast,
43
+ prevents segfaults,
44
+ and guarantees thread safety.
45
+ <br/>
46
+ <b><a href="friends.html">See who's using Rust.</a></b>
47
+ </p>
48
+ </div>
49
+ <div class="col-md-4">
50
+ <a class="release-button" href="install.html">
51
+ <div class="release-version">Install Rust <span>1.16.0</span></div>
52
+ </a>
53
+ <div class="release-date">March 16, 2017</div>
54
+ </div>
55
+ </div>
56
+
57
+ <div class="row code-row">
58
+ <div class="col-md-4">
59
+ <h2>Featuring</h2>
60
+ <ul class="laundry-list">
61
+ <li>zero-cost abstractions</li>
62
+ <li>move semantics</li>
63
+ <li>guaranteed memory safety</li>
64
+ <li>threads without data races</li>
65
+ <li>trait-based generics</li>
66
+ <li>pattern matching</li>
67
+ <li>type inference</li>
68
+ <li>minimal runtime</li>
69
+ <li>efficient C bindings</li>
70
+ </ul>
71
+ </div>
72
+ <div class="col-md-8">
73
+ <div id="active-code">
74
+ <button type="button" class="btn btn-primary btn-sm" id="run-code">Run</button>
75
+ <div id="editor">fn main() {
76
+ let greetings = ["Hello", "Hola", "Bonjour",
77
+ "こんにちは", "您好"];
78
+
79
+ for (num, greeting) in greetings.iter().enumerate() {
80
+ println!("{}", greeting);
81
+ match num {
82
+ 0 => println!("This code is editable and runnable!"),
83
+ 1 => println!("Este código es editable y ejecutable!"),
84
+ 2 => println!("Ce code est modifiable et exécutable!"),
85
+ 3 => println!("このコードは編集して実行出来ます!"),
86
+ 4 => println!("这个代码是可以编辑并且能够运行的!"),
87
+ _ => {},
88
+ }
89
+ }
90
+ }
91
+ </div>
92
+ <div id="result" data-msg-running="Running...">
93
+ <a id="playlink"><i class="icon-link-ext"></i></a>
94
+ </div>
95
+ </div>
96
+ <div id="static-code"><pre class='rust'>
97
+ <span class='kw'>fn</span> main() {
98
+ <span class='kw'>let</span> greetings = [<span class='string'>"Hello"</span>, <span class='string'>"Hola"<span>, <span class='string'>"Bonjour"</span>,
99
+ <span class='string'>"こんにちは"</span>, <span class='string'>"您好"</span>];
100
+
101
+ <span class='kw'>for</span> (num, greeting) in greetings.iter().enumerate() {
102
+ <span class='prelude-val'>println!</span>(<span class='string'>"{}"</span>, greeting);
103
+ <span class='kw'>match</span> num {
104
+ 0 => <span class='prelude-val'>println!</span>(<span class='string'>"This code is editable and runnable!"</span>),
105
+ 1 => <span class='prelude-val'>println!</span>(<span class='string'>"Este código es editable y ejecutable!"</span>),
106
+ 2 => <span class='prelude-val'>println!</span>(<span class='string'>"Ce code est modifiable et exécutable!"</span>),
107
+ 3 => <span class='prelude-val'>println!</span>(<span class='string'>"このコードは編集して実行出来ます!"</span>),
108
+ 4 => <span class='prelude-val'>println!</span>(<span class='string'>"这个代码是可以编辑并且能够运行的!"</span>),
109
+ _ => {},
110
+ }
111
+ }
112
+ }
113
+ </pre>
114
+ </div>
115
+ <div class="more-examples">
116
+ <a href="http://rustbyexample.com/">More examples</a>
117
+ </div>
118
+ </div>
119
+ </div>
120
+
121
+ <script type="text/javascript">
122
+ include = function() {
123
+
124
+ // save references to save a few bytes
125
+ var args = arguments;
126
+ var doc = document;
127
+
128
+ var toLoad = args.length; // load this many scripts
129
+ var lastArgument = args[toLoad - 1];
130
+ var hasCallback = lastArgument.call; // is the last arg a callback?
131
+ if (hasCallback) {
132
+ toLoad--;
133
+ }
134
+
135
+ function onScriptLoaded() {
136
+ var readyState = this.readyState; // we test for "complete" or "loaded" if on IE
137
+ if (!readyState || /ded|te/.test(readyState)) {
138
+ toLoad--;
139
+ if (!toLoad && hasCallback) {
140
+ lastArgument();
141
+ }
142
+ }
143
+ }
144
+
145
+ for (var i = 0; i < toLoad; i++) {
146
+
147
+ var script = doc.createElement('script');
148
+ script.src = arguments[i];
149
+ script.async = true;
150
+ script.onload = script.onerror = script.onreadystatechange = onScriptLoaded;
151
+ (
152
+ doc.head ||
153
+ doc.getElementsByTagName('head')[0]
154
+ ).appendChild(script);
155
+
156
+ }
157
+
158
+ };
159
+
160
+
161
+ include("https://cdn.jsdelivr.net/ace/1.1.3/noconflict/ace.js", function () {
162
+ include("https://cdn.jsdelivr.net/ace/1.1.3/noconflict/mode-rust.js", function () {
163
+ (function () {
164
+ "use strict";
165
+ // ECMAScript 6 Backwards compatability
166
+ if (typeof String.prototype.startsWith !== 'function') {
167
+ String.prototype.startsWith = function(str) {
168
+ return this.slice(0, str.length) === str;
169
+ };
170
+ }
171
+
172
+ // Regex for finding new lines
173
+ var newLineRegex = /(?:\r\n|\r|\n)/g;
174
+
175
+ // Fetching DOM items
176
+ var activeCode = document.getElementById("active-code");
177
+ var editorDiv = document.getElementById("editor");
178
+ var staticCode = document.getElementById("static-code");
179
+ var runButton = document.getElementById("run-code");
180
+ var resultDiv = document.getElementById("result");
181
+ var playLink = document.getElementById("playlink");
182
+
183
+ // Background colors for program result on success/error
184
+ var successColor = "#E2EEF6";
185
+ var errorColor = "#F6E2E2";
186
+ var warningColor = "#FFFBCB";
187
+
188
+ // Message to show when the program is running
189
+ var runningMsg = resultDiv.getAttribute("data-msg-running") || "Running...";
190
+
191
+ // Error message to return when there's a server failure
192
+ var errMsg = "The server encountered an error while running the program.";
193
+
194
+ // Stores ACE editor markers (highights) for errors
195
+ var markers = [];
196
+
197
+ // Status codes, because there are no enums in Javascript
198
+ var SUCCESS = 0;
199
+ var ERROR = 1;
200
+ var WARNING = 2;
201
+
202
+ // JS exists, display ACE editor
203
+ staticCode.style.display = "none";
204
+ activeCode.style.display = "block";
205
+
206
+ // Setting up ace editor
207
+ var editor = ace.edit("editor");
208
+ var Range = ace.require('ace/range').Range;
209
+ editor.setTheme("ace/theme/chrome");
210
+ editor.getSession().setMode("ace/mode/rust");
211
+ editor.setShowPrintMargin(false);
212
+ editor.renderer.setShowGutter(false);
213
+ editor.setHighlightActiveLine(false);
214
+
215
+ // Changes the height of the editor to match its contents
216
+ function updateEditorHeight() {
217
+ // https://stackoverflow.com/questions/11584061/
218
+ var newHeight = editor.getSession().getScreenLength()
219
+ * editor.renderer.lineHeight
220
+ + editor.renderer.scrollBar.getWidth();
221
+
222
+ editorDiv.style.height = Math.ceil(newHeight).toString() + "px";
223
+ editor.resize();
224
+ }
225
+
226
+ // Set initial size to match initial content
227
+ updateEditorHeight();
228
+
229
+ // Safely remove all content from the result div
230
+ function clearResultDiv() {
231
+ // Clearing the result div will break our reference to
232
+ // the playlink icon, so let's save it if it exists
233
+ var newPlayLink = document.getElementById("playlink");
234
+ if (newPlayLink) {
235
+ playLink = resultDiv.removeChild(newPlayLink);
236
+ }
237
+ resultDiv.innerHTML = "";
238
+ }
239
+
240
+ function escapeHTML(unsafe) {
241
+ return unsafe
242
+ .replace(/&/g, "&amp;")
243
+ .replace(/</g, "&lt;")
244
+ .replace(/>/g, "&gt;")
245
+ .replace(/"/g, "&quot;")
246
+ .replace(/'/g, "&#039;")
247
+ .replace(newLineRegex, '<br />');
248
+ }
249
+
250
+ // Dispatches a XMLHttpRequest to the Rust playpen, running the program, and
251
+ // issues a callback to `callback` with the result (or null on error)
252
+ function runProgram(program, callback) {
253
+ var req = new XMLHttpRequest();
254
+ var data = JSON.stringify({
255
+ version: "beta",
256
+ optimize: "0",
257
+ code: program
258
+ });
259
+
260
+ req.timeout = 6000;
261
+
262
+ // console.log("Sending", data);
263
+ req.open('POST', "https://play.rust-lang.org/evaluate.json", true);
264
+ req.onload = function(e) {
265
+ var statusCode = false;
266
+ var result = null;
267
+
268
+ if (req.readyState === 4 && req.status === 200) {
269
+ result = JSON.parse(req.response);
270
+
271
+ // handle application errors from playpen
272
+ if (typeof result['error'] === 'string') {
273
+ statusCode = ERROR;
274
+ result = 'Playpen Error: ' + result['error'];
275
+ } else if (typeof result['result'] === 'string') {
276
+ statusCode = SUCCESS;
277
+ result = result['result'];
278
+
279
+ // handle rustc errors/warnings
280
+ // Need server support to get an accurate version of this.
281
+ if (result.indexOf("error:") !== -1) {
282
+ statusCode = ERROR;
283
+ } else if (result.indexOf("warning:") !== -1) {
284
+ statusCode = WARNING;
285
+ }
286
+ }
287
+ }
288
+
289
+ callback(statusCode, result);
290
+ };
291
+
292
+ req.onerror = function(e) {
293
+ callback(false, null);
294
+ };
295
+
296
+ req.ontimeout = function(e) {
297
+ var statusCode = ERROR;
298
+ var result = "play.rust-lang.org not responding, please check back later";
299
+
300
+ callback(statusCode, result);
301
+ }
302
+
303
+ req.setRequestHeader("Content-Type", "application/json");
304
+ req.send(data);
305
+ }
306
+
307
+ // The callback to runProgram
308
+ function handleResult(statusCode, message) {
309
+ // Dispatch depending on result type
310
+ if (result == null) {
311
+ clearResultDiv();
312
+ resultDiv.style.backgroundColor = errorColor;
313
+ resultDiv.innerHTML = errMsg;
314
+ } else if (statusCode === SUCCESS) {
315
+ handleSuccess(message);
316
+ } else if (statusCode === WARNING) {
317
+ handleWarning(message);
318
+ } else {
319
+ handleError(message);
320
+ }
321
+ }
322
+
323
+ // Called on successful program run: display output and playground icon
324
+ function handleSuccess(message) {
325
+ resultDiv.style.backgroundColor = successColor;
326
+ displayOutput(escapeHTML(message), editor.getValue());
327
+ }
328
+
329
+ // Called when program run results in warning(s)
330
+ function handleWarning(message) {
331
+ resultDiv.style.backgroundColor = warningColor;
332
+ handleProblem(message, "warning");
333
+ }
334
+
335
+ // Called when program run results in error(s)
336
+ function handleError(message) {
337
+ resultDiv.style.backgroundColor = errorColor;
338
+ handleProblem(message, "error");
339
+ }
340
+
341
+ // Called on unsuccessful program run. Detects and prints problems (either
342
+ // warnings or errors) in program output and highlights relevant lines and text
343
+ // in the code.
344
+ function handleProblem(message, problem) {
345
+ // Getting list of ranges with problems
346
+ var lines = message.split(newLineRegex);
347
+
348
+ // Cleaning up the message: keeps only relevant problem output.
349
+ var cleanMessage = lines.filter(function(line) {
350
+ return !line.trim().startsWith("--> <anon>")
351
+ && !line.startsWith("playpen:")
352
+ && !line.trim().startsWith("error: aborting");
353
+ }).map(function(line) {
354
+ return escapeHTML(line);
355
+ }).filter(function(line) {
356
+ return line != "";
357
+ }).map(function(line) {
358
+ return line.replace(/ /g, '\u00a0\u00a0');
359
+ }).join("<br />");
360
+
361
+ // Get all of the row:col in the message.
362
+ var errorLines = lines.filter(function(line) {
363
+ return line.indexOf("--> <anon>") !== -1;
364
+ }).map(function(line) {
365
+ var lineIndex = line.indexOf(":");
366
+ if (lineIndex !== -1) {
367
+ return line.slice(lineIndex);
368
+ }
369
+
370
+ return "";
371
+ }).filter(function(line) {
372
+ return line != "";
373
+ });
374
+
375
+ // Setting message
376
+ displayOutput(cleanMessage, editor.getValue());
377
+
378
+ // Highlighting the lines
379
+ var ranges = parseProblems(errorLines);
380
+ markers = ranges.map(function(range) {
381
+ return editor.getSession().addMarker(range, "ace-" + problem + "-line",
382
+ "fullLine", false);
383
+ });
384
+
385
+ // Highlighting the specific text
386
+ markers = markers.concat(ranges.map(function(range) {
387
+ return editor.getSession().addMarker(range, "ace-" + problem + "-text",
388
+ "text", false);
389
+ }));
390
+ }
391
+
392
+ // Parses a problem message returning a list of ranges (row:col, row:col) where
393
+ // problems in the code have occured.
394
+ function parseProblems(lines) {
395
+ var ranges = [];
396
+ for (var i in lines) {
397
+ var line = lines[i];
398
+ var parts = line.split(/:\s?|\s+/, 5).slice(1, 5);
399
+ var ip = parts.map(function(p) { return parseInt(p, 10) - 1; });
400
+ console.log("line:", line, parts, ip);
401
+ ranges.push(new Range(ip[0], ip[1], ip[2], ip[3]));
402
+ }
403
+
404
+ return ranges;
405
+ }
406
+
407
+ // Registering handler for run button click
408
+ runButton.addEventListener("click", function(ev) {
409
+ resultDiv.style.display = "block";
410
+ clearResultDiv();
411
+ resultDiv.innerHTML = runningMsg;
412
+
413
+ // clear previous markers, if any
414
+ markers.map(function(id) { editor.getSession().removeMarker(id); });
415
+
416
+ // Get the code, run the program
417
+ var program = editor.getValue();
418
+ runProgram(program, handleResult);
419
+ });
420
+
421
+ // Display an output message and a link to the Rust playground
422
+ function displayOutput(message, program) {
423
+ var programUrl = "https://play.rust-lang.org/?code=" +
424
+ encodeURIComponent(program) + "&run=1";
425
+ playLink.href = programUrl;
426
+
427
+ clearResultDiv(); // clear resultDiv, then add
428
+ resultDiv.appendChild(playLink); // playLink icon and message
429
+ resultDiv.innerHTML += message;
430
+ }
431
+
432
+ // Highlight active line when focused
433
+ editor.on('focus', function() {
434
+ editor.setHighlightActiveLine(true);
435
+ });
436
+
437
+ // Don't when not
438
+ editor.on('blur', function() {
439
+ editor.setHighlightActiveLine(false);
440
+ });
441
+ }());
442
+
443
+ });
444
+ });
445
+ </script>
446
+
447
+
448
+ <footer>
449
+ <p>Our site in other languages:
450
+ <a href="/en-US/">English</a>,
451
+ <a href="/es-ES/">Español</a>,
452
+ <a href="/fr-FR/">Français</a>,
453
+ <a href="/it-IT/">Italiano</a>,
454
+ <a href="/ja-JP/">日本語</a>,
455
+ <a href="/ko-KR/">한국어</a>,
456
+ <a href="/pl-PL/">Polski</a>,
457
+ <a href="/pt-BR/">Português</a>,
458
+ <a href="/ru-RU/">Русский</a>,
459
+ <a href="/vi-VN/">Tiếng việt</a>,
460
+ <a href="/zh-CN/">简体中文</a>
461
+
462
+ </p>
463
+ </footer>
464
+
465
+ <script>
466
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
467
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
468
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
469
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
470
+
471
+ ga('create', 'UA-58390457-1', 'auto');
472
+ ga('send', 'pageview');
473
+
474
+ </script>
475
+ </body>
476
+ </html>
@@ -1 +1 @@
1
- {"url":"https://linuxfr.org/","messages":[{"type":"info","lastLine":198,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the h1element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":195,"lastColumn":20,"firstColumn":1,"subType":"warning","message":"Section lacks heading. Consider using “h2”-“h6” elements to add identifying headings to all sections.","extract":"eil\"</h1>\n<section id=\"phare\">\n<arti","hiliteStart":10,"hiliteLength":20},{"type":"info","lastLine":313,"lastColumn":38,"firstColumn":7,"subType":"warning","message":"The “main” role is unnecessary for element “main”.","extract":"av>\n</nav><main id=\"contents\" role=\"main\">\n<arti","hiliteStart":10,"hiliteLength":32},{"type":"info","lastLine":316,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":374,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":429,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":488,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":546,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":624,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":663,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":739,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":781,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":845,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":908,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":967,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":1015,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"info","lastLine":1079,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40},{"type":"error","lastLine":1098,"lastColumn":18,"firstColumn":1,"message":"Duplicate ID “sommaire”.","extract":"ibre.</p>\n<h2 id=\"sommaire\">Sommai","hiliteStart":10,"hiliteLength":18},{"type":"info","lastLine":507,"lastColumn":18,"firstColumn":1,"subType":"warning","message":"The first occurrence of ID “sommaire” was here.","extract":"ibre.</p>\n<h2 id=\"sommaire\">Sommai","hiliteStart":10,"hiliteLength":18},{"type":"info","lastLine":1138,"lastColumn":40,"firstColumn":1,"subType":"warning","message":"Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).","extract":"\n<header>\n<h1 class=\"entry-title\" itemprop=\"name\"><a hre","hiliteStart":10,"hiliteLength":40}],"language":"fr"}
1
+ {"url":"https://www.rust-lang.org/en-US/","messages":[{"type":"error","lastLine":113,"lastColumn":6,"firstColumn":1,"message":"End tagpreseen, but there were open elements.","extract":"}\n }\n}\n</pre>\n</div","hiliteStart":10,"hiliteLength":6},{"type":"error","lastLine":98,"lastColumn":115,"firstColumn":110,"message":"Unclosed element “span”.","extract":"ng'>\"Hola\"<span>, <spa","hiliteStart":10,"hiliteLength":6},{"type":"error","lastLine":98,"lastColumn":103,"firstColumn":83,"message":"Unclosed element “span”.","extract":"\"</span>, <span class='string'>\"Hola\"","hiliteStart":10,"hiliteLength":21}]}
@@ -39,7 +39,7 @@ describe ValidateWebsite::Static do
39
39
  markup: false,
40
40
  not_found: true)
41
41
  end
42
- @validate_website.not_founds_count.must_equal 193
42
+ @validate_website.not_founds_count.must_equal 213
43
43
  end
44
44
  end
45
45
 
@@ -19,7 +19,7 @@ describe ValidateWebsite::Validator do
19
19
  ignore = /width|height|Length/
20
20
  validator = subject.new(@xhtml1_page.doc,
21
21
  @xhtml1_page.body,
22
- ignore)
22
+ ignore: ignore)
23
23
  validator.valid?.must_equal true
24
24
  validator.errors.must_equal []
25
25
  end
@@ -35,7 +35,7 @@ describe ValidateWebsite::Validator do
35
35
  ignore = /width|height|Length/
36
36
  validator = subject.new(@xhtml1_page.doc,
37
37
  @xhtml1_page.body,
38
- ignore)
38
+ ignore: ignore)
39
39
  validator.dtd.system_id.must_equal dtd_uri
40
40
  validator.namespace.must_equal name
41
41
  validator.valid?.must_equal true
@@ -62,12 +62,13 @@ describe ValidateWebsite::Validator do
62
62
  validator.valid?.must_equal true
63
63
  end
64
64
  end
65
+
65
66
  describe('when not valid') do
66
67
  before do
67
68
  validator_res = File.join('test', 'data', 'validator.nu-failure.json')
68
69
  stub_request(:any, /#{subject.html5_validator_service_url}/)
69
70
  .to_return(body: open(validator_res).read)
70
- name = 'html5'
71
+ name = 'html5-fail'
71
72
  file = File.join('test', 'data', "#{name}.html")
72
73
  page = FakePage.new(name,
73
74
  body: open(file).read,
@@ -75,20 +76,42 @@ describe ValidateWebsite::Validator do
75
76
  @html5_page = @http.get_page(page.url)
76
77
  end
77
78
 
78
- it 'should have an array of errors' do
79
- validator = subject.new(@html5_page.doc,
80
- @html5_page.body)
81
- validator.valid?.must_equal false
82
- validator.errors.size.must_equal 1
79
+ describe('without tidy') do
80
+ it 'should have an array of errors' do
81
+ validator = subject.new(@html5_page.doc,
82
+ @html5_page.body,
83
+ html5_validator: :nu)
84
+ validator.valid?.must_equal false
85
+ validator.errors.size.must_equal 3
86
+ end
87
+
88
+ it 'should exclude errors ignored by :ignore option' do
89
+ ignore = /Unclosed element/
90
+ validator = subject.new(@html5_page.doc,
91
+ @html5_page.body,
92
+ ignore: ignore,
93
+ html5_validator: :nu)
94
+ validator.valid?.must_equal false
95
+ validator.errors.size.must_equal 1
96
+ end
83
97
  end
84
98
 
85
- it 'should exclude errors ignored by :ignore option' do
86
- ignore = /Duplicate ID/
87
- validator = subject.new(@html5_page.doc,
88
- @html5_page.body,
89
- ignore)
90
- validator.valid?.must_equal true
91
- validator.errors.size.must_equal 0
99
+ describe('with tidy') do
100
+ it 'should have an array of errors' do
101
+ validator = subject.new(@html5_page.doc,
102
+ @html5_page.body)
103
+ validator.valid?.must_equal false
104
+ validator.errors.size.must_equal 4
105
+ end
106
+
107
+ it 'should exclude errors ignored by :ignore option' do
108
+ ignore = /letter not allowed here|trimming empty/
109
+ validator = subject.new(@html5_page.doc,
110
+ @html5_page.body,
111
+ ignore: ignore)
112
+ validator.valid?.must_equal false
113
+ validator.errors.size.must_equal 2
114
+ end
92
115
  end
93
116
  end
94
117
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'webmock/minitest'
3
2
 
4
3
  # FakePage html helper for webmock
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validate-website
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Arnoud
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-08 00:00:00.000000000 Z
11
+ date: 2017-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spidr
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tidy_ffi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: slop
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -198,6 +212,7 @@ files:
198
212
  - lib/validate_website/static_link.rb
199
213
  - lib/validate_website/utils.rb
200
214
  - lib/validate_website/validator.rb
215
+ - lib/validate_website/validator_class_methods.rb
201
216
  - lib/validate_website/version.rb
202
217
  - man/man1/validate-website-static.1
203
218
  - man/man1/validate-website.1
@@ -206,6 +221,7 @@ files:
206
221
  - test/data/assets/application-92f19110a9d47a56d2ebe744e15af301.css
207
222
  - test/data/cozy-community.html
208
223
  - test/data/html4-strict.html
224
+ - test/data/html5-fail.html
209
225
  - test/data/html5.html
210
226
  - test/data/news/ryzom-naissance-du-projet-libre-ryzom-forge.md
211
227
  - test/data/validator.nu-failure.json