6 |
7 |
8 |
9 | # The A11y Machine
10 |
11 | [](https://github.com/liip/TheA11yMachine)
12 | [](https://www.npmjs.com/package/the-a11y-machine)
13 | [](#authors-and-license)
14 |
15 | > Note: TheA11yMachine is no longer maintained.
16 |
17 | **The A11y Machine** (or `a11ym` for short, spelled “alym”) is an **automated
18 | accessibility testing tool** which **crawls** and **tests** pages of any Web
19 | application to produce detailed reports. It validates pages against the
20 | following specifications/laws:
21 |
22 | * [W3C Web Content Accessibility Guidelines](http://www.w3.org/TR/WCAG20/)
23 | (WCAG) 2.0, including A, AA and AAA levels ([understanding levels of
24 | conformance](http://www.w3.org/TR/UNDERSTANDING-WCAG20/conformance.html#uc-levels-head)),
25 | * U.S. [Section 508](http://www.section508.gov/) legislation,
26 | * [W3C HTML5 Recommendation](https://www.w3.org/TR/html/).
27 |
28 | ## Table of contents
29 |
30 | * [Why?](#why)
31 | * [Installation](#installation)
32 | * [Usage](#usage)
33 | * [List of URLs instead of crawling](#list-of-urls-instead-of-crawling)
34 | * [Possible output](#possible-output)
35 | * [How does it work?](#how-does-it-work)
36 | * [Write your custom rules](#write-your-custom-rules)
37 | * [Watch the dashboard](#watch-the-dashboard)
38 | * [Roadmap and board](#roadmap-and-board)
39 | * [Authors and license](#authors-and-license)
40 |
41 | ## Why?
42 |
43 | If **privacy** matters for you, you're likely to install The A11y Machine over
44 | any SaaS services: It runs locally so you don't need to send your code
45 | somewhere, you can test all parts of your application including the ones which
46 | require an authentification (like a checkout, a back-office etc.)…
47 |
48 | Here are some pros and cons compared to SaaS solutions:
49 |
50 | Properties | The A11y Machine | SaaS services
51 | -----------|------------------|---------------
52 | Can run locally | yes | no
53 | Can test each patch | yes | no (except if deployed)
54 | Reduce the test loop | yes | no (the loop is longer)
55 | Can test private code | yes | no (you must send your code)
56 | Can test auth-required parts | yes | no
57 | Can crawl all your pages | yes | yes (but it can be pricey)
58 |
59 | Accessibility is not only a concern for disabled people. Bots can be considered
60 | as such, like [DuckDuckGo](https://duckduckgo.com),
61 | [Google](https://google.com/) or [Bing](https://bing.com/). By respecting these
62 | standards, you're likely to have a better ranking. Also it helps to clean your
63 | code. Accessibility issues are often left unaddressed for budget reasons. In
64 | fact most of the cost is spent looking for errors on your website. The A11y
65 | Machine greatly help with this task, you can thus focus on fixing your code and
66 | reap the benefits.
67 |
68 | ## Installation
69 |
70 | [NPM](http://npmjs.org/) is required. Then, execute the following lines:
71 |
72 | ```sh
73 | $ npm install -g the-a11y-machine
74 | ```
75 |
76 | If you would like to validate your pages against the HTML5 recommendation, then
77 | you need to [install Java](https://www.java.com/en/download/).
78 |
79 | As an alternative you can run a Docker image instead, which will ensure the image
80 | is available locally:
81 |
82 | ```sh
83 | $ docker build -t liip/the-a11y-machine .
84 | $ docker run liip/the-a11y-machine --help
85 | ```
86 |
87 | To get access to a report you will need to:
88 |
89 | * Mount a path into the container,
90 | * Specifify that internal path in your `a11ym` CLI options.
91 |
92 | For example:
93 |
94 | ```sh
95 | $ docker run -v $PWD:/var/output liip/the-a11y-machine -o /var/output http://example.org
96 | ```
97 |
98 | ## Usage
99 |
100 | As a prelude, see the help:
101 |
102 | ```sh
103 | Usage: a11ym [options] url …
104 |
105 | Options:
106 |
107 | -h, --help output usage information
108 | -b, --bootstrap Bootstrap file, i.e. the configuration file. All CLI options will overwrite options defined in the configuration file.
109 | -e, --error-level Minimum error level: In ascending order, `notice` (default), `warning`, and `error` (e.g. `warning` includes all warnings and errors).
110 | -c, --filter-by-codes Filter results by comma-separated WCAG codes (e.g. `H25,H91,G18`).
111 | -C, --exclude-by-codes Exclude results by comma-separated WCAG codes (e.g. `H25,H91,G18`).
112 | -d, --maximum-depth Explore up to a maximum depth (hops).
113 | -m, --maximum-urls Maximum number of URLs to compute.
114 | -o, --output-directory Output directory.
115 | -r, --report Report format: `cli`, `csv`, `html` (default), `json` or `markdown`.
116 | -s, --standards Standard to use: `WCAG2A`, `WCAG2AA` (default), ` WCAG2AAA`, `Section508`, `HTML` or your own (see `--sniffers`). `HTML` can be combined with any other by a comma.
117 | -S, --sniffers Path to the sniffers file, e.g. `resource/sniffers.js` (default).
118 | -u, --filter-by-urls Filter URL to test by using a regular expression without delimiters (e.g. 'news|contact').
119 | -U, --exclude-by-urls Exclude URL to test by using a regular expression without delimiters (e.g. 'news|contact').
120 | -w, --workers Number of workers, i.e. number of URLs computed in parallel.
121 | --http-auth-user Username to authenticate all HTTP requests.
122 | --http-auth-password Password to authenticate all HTTP requests.
123 | --http-tls-disable Disable TLS/SSL when crawling or downloading pages.
124 | -V, --no-verbose Make the program silent.
125 | --ignore-robots-txt Ignore robots.txt file.
126 |
127 | ```
128 |
129 | Thus, the simplest use is to run `a11ym` with a URL:
130 |
131 | ```sh
132 | $ ./a11ym http://example.org/
133 | ```
134 |
135 | All URLs accessible from `http://example.org/` will be tested against the
136 | WCAG2AA standard. See the `--maximum-urls` options to reduce the number of
137 | URLs to test.
138 |
139 | Then open `a11ym_output/index.html` and browser the result!
140 |
141 | ### List of URLs instead of crawling
142 |
143 | You can compute several URLs by adding them to the command-line, like this:
144 |
145 | ```sh
146 | $ ./a11ym http://example.org/A http://example.org/B http://example.org/C
147 | ```
148 |
149 | Alternatively, this is possible to read URLs from STDIN, as follows:
150 |
151 | ```sh
152 | $ cat URLs.lists | ./a11ym -
153 | ```
154 |
155 | Note the `-`: It means “Read URLs from STDIN please”.
156 |
157 | When reading several URLs, the `--maximum-depth` option will be forced to 1.
158 |
159 | ### Possible output
160 |
161 | The index of the reports:
162 |
163 | 
164 |
165 | Report of a specific URL:
166 |
167 | 
168 |
169 | The dashboard of all reports:
170 |
171 | 
172 |
173 | ### Selecting standards
174 |
175 | As mentionned, the following standards are supported:
176 | * W3C WCAG,
177 | * U.S. Section 508 legislation,
178 | * W3C HTML5 recommendation.
179 |
180 | You cannot combine standards between each other, except HTML5 that can be
181 | combined with any other. So for instance, to run `WCAG2AAA`:
182 |
183 | ```sh
184 | $ ./a11ym --standards WCAG2AAA http://example.org/
185 | ```
186 |
187 | To run `WCAG2AA` along with `HTML`:
188 |
189 | ```sh
190 | $ ./a11ym --standards WCAG2AA,HTML http://example.org/
191 | ```
192 |
193 | ### How does it work?
194 |
195 | The pipe looks like this:
196 |
197 | 1. The [`node-simplecrawler`](https://github.com/cgiffard/node-simplecrawler/)
198 | tool is used to crawl a Web application based on the given URLs, with **our
199 | own specific exploration algorithm** to provide better results quickly, in
200 | addition to support **parallelism**,
201 | 2. For each URL found, 2 kind of tests are applied:
202 | 1. **Accessibility**: [PhantomJS](http://phantomjs.org/) runs and
203 | [`HTML_CodeSniffer`](https://github.com/squizlabs/HTML_CodeSniffer) is
204 | injected in order to check the page conformance; This step is
205 | semi-automated by the help of
206 | [`pa11y`](https://github.com/nature/pa11y), which is a very thin layer
207 | of code wrapping PhantomJS and `HTML_CodeSniffer`,
208 | 2. **HTML**: [The Nu Html Checker](http://validator.github.io/validator/)
209 | (v.Nu) is run on the same URL.
210 | 3. Finally, results from different tools are normalized, and enhanced and easy
211 | to use reports are produced.
212 |
213 | PhantomJS and `HTML_CodeSniffer` are widely-used, tested and precise tools.
214 | `pa11y` simplifies the use of these two latters. The Nu Html Checker is the tool
215 | used by the W3C to validate documents online. However, in this case, we **do all
216 | validations offline**! Nothing is sent over the network. Again, privacy.
217 |
218 | ### Write your custom rules
219 |
220 | `HTML_CodeSniffer` is build in a way that allows you to extend existing rules or
221 | write your own. A rule is represented as a sniffer (this is another
222 | terminology). The `resource/sniffers/` directory contains an example of
223 | a custom sniffer.
224 |
225 | The A11y Machine comes with a default file containing all the sniffers:
226 | `resource/sniffers.js`. You can provide your own by using the `--sniffers`
227 | option. To build your own sniffers, simply copy the `resource/sniffers/`
228 | somewhere as a basis, complete it, then compile it with the `a11ym-sniffers`
229 | utility:
230 |
231 | ```sh
232 | $ ./a11ym-sniffers --directory my/sniffers/ --output-directory my_sniffers.js
233 | ```
234 |
235 | Then, to effectively use it:
236 |
237 | ```sh
238 | $ ./a11ym --sniffers my_sniffers.js --standard MyStandard http://example.org/
239 | ```
240 |
241 | ### Watch the dashboard
242 |
243 | Run the `a11ym-dashboard` command to serve the dashboard. The dashboard is an
244 | overview of several reports generated by the `a11ym` command. The command can
245 | serves the dashboard over HTTP, or over static files. In addition to requiring
246 | a root directory, it requires: In the first case, an address, and a port, in the
247 | second, nothing more than just a flag. For instance, if the reports are
248 | generated with the following command:
249 |
250 | ```sh
251 | $ ./a11ym --output-directory my_reports/`date +%s`/ http://example.org/A http://example.org/B
252 | ```
253 |
254 | Then, the root directory is `my_reports/` and thus the dashboard will be started
255 | over HTTP with the following command:
256 |
257 | ```sh
258 | $ ./a11ym-dashboard --root my_reports
259 | ```
260 |
261 | Browse `127.0.0.1:8080` (by default) to see the dashboard!
262 |
263 | Or to generate static files:
264 |
265 | ```sh
266 | $ ./a11ym-dashboard --root my_reports --static-output
267 | ```
268 |
269 | Open `my_reports/index.html`, and do the same!
270 |
271 | Bonus: Use the `--open` option to automatically open the dashboard in your
272 | favorite browser.
273 |
274 | ## Roadmap and board
275 |
276 | The roadmap is public:
277 | * See [the incoming
278 | milestones](https://github.com/liip/TheA11yMachine/milestones),
279 | * See [the in progress
280 | issues](https://github.com/liip/TheA11yMachine/labels/in%20progress).
281 |
282 | The board is publicly available at the following URL: https://waffle.io/liip/TheA11yMachine.
283 |
284 | ## Authors and license
285 |
286 | Original author is [Ivan Enderlin](http://mnt.io/), accompagnied by [Gilles
287 | Crettenand](https://github.com/krtek4) and [David
288 | Jeanmonod](https://github.com/jeanmonod). This software is backed by
289 | [Liip](https://liip.ch/).
290 |
291 | [BSD-3-Clause](http://opensource.org/licenses/BSD-3-Clause):
292 |
293 | > Copyright (c), Ivan Enderlin and Liip
294 | > All rights reserved.
295 | >
296 | > Redistribution and use in source and binary forms, with or without modification,
297 | > are permitted provided that the following conditions are met:
298 | >
299 | > 1. Redistributions of source code must retain the above copyright notice, this
300 | > list of conditions and the following disclaimer.
301 | >
302 | > 2. Redistributions in binary form must reproduce the above copyright notice,
303 | > this list of conditions and the following disclaimer in the documentation
304 | > and/or other materials provided with the distribution.
305 | >
306 | > 3. Neither the name of the copyright holder nor the names of its contributors
307 | > may be used to endorse or promote products derived from this software without
308 | > specific prior written permission.
309 | >
310 | > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
311 | > ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
312 | > WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
313 | > DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
314 | > ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
315 | > (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
316 | > LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
317 | > ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
318 | > (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
319 | > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
320 |
--------------------------------------------------------------------------------
/a11ym:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | /**
6 | * Copyright (c) 2016, Ivan Enderlin and Liip
7 | * All rights reserved.
8 | *
9 | * Redistribution and use in source and binary forms, with or without modification,
10 | * are permitted provided that the following conditions are met:
11 | *
12 | * 1. Redistributions of source code must retain the above copyright notice, this
13 | * list of conditions and the following disclaimer.
14 | *
15 | * 2. Redistributions in binary form must reproduce the above copyright notice,
16 | * this list of conditions and the following disclaimer in the documentation
17 | * and/or other materials provided with the distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its contributors
20 | * may be used to endorse or promote products derived from this software without
21 | * specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 |
35 | var a11ym = require('./lib/a11ym');
36 | var program = require('commander');
37 |
38 | // Define all the options, with their description and default value.
39 | program
40 | .usage('[options] url …')
41 | .option(
42 | '-b, --bootstrap ',
43 | 'Bootstrap file, i.e. the configuration file. All CLI options will overwrite options defined in the configuration file.'
44 | )
45 | .option(
46 | '-e, --error-level ',
47 | 'Minimum error level: In ascending order, `notice` (default), `warning`, and `error` (e.g. `warning` includes all warnings and errors).',
48 | /^notice|warning|error$/i
49 | )
50 | .option(
51 | '-c, --filter-by-codes ',
52 | 'Filter results by comma-separated WCAG codes (e.g. `H25,H91,G18`).'
53 | )
54 | .option(
55 | '-C, --exclude-by-codes ',
56 | 'Exclude results by comma-separated WCAG codes (e.g. `H25,H91,G18`).'
57 | )
58 | .option(
59 | '-d, --maximum-depth ',
60 | 'Explore up to a maximum depth (hops).',
61 | /^\d+$/
62 | )
63 | .option(
64 | '-m, --maximum-urls ',
65 | 'Maximum number of URLs to compute.',
66 | /^\d+$/
67 | )
68 | .option(
69 | '-o, --output-directory ',
70 | 'Output directory.'
71 | )
72 | .option(
73 | '-r, --report ',
74 | 'Report format: `cli`, `csv`, `html` (default), `json` or `markdown`, or your own absolute path to a reporter.'
75 | )
76 | .option(
77 | '--report-options ',
78 | 'Report options, as a JSON formatted object.'
79 | )
80 | .option(
81 | '-s, --standards ',
82 | 'Standard to use: `WCAG2A`, `WCAG2AA` (default), ` WCAG2AAA`, `Section508`, `HTML` or your own (see `--sniffers`). `HTML` can be combined with any other by a comma.'
83 | )
84 | .option(
85 | '-S, --sniffers ',
86 | 'Path to the sniffers file, e.g. `resource/sniffers.js` (default).'
87 | )
88 | .option(
89 | '-u, --filter-by-urls ',
90 | 'Filter URL to test by using a regular expression without delimiters (e.g. \'news|contact\').'
91 | )
92 | .option(
93 | '-U, --exclude-by-urls ',
94 | 'Exclude URL to test by using a regular expression without delimiters (e.g. \'news|contact\').'
95 | )
96 | .option(
97 | '-w, --workers ',
98 | 'Number of workers, i.e. number of URLs computed in parallel.',
99 | /^\d+$/i
100 | )
101 | .option(
102 | '--http-auth-user ',
103 | 'Username to authenticate all HTTP requests.'
104 | )
105 | .option(
106 | '--http-auth-password ',
107 | 'Password to authenticate all HTTP requests.'
108 | )
109 | .option(
110 | '--http-tls-disable',
111 | 'Disable TLS/SSL when crawling or downloading pages.'
112 | )
113 | .option(
114 | '-V, --no-verbose',
115 | 'Make the program silent.'
116 | )
117 | .option(
118 | '--ignore-robots-txt',
119 | 'Ignore robots.txt file.'
120 | )
121 | .parse(process.argv);
122 |
123 | if (false === a11ym.start(program.opts(), program.args)) {
124 | program.help();
125 | process.exit(1);
126 | }
127 |
--------------------------------------------------------------------------------
/a11ym-dashboard:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | /**
6 | * Copyright (c) 2016, Ivan Enderlin and Liip
7 | * All rights reserved.
8 | *
9 | * Redistribution and use in source and binary forms, with or without modification,
10 | * are permitted provided that the following conditions are met:
11 | *
12 | * 1. Redistributions of source code must retain the above copyright notice, this
13 | * list of conditions and the following disclaimer.
14 | *
15 | * 2. Redistributions in binary form must reproduce the above copyright notice,
16 | * this list of conditions and the following disclaimer in the documentation
17 | * and/or other materials provided with the distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its contributors
20 | * may be used to endorse or promote products derived from this software without
21 | * specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 |
35 | var URL = require('url');
36 | var _ = require('underscore');
37 | var fs = require('fs');
38 | var glob = require('glob');
39 | var http = require('http');
40 | var open = require('open');
41 | var path = require('path');
42 | var program = require('commander');
43 |
44 | // Define all the options, with their description and default value.
45 | program
46 | .usage('[options]')
47 | .option(
48 | '-r, --root ',
49 | 'Path to the directory containing all the report directories.'
50 | )
51 | .option(
52 | '-a, --address ',
53 | 'Start an HTTP server, and listen this address.',
54 | '127.0.0.1'
55 | )
56 | .option(
57 | '-p, --port ',
58 | 'Port the HTTP server must listen to.',
59 | 8080
60 | )
61 | .option(
62 | '-s, --static-output',
63 | 'Generate static files instead of serving them over HTTP.'
64 | )
65 | .option(
66 | '-o, --open',
67 | 'Directly open the dashboard in your favorite browser.'
68 | )
69 | .parse(process.argv);
70 |
71 | // No address and port to compute? Then exit.
72 | if (!program.root) {
73 | program.help();
74 | process.exit(2);
75 | }
76 |
77 | function computeIndex() {
78 | var render = _.template(
79 | fs.readFileSync(__dirname + '/view/dashboard/index.html', {encoding: 'utf-8'})
80 | );
81 |
82 | return render({
83 | css: {
84 | common: fs.readFileSync(__dirname + '/view/common.css', {encoding: 'utf-8'})
85 | },
86 | js: {
87 | allStatistics: JSON.stringify(computeAllStatistics())
88 | }
89 | });
90 | }
91 |
92 | function computeAllStatistics() {
93 | var stats = [];
94 |
95 | glob
96 | .sync(program.root + '/*/statistics.json')
97 | .forEach(
98 | function (file) {
99 | stats.push(
100 | JSON
101 | .parse(fs.readFileSync(file, {encoding: 'utf-8'}))
102 | .reduce(
103 | function (previous, current) {
104 | return {
105 | reportId : previous.reportId,
106 | reportDirectory: previous.reportDirectory,
107 | date : previous.date || current.date,
108 | errorCount : previous.errorCount + current.errorCount,
109 | warningCount : previous.warningCount + current.warningCount,
110 | noticeCount : previous.noticeCount + current.noticeCount,
111 | }
112 | },
113 | {
114 | reportId : path.basename(path.dirname(file)),
115 | reportDirectory: path.basename(path.dirname(path.dirname(file))),
116 | date : null,
117 | errorCount : 0,
118 | noticeCount : 0,
119 | warningCount : 0
120 | }
121 | )
122 | );
123 | }
124 | );
125 |
126 | return stats;
127 | }
128 |
129 | // Create an HTTP server.
130 | if (undefined === program.staticOutput) {
131 | var server = http.createServer(
132 | new function () {
133 | var indexRegex = /^\/$/;
134 | var reportRegex = new RegExp('^\/([^/]+)/(.+)');
135 |
136 | return function (request, response) {
137 | var url = URL.parse(request.url);
138 | var matches = null;
139 |
140 | if (url.pathname.match(indexRegex)) {
141 | response.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
142 |
143 | response.end(computeIndex());
144 | } else if (matches = url.pathname.match(reportRegex)) {
145 | var index = program.root + '/' + matches[1] + '/' + matches[2];
146 |
147 | fs.access(
148 | index,
149 | fs.R_OK,
150 | function (error) {
151 | if (error) {
152 | response.writeHead(404, {'Content-Type': 'text/plain'});
153 | response.end('Report not found! Sorry.');
154 |
155 | return;
156 | }
157 |
158 | response.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
159 | response.end(fs.readFileSync(index));
160 | }
161 | );
162 | } else {
163 | response.writeHead(404, {'Content-Type': 'text/plain'});
164 | response.end('URL not found! Sorry.');
165 | }
166 | };
167 | }
168 | );
169 |
170 | // Listen!
171 | server.listen(program.port, program.address);
172 |
173 | console.log('Server is listening on ' + program.address + ':' + program.port + '!');
174 |
175 | if (program.open) {
176 | open('http://' + program.address + ':' + program.port);
177 | }
178 | }
179 | // Generate static files.
180 | else {
181 | var dashboardIndexPath = program.root + '/index.html';
182 | var dashboardIndex = fs.createWriteStream(
183 | dashboardIndexPath,
184 | {
185 | flag : 'w',
186 | defaultEncoding: 'utf8'
187 | }
188 | );
189 | dashboardIndex.write(computeIndex());
190 |
191 | console.log('Dashboard generated!');
192 |
193 | if (program.open) {
194 | open(dashboardIndexPath);
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/a11ym-sniffers:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | 'use strict';
4 |
5 | /**
6 | * Copyright (c) 2016, Ivan Enderlin and Liip
7 | * All rights reserved.
8 | *
9 | * Redistribution and use in source and binary forms, with or without modification,
10 | * are permitted provided that the following conditions are met:
11 | *
12 | * 1. Redistributions of source code must retain the above copyright notice, this
13 | * list of conditions and the following disclaimer.
14 | *
15 | * 2. Redistributions in binary form must reproduce the above copyright notice,
16 | * this list of conditions and the following disclaimer in the documentation
17 | * and/or other materials provided with the distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its contributors
20 | * may be used to endorse or promote products derived from this software without
21 | * specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 |
35 | var fs = require('fs');
36 | var glob = require('glob');
37 | var path = require('path');
38 | var program = require('commander');
39 |
40 | program
41 | .usage('[options]')
42 | .option(
43 | '-d, --directory ',
44 | 'Directory where sniffer files are located.'
45 | )
46 | .option(
47 | '-o, --output