1 | #!/usr/bin/env node
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | var fs, system, esprima, options, fnames, count;
|
30 |
|
31 | if (typeof esprima === 'undefined') {
|
32 |
|
33 | if (typeof phantom === 'object') {
|
34 | fs = require('fs');
|
35 | system = require('system');
|
36 | esprima = require('./esprima');
|
37 | } else if (typeof require === 'function') {
|
38 | fs = require('fs');
|
39 | esprima = require('esprima');
|
40 | } else if (typeof load === 'function') {
|
41 | try {
|
42 | load('esprima.js');
|
43 | } catch (e) {
|
44 | load('../esprima.js');
|
45 | }
|
46 | }
|
47 | }
|
48 |
|
49 |
|
50 | if (typeof phantom === 'object') {
|
51 | fs.readFileSync = fs.read;
|
52 | process = {
|
53 | argv: [].slice.call(system.args),
|
54 | exit: phantom.exit
|
55 | };
|
56 | process.argv.unshift('phantomjs');
|
57 | }
|
58 |
|
59 |
|
60 | if (typeof console === 'undefined' && typeof process === 'undefined') {
|
61 | console = { log: print };
|
62 | fs = { readFileSync: readFile };
|
63 | process = { argv: arguments, exit: quit };
|
64 | process.argv.unshift('esvalidate.js');
|
65 | process.argv.unshift('rhino');
|
66 | }
|
67 |
|
68 | function showUsage() {
|
69 | console.log('Usage:');
|
70 | console.log(' esvalidate [options] file.js');
|
71 | console.log();
|
72 | console.log('Available options:');
|
73 | console.log();
|
74 | console.log(' --format=type Set the report format, plain (default) or junit');
|
75 | console.log(' -v, --version Print program version');
|
76 | console.log();
|
77 | process.exit(1);
|
78 | }
|
79 |
|
80 | if (process.argv.length <= 2) {
|
81 | showUsage();
|
82 | }
|
83 |
|
84 | options = {
|
85 | format: 'plain'
|
86 | };
|
87 |
|
88 | fnames = [];
|
89 |
|
90 | process.argv.splice(2).forEach(function (entry) {
|
91 |
|
92 | if (entry === '-h' || entry === '--help') {
|
93 | showUsage();
|
94 | } else if (entry === '-v' || entry === '--version') {
|
95 | console.log('ECMAScript Validator (using Esprima version', esprima.version, ')');
|
96 | console.log();
|
97 | process.exit(0);
|
98 | } else if (entry.slice(0, 9) === '--format=') {
|
99 | options.format = entry.slice(9);
|
100 | if (options.format !== 'plain' && options.format !== 'junit') {
|
101 | console.log('Error: unknown report format ' + options.format + '.');
|
102 | process.exit(1);
|
103 | }
|
104 | } else if (entry.slice(0, 2) === '--') {
|
105 | console.log('Error: unknown option ' + entry + '.');
|
106 | process.exit(1);
|
107 | } else {
|
108 | fnames.push(entry);
|
109 | }
|
110 | });
|
111 |
|
112 | if (fnames.length === 0) {
|
113 | console.log('Error: no input file.');
|
114 | process.exit(1);
|
115 | }
|
116 |
|
117 | if (options.format === 'junit') {
|
118 | console.log('<?xml version="1.0" encoding="UTF-8"?>');
|
119 | console.log('<testsuites>');
|
120 | }
|
121 |
|
122 | count = 0;
|
123 | fnames.forEach(function (fname) {
|
124 | var content, timestamp, syntax, name;
|
125 | try {
|
126 | content = fs.readFileSync(fname, 'utf-8');
|
127 |
|
128 | if (content[0] === '#' && content[1] === '!') {
|
129 | content = '//' + content.substr(2, content.length);
|
130 | }
|
131 |
|
132 | timestamp = Date.now();
|
133 | syntax = esprima.parse(content, { tolerant: true });
|
134 |
|
135 | if (options.format === 'junit') {
|
136 |
|
137 | name = fname;
|
138 | if (name.lastIndexOf('/') >= 0) {
|
139 | name = name.slice(name.lastIndexOf('/') + 1);
|
140 | }
|
141 |
|
142 | console.log('<testsuite name="' + fname + '" errors="0" ' +
|
143 | ' failures="' + syntax.errors.length + '" ' +
|
144 | ' tests="' + syntax.errors.length + '" ' +
|
145 | ' time="' + Math.round((Date.now() - timestamp) / 1000) +
|
146 | '">');
|
147 |
|
148 | syntax.errors.forEach(function (error) {
|
149 | var msg = error.message;
|
150 | msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
151 | console.log(' <testcase name="Line ' + error.lineNumber + ': ' + msg + '" ' +
|
152 | ' time="0">');
|
153 | console.log(' <error type="SyntaxError" message="' + error.message + '">' +
|
154 | error.message + '(' + name + ':' + error.lineNumber + ')' +
|
155 | '</error>');
|
156 | console.log(' </testcase>');
|
157 | });
|
158 |
|
159 | console.log('</testsuite>');
|
160 |
|
161 | } else if (options.format === 'plain') {
|
162 |
|
163 | syntax.errors.forEach(function (error) {
|
164 | var msg = error.message;
|
165 | msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
166 | msg = fname + ':' + error.lineNumber + ': ' + msg;
|
167 | console.log(msg);
|
168 | ++count;
|
169 | });
|
170 |
|
171 | }
|
172 | } catch (e) {
|
173 | ++count;
|
174 | if (options.format === 'junit') {
|
175 | console.log('<testsuite name="' + fname + '" errors="1" failures="0" tests="1" ' +
|
176 | ' time="' + Math.round((Date.now() - timestamp) / 1000) + '">');
|
177 | console.log(' <testcase name="' + e.message + '" ' + ' time="0">');
|
178 | console.log(' <error type="ParseError" message="' + e.message + '">' +
|
179 | e.message + '(' + fname + ((e.lineNumber) ? ':' + e.lineNumber : '') +
|
180 | ')</error>');
|
181 | console.log(' </testcase>');
|
182 | console.log('</testsuite>');
|
183 | } else {
|
184 | console.log('Error: ' + e.message);
|
185 | }
|
186 | }
|
187 | });
|
188 |
|
189 | if (options.format === 'junit') {
|
190 | console.log('</testsuites>');
|
191 | }
|
192 |
|
193 | if (count > 0) {
|
194 | process.exit(1);
|
195 | }
|
196 |
|
197 | if (count === 0 && typeof phantom === 'object') {
|
198 | process.exit(0);
|
199 | }
|