Enable and fix a number of lints (#45)
- Disable implicit casts and fix errors.
- Enable lints that are used in other well maintained dart-lang repos.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 108d105..f28d5a1 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1 +1,92 @@
include: package:pedantic/analysis_options.yaml
+analyzer:
+ strong-mode:
+ implicit-casts: false
+linter:
+ rules:
+ - always_declare_return_types
+ - annotate_overrides
+ - avoid_bool_literals_in_conditional_expressions
+ - avoid_classes_with_only_static_members
+ - avoid_empty_else
+ - avoid_function_literals_in_foreach_calls
+ - avoid_init_to_null
+ - avoid_null_checks_in_equality_operators
+ - avoid_relative_lib_imports
+ - avoid_renaming_method_parameters
+ - avoid_return_types_on_setters
+ - avoid_returning_null
+ - avoid_returning_null_for_future
+ - avoid_returning_null_for_void
+ - avoid_returning_this
+ - avoid_shadowing_type_parameters
+ - avoid_single_cascade_in_expression_statements
+ - avoid_types_as_parameter_names
+ - avoid_unused_constructor_parameters
+ - await_only_futures
+ - camel_case_types
+ - cancel_subscriptions
+ - cascade_invocations
+ # Enable once https://github.com/dart-lang/sdk/issues/31761 is fixed
+ #- comment_references
+ - constant_identifier_names
+ - control_flow_in_finally
+ - directives_ordering
+ - empty_catches
+ - empty_constructor_bodies
+ - empty_statements
+ - file_names
+ - hash_and_equals
+ - implementation_imports
+ - invariant_booleans
+ - iterable_contains_unrelated_type
+ - library_names
+ - library_prefixes
+ - list_remove_unrelated_type
+ - no_adjacent_strings_in_list
+ - no_duplicate_case_values
+ - non_constant_identifier_names
+ - null_closures
+ - omit_local_variable_types
+ - only_throw_errors
+ - overridden_fields
+ - package_api_docs
+ - package_names
+ - package_prefixed_library_names
+ - prefer_adjacent_string_concatenation
+ - prefer_collection_literals
+ - prefer_conditional_assignment
+ - prefer_const_constructors
+ - prefer_contains
+ - prefer_equal_for_default_values
+ - prefer_final_fields
+ - prefer_final_locals
+ - prefer_generic_function_type_aliases
+ - prefer_initializing_formals
+ - prefer_interpolation_to_compose_strings
+ - prefer_is_empty
+ - prefer_is_not_empty
+ - prefer_null_aware_operators
+ #- prefer_single_quotes
+ - prefer_typing_uninitialized_variables
+ - recursive_getters
+ - slash_for_doc_comments
+ - test_types_in_equals
+ - throw_in_finally
+ - type_init_formals
+ - unawaited_futures
+ - unnecessary_await_in_return
+ - unnecessary_brace_in_string_interps
+ - unnecessary_const
+ - unnecessary_getters_setters
+ - unnecessary_lambdas
+ - unnecessary_new
+ - unnecessary_null_aware_assignments
+ - unnecessary_parenthesis
+ - unnecessary_statements
+ - unnecessary_this
+ - unrelated_type_equality_checks
+ - use_function_type_syntax_for_parameters
+ - use_rethrow_when_possible
+ - valid_regexps
+ - void_checks
diff --git a/lib/src/colors.dart b/lib/src/colors.dart
index 2931eea..b48d468 100644
--- a/lib/src/colors.dart
+++ b/lib/src/colors.dart
@@ -3,10 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
// Color constants used for generating messages.
-const String RED = '\u001b[31m';
+const String red = '\u001b[31m';
-const String YELLOW = '\u001b[33m';
+const String yellow = '\u001b[33m';
-const String BLUE = '\u001b[34m';
+const String blue = '\u001b[34m';
-const String NONE = '\u001b[0m';
+const String none = '\u001b[0m';
diff --git a/lib/src/file.dart b/lib/src/file.dart
index 44760c7..97a2f65 100644
--- a/lib/src/file.dart
+++ b/lib/src/file.dart
@@ -12,8 +12,8 @@
import 'span_with_context.dart';
// Constants to determine end-of-lines.
-const int _LF = 10;
-const int _CR = 13;
+const int _lf = 10;
+const int _cr = 13;
/// A class representing a source file.
///
@@ -71,28 +71,28 @@
/// forwards-compatibility, callers should only pass in characters less than
/// or equal to `0xFFFF`.
SourceFile.decoded(Iterable<int> decodedChars, {url})
- : url = url is String ? Uri.parse(url) : url,
+ : url = url is String ? Uri.parse(url) : url as Uri,
_decodedChars = Uint32List.fromList(decodedChars.toList()) {
for (var i = 0; i < _decodedChars.length; i++) {
var c = _decodedChars[i];
- if (c == _CR) {
+ if (c == _cr) {
// Return not followed by newline is treated as a newline
- var j = i + 1;
- if (j >= _decodedChars.length || _decodedChars[j] != _LF) c = _LF;
+ final j = i + 1;
+ if (j >= _decodedChars.length || _decodedChars[j] != _lf) c = _lf;
}
- if (c == _LF) _lineStarts.add(i + 1);
+ if (c == _lf) _lineStarts.add(i + 1);
}
}
- /// Returns a span in [this] from [start] to [end] (exclusive).
+ /// Returns a span from [start] to [end] (exclusive).
///
/// If [end] isn't passed, it defaults to the end of the file.
FileSpan span(int start, [int end]) {
- if (end == null) end = length;
+ end ??= length;
return _FileSpan(this, start, end);
}
- /// Returns a location in [this] at [offset].
+ /// Returns a location at [offset].
FileLocation location(int offset) => FileLocation._(this, offset);
/// Gets the 0-based line corresponding to [offset].
@@ -143,10 +143,10 @@
///
/// Returns the index of the line in [_lineStarts].
int _binarySearch(int offset) {
- int min = 0;
- int max = _lineStarts.length - 1;
+ var min = 0;
+ var max = _lineStarts.length - 1;
while (min < max) {
- var half = min + ((max - min) ~/ 2);
+ final half = min + ((max - min) ~/ 2);
if (_lineStarts[half] > offset) {
max = half;
} else {
@@ -178,7 +178,7 @@
"lines in the file, $lines.");
}
- var lineStart = _lineStarts[line];
+ final lineStart = _lineStarts[line];
if (lineStart > offset) {
throw RangeError("Line $line comes after offset $offset.");
}
@@ -190,7 +190,7 @@
///
/// [column] defaults to 0.
int getOffset(int line, [int column]) {
- if (column == null) column = 0;
+ column ??= 0;
if (line < 0) {
throw RangeError("Line may not be negative, was $line.");
@@ -201,7 +201,7 @@
throw RangeError("Column may not be negative, was $column.");
}
- var result = _lineStarts[line] + column;
+ final result = _lineStarts[line] + column;
if (result > length ||
(line + 1 < lines && result >= _lineStarts[line + 1])) {
throw RangeError("Line $line doesn't have $column columns.");
@@ -224,12 +224,19 @@
///
/// A [FileLocation] can be created using [SourceFile.location].
class FileLocation extends SourceLocationMixin implements SourceLocation {
- /// The [file] that [this] belongs to.
+ /// The [file] that `this` belongs to.
final SourceFile file;
+ @override
final int offset;
+
+ @override
Uri get sourceUrl => file.url;
+
+ @override
int get line => file.getLine(offset);
+
+ @override
int get column => file.getColumn(offset);
FileLocation._(this.file, this.offset) {
@@ -241,27 +248,31 @@
}
}
+ @override
FileSpan pointSpan() => _FileSpan(file, offset, offset);
}
/// A [SourceSpan] within a [SourceFile].
///
/// Unlike the base [SourceSpan], [FileSpan] lazily computes its line and column
-/// values based on its offset and the contents of [file]. [FileSpan.message] is
-/// also able to provide more context then [SourceSpan.message], and
-/// [FileSpan.union] will return a [FileSpan] if possible.
+/// values based on its offset and the contents of [file]. [SourceSpan.message]
+/// is also able to provide more context then [SourceSpan.message], and
+/// [SourceSpan.union] will return a [FileSpan] if possible.
///
/// A [FileSpan] can be created using [SourceFile.span].
abstract class FileSpan implements SourceSpanWithContext {
- /// The [file] that [this] belongs to.
+ /// The [file] that `this` belongs to.
SourceFile get file;
+ @override
FileLocation get start;
+
+ @override
FileLocation get end;
- /// Returns a new span that covers both [this] and [other].
+ /// Returns a new span that covers both `this` and [other].
///
- /// Unlike [union], [other] may be disjoint from [this]. If it is, the text
+ /// Unlike [union], [other] may be disjoint from `this`. If it is, the text
/// between the two will be covered by the returned span.
FileSpan expand(FileSpan other);
}
@@ -272,6 +283,7 @@
/// to make certain operations more efficient. If we used `is FileSpan`, that
/// would break if external classes implemented the interface.
class _FileSpan extends SourceSpanMixin implements FileSpan {
+ @override
final SourceFile file;
/// The offset of the beginning of the span.
@@ -286,15 +298,25 @@
/// objects.
final int _end;
+ @override
Uri get sourceUrl => file.url;
+
+ @override
int get length => _end - _start;
+
+ @override
FileLocation get start => FileLocation._(file, _start);
+
+ @override
FileLocation get end => FileLocation._(file, _end);
+
+ @override
String get text => file.getText(_start, _end);
+ @override
String get context {
- var endLine = file.getLine(_end);
- var endColumn = file.getColumn(_end);
+ final endLine = file.getLine(_end);
+ final endColumn = file.getColumn(_end);
int endOffset;
if (endColumn == 0 && endLine != 0) {
@@ -336,25 +358,27 @@
}
}
+ @override
int compareTo(SourceSpan other) {
if (other is! _FileSpan) return super.compareTo(other);
- _FileSpan otherFile = other;
- var result = _start.compareTo(otherFile._start);
+ final otherFile = other as _FileSpan;
+ final result = _start.compareTo(otherFile._start);
return result == 0 ? _end.compareTo(otherFile._end) : result;
}
+ @override
SourceSpan union(SourceSpan other) {
if (other is! FileSpan) return super.union(other);
- _FileSpan span = expand(other);
+ final span = expand(other as _FileSpan);
if (other is _FileSpan) {
- if (this._start > other._end || other._start > this._end) {
+ if (_start > other._end || other._start > _end) {
throw ArgumentError("Spans $this and $other are disjoint.");
}
} else {
- if (this._start > other.end.offset || other.start.offset > this._end) {
+ if (_start > other.end.offset || other.start.offset > _end) {
throw ArgumentError("Spans $this and $other are disjoint.");
}
}
@@ -362,6 +386,7 @@
return span;
}
+ @override
bool operator ==(other) {
if (other is! FileSpan) return super == other;
if (other is! _FileSpan) {
@@ -374,25 +399,27 @@
}
// Eliminates dart2js warning about overriding `==`, but not `hashCode`
+ @override
int get hashCode => super.hashCode;
- /// Returns a new span that covers both [this] and [other].
+ /// Returns a new span that covers both `this` and [other].
///
- /// Unlike [union], [other] may be disjoint from [this]. If it is, the text
+ /// Unlike [union], [other] may be disjoint from `this`. If it is, the text
/// between the two will be covered by the returned span.
+ @override
FileSpan expand(FileSpan other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
" \"${other.sourceUrl}\" don't match.");
}
if (other is _FileSpan) {
- var start = math.min(this._start, other._start);
- var end = math.max(this._end, other._end);
+ final start = math.min(_start, other._start);
+ final end = math.max(_end, other._end);
return _FileSpan(file, start, end);
} else {
- var start = math.min(this._start, other.start.offset);
- var end = math.max(this._end, other.end.offset);
+ final start = math.min(_start, other.start.offset);
+ final end = math.max(_end, other.end.offset);
return _FileSpan(file, start, end);
}
}
diff --git a/lib/src/highlighter.dart b/lib/src/highlighter.dart
index f68e52a..94bc857 100644
--- a/lib/src/highlighter.dart
+++ b/lib/src/highlighter.dart
@@ -44,8 +44,8 @@
/// alignment.
static const _spacesPerTab = 4;
- /// Creats a [Highlighter] that will return a message associated with [span]
- /// when [write] is called.
+ /// Creates a [Highlighter] that will return a message associated with [span]
+ /// when [highlight] is called.
///
/// [color] may either be a [String], a [bool], or `null`. If it's a string,
/// it indicates an [ANSI terminal color
@@ -55,7 +55,7 @@
/// highlighted using the default color. If it's `false` or `null`, it
/// indicates that the text shouldn't be highlighted.
factory Highlighter(SourceSpan span, {color}) {
- if (color == true) color = colors.RED;
+ if (color == true) color = colors.red;
if (color == false) color = null;
var newSpan = _normalizeContext(span);
@@ -63,7 +63,7 @@
newSpan = _normalizeTrailingNewline(newSpan);
newSpan = _normalizeEndOfLine(newSpan);
- return Highlighter._(newSpan, color);
+ return Highlighter._(newSpan, color as String);
}
/// Normalizes [span] to ensure that it's a [SourceSpanWithContext] whose
@@ -89,7 +89,7 @@
/// Normalizes [span] to replace Windows-style newlines with Unix-style
/// newlines.
static SourceSpanWithContext _normalizeNewlines(SourceSpanWithContext span) {
- var text = span.text;
+ final text = span.text;
if (!text.contains("\r\n")) return span;
var endOffset = span.end.offset;
@@ -121,7 +121,7 @@
// significant, so we shouldn't trim it.
if (span.text.endsWith("\n\n")) return span;
- var context = span.context.substring(0, span.context.length - 1);
+ final context = span.context.substring(0, span.context.length - 1);
var text = span.text;
var start = span.start;
var end = span.end;
@@ -142,7 +142,7 @@
if (span.end.column != 0) return span;
if (span.end.line == span.start.line) return span;
- var text = span.text.substring(0, span.text.length - 1);
+ final text = span.text.substring(0, span.text.length - 1);
return SourceSpanWithContext(
span.start,
@@ -192,7 +192,7 @@
// If [_span.context] contains lines prior to the one [_span.text] appears
// on, write those first.
- var lineStart =
+ final lineStart =
findLineStart(_span.context, _span.text, _span.start.column);
assert(lineStart != null); // enforced by [_normalizeContext]
@@ -202,7 +202,7 @@
// [findLineStart] is guaranteed to return a position immediately after a
// newline. Including that newline would add an extra empty line to the
// end of [lines].
- var lines = context.substring(0, lineStart - 1).split("\n");
+ final lines = context.substring(0, lineStart - 1).split("\n");
var lineNumber = _span.start.line - lines.length;
for (var line in lines) {
_writeSidebar(line: lineNumber);
@@ -214,9 +214,9 @@
context = context.substring(lineStart);
}
- var lines = context.split("\n");
+ final lines = context.split("\n");
- var lastLineIndex = _span.end.line - _span.start.line;
+ final lastLineIndex = _span.end.line - _span.start.line;
if (lines.last.isEmpty && lines.length > lastLineIndex + 1) {
// Trim a trailing newline so we don't add an empty line to the end of the
// highlight.
@@ -242,15 +242,14 @@
var startColumn = math.min(_span.start.column, line.length);
var endColumn = math.min(
startColumn + _span.end.offset - _span.start.offset, line.length);
- var textBefore = line.substring(0, startColumn);
+ final textBefore = line.substring(0, startColumn);
// If the span covers the entire first line other than initial whitespace,
// don't bother pointing out exactly where it begins.
if (_multiline && _isOnlyWhitespace(textBefore)) {
_buffer.write(" ");
_colorize(() {
- _buffer.write(glyph.glyphOrAscii("┌", "/"));
- _buffer.write(" ");
+ _buffer..write(glyph.glyphOrAscii("┌", "/"))..write(" ");
_writeText(line);
});
_buffer.writeln();
@@ -259,15 +258,15 @@
_buffer.write(" " * _paddingAfterSidebar);
_writeText(textBefore);
- var textInside = line.substring(startColumn, endColumn);
+ final textInside = line.substring(startColumn, endColumn);
_colorize(() => _writeText(textInside));
_writeText(line.substring(endColumn));
_buffer.writeln();
// Adjust the start and end column to account for any tabs that were
// converted to spaces.
- var tabsBefore = _countTabs(textBefore);
- var tabsInside = _countTabs(textInside);
+ final tabsBefore = _countTabs(textBefore);
+ final tabsInside = _countTabs(textInside);
startColumn = startColumn + tabsBefore * (_spacesPerTab - 1);
endColumn = endColumn + (tabsBefore + tabsInside) * (_spacesPerTab - 1);
@@ -277,9 +276,10 @@
if (_multiline) {
_buffer.write(" ");
_colorize(() {
- _buffer.write(glyph.topLeftCorner);
- _buffer.write(glyph.horizontalLine * (startColumn + 1));
- _buffer.write("^");
+ _buffer
+ ..write(glyph.topLeftCorner)
+ ..write(glyph.horizontalLine * (startColumn + 1))
+ ..write("^");
});
} else {
_buffer.write(" " * (startColumn + 1));
@@ -300,8 +300,7 @@
_buffer.write(" ");
_colorize(() {
- _buffer.write(glyph.verticalLine);
- _buffer.write(" ");
+ _buffer..write(glyph.verticalLine)..write(" ");
_writeText(line);
});
_buffer.writeln();
@@ -323,8 +322,7 @@
if (_multiline && endColumn == line.length) {
_buffer.write(" ");
_colorize(() {
- _buffer.write(glyph.glyphOrAscii("└", "\\"));
- _buffer.write(" ");
+ _buffer..write(glyph.glyphOrAscii("└", "\\"))..write(" ");
_writeText(line);
});
_buffer.writeln();
@@ -332,10 +330,9 @@
}
_buffer.write(" ");
- var textInside = line.substring(0, endColumn);
+ final textInside = line.substring(0, endColumn);
_colorize(() {
- _buffer.write(glyph.verticalLine);
- _buffer.write(" ");
+ _buffer..write(glyph.verticalLine)..write(" ");
_writeText(textInside);
});
_writeText(line.substring(endColumn));
@@ -343,7 +340,7 @@
// Adjust the end column to account for any tabs that were converted to
// spaces.
- var tabsInside = _countTabs(textInside);
+ final tabsInside = _countTabs(textInside);
endColumn = endColumn + tabsInside * (_spacesPerTab - 1);
// Write the highlight for the final line, which is an arrow pointing to the
@@ -351,9 +348,10 @@
_writeSidebar();
_buffer.write(" ");
_colorize(() {
- _buffer.write(glyph.bottomLeftCorner);
- _buffer.write(glyph.horizontalLine * endColumn);
- _buffer.write("^");
+ _buffer
+ ..write(glyph.bottomLeftCorner)
+ ..write(glyph.horizontalLine * endColumn)
+ ..write("^");
});
_buffer.writeln();
}
@@ -395,7 +393,7 @@
_buffer.write(" " * _paddingBeforeSidebar);
}
_buffer.write(end ?? glyph.verticalLine);
- }, color: colors.BLUE);
+ }, color: colors.blue);
}
/// Returns the number of hard tabs in [text].
@@ -419,9 +417,9 @@
/// enabled.
///
/// If [color] is passed, it's used as the color; otherwise, [_color] is used.
- void _colorize(void callback(), {String color}) {
+ void _colorize(void Function() callback, {String color}) {
if (_color != null) _buffer.write(color ?? _color);
callback();
- if (_color != null) _buffer.write(colors.NONE);
+ if (_color != null) _buffer.write(colors.none);
}
}
diff --git a/lib/src/location.dart b/lib/src/location.dart
index a271880..c03c98c 100644
--- a/lib/src/location.dart
+++ b/lib/src/location.dart
@@ -32,7 +32,7 @@
///
/// This prints 1-based lines and columns.
String get toolString {
- var source = sourceUrl == null ? 'unknown source' : sourceUrl;
+ final source = sourceUrl == null ? 'unknown source' : sourceUrl;
return '$source:${line + 1}:${column + 1}';
}
@@ -42,9 +42,9 @@
/// means that [line] defaults to 0 and [column] defaults to [offset].
///
/// [sourceUrl] may be either a [String], a [Uri], or `null`.
- SourceLocation(int offset, {sourceUrl, int line, int column})
- : sourceUrl = sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl,
- offset = offset,
+ SourceLocation(this.offset, {sourceUrl, int line, int column})
+ : sourceUrl =
+ sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri,
line = line == null ? 0 : line,
column = column == null ? offset : column {
if (offset < 0) {
@@ -56,12 +56,12 @@
}
}
- /// Returns the distance in characters between [this] and [other].
+ /// Returns the distance in characters between `this` and [other].
///
/// This always returns a non-negative value.
int distance(SourceLocation other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
"\"${other.sourceUrl}\" don't match.");
}
return (offset - other.offset).abs();
@@ -72,22 +72,26 @@
/// Compares two locations.
///
- /// [other] must have the same source URL as [this].
+ /// [other] must have the same source URL as `this`.
+ @override
int compareTo(SourceLocation other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
"\"${other.sourceUrl}\" don't match.");
}
return offset - other.offset;
}
+ @override
bool operator ==(other) =>
other is SourceLocation &&
sourceUrl == other.sourceUrl &&
offset == other.offset;
+ @override
int get hashCode => sourceUrl.hashCode + offset;
+ @override
String toString() => '<$runtimeType: $offset $toolString>';
}
diff --git a/lib/src/location_mixin.dart b/lib/src/location_mixin.dart
index 7d34311..bd773ae 100644
--- a/lib/src/location_mixin.dart
+++ b/lib/src/location_mixin.dart
@@ -14,35 +14,42 @@
/// A mixin for easily implementing [SourceLocation].
abstract class SourceLocationMixin implements SourceLocation {
+ @override
String get toolString {
- var source = sourceUrl == null ? 'unknown source' : sourceUrl;
+ final source = sourceUrl == null ? 'unknown source' : sourceUrl;
return '$source:${line + 1}:${column + 1}';
}
+ @override
int distance(SourceLocation other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
"\"${other.sourceUrl}\" don't match.");
}
return (offset - other.offset).abs();
}
+ @override
SourceSpan pointSpan() => SourceSpan(this, this, "");
+ @override
int compareTo(SourceLocation other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
"\"${other.sourceUrl}\" don't match.");
}
return offset - other.offset;
}
+ @override
bool operator ==(other) =>
other is SourceLocation &&
sourceUrl == other.sourceUrl &&
offset == other.offset;
+ @override
int get hashCode => sourceUrl.hashCode + offset;
+ @override
String toString() => '<$runtimeType: $offset $toolString>';
}
diff --git a/lib/src/span.dart b/lib/src/span.dart
index b32e1ff..87ce846 100644
--- a/lib/src/span.dart
+++ b/lib/src/span.dart
@@ -6,6 +6,7 @@
import 'location.dart';
import 'span_mixin.dart';
+import 'span_with_context.dart';
/// A class that describes a segment of source text.
abstract class SourceSpan implements Comparable<SourceSpan> {
@@ -35,16 +36,17 @@
factory SourceSpan(SourceLocation start, SourceLocation end, String text) =>
SourceSpanBase(start, end, text);
- /// Creates a new span that's the union of [this] and [other].
+ /// Creates a new span that's the union of `this` and [other].
///
/// The two spans must have the same source URL and may not be disjoint.
- /// [text] is computed by combining [this.text] and [other.text].
+ /// [text] is computed by combining `this.text` and `other.text`.
SourceSpan union(SourceSpan other);
/// Compares two spans.
///
- /// [other] must have the same source URL as [this]. This orders spans by
+ /// [other] must have the same source URL as `this`. This orders spans by
/// [start] then [length].
+ @override
int compareTo(SourceSpan other);
/// Formats [message] in a human-friendly way associated with this span.
@@ -85,8 +87,11 @@
/// A base class for source spans with [start], [end], and [text] known at
/// construction time.
class SourceSpanBase extends SourceSpanMixin {
+ @override
final SourceLocation start;
+ @override
final SourceLocation end;
+ @override
final String text;
SourceSpanBase(this.start, this.end, this.text) {
diff --git a/lib/src/span_exception.dart b/lib/src/span_exception.dart
index 6d3448b..2ce0f1a 100644
--- a/lib/src/span_exception.dart
+++ b/lib/src/span_exception.dart
@@ -20,16 +20,17 @@
SourceSpanException(this._message, this._span);
- /// Returns a string representation of [this].
+ /// Returns a string representation of `this`.
///
/// [color] may either be a [String], a [bool], or `null`. If it's a string,
- /// it indicates an ANSII terminal color escape that should be used to
+ /// it indicates an ANSI terminal color escape that should be used to
/// highlight the span's text. If it's `true`, it indicates that the text
/// should be highlighted using the default color. If it's `false` or `null`,
/// it indicates that the text shouldn't be highlighted.
+ @override
String toString({color}) {
if (span == null) return message;
- return "Error on " + span.message(message, color: color);
+ return "Error on ${span.message(message, color: color)}";
}
}
@@ -37,11 +38,12 @@
class SourceSpanFormatException extends SourceSpanException
implements FormatException {
// This is a getter so that subclasses can override it.
- dynamic get source => _source;
- final _source;
+ @override
+ final dynamic source;
- int get offset => span == null ? null : span.start.offset;
+ @override
+ int get offset => span?.start?.offset;
- SourceSpanFormatException(String message, SourceSpan span, [this._source])
+ SourceSpanFormatException(String message, SourceSpan span, [this.source])
: super(message, span);
}
diff --git a/lib/src/span_mixin.dart b/lib/src/span_mixin.dart
index 75ecb3d..8960611 100644
--- a/lib/src/span_mixin.dart
+++ b/lib/src/span_mixin.dart
@@ -16,58 +16,69 @@
/// [start] comes before [end], and that [text] has a number of characters equal
/// to the distance between [start] and [end].
abstract class SourceSpanMixin implements SourceSpan {
+ @override
Uri get sourceUrl => start.sourceUrl;
+
+ @override
int get length => end.offset - start.offset;
+ @override
int compareTo(SourceSpan other) {
- var result = start.compareTo(other.start);
+ final result = start.compareTo(other.start);
return result == 0 ? end.compareTo(other.end) : result;
}
+ @override
SourceSpan union(SourceSpan other) {
if (sourceUrl != other.sourceUrl) {
- throw ArgumentError("Source URLs \"${sourceUrl}\" and "
+ throw ArgumentError("Source URLs \"$sourceUrl\" and "
" \"${other.sourceUrl}\" don't match.");
}
- var start = min(this.start, other.start);
- var end = max(this.end, other.end);
- var beginSpan = start == this.start ? this : other;
- var endSpan = end == this.end ? this : other;
+ final start = min(this.start, other.start);
+ final end = max(this.end, other.end);
+ final beginSpan = start == this.start ? this : other;
+ final endSpan = end == this.end ? this : other;
if (beginSpan.end.compareTo(endSpan.start) < 0) {
throw ArgumentError("Spans $this and $other are disjoint.");
}
- var text = beginSpan.text +
+ final text = beginSpan.text +
endSpan.text.substring(beginSpan.end.distance(endSpan.start));
return SourceSpan(start, end, text);
}
+ @override
String message(String message, {color}) {
- var buffer = StringBuffer();
- buffer.write('line ${start.line + 1}, column ${start.column + 1}');
+ final buffer = StringBuffer()
+ ..write('line ${start.line + 1}, column ${start.column + 1}');
if (sourceUrl != null) buffer.write(' of ${p.prettyUri(sourceUrl)}');
buffer.write(': $message');
- var highlight = this.highlight(color: color);
+ final highlight = this.highlight(color: color);
if (highlight.isNotEmpty) {
- buffer.writeln();
- buffer.write(highlight);
+ buffer
+ ..writeln()
+ ..write(highlight);
}
return buffer.toString();
}
+ @override
String highlight({color}) {
- if (this is! SourceSpanWithContext && this.length == 0) return "";
+ if (this is! SourceSpanWithContext && length == 0) return "";
return Highlighter(this, color: color).highlight();
}
+ @override
bool operator ==(other) =>
other is SourceSpan && start == other.start && end == other.end;
+ @override
int get hashCode => start.hashCode + (31 * end.hashCode);
+ @override
String toString() => '<$runtimeType: from $start to $end "$text">';
}
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 228b240..33791de 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -4,12 +4,12 @@
/// Returns the minimum of [obj1] and [obj2] according to
/// [Comparable.compareTo].
-Comparable min(Comparable obj1, Comparable obj2) =>
+T min<T extends Comparable>(T obj1, T obj2) =>
obj1.compareTo(obj2) > 0 ? obj2 : obj1;
/// Returns the maximum of [obj1] and [obj2] according to
/// [Comparable.compareTo].
-Comparable max(Comparable obj1, Comparable obj2) =>
+T max<T extends Comparable>(T obj1, T obj2) =>
obj1.compareTo(obj2) > 0 ? obj1 : obj2;
/// Returns the number of instances of [codeUnit] in [string].
@@ -31,7 +31,7 @@
if (text.isEmpty) {
var beginningOfLine = 0;
while (true) {
- var index = context.indexOf("\n", beginningOfLine);
+ final index = context.indexOf("\n", beginningOfLine);
if (index == -1) {
return context.length - beginningOfLine >= column
? beginningOfLine
@@ -46,10 +46,11 @@
var index = context.indexOf(text);
while (index != -1) {
// Start looking before [index] in case [text] starts with a newline.
- var lineStart = index == 0 ? 0 : context.lastIndexOf('\n', index - 1) + 1;
- var textColumn = index - lineStart;
+ final lineStart = index == 0 ? 0 : context.lastIndexOf('\n', index - 1) + 1;
+ final textColumn = index - lineStart;
if (column == textColumn) return lineStart;
index = context.indexOf(text, index + 1);
}
+ // ignore: avoid_returning_null
return null;
}
diff --git a/test/file_test.dart b/test/file_test.dart
index 6759ca2..2cfe2d4 100644
--- a/test/file_test.dart
+++ b/test/file_test.dart
@@ -5,8 +5,8 @@
import 'package:test/test.dart';
import 'package:source_span/source_span.dart';
-main() {
- var file;
+void main() {
+ SourceFile file;
setUp(() {
file = SourceFile.fromString("""
foo bar baz
@@ -109,7 +109,7 @@
group("for span().union()", () {
test("source URLs must match", () {
- var other = SourceSpan(SourceLocation(10), SourceLocation(11), "_");
+ final other = SourceSpan(SourceLocation(10), SourceLocation(11), "_");
expect(() => file.span(9, 10).union(other), throwsArgumentError);
});
@@ -121,7 +121,7 @@
});
test("for span().expand() source URLs must match", () {
- var other = SourceFile.fromString("""
+ final other = SourceFile.fromString("""
foo bar baz
whiz bang boom
zip zap zop""", url: "bar.dart").span(10, 11);
@@ -148,13 +148,13 @@
group("span()", () {
test("returns a span between the given offsets", () {
- var span = file.span(5, 10);
+ final span = file.span(5, 10);
expect(span.start, equals(file.location(5)));
expect(span.end, equals(file.location(10)));
});
test("end defaults to the end of the file", () {
- var span = file.span(5);
+ final span = file.span(5);
expect(span.start, equals(file.location(5)));
expect(span.end, equals(file.location(file.length)));
});
@@ -238,8 +238,8 @@
});
test("pointSpan() returns a FileSpan", () {
- var location = file.location(15);
- var span = location.pointSpan();
+ final location = file.location(15);
+ final span = location.pointSpan();
expect(span, isA<FileSpan>());
expect(span.start, equals(location));
expect(span.end, equals(location));
@@ -258,26 +258,26 @@
group("context", () {
test("contains the span's text", () {
- var span = file.span(8, 15);
+ final span = file.span(8, 15);
expect(span.context.contains(span.text), isTrue);
expect(span.context, equals('foo bar baz\nwhiz bang boom\n'));
});
test("contains the previous line for a point span at the end of a line",
() {
- var span = file.span(25, 25);
+ final span = file.span(25, 25);
expect(span.context, equals('whiz bang boom\n'));
});
test("contains the next line for a point span at the beginning of a line",
() {
- var span = file.span(12, 12);
+ final span = file.span(12, 12);
expect(span.context, equals('whiz bang boom\n'));
});
group("for a point span at the end of a file", () {
test("without a newline, contains the last line", () {
- var span = file.span(file.length, file.length);
+ final span = file.span(file.length, file.length);
expect(span.context, equals('zip zap zop'));
});
@@ -288,57 +288,57 @@
zip zap zop
""", url: "foo.dart");
- var span = file.span(file.length, file.length);
+ final span = file.span(file.length, file.length);
expect(span.context, isEmpty);
});
});
});
group("union()", () {
- var span;
+ FileSpan span;
setUp(() {
span = file.span(5, 12);
});
test("works with a preceding adjacent span", () {
- var other = file.span(0, 5);
- var result = span.union(other);
+ final other = file.span(0, 5);
+ final result = span.union(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("foo bar baz\n"));
});
test("works with a preceding overlapping span", () {
- var other = file.span(0, 8);
- var result = span.union(other);
+ final other = file.span(0, 8);
+ final result = span.union(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("foo bar baz\n"));
});
test("works with a following adjacent span", () {
- var other = file.span(12, 16);
- var result = span.union(other);
+ final other = file.span(12, 16);
+ final result = span.union(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("ar baz\nwhiz"));
});
test("works with a following overlapping span", () {
- var other = file.span(9, 16);
- var result = span.union(other);
+ final other = file.span(9, 16);
+ final result = span.union(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("ar baz\nwhiz"));
});
test("works with an internal overlapping span", () {
- var other = file.span(7, 10);
+ final other = file.span(7, 10);
expect(span.union(other), equals(span));
});
test("works with an external overlapping span", () {
- var other = file.span(0, 16);
+ final other = file.span(0, 16);
expect(span.union(other), equals(other));
});
@@ -347,9 +347,9 @@
});
test("returns a base SourceSpan for a SourceSpan input", () {
- var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
SourceLocation(5, sourceUrl: "foo.dart"), "hey, ");
- var result = span.union(other);
+ final result = span.union(other);
expect(result, isNot(isA<FileSpan>()));
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
@@ -358,50 +358,50 @@
});
group("expand()", () {
- var span;
+ FileSpan span;
setUp(() {
span = file.span(5, 12);
});
test("works with a preceding nonadjacent span", () {
- var other = file.span(0, 3);
- var result = span.expand(other);
+ final other = file.span(0, 3);
+ final result = span.expand(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("foo bar baz\n"));
});
test("works with a preceding overlapping span", () {
- var other = file.span(0, 8);
- var result = span.expand(other);
+ final other = file.span(0, 8);
+ final result = span.expand(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("foo bar baz\n"));
});
test("works with a following nonadjacent span", () {
- var other = file.span(14, 16);
- var result = span.expand(other);
+ final other = file.span(14, 16);
+ final result = span.expand(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("ar baz\nwhiz"));
});
test("works with a following overlapping span", () {
- var other = file.span(9, 16);
- var result = span.expand(other);
+ final other = file.span(9, 16);
+ final result = span.expand(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("ar baz\nwhiz"));
});
test("works with an internal overlapping span", () {
- var other = file.span(7, 10);
+ final other = file.span(7, 10);
expect(span.expand(other), equals(span));
});
test("works with an external overlapping span", () {
- var other = file.span(0, 16);
+ final other = file.span(0, 16);
expect(span.expand(other), equals(other));
});
});
diff --git a/test/highlight_test.dart b/test/highlight_test.dart
index c215680..33719bc 100644
--- a/test/highlight_test.dart
+++ b/test/highlight_test.dart
@@ -2,13 +2,14 @@
// 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:term_glyph/term_glyph.dart' as glyph;
-import 'package:test/test.dart';
+// ignore_for_file: prefer_interpolation_to_compose_strings
import 'package:source_span/source_span.dart';
import 'package:source_span/src/colors.dart' as colors;
+import 'package:term_glyph/term_glyph.dart' as glyph;
+import 'package:test/test.dart';
-main() {
+void main() {
bool oldAscii;
setUpAll(() {
oldAscii = glyph.ascii;
@@ -19,7 +20,7 @@
glyph.ascii = oldAscii;
});
- var file;
+ SourceFile file;
setUp(() {
file = SourceFile.fromString("""
foo bar baz
@@ -37,7 +38,7 @@
});
test("gracefully handles a missing source URL", () {
- var span = SourceFile.fromString("foo bar baz").span(4, 7);
+ final span = SourceFile.fromString("foo bar baz").span(4, 7);
expect(span.highlight(), equals("""
,
1 | foo bar baz
@@ -122,7 +123,7 @@
});
test("on an empty line", () {
- var file = SourceFile.fromString("foo\n\nbar");
+ final file = SourceFile.fromString("foo\n\nbar");
expect(file.location(4).pointSpan().highlight(), equals("""
,
2 |
@@ -193,7 +194,7 @@
});
test("highlights the full first line even if it's indented", () {
- var file = SourceFile.fromString("""
+ final file = SourceFile.fromString("""
foo bar baz
whiz bang boom
zip zap zop
@@ -209,7 +210,7 @@
});
test("highlights the full first line if it's empty", () {
- var file = SourceFile.fromString("""
+ final file = SourceFile.fromString("""
foo
bar
@@ -241,7 +242,7 @@
});
test("highlights the full last line with a trailing Windows newline", () {
- var file = SourceFile.fromString("""
+ final file = SourceFile.fromString("""
foo bar baz\r
whiz bang boom\r
zip zap zop\r
@@ -268,7 +269,7 @@
test(
"highlights the full last line at the end of the file with no trailing "
"newline", () {
- var file = SourceFile.fromString("""
+ final file = SourceFile.fromString("""
foo bar baz
whiz bang boom
zip zap zop""");
@@ -283,7 +284,7 @@
});
test("highlights the full last line if it's empty", () {
- var file = SourceFile.fromString("""
+ final file = SourceFile.fromString("""
foo
bar
@@ -297,7 +298,7 @@
});
test("highlights multiple empty lines", () {
- var file = SourceFile.fromString("foo\n\n\n\nbar");
+ final file = SourceFile.fromString("foo\n\n\n\nbar");
expect(file.span(4, 7).highlight(), equals("""
,
2 | /
@@ -308,7 +309,7 @@
// Regression test for #32
test("highlights the end of a line and an empty line", () {
- var file = SourceFile.fromString("foo\n\n");
+ final file = SourceFile.fromString("foo\n\n");
expect(file.span(3, 5).highlight(), equals("""
,
1 | foo
@@ -321,7 +322,7 @@
group("prints tabs as spaces", () {
group("in a single-line span", () {
test("before the highlighted section", () {
- var span = SourceFile.fromString("foo\tbar baz").span(4, 7);
+ final span = SourceFile.fromString("foo\tbar baz").span(4, 7);
expect(span.highlight(), equals("""
,
@@ -331,7 +332,7 @@
});
test("within the highlighted section", () {
- var span = SourceFile.fromString("foo bar\tbaz bang").span(4, 11);
+ final span = SourceFile.fromString("foo bar\tbaz bang").span(4, 11);
expect(span.highlight(), equals("""
,
@@ -341,7 +342,7 @@
});
test("after the highlighted section", () {
- var span = SourceFile.fromString("foo bar\tbaz").span(4, 7);
+ final span = SourceFile.fromString("foo bar\tbaz").span(4, 7);
expect(span.highlight(), equals("""
,
@@ -353,7 +354,7 @@
group("in a multi-line span", () {
test("before the highlighted section", () {
- var span = SourceFile.fromString("""
+ final span = SourceFile.fromString("""
foo\tbar baz
whiz bang boom
""").span(4, 21);
@@ -368,7 +369,7 @@
});
test("within the first highlighted line", () {
- var span = SourceFile.fromString("""
+ final span = SourceFile.fromString("""
foo bar\tbaz
whiz bang boom
""").span(4, 21);
@@ -383,7 +384,7 @@
});
test("within a middle highlighted line", () {
- var span = SourceFile.fromString("""
+ final span = SourceFile.fromString("""
foo bar baz
whiz\tbang boom
zip zap zop
@@ -400,7 +401,7 @@
});
test("within the last highlighted line", () {
- var span = SourceFile.fromString("""
+ final span = SourceFile.fromString("""
foo bar baz
whiz\tbang boom
""").span(4, 21);
@@ -415,7 +416,7 @@
});
test("after the highlighted section", () {
- var span = SourceFile.fromString("""
+ final span = SourceFile.fromString("""
foo bar baz
whiz bang\tboom
""").span(4, 21);
@@ -433,7 +434,7 @@
group("supports lines of preceding and following context for a span", () {
test("within a single line", () {
- var span = SourceSpanWithContext(
+ final span = SourceSpanWithContext(
SourceLocation(20, line: 2, column: 5, sourceUrl: "foo.dart"),
SourceLocation(27, line: 2, column: 12, sourceUrl: "foo.dart"),
"foo bar",
@@ -450,7 +451,7 @@
});
test("covering a full line", () {
- var span = SourceSpanWithContext(
+ final span = SourceSpanWithContext(
SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"),
SourceLocation(33, line: 3, column: 0, sourceUrl: "foo.dart"),
"-----foo bar-----\n",
@@ -467,7 +468,7 @@
});
test("covering multiple full lines", () {
- var span = SourceSpanWithContext(
+ final span = SourceSpanWithContext(
SourceLocation(15, line: 2, column: 0, sourceUrl: "foo.dart"),
SourceLocation(23, line: 4, column: 0, sourceUrl: "foo.dart"),
"foo\nbar\n",
@@ -495,38 +496,38 @@
test("colorizes if color is true", () {
expect(file.span(4, 7).highlight(color: true), equals("""
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} foo ${colors.RED}bar${colors.NONE} baz
-${colors.BLUE} |${colors.NONE} ${colors.RED}^^^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.red}bar${colors.none} baz
+${colors.blue} |${colors.none} ${colors.red}^^^${colors.none}
+${colors.blue} '${colors.none}"""));
});
test("uses the given color if it's passed", () {
- expect(file.span(4, 7).highlight(color: colors.YELLOW), equals("""
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} foo ${colors.YELLOW}bar${colors.NONE} baz
-${colors.BLUE} |${colors.NONE} ${colors.YELLOW}^^^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+ expect(file.span(4, 7).highlight(color: colors.yellow), equals("""
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.yellow}bar${colors.none} baz
+${colors.blue} |${colors.none} ${colors.yellow}^^^${colors.none}
+${colors.blue} '${colors.none}"""));
});
test("colorizes a multiline span", () {
expect(file.span(4, 34).highlight(color: true), equals("""
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} foo ${colors.RED}bar baz${colors.NONE}
-${colors.BLUE} |${colors.NONE} ${colors.RED},-----^${colors.NONE}
-${colors.BLUE}2 |${colors.NONE} ${colors.RED}| whiz bang boom${colors.NONE}
-${colors.BLUE}3 |${colors.NONE} ${colors.RED}| zip zap${colors.NONE} zop
-${colors.BLUE} |${colors.NONE} ${colors.RED}'-------^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} foo ${colors.red}bar baz${colors.none}
+${colors.blue} |${colors.none} ${colors.red},-----^${colors.none}
+${colors.blue}2 |${colors.none} ${colors.red}| whiz bang boom${colors.none}
+${colors.blue}3 |${colors.none} ${colors.red}| zip zap${colors.none} zop
+${colors.blue} |${colors.none} ${colors.red}'-------^${colors.none}
+${colors.blue} '${colors.none}"""));
});
test("colorizes a multiline span that highlights full lines", () {
expect(file.span(0, 39).highlight(color: true), equals("""
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} ${colors.RED}/ foo bar baz${colors.NONE}
-${colors.BLUE}2 |${colors.NONE} ${colors.RED}| whiz bang boom${colors.NONE}
-${colors.BLUE}3 |${colors.NONE} ${colors.RED}\\ zip zap zop${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.red}/ foo bar baz${colors.none}
+${colors.blue}2 |${colors.none} ${colors.red}| whiz bang boom${colors.none}
+${colors.blue}3 |${colors.none} ${colors.red}\\ zip zap zop${colors.none}
+${colors.blue} '${colors.none}"""));
});
});
diff --git a/test/location_test.dart b/test/location_test.dart
index 9032936..c0e9c07 100644
--- a/test/location_test.dart
+++ b/test/location_test.dart
@@ -2,11 +2,11 @@
// 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:test/test.dart';
import 'package:source_span/source_span.dart';
+import 'package:test/test.dart';
-main() {
- var location;
+void main() {
+ SourceLocation location;
setUp(() {
location = SourceLocation(15, line: 2, column: 6, sourceUrl: "foo.dart");
});
@@ -48,19 +48,19 @@
});
test('gracefully handles a missing source URL', () {
- var location = SourceLocation(15, line: 2, column: 6);
+ final location = SourceLocation(15, line: 2, column: 6);
expect(location.toolString, equals('unknown source:3:7'));
});
});
test("distance returns the absolute distance between locations", () {
- var other = SourceLocation(10, sourceUrl: "foo.dart");
+ final other = SourceLocation(10, sourceUrl: "foo.dart");
expect(location.distance(other), equals(5));
expect(other.distance(location), equals(5));
});
test("pointSpan returns an empty span at location", () {
- var span = location.pointSpan();
+ final span = location.pointSpan();
expect(span.start, equals(location));
expect(span.end, equals(location));
expect(span.text, isEmpty);
@@ -68,7 +68,7 @@
group("compareTo()", () {
test("sorts by offset", () {
- var other = SourceLocation(20, sourceUrl: "foo.dart");
+ final other = SourceLocation(20, sourceUrl: "foo.dart");
expect(location.compareTo(other), lessThan(0));
expect(other.compareTo(location), greaterThan(0));
});
@@ -80,17 +80,17 @@
group("equality", () {
test("two locations with the same offset and source are equal", () {
- var other = SourceLocation(15, sourceUrl: "foo.dart");
+ final other = SourceLocation(15, sourceUrl: "foo.dart");
expect(location, equals(other));
});
test("a different offset isn't equal", () {
- var other = SourceLocation(10, sourceUrl: "foo.dart");
+ final other = SourceLocation(10, sourceUrl: "foo.dart");
expect(location, isNot(equals(other)));
});
test("a different source isn't equal", () {
- var other = SourceLocation(15, sourceUrl: "bar.dart");
+ final other = SourceLocation(15, sourceUrl: "bar.dart");
expect(location, isNot(equals(other)));
});
});
diff --git a/test/span_test.dart b/test/span_test.dart
index 6a18b42..d53e1e0 100644
--- a/test/span_test.dart
+++ b/test/span_test.dart
@@ -8,7 +8,7 @@
import 'package:source_span/source_span.dart';
import 'package:source_span/src/colors.dart' as colors;
-main() {
+void main() {
bool oldAscii;
setUpAll(() {
oldAscii = glyph.ascii;
@@ -19,7 +19,7 @@
glyph.ascii = oldAscii;
});
- var span;
+ SourceSpan span;
setUp(() {
span = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
SourceLocation(12, sourceUrl: "foo.dart"), "foo bar");
@@ -28,42 +28,42 @@
group('errors', () {
group('for new SourceSpan()', () {
test('source URLs must match', () {
- var start = SourceLocation(0, sourceUrl: "foo.dart");
- var end = SourceLocation(1, sourceUrl: "bar.dart");
+ final start = SourceLocation(0, sourceUrl: "foo.dart");
+ final end = SourceLocation(1, sourceUrl: "bar.dart");
expect(() => SourceSpan(start, end, "_"), throwsArgumentError);
});
test('end must come after start', () {
- var start = SourceLocation(1);
- var end = SourceLocation(0);
+ final start = SourceLocation(1);
+ final end = SourceLocation(0);
expect(() => SourceSpan(start, end, "_"), throwsArgumentError);
});
test('text must be the right length', () {
- var start = SourceLocation(0);
- var end = SourceLocation(1);
+ final start = SourceLocation(0);
+ final end = SourceLocation(1);
expect(() => SourceSpan(start, end, "abc"), throwsArgumentError);
});
});
group('for new SourceSpanWithContext()', () {
test('context must contain text', () {
- var start = SourceLocation(2);
- var end = SourceLocation(5);
+ final start = SourceLocation(2);
+ final end = SourceLocation(5);
expect(() => SourceSpanWithContext(start, end, "abc", "--axc--"),
throwsArgumentError);
});
test('text starts at start.column in context', () {
- var start = SourceLocation(3);
- var end = SourceLocation(5);
+ final start = SourceLocation(3);
+ final end = SourceLocation(5);
expect(() => SourceSpanWithContext(start, end, "abc", "--abc--"),
throwsArgumentError);
});
test('text starts at start.column of line in multi-line context', () {
- var start = SourceLocation(4, line: 55, column: 3);
- var end = SourceLocation(7, line: 55, column: 6);
+ final start = SourceLocation(4, line: 55, column: 3);
+ final end = SourceLocation(7, line: 55, column: 6);
expect(() => SourceSpanWithContext(start, end, "abc", "\n--abc--"),
throwsArgumentError);
expect(() => SourceSpanWithContext(start, end, "abc", "\n----abc--"),
@@ -77,10 +77,10 @@
});
test('text can occur multiple times in context', () {
- var start1 = SourceLocation(4, line: 55, column: 2);
- var end1 = SourceLocation(7, line: 55, column: 5);
- var start2 = SourceLocation(4, line: 55, column: 8);
- var end2 = SourceLocation(7, line: 55, column: 11);
+ final start1 = SourceLocation(4, line: 55, column: 2);
+ final end1 = SourceLocation(7, line: 55, column: 5);
+ final start2 = SourceLocation(4, line: 55, column: 8);
+ final end2 = SourceLocation(7, line: 55, column: 11);
SourceSpanWithContext(start1, end1, "abc", "--abc---abc--\n");
SourceSpanWithContext(start1, end1, "abc", "--abc--abc--\n");
SourceSpanWithContext(start2, end2, "abc", "--abc---abc--\n");
@@ -96,14 +96,14 @@
group('for union()', () {
test('source URLs must match', () {
- var other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"),
+ final other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"),
SourceLocation(13, sourceUrl: "bar.dart"), "_");
expect(() => span.union(other), throwsArgumentError);
});
test('spans may not be disjoint', () {
- var other = SourceSpan(SourceLocation(13, sourceUrl: 'foo.dart'),
+ final other = SourceSpan(SourceLocation(13, sourceUrl: 'foo.dart'),
SourceLocation(14, sourceUrl: 'foo.dart'), "_");
expect(() => span.union(other), throwsArgumentError);
@@ -111,7 +111,7 @@
});
test('for compareTo() source URLs must match', () {
- var other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"),
+ final other = SourceSpan(SourceLocation(12, sourceUrl: "bar.dart"),
SourceLocation(13, sourceUrl: "bar.dart"), "_");
expect(() => span.compareTo(other), throwsArgumentError);
@@ -127,54 +127,54 @@
group("union()", () {
test("works with a preceding adjacent span", () {
- var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
SourceLocation(5, sourceUrl: "foo.dart"), "hey, ");
- var result = span.union(other);
+ final result = span.union(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("hey, foo bar"));
});
test("works with a preceding overlapping span", () {
- var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
SourceLocation(8, sourceUrl: "foo.dart"), "hey, foo");
- var result = span.union(other);
+ final result = span.union(other);
expect(result.start, equals(other.start));
expect(result.end, equals(span.end));
expect(result.text, equals("hey, foo bar"));
});
test("works with a following adjacent span", () {
- var other = SourceSpan(SourceLocation(12, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(12, sourceUrl: "foo.dart"),
SourceLocation(16, sourceUrl: "foo.dart"), " baz");
- var result = span.union(other);
+ final result = span.union(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("foo bar baz"));
});
test("works with a following overlapping span", () {
- var other = SourceSpan(SourceLocation(9, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(9, sourceUrl: "foo.dart"),
SourceLocation(16, sourceUrl: "foo.dart"), "bar baz");
- var result = span.union(other);
+ final result = span.union(other);
expect(result.start, equals(span.start));
expect(result.end, equals(other.end));
expect(result.text, equals("foo bar baz"));
});
test("works with an internal overlapping span", () {
- var other = SourceSpan(SourceLocation(7, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(7, sourceUrl: "foo.dart"),
SourceLocation(10, sourceUrl: "foo.dart"), "o b");
expect(span.union(other), equals(span));
});
test("works with an external overlapping span", () {
- var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
SourceLocation(16, sourceUrl: "foo.dart"), "hey, foo bar baz");
expect(span.union(other), equals(other));
@@ -192,7 +192,7 @@
});
test("gracefully handles a missing source URL", () {
- var span = SourceSpan(SourceLocation(5), SourceLocation(12), "foo bar");
+ final span = SourceSpan(SourceLocation(5), SourceLocation(12), "foo bar");
expect(span.message("oh no"), equalsIgnoringWhitespace("""
line 1, column 6: oh no
@@ -203,7 +203,7 @@
});
test("gracefully handles empty text", () {
- var span = SourceSpan(SourceLocation(5), SourceLocation(5), "");
+ final span = SourceSpan(SourceLocation(5), SourceLocation(5), "");
expect(span.message("oh no"), equals("line 1, column 6: oh no"));
});
@@ -220,40 +220,40 @@
test("colorizes if color is true", () {
expect(span.message("oh no", color: true), equals("""
line 1, column 6 of foo.dart: oh no
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} ${colors.RED}foo bar${colors.NONE}
-${colors.BLUE} |${colors.NONE} ${colors.RED}^^^^^^^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.red}foo bar${colors.none}
+${colors.blue} |${colors.none} ${colors.red}^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
});
test("uses the given color if it's passed", () {
- expect(span.message("oh no", color: colors.YELLOW), equals("""
+ expect(span.message("oh no", color: colors.yellow), equals("""
line 1, column 6 of foo.dart: oh no
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} ${colors.YELLOW}foo bar${colors.NONE}
-${colors.BLUE} |${colors.NONE} ${colors.YELLOW}^^^^^^^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} ${colors.yellow}foo bar${colors.none}
+${colors.blue} |${colors.none} ${colors.yellow}^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
});
test("with context, underlines the right column", () {
- var spanWithContext = SourceSpanWithContext(
+ final spanWithContext = SourceSpanWithContext(
SourceLocation(5, sourceUrl: "foo.dart"),
SourceLocation(12, sourceUrl: "foo.dart"),
"foo bar",
"-----foo bar-----");
- expect(spanWithContext.message("oh no", color: colors.YELLOW), equals("""
+ expect(spanWithContext.message("oh no", color: colors.yellow), equals("""
line 1, column 6 of foo.dart: oh no
-${colors.BLUE} ,${colors.NONE}
-${colors.BLUE}1 |${colors.NONE} -----${colors.YELLOW}foo bar${colors.NONE}-----
-${colors.BLUE} |${colors.NONE} ${colors.YELLOW}^^^^^^^${colors.NONE}
-${colors.BLUE} '${colors.NONE}"""));
+${colors.blue} ,${colors.none}
+${colors.blue}1 |${colors.none} -----${colors.yellow}foo bar${colors.none}-----
+${colors.blue} |${colors.none} ${colors.yellow}^^^^^^^${colors.none}
+${colors.blue} '${colors.none}"""));
});
});
group("compareTo()", () {
test("sorts by start location first", () {
- var other = SourceSpan(SourceLocation(6, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(6, sourceUrl: "foo.dart"),
SourceLocation(14, sourceUrl: "foo.dart"), "oo bar b");
expect(span.compareTo(other), lessThan(0));
@@ -261,7 +261,7 @@
});
test("sorts by length second", () {
- var other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
SourceLocation(14, sourceUrl: "foo.dart"), "foo bar b");
expect(span.compareTo(other), lessThan(0));
@@ -275,28 +275,28 @@
group("equality", () {
test("two spans with the same locations are equal", () {
- var other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
SourceLocation(12, sourceUrl: "foo.dart"), "foo bar");
expect(span, equals(other));
});
test("a different start isn't equal", () {
- var other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(0, sourceUrl: "foo.dart"),
SourceLocation(12, sourceUrl: "foo.dart"), "hey, foo bar");
expect(span, isNot(equals(other)));
});
test("a different end isn't equal", () {
- var other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
+ final other = SourceSpan(SourceLocation(5, sourceUrl: "foo.dart"),
SourceLocation(16, sourceUrl: "foo.dart"), "foo bar baz");
expect(span, isNot(equals(other)));
});
test("a different source URL isn't equal", () {
- var other = SourceSpan(SourceLocation(5, sourceUrl: "bar.dart"),
+ final other = SourceSpan(SourceLocation(5, sourceUrl: "bar.dart"),
SourceLocation(12, sourceUrl: "bar.dart"), "foo bar");
expect(span, isNot(equals(other)));
diff --git a/test/utils_test.dart b/test/utils_test.dart
index a8146e3..a4a372e 100644
--- a/test/utils_test.dart
+++ b/test/utils_test.dart
@@ -5,18 +5,18 @@
import 'package:test/test.dart';
import 'package:source_span/src/utils.dart';
-main() {
+void main() {
group('find line start', () {
test('skip entries in wrong column', () {
- var context = '0_bb\n1_bbb\n2b____\n3bbb\n';
- var index = findLineStart(context, 'b', 1);
+ final context = '0_bb\n1_bbb\n2b____\n3bbb\n';
+ final index = findLineStart(context, 'b', 1);
expect(index, 11);
expect(context.substring(index - 1, index + 3), '\n2b_');
});
test('end of line column for empty text', () {
- var context = '0123\n56789\nabcdefgh\n';
- var index = findLineStart(context, '', 5);
+ final context = '0123\n56789\nabcdefgh\n';
+ final index = findLineStart(context, '', 5);
expect(index, 5);
expect(context[index], '5');
});
@@ -33,25 +33,25 @@
});
test('empty text in empty context', () {
- var index = findLineStart('', '', 0);
+ final index = findLineStart('', '', 0);
expect(index, 0);
});
test('found on the first line', () {
- var context = '0\n2\n45\n';
- var index = findLineStart(context, '0', 0);
+ final context = '0\n2\n45\n';
+ final index = findLineStart(context, '0', 0);
expect(index, 0);
});
test('finds text that starts with a newline', () {
- var context = '0\n2\n45\n';
- var index = findLineStart(context, '\n2', 1);
+ final context = '0\n2\n45\n';
+ final index = findLineStart(context, '\n2', 1);
expect(index, 0);
});
test('not found', () {
- var context = '0\n2\n45\n';
- var index = findLineStart(context, '0', 1);
+ final context = '0\n2\n45\n';
+ final index = findLineStart(context, '0', 1);
expect(index, isNull);
});
});