Skip to content
This repository was archived by the owner on May 1, 2020. It is now read-only.

Commit 433150b

Browse files
committed
feat(logger): pretty print sass diagnostics
1 parent 5407ec3 commit 433150b

File tree

5 files changed

+214
-59
lines changed

5 files changed

+214
-59
lines changed

src/sass.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { emit, EventType } from './util/events';
55
import { ensureDirSync, readdirSync, writeFile } from 'fs-extra';
66
import { fillConfigDefaults, generateContext, getUserConfigFile, replacePathVars } from './util/config';
77
import { getModulePathsCache } from './util/helpers';
8+
import { runDiagnostics } from './util/logger-sass';
89
import { SassError, render as nodeSassRender, Result } from 'node-sass';
910
import * as postcss from 'postcss';
1011
import * as autoprefixer from 'autoprefixer';
@@ -245,30 +246,14 @@ function render(context: BuildContext, sassConfig: SassConfig) {
245246
sassConfig.sourceMapContents = true;
246247
}
247248

248-
nodeSassRender(sassConfig, (renderErr: SassError, sassResult: Result) => {
249-
if (renderErr) {
250-
// sass render error!
251-
if (renderErr.file) {
252-
let sassFile: string = renderErr.file;
253-
sassFile = sassFile.replace(context.rootDir, '');
254-
if (/\/|\\/.test(sassFile.charAt(0))) {
255-
sassFile = sassFile.substr(1);
256-
}
257-
if (sassFile.length > 80) {
258-
sassFile = '...' + sassFile.substr(sassFile.length - 80);
259-
}
260-
Logger.error(`sass: ${sassFile}, line: ${renderErr.line}`);
261-
Logger.log(renderErr.message);
262-
console.log(''); // just for a new line
263-
264-
} else {
265-
Logger.error(`sass error: ${renderErr}`);
266-
}
267-
268-
reject();
249+
nodeSassRender(sassConfig, (sassError: SassError, sassResult: Result) => {
250+
const hasDiagnostics = runDiagnostics(context, sassError);
251+
if (hasDiagnostics) {
252+
// sass render error :(
253+
reject(new BuildError());
269254

270255
} else {
271-
// sass render success!
256+
// sass render success :)
272257
renderSassSuccess(context, sassResult, sassConfig).then(() => {
273258
lastRenderKey = getRenderCacheKey(sassConfig);
274259
resolve();

src/util/logger-sass.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { BuildContext } from './interfaces';
2+
import { Diagnostic, Logger, PrintLine } from './logger';
3+
import { objectAssign } from './helpers';
4+
import { SassError } from 'node-sass';
5+
import { readFileSync } from 'fs';
6+
7+
8+
export function runDiagnostics(context: BuildContext, sassError: SassError) {
9+
const d = loadDiagnostic(context, sassError);
10+
11+
if (d) {
12+
Logger.printDiagnostic(objectAssign({}, d));
13+
return true;
14+
}
15+
16+
return false;
17+
}
18+
19+
20+
function loadDiagnostic(context: BuildContext, sassError: SassError) {
21+
if (!sassError) {
22+
return null;
23+
}
24+
25+
const d: Diagnostic = {
26+
level: 'error',
27+
syntax: 'css',
28+
type: 'sass',
29+
header: 'sass error',
30+
code: sassError.status && sassError.status.toString(),
31+
fileName: null,
32+
messageText: sassError.message,
33+
lines: []
34+
};
35+
36+
if (sassError.file) {
37+
d.fileName = Logger.formatFileName(context.rootDir, sassError.file);
38+
d.header = Logger.formatHeader('sass', sassError.file, context.rootDir, sassError.line);
39+
40+
if (sassError.line > -1) {
41+
try {
42+
const srcLines = readFileSync(sassError.file, 'utf8').replace(/\\r/g, '\n').split('\n');
43+
44+
const errorLine: PrintLine = {
45+
lineIndex: sassError.line - 1,
46+
lineNumber: sassError.line,
47+
text: srcLines[sassError.line - 1],
48+
errorCharStart: sassError.column,
49+
errorLength: 0
50+
};
51+
52+
for (var i = errorLine.errorCharStart; i >= 0; i--) {
53+
if (STOP_CHARS.indexOf(errorLine.text.charAt(i)) > -1) {
54+
break;
55+
}
56+
errorLine.errorCharStart = i;
57+
}
58+
59+
for (var i = errorLine.errorCharStart; i <= errorLine.text.length; i++) {
60+
if (STOP_CHARS.indexOf(errorLine.text.charAt(i)) > -1) {
61+
break;
62+
}
63+
errorLine.errorLength++;
64+
}
65+
66+
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
67+
errorLine.errorLength = 1;
68+
errorLine.errorCharStart--;
69+
}
70+
71+
d.lines.push(errorLine);
72+
73+
if (errorLine.lineIndex > 0 && Logger.meaningfulLine(srcLines[errorLine.lineIndex - 1])) {
74+
const previousLine: PrintLine = {
75+
lineIndex: errorLine.lineIndex - 1,
76+
lineNumber: errorLine.lineNumber - 1,
77+
text: srcLines[errorLine.lineIndex - 1],
78+
errorCharStart: -1,
79+
errorLength: -1
80+
};
81+
d.lines.unshift(previousLine);
82+
}
83+
84+
if (errorLine.lineIndex + 1 < srcLines.length && Logger.meaningfulLine(srcLines[errorLine.lineIndex + 1])) {
85+
const nextLine: PrintLine = {
86+
lineIndex: errorLine.lineIndex + 1,
87+
lineNumber: errorLine.lineNumber + 1,
88+
text: srcLines[errorLine.lineIndex + 1],
89+
errorCharStart: -1,
90+
errorLength: -1
91+
};
92+
d.lines.push(nextLine);
93+
}
94+
95+
} catch (e) {
96+
Logger.debug(`sass loadDiagnostic, ${e}`);
97+
}
98+
}
99+
100+
}
101+
102+
return d;
103+
}
104+
105+
const STOP_CHARS = ['', '\n', '\r', '\t', ' ', ':', ';', ',', '{', '}', '.', '#', '@', '!', '[', ']', '(', ')', '&', '+', '~', '^', '*', '$'];

src/util/logger-tslint.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function runDiagnostics(context: BuildContext, failures: RuleFailure[]) {
1010

1111
if (diagnostics.length) {
1212
diagnostics.forEach(d => {
13-
Logger.printDiagnostic(objectAssign({}, d), 'warn');
13+
Logger.printDiagnostic(objectAssign({}, d));
1414
});
1515
return true;
1616
}
@@ -24,11 +24,14 @@ function loadDiagnostic(context: BuildContext, f: RuleFailure) {
2424
const end: RuleFailurePosition = f.endPosition.toJson();
2525

2626
const d: Diagnostic = {
27+
level: 'warn',
28+
syntax: 'js',
2729
type: 'tslint',
30+
fileName: Logger.formatFileName(context.rootDir, f.fileName),
2831
header: Logger.formatHeader('tslint', f.fileName, context.rootDir, start.line + 1, end.line + 1),
2932
code: f.ruleName,
3033
messageText: f.failure,
31-
printLines: []
34+
lines: []
3235
};
3336

3437
if (f.sourceFile && f.sourceFile.text) {
@@ -49,7 +52,13 @@ function loadDiagnostic(context: BuildContext, f: RuleFailure) {
4952
}
5053
errorLine.errorLength++;
5154
}
52-
d.printLines.push(errorLine);
55+
56+
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
57+
errorLine.errorLength = 1;
58+
errorLine.errorCharStart--;
59+
}
60+
61+
d.lines.push(errorLine);
5362
}
5463
}
5564

@@ -61,7 +70,7 @@ function loadDiagnostic(context: BuildContext, f: RuleFailure) {
6170
errorCharStart: -1,
6271
errorLength: -1
6372
};
64-
d.printLines.unshift(beforeLine);
73+
d.lines.unshift(beforeLine);
6574
}
6675

6776
if (end.line < srcLines.length && Logger.meaningfulLine(srcLines[end.line + 1])) {
@@ -72,7 +81,7 @@ function loadDiagnostic(context: BuildContext, f: RuleFailure) {
7281
errorCharStart: -1,
7382
errorLength: -1
7483
};
75-
d.printLines.push(afterLine);
84+
d.lines.push(afterLine);
7685
}
7786
}
7887

src/util/logger-typescript.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function runDiagnostics(context: BuildContext, tsDiagnostics: ts.Diagnost
1616

1717
if (diagnostics.length > 0) {
1818
diagnostics.forEach(d => {
19-
Logger.printDiagnostic(objectAssign({}, d), 'error');
19+
Logger.printDiagnostic(objectAssign({}, d));
2020
});
2121
return true;
2222
}
@@ -27,15 +27,19 @@ export function runDiagnostics(context: BuildContext, tsDiagnostics: ts.Diagnost
2727

2828
function loadDiagnostic(context: BuildContext, tsDiagnostic: ts.Diagnostic) {
2929
const d: Diagnostic = {
30+
level: 'error',
31+
syntax: 'js',
3032
type: 'typescript',
3133
header: 'typescript error',
3234
code: tsDiagnostic.code.toString(),
3335
messageText: ts.flattenDiagnosticMessageText(tsDiagnostic.messageText, '\n'),
3436
fileName: null,
35-
printLines: []
37+
lines: []
3638
};
3739

3840
if (tsDiagnostic.file) {
41+
d.fileName = Logger.formatFileName(context.rootDir, tsDiagnostic.file.fileName);
42+
3943
const srcLines = tsDiagnostic.file.getText().replace(/\\r/g, '\n').split('\n');
4044
const posData = tsDiagnostic.file.getLineAndCharacterOfPosition(tsDiagnostic.start);
4145

@@ -46,30 +50,35 @@ function loadDiagnostic(context: BuildContext, tsDiagnostic: ts.Diagnostic) {
4650
errorCharStart: posData.character,
4751
errorLength: Math.max(tsDiagnostic.length, 1)
4852
};
49-
d.printLines.push(errorLine);
53+
d.lines.push(errorLine);
54+
55+
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
56+
errorLine.errorLength = 1;
57+
errorLine.errorCharStart--;
58+
}
5059

5160
d.header = Logger.formatHeader('typescript', tsDiagnostic.file.fileName, context.rootDir, errorLine.lineNumber);
5261

5362
if (errorLine.lineIndex > 0 && Logger.meaningfulLine(srcLines[errorLine.lineIndex - 1])) {
5463
const previousLine: PrintLine = {
5564
lineIndex: errorLine.lineIndex - 1,
56-
lineNumber: errorLine.lineIndex,
65+
lineNumber: errorLine.lineNumber - 1,
5766
text: srcLines[errorLine.lineIndex - 1],
5867
errorCharStart: -1,
5968
errorLength: -1
6069
};
61-
d.printLines.unshift(previousLine);
70+
d.lines.unshift(previousLine);
6271
}
6372

6473
if (errorLine.lineIndex + 1 < srcLines.length && Logger.meaningfulLine(srcLines[errorLine.lineIndex + 1])) {
6574
const nextLine: PrintLine = {
6675
lineIndex: errorLine.lineIndex + 1,
67-
lineNumber: errorLine.lineIndex + 2,
76+
lineNumber: errorLine.lineNumber + 1,
6877
text: srcLines[errorLine.lineIndex + 1],
6978
errorCharStart: -1,
7079
errorLength: -1
7180
};
72-
d.printLines.push(nextLine);
81+
d.lines.push(nextLine);
7382
}
7483
}
7584

0 commit comments

Comments
 (0)