// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'package:source_span/source_span.dart'; import 'preprocessor_options.dart'; enum MessageLevel { info, warning, severe } // TODO(#159): Remove the global messages, use some object that tracks // compilation state. /// The global [Messages] for tracking info/warnings/messages. late Messages messages; // Color constants used for generating messages. const _greenColor = '\u001b[32m'; const _redColor = '\u001b[31m'; const _magentaColor = '\u001b[35m'; const _noColor = '\u001b[0m'; /// Map between error levels and their display color. const Map _errorColors = { MessageLevel.severe: _redColor, MessageLevel.warning: _magentaColor, MessageLevel.info: _greenColor, }; /// Map between error levels and their friendly name. const Map _errorLabel = { MessageLevel.severe: 'error', MessageLevel.warning: 'warning', MessageLevel.info: 'info', }; /// A single message from the compiler. class Message { final MessageLevel level; final String message; final SourceSpan? span; final bool useColors; Message(this.level, this.message, {this.span, this.useColors = false}); String get describe { var span = this.span; if (span == null) { return message; } var start = span.start; return '${start.line + 1}:${start.column + 1}:$message'; } @override String toString() { var output = StringBuffer(); var colors = useColors && _errorColors.containsKey(level); var levelColor = colors ? _errorColors[level] : null; if (colors) output.write(levelColor); output ..write(_errorLabel[level]) ..write(' '); if (colors) output.write(_noColor); if (span == null) { output.write(message); } else { output.write('on '); output.write(span!.message(message, color: levelColor)); } return output.toString(); } } /// This class tracks and prints information, warnings, and errors emitted by /// the compiler. class Messages { /// Called on every error. Set to blank function to suppress printing. final void Function(Message obj) printHandler; final PreprocessorOptions options; final List messages = []; Messages({PreprocessorOptions? options, this.printHandler = print}) : options = options ?? const PreprocessorOptions(); /// Report a compile-time CSS error. void error(String message, SourceSpan? span) { var msg = Message(MessageLevel.severe, message, span: span, useColors: options.useColors); messages.add(msg); printHandler(msg); } /// Report a compile-time CSS warning. void warning(String message, SourceSpan? span) { if (options.warningsAsErrors) { error(message, span); } else { var msg = Message(MessageLevel.warning, message, span: span, useColors: options.useColors); messages.add(msg); } } /// Report and informational message about what the compiler is doing. void info(String message, SourceSpan span) { var msg = Message(MessageLevel.info, message, span: span, useColors: options.useColors); messages.add(msg); if (options.verbose) printHandler(msg); } /// Merge [newMessages] to this message list. void mergeMessages(Messages newMessages) { messages.addAll(newMessages.messages); newMessages.messages .where((message) => message.level == MessageLevel.severe || options.verbose) .forEach(printHandler); } }