1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var helpers_1 = require("../util/helpers");
|
4 | var highlight_1 = require("../highlight/highlight");
|
5 | var path_1 = require("path");
|
6 | var logger_1 = require("./logger");
|
7 | var fs_1 = require("fs");
|
8 | var chalk = require("chalk");
|
9 | function printDiagnostics(context, diagnosticsType, diagnostics, consoleLogDiagnostics, writeHtmlDiagnostics) {
|
10 | if (diagnostics && diagnostics.length) {
|
11 | if (consoleLogDiagnostics) {
|
12 | diagnostics.forEach(consoleLogDiagnostic);
|
13 | }
|
14 | if (writeHtmlDiagnostics) {
|
15 | var content = diagnostics.map(generateDiagnosticHtml);
|
16 | var fileName = getDiagnosticsFileName(context.buildDir, diagnosticsType);
|
17 | fs_1.writeFileSync(fileName, content.join('\n'), { encoding: 'utf8' });
|
18 | }
|
19 | }
|
20 | }
|
21 | exports.printDiagnostics = printDiagnostics;
|
22 | function consoleLogDiagnostic(d) {
|
23 | if (d.level === 'warn') {
|
24 | logger_1.Logger.warn(d.header);
|
25 | }
|
26 | else {
|
27 | logger_1.Logger.error(d.header);
|
28 | }
|
29 | logger_1.Logger.wordWrap([d.messageText]).forEach(function (m) {
|
30 | console.log(m);
|
31 | });
|
32 | console.log('');
|
33 | if (d.lines && d.lines.length) {
|
34 | var lines = prepareLines(d.lines, 'text');
|
35 | lines.forEach(function (l) {
|
36 | if (!isMeaningfulLine(l.text)) {
|
37 | return;
|
38 | }
|
39 | var msg = "L" + l.lineNumber + ": ";
|
40 | while (msg.length < logger_1.Logger.INDENT.length) {
|
41 | msg = ' ' + msg;
|
42 | }
|
43 | var text = l.text;
|
44 | if (l.errorCharStart > -1) {
|
45 | text = consoleHighlightError(text, l.errorCharStart, l.errorLength);
|
46 | }
|
47 | msg = chalk.dim(msg);
|
48 | if (d.language === 'javascript') {
|
49 | msg += jsConsoleSyntaxHighlight(text);
|
50 | }
|
51 | else if (d.language === 'scss') {
|
52 | msg += cssConsoleSyntaxHighlight(text, l.errorCharStart);
|
53 | }
|
54 | else {
|
55 | msg += text;
|
56 | }
|
57 | console.log(msg);
|
58 | });
|
59 | console.log('');
|
60 | }
|
61 | }
|
62 | function consoleHighlightError(errorLine, errorCharStart, errorLength) {
|
63 | var rightSideChars = errorLine.length - errorCharStart + errorLength - 1;
|
64 | while (errorLine.length + logger_1.Logger.INDENT.length > logger_1.Logger.MAX_LEN) {
|
65 | if (errorCharStart > (errorLine.length - errorCharStart + errorLength) && errorCharStart > 5) {
|
66 |
|
67 | errorLine = errorLine.substr(1);
|
68 | errorCharStart--;
|
69 | }
|
70 | else if (rightSideChars > 1) {
|
71 |
|
72 | errorLine = errorLine.substr(0, errorLine.length - 1);
|
73 | rightSideChars--;
|
74 | }
|
75 | else {
|
76 | break;
|
77 | }
|
78 | }
|
79 | var lineChars = [];
|
80 | var lineLength = Math.max(errorLine.length, errorCharStart + errorLength);
|
81 | for (var i = 0; i < lineLength; i++) {
|
82 | var chr = errorLine.charAt(i);
|
83 | if (i >= errorCharStart && i < errorCharStart + errorLength) {
|
84 | chr = chalk.bgRed(chr === '' ? ' ' : chr);
|
85 | }
|
86 | lineChars.push(chr);
|
87 | }
|
88 | return lineChars.join('');
|
89 | }
|
90 | var diagnosticsHtmlCache = {};
|
91 | function clearDiagnosticsCache() {
|
92 | diagnosticsHtmlCache = {};
|
93 | }
|
94 | exports.clearDiagnosticsCache = clearDiagnosticsCache;
|
95 | function clearDiagnostics(context, type) {
|
96 | try {
|
97 | delete diagnosticsHtmlCache[type];
|
98 | fs_1.unlinkSync(getDiagnosticsFileName(context.buildDir, type));
|
99 | }
|
100 | catch (e) { }
|
101 | }
|
102 | exports.clearDiagnostics = clearDiagnostics;
|
103 | function hasDiagnostics(buildDir) {
|
104 | loadBuildDiagnosticsHtml(buildDir);
|
105 | var keys = Object.keys(diagnosticsHtmlCache);
|
106 | for (var i = 0; i < keys.length; i++) {
|
107 | if (typeof diagnosticsHtmlCache[keys[i]] === 'string') {
|
108 | return true;
|
109 | }
|
110 | }
|
111 | return false;
|
112 | }
|
113 | exports.hasDiagnostics = hasDiagnostics;
|
114 | function loadBuildDiagnosticsHtml(buildDir) {
|
115 | try {
|
116 | if (diagnosticsHtmlCache[exports.DiagnosticsType.TypeScript] === undefined) {
|
117 | diagnosticsHtmlCache[exports.DiagnosticsType.TypeScript] = fs_1.readFileSync(getDiagnosticsFileName(buildDir, exports.DiagnosticsType.TypeScript), 'utf8');
|
118 | }
|
119 | }
|
120 | catch (e) {
|
121 | diagnosticsHtmlCache[exports.DiagnosticsType.TypeScript] = false;
|
122 | }
|
123 | try {
|
124 | if (diagnosticsHtmlCache[exports.DiagnosticsType.Sass] === undefined) {
|
125 | diagnosticsHtmlCache[exports.DiagnosticsType.Sass] = fs_1.readFileSync(getDiagnosticsFileName(buildDir, exports.DiagnosticsType.Sass), 'utf8');
|
126 | }
|
127 | }
|
128 | catch (e) {
|
129 | diagnosticsHtmlCache[exports.DiagnosticsType.Sass] = false;
|
130 | }
|
131 | }
|
132 | function injectDiagnosticsHtml(buildDir, content) {
|
133 | if (!hasDiagnostics(buildDir)) {
|
134 | return content;
|
135 | }
|
136 | var contentStr = content.toString();
|
137 | var c = [];
|
138 | c.push("<div id=\"ion-diagnostics\">");
|
139 |
|
140 | c.push(getDiagnosticsHtmlContent(buildDir));
|
141 | c.push("</div>");
|
142 | var match = contentStr.match(/<body>(?![\s\S]*<body>)/i);
|
143 | if (match) {
|
144 | contentStr = contentStr.replace(match[0], match[0] + '\n' + c.join('\n'));
|
145 | }
|
146 | else {
|
147 | contentStr = c.join('\n') + contentStr;
|
148 | }
|
149 | return contentStr;
|
150 | }
|
151 | exports.injectDiagnosticsHtml = injectDiagnosticsHtml;
|
152 | function getDiagnosticsHtmlContent(buildDir, includeDiagnosticsHtml) {
|
153 | var c = [];
|
154 |
|
155 | c.push("\n <div class=\"ion-diagnostics-header\">\n <div class=\"ion-diagnostics-header-content\">\n <div class=\"ion-diagnostics-header-inner\">Error</div>\n <div class=\"ion-diagnostics-buttons\">\n <button id=\"ion-diagnostic-close\">Close</button>\n </div>\n </div>\n </div>\n ");
|
156 | c.push("<div class=\"ion-diagnostics-content\">");
|
157 | if (includeDiagnosticsHtml) {
|
158 | c.push(includeDiagnosticsHtml);
|
159 | }
|
160 | loadBuildDiagnosticsHtml(buildDir);
|
161 | var keys = Object.keys(diagnosticsHtmlCache);
|
162 | for (var i = 0; i < keys.length; i++) {
|
163 | if (typeof diagnosticsHtmlCache[keys[i]] === 'string') {
|
164 | c.push(diagnosticsHtmlCache[keys[i]]);
|
165 | }
|
166 | }
|
167 | c.push("</div>");
|
168 | return c.join('\n');
|
169 | }
|
170 | exports.getDiagnosticsHtmlContent = getDiagnosticsHtmlContent;
|
171 | function generateDiagnosticHtml(d) {
|
172 | var c = [];
|
173 | c.push("<div class=\"ion-diagnostic\">");
|
174 | c.push("<div class=\"ion-diagnostic-masthead\" title=\"" + helpers_1.escapeHtml(d.type) + " error: " + helpers_1.escapeHtml(d.code) + "\">");
|
175 | var title = helpers_1.titleCase(d.type) + " " + helpers_1.titleCase(d.level);
|
176 | c.push("<div class=\"ion-diagnostic-title\">" + helpers_1.escapeHtml(title) + "</div>");
|
177 | c.push("<div class=\"ion-diagnostic-message\" data-error-code=\"" + helpers_1.escapeHtml(d.type) + "-" + helpers_1.escapeHtml(d.code) + "\">" + helpers_1.escapeHtml(d.messageText) + "</div>");
|
178 | c.push("</div>");
|
179 | c.push(generateCodeBlock(d));
|
180 | c.push("</div>");
|
181 | return c.join('\n');
|
182 | }
|
183 | exports.generateDiagnosticHtml = generateDiagnosticHtml;
|
184 | function generateCodeBlock(d) {
|
185 | var c = [];
|
186 | c.push("<div class=\"ion-diagnostic-file\">");
|
187 | c.push("<div class=\"ion-diagnostic-file-header\" title=\"" + helpers_1.escapeHtml(d.absFileName) + "\">" + helpers_1.escapeHtml(d.relFileName) + "</div>");
|
188 | if (d.lines && d.lines.length) {
|
189 | c.push("<div class=\"ion-diagnostic-blob\">");
|
190 | c.push("<table class=\"ion-diagnostic-table\">");
|
191 | prepareLines(d.lines, 'html').forEach(function (l) {
|
192 | c.push("<tr" + ((l.errorCharStart > -1) ? ' class="ion-diagnostic-error-line"' : '') + ">");
|
193 | c.push("<td class=\"ion-diagnostic-blob-num\" data-line-number=\"" + l.lineNumber + "\"></td>");
|
194 | c.push("<td class=\"ion-diagnostic-blob-code\">" + highlight_1.highlightError(l.html, l.errorCharStart, l.errorLength) + "</td>");
|
195 | c.push("</tr>");
|
196 | });
|
197 | c.push("</table>");
|
198 | c.push("</div>");
|
199 | }
|
200 | c.push("</div>");
|
201 | return c.join('\n');
|
202 | }
|
203 | exports.generateCodeBlock = generateCodeBlock;
|
204 | function jsConsoleSyntaxHighlight(text) {
|
205 | if (text.trim().startsWith('//')) {
|
206 | return chalk.dim(text);
|
207 | }
|
208 | var words = text.split(' ').map(function (word) {
|
209 | if (JS_KEYWORDS.indexOf(word) > -1) {
|
210 | return chalk.cyan(word);
|
211 | }
|
212 | return word;
|
213 | });
|
214 | return words.join(' ');
|
215 | }
|
216 | function cssConsoleSyntaxHighlight(text, errorCharStart) {
|
217 | var cssProp = true;
|
218 | var safeChars = 'abcdefghijklmnopqrstuvwxyz-_';
|
219 | var notProp = '.#,:}@$[]/*';
|
220 | var chars = [];
|
221 | for (var i = 0; i < text.length; i++) {
|
222 | var c = text.charAt(i);
|
223 | if (c === ';' || c === '{') {
|
224 | cssProp = true;
|
225 | }
|
226 | else if (notProp.indexOf(c) > -1) {
|
227 | cssProp = false;
|
228 | }
|
229 | if (cssProp && safeChars.indexOf(c.toLowerCase()) > -1) {
|
230 | chars.push(chalk.cyan(c));
|
231 | continue;
|
232 | }
|
233 | chars.push(c);
|
234 | }
|
235 | return chars.join('');
|
236 | }
|
237 | function prepareLines(orgLines, code) {
|
238 | var lines = JSON.parse(JSON.stringify(orgLines));
|
239 | for (var i = 0; i < 100; i++) {
|
240 | if (!eachLineHasLeadingWhitespace(lines, code)) {
|
241 | return lines;
|
242 | }
|
243 | for (var i_1 = 0; i_1 < lines.length; i_1++) {
|
244 | lines[i_1][code] = lines[i_1][code].substr(1);
|
245 | lines[i_1].errorCharStart--;
|
246 | if (!lines[i_1][code].length) {
|
247 | return lines;
|
248 | }
|
249 | }
|
250 | }
|
251 | return lines;
|
252 | }
|
253 | function eachLineHasLeadingWhitespace(lines, code) {
|
254 | if (!lines.length) {
|
255 | return false;
|
256 | }
|
257 | for (var i = 0; i < lines.length; i++) {
|
258 | if (!lines[i][code] || lines[i][code].length < 1) {
|
259 | return false;
|
260 | }
|
261 | var firstChar = lines[i][code].charAt(0);
|
262 | if (firstChar !== ' ' && firstChar !== '\t') {
|
263 | return false;
|
264 | }
|
265 | }
|
266 | return true;
|
267 | }
|
268 | var JS_KEYWORDS = [
|
269 | 'abstract', 'any', 'as', 'break', 'boolean', 'case', 'catch', 'class',
|
270 | 'console', 'const', 'continue', 'debugger', 'declare', 'default', 'delete',
|
271 | 'do', 'else', 'enum', 'export', 'extends', 'false', 'finally', 'for', 'from',
|
272 | 'function', 'get', 'if', 'import', 'in', 'implements', 'Infinity',
|
273 | 'instanceof', 'let', 'module', 'namespace', 'NaN', 'new', 'number', 'null',
|
274 | 'public', 'private', 'protected', 'require', 'return', 'static', 'set',
|
275 | 'string', 'super', 'switch', 'this', 'throw', 'try', 'true', 'type',
|
276 | 'typeof', 'undefined', 'var', 'void', 'with', 'while', 'yield',
|
277 | ];
|
278 | function getDiagnosticsFileName(buildDir, type) {
|
279 | return path_1.join(buildDir, ".ion-diagnostic-" + type + ".html");
|
280 | }
|
281 | function isMeaningfulLine(line) {
|
282 | if (line) {
|
283 | line = line.trim();
|
284 | if (line.length) {
|
285 | return (MEH_LINES.indexOf(line) < 0);
|
286 | }
|
287 | }
|
288 | return false;
|
289 | }
|
290 | var MEH_LINES = [';', ':', '{', '}', '(', ')', '/**', '/*', '*/', '*', '({', '})'];
|
291 | exports.DiagnosticsType = {
|
292 | TypeScript: 'typescript',
|
293 | Sass: 'sass',
|
294 | TsLint: 'tslint'
|
295 | };
|