mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
Formatted alerts (#35)
This commit is contained in:
parent
b0680836d4
commit
831e5e903e
@ -39,7 +39,9 @@ void main(List<String> args) {
|
||||
request.style == InboundMessage_CompileRequest_OutputStyle.COMPRESSED
|
||||
? sass.OutputStyle.compressed
|
||||
: sass.OutputStyle.expanded;
|
||||
var logger = Logger(dispatcher, request.id);
|
||||
var color = request.alertColor ?? false;
|
||||
var ascii = request.alertAscii ?? false;
|
||||
var logger = Logger(dispatcher, request.id, color: color, ascii: ascii);
|
||||
|
||||
try {
|
||||
String result;
|
||||
@ -59,6 +61,7 @@ void main(List<String> args) {
|
||||
case InboundMessage_CompileRequest_Input.string:
|
||||
var input = request.string;
|
||||
result = sass.compileString(input.source,
|
||||
color: color,
|
||||
logger: logger,
|
||||
importers: importers,
|
||||
importer: _decodeImporter(dispatcher, request, input.importer),
|
||||
@ -72,6 +75,7 @@ void main(List<String> args) {
|
||||
case InboundMessage_CompileRequest_Input.path:
|
||||
try {
|
||||
result = sass.compile(request.path,
|
||||
color: color,
|
||||
logger: logger,
|
||||
importers: importers,
|
||||
functions: globalFunctions,
|
||||
@ -97,11 +101,14 @@ void main(List<String> args) {
|
||||
}
|
||||
return OutboundMessage_CompileResponse()..success = success;
|
||||
} on sass.SassException catch (error) {
|
||||
var formatted = withGlyphs(() => error.toString(color: color),
|
||||
ascii: request.alertAscii);
|
||||
return OutboundMessage_CompileResponse()
|
||||
..failure = (OutboundMessage_CompileResponse_CompileFailure()
|
||||
..message = error.message
|
||||
..span = protofySpan(error.span)
|
||||
..stackTrace = error.trace.toString());
|
||||
..stackTrace = error.trace.toString()
|
||||
..formatted = formatted);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// MIT-style license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:sass/sass.dart' as sass;
|
||||
import 'package:source_span/source_span.dart';
|
||||
import 'package:stack_trace/stack_trace.dart';
|
||||
@ -18,24 +19,65 @@ class Logger implements sass.Logger {
|
||||
/// The ID of the compilation to which this logger is passed.
|
||||
final int _compilationId;
|
||||
|
||||
Logger(this._dispatcher, this._compilationId);
|
||||
/// Whether the formatted message should contain terminal colors.
|
||||
final bool _color;
|
||||
|
||||
/// Whether the formatted message should use ASCII encoding.
|
||||
final bool _ascii;
|
||||
|
||||
Logger(this._dispatcher, this._compilationId,
|
||||
{bool color = false, bool ascii = false})
|
||||
: _color = color,
|
||||
_ascii = ascii;
|
||||
|
||||
void debug(String message, SourceSpan span) {
|
||||
var url =
|
||||
span.start.sourceUrl == null ? '-' : p.prettyUri(span.start.sourceUrl);
|
||||
var buffer = StringBuffer()
|
||||
..write('$url:${span.start.line + 1} ')
|
||||
..write(_color ? '\u001b[1mDebug\u001b[0m' : 'DEBUG')
|
||||
..writeln(': $message');
|
||||
|
||||
_dispatcher.sendLog(OutboundMessage_LogEvent()
|
||||
..compilationId = _compilationId
|
||||
..type = OutboundMessage_LogEvent_Type.DEBUG
|
||||
..message = message
|
||||
..span = protofySpan(span));
|
||||
..span = protofySpan(span)
|
||||
..formatted = buffer.toString());
|
||||
}
|
||||
|
||||
void warn(String message,
|
||||
{FileSpan span, Trace trace, bool deprecation = false}) {
|
||||
var formatted = withGlyphs(() {
|
||||
var buffer = new StringBuffer();
|
||||
if (_color) {
|
||||
buffer.write('\u001b[33m\u001b[1m');
|
||||
if (deprecation) buffer.write('Deprecation ');
|
||||
buffer.write('Warning\u001b[0m');
|
||||
} else {
|
||||
if (deprecation) buffer.write('DEPRECATION ');
|
||||
buffer.write('WARNING');
|
||||
}
|
||||
if (span == null) {
|
||||
buffer.writeln(': $message');
|
||||
} else if (trace != null) {
|
||||
buffer.writeln(': $message\n\n${span.highlight(color: _color)}');
|
||||
} else {
|
||||
buffer.writeln(' on ${span.message("\n" + message, color: _color)}');
|
||||
}
|
||||
if (trace != null) {
|
||||
buffer.writeln(indent(trace.toString().trimRight(), 4));
|
||||
}
|
||||
return buffer.toString();
|
||||
}, ascii: _ascii);
|
||||
|
||||
var event = OutboundMessage_LogEvent()
|
||||
..compilationId = _compilationId
|
||||
..type = deprecation
|
||||
? OutboundMessage_LogEvent_Type.DEPRECATION_WARNING
|
||||
: OutboundMessage_LogEvent_Type.WARNING
|
||||
..message = message;
|
||||
..message = message
|
||||
..formatted = formatted;
|
||||
if (span != null) event.span = protofySpan(span);
|
||||
if (trace != null) event.stackTrace = trace.toString();
|
||||
_dispatcher.sendLog(event);
|
||||
|
@ -2,8 +2,10 @@
|
||||
// MIT-style license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:sass/sass.dart' as sass;
|
||||
import 'package:source_span/source_span.dart';
|
||||
import 'package:term_glyph/term_glyph.dart' as term_glyph;
|
||||
|
||||
import 'embedded_sass.pb.dart' as proto;
|
||||
import 'embedded_sass.pb.dart' hide SourceSpan;
|
||||
@ -57,3 +59,17 @@ sass.Syntax syntaxToSyntax(InboundMessage_Syntax syntax) {
|
||||
throw "Unknown syntax $syntax.";
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [string] with every line indented [indentation] spaces.
|
||||
String indent(String string, int indentation) =>
|
||||
string.split("\n").map((line) => (" " * indentation) + line).join("\n");
|
||||
|
||||
/// Returns the result of running [callback] with the global ASCII config set
|
||||
/// to [ascii].
|
||||
T withGlyphs<T>(T callback(), {@required bool ascii}) {
|
||||
var currentConfig = term_glyph.ascii;
|
||||
term_glyph.ascii = ascii;
|
||||
var result = callback();
|
||||
term_glyph.ascii = currentConfig;
|
||||
return result;
|
||||
}
|
||||
|
@ -97,22 +97,6 @@ void main() {
|
||||
await expectLater(process.outbound, emits(isSuccess(equals("a{b:3px}"))));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("expanded mode when nested mode is passed", () async {
|
||||
process.inbound.add(compileString("a {b: 1px + 2px}",
|
||||
style: InboundMessage_CompileRequest_OutputStyle.NESTED));
|
||||
await expectLater(
|
||||
process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}"))));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("expanded mode when compact mode is passed", () async {
|
||||
process.inbound.add(compileString("a {b: 1px + 2px}",
|
||||
style: InboundMessage_CompileRequest_OutputStyle.COMPACT));
|
||||
await expectLater(
|
||||
process.outbound, emits(isSuccess(equals("a {\n b: 3px;\n}"))));
|
||||
await process.kill();
|
||||
});
|
||||
});
|
||||
|
||||
test("doesn't include a source map by default", () async {
|
||||
@ -145,7 +129,8 @@ void main() {
|
||||
});
|
||||
|
||||
group("emits a log event", () {
|
||||
test("for a @debug rule", () async {
|
||||
group("for a @debug rule", () {
|
||||
test("with correct fields", () async {
|
||||
process.inbound.add(compileString("a {@debug hello}"));
|
||||
|
||||
var logEvent = getLogEvent(await process.outbound.next);
|
||||
@ -157,10 +142,22 @@ void main() {
|
||||
expect(logEvent.span.end, equals(location(15, 0, 15)));
|
||||
expect(logEvent.span.context, equals("a {@debug hello}"));
|
||||
expect(logEvent.stackTrace, isEmpty);
|
||||
expect(logEvent.formatted, equals('-:1 DEBUG: hello\n'));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("for a @warn rule", () async {
|
||||
test("formatted with terminal colors", () async {
|
||||
process.inbound
|
||||
.add(compileString("a {@debug hello}", alertColor: true));
|
||||
var logEvent = getLogEvent(await process.outbound.next);
|
||||
expect(
|
||||
logEvent.formatted, equals('-:1 \u001b[1mDebug\u001b[0m: hello\n'));
|
||||
await process.kill();
|
||||
});
|
||||
});
|
||||
|
||||
group("for a @warn rule", () {
|
||||
test("with correct fields", () async {
|
||||
process.inbound.add(compileString("a {@warn hello}"));
|
||||
|
||||
var logEvent = getLogEvent(await process.outbound.next);
|
||||
@ -169,9 +166,39 @@ void main() {
|
||||
expect(logEvent.message, equals("hello"));
|
||||
expect(logEvent.span, equals(SourceSpan()));
|
||||
expect(logEvent.stackTrace, equals("- 1:4 root stylesheet\n"));
|
||||
expect(
|
||||
logEvent.formatted,
|
||||
equals('WARNING: hello\n'
|
||||
' - 1:4 root stylesheet\n'));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("formatted with terminal colors", () async {
|
||||
process.inbound.add(compileString("a {@warn hello}", alertColor: true));
|
||||
var logEvent = getLogEvent(await process.outbound.next);
|
||||
expect(
|
||||
logEvent.formatted,
|
||||
equals('\x1B[33m\x1B[1mWarning\x1B[0m: hello\n'
|
||||
' - 1:4 root stylesheet\n'));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("encoded in ASCII", () async {
|
||||
process.inbound
|
||||
.add(compileString("a {@debug a && b}", alertAscii: true));
|
||||
var logEvent = getLogEvent(await process.outbound.next);
|
||||
expect(
|
||||
logEvent.formatted,
|
||||
equals('WARNING on line 1, column 13: \n'
|
||||
'In Sass, "&&" means two copies of the parent selector. You probably want to use "and" instead.\n'
|
||||
' ,\n'
|
||||
'1 | a {@debug a && b}\n'
|
||||
' | ^^\n'
|
||||
' \'\n'));
|
||||
await process.kill();
|
||||
});
|
||||
});
|
||||
|
||||
test("for a parse-time deprecation warning", () async {
|
||||
process.inbound.add(compileString("@if true {} @elseif true {}"));
|
||||
|
||||
@ -343,5 +370,54 @@ a {
|
||||
expect(failure.stackTrace, equals("- 1:11 root stylesheet\n"));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
group("and provides a formatted", () {
|
||||
test("message", () async {
|
||||
process.inbound.add(compileString("a {b: 1px + 1em}"));
|
||||
|
||||
var failure = getCompileFailure(await process.outbound.next);
|
||||
expect(
|
||||
failure.formatted,
|
||||
equals('Error: 1px and 1em have incompatible units.\n'
|
||||
' ╷\n'
|
||||
'1 │ a {b: 1px + 1em}\n'
|
||||
' │ ^^^^^^^^^\n'
|
||||
' ╵\n'
|
||||
' - 1:7 root stylesheet'));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("message with terminal colors", () async {
|
||||
process.inbound
|
||||
.add(compileString("a {b: 1px + 1em}", alertColor: true));
|
||||
|
||||
var failure = getCompileFailure(await process.outbound.next);
|
||||
expect(
|
||||
failure.formatted,
|
||||
equals('Error: 1px and 1em have incompatible units.\n'
|
||||
'\x1B[34m ╷\x1B[0m\n'
|
||||
'\x1B[34m1 │\x1B[0m a {b: \x1B[31m1px + 1em\x1B[0m}\n'
|
||||
'\x1B[34m │\x1B[0m \x1B[31m ^^^^^^^^^\x1B[0m\n'
|
||||
'\x1B[34m ╵\x1B[0m\n'
|
||||
' - 1:7 root stylesheet'));
|
||||
await process.kill();
|
||||
});
|
||||
|
||||
test("message with ASCII encoding", () async {
|
||||
process.inbound
|
||||
.add(compileString("a {b: 1px + 1em}", alertAscii: true));
|
||||
|
||||
var failure = getCompileFailure(await process.outbound.next);
|
||||
expect(
|
||||
failure.formatted,
|
||||
equals('Error: 1px and 1em have incompatible units.\n'
|
||||
' ,\n'
|
||||
'1 | a {b: 1px + 1em}\n'
|
||||
' | ^^^^^^^^^\n'
|
||||
' \'\n'
|
||||
' - 1:7 root stylesheet'));
|
||||
await process.kill();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import 'embedded_process.dart';
|
||||
/// string.
|
||||
InboundMessage compileString(String css,
|
||||
{int id,
|
||||
bool alertColor,
|
||||
bool alertAscii,
|
||||
InboundMessage_Syntax syntax,
|
||||
InboundMessage_CompileRequest_OutputStyle style,
|
||||
String url,
|
||||
@ -32,6 +34,8 @@ InboundMessage compileString(String css,
|
||||
if (style != null) request.style = style;
|
||||
if (sourceMap != null) request.sourceMap = sourceMap;
|
||||
if (functions != null) request.globalFunctions.addAll(functions);
|
||||
if (alertColor != null) request.alertColor = alertColor;
|
||||
if (alertAscii != null) request.alertAscii = alertAscii;
|
||||
|
||||
return InboundMessage()..compileRequest = request;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user